Google
 

Trailing-Edge - PDP-10 Archives - tops20-v7-ft-dist2-clock - galaxy-sources/mountr.mac
There are 35 other files named mountr.mac in the archive. Click here to see a list.
TITLE	MOUNTR
SUBTTL	Preliminaries

;	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1979, 1988.
;	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 THAT IS NOT SUPPLIED BY DIGITAL.


; Required UNV and REL files

	SEARCH MTRMAC
	SEARCH MONSYM,MACSYM,ACTSYM,SERCOD,GLXMAC,QSRMAC,ORNMAC,NEBMAC
	.REQUIRE SYS:MACREL
SUBTTL Version Information
; Version Information

	MTRVER==6		;MAJOR VERSION #
	MTRMIN==0		;MINOR VERSION #
	MTRMAN==0		;Maintenance edit level
	MTRDEV==6032		;Development edit level
	MTRWHO==0		;GROUP WHO LAST EDITED (0=DEC DEVELOPMENT)

	VERSIN (MTR)		;Generate version number

	EXTERNAL CFSMAN,CFSDEV,CFSEDT,USRMAN,USRDEV,USREDT

;  Externals used from MTRDDB

	EXTERNAL DSFINI		;Initialize disk data base
	EXTERNAL DSFUDE		;Update disk entry
	EXTERNAL DSFGET		;Get disk entry
	EXTERNAL DSFGNX		;Get next entry of specific type
	EXTERNAL DSFCRE		;Create disk entry
	EXTERNAL DSFLOC		;Locate disk entry
	EXTERNAL DSFNUP,DSFYUP	;Routines to stop/start updating of DDB
	EXTERNAL DSFDLE		;Delete disk entry

	EXTERNAL DSFE
	EXTERNAL PRTINI,CFSCHK

	MTRVER==<VRSN.(MTR)>+CFSEDT+USREDT+MACEDT

MTRVEC:	BLDVEC (MOUNTR,MTR,L)
	BLDVEC (MTRCFS,CFS)
	BLDVEC (MTRUSR,USR)
	BLDVEC (MTRMAC,MAC,L)
	BLDVEC (GLXMAC,GMC,L)
	BLDVEC (ORNMAC,OMC,L)
	BLDVEC (QSRMAC,QMC,L)

	EXTERN .JBOPS		;JOBDAT CELL COMMANDEERED FOR TEST FLAG
	EXTERN .JBSA		;LH/ ADDR OF 1ST LOCATION AFTER PROGRAM
	EXTERN .JBSYM		;POINTER TO SYMBOL TABLE FOR DDT
	EXTERN .RLEND		;LAST LOCATION IN MACREL

	SALL
	.DIRECTIVE FLBLST	;SUPPRESS ASCIZ MACHINE CODE EXPANSION
	SUBTTL	Table of Contents


;		Table of Contents for MOUNTR
;
;
;			   Section			      Page
;   1. Preliminaries. . . . . . . . . . . . . . . . . . . . .    1
;   2. Version Information. . . . . . . . . . . . . . . . . .    2
;   3. Table of Contents. . . . . . . . . . . . . . . . . . .    3
;   4. Edit history . . . . . . . . . . . . . . . . . . . . .    4
;   5. PREFACE. . . . . . . . . . . . . . . . . . . . . . . .    5
;   6. MODIFYABLE DATA AREA . . . . . . . . . . . . . . . . .    9
;   7. STORAGE AREA FOR USAGE DATA. . . . . . . . . . . . . .   10
;   8. STATIC DATA AREA . . . . . . . . . . . . . . . . . . .   11
;   9. INITIALIZATION . . . . . . . . . . . . . . . . . . . .   17
;  10. SERVICE SCHEDULER (SS) . . . . . . . . . . . . . . . .   18
;  11. ACCOUNTING ROUTINES. . . . . . . . . . . . . . . . . .   21
;  12. AVR - AUTOMATIC VOLUME RECOGNITION . . . . . . . . . .   27
;  13. DECTAPE SUPPORT. . . . . . . . . . . . . . . . . . . .   36
;  14. IPCF SEND AND RECEIVE. . . . . . . . . . . . . . . . .   39
;  15. LABELED TAPE INITIALIZATION. . . . . . . . . . . . . .   47
;  16. OPERATOR INTERFACE . . . . . . . . . . . . . . . . . .   52
;  17. QUASAR INTERFACE . . . . . . . . . . . . . . . . . . .   85
;  18. STRUCTURE ROUTINES . . . . . . . . . . . . . . . . . .   95
;  19. Update all disks
;       19.1.   Flow of update. . . . . . . . . . . . . . . .   96
;       19.2.   DDSCIH - Update all disk drives . . . . . . .   97
;       19.3.   DSTINI - Initialize MSTR block for scanning units   98
;       19.4.   DSTNXT - Get status of the next disk. . . . .   98
;       19.5.   DSTSRC - LOOK FOR THE DISK ENTRY MATCHING SPECIFIED CKU NUMBERS   99
;       19.6.   DDSNEW - Add new disk to data bases . . . . .  100
;       19.7.   DDSCHK - Check disk already existing. . . . .  101
;       19.8.   DDSDEL - DELETE STRUCTURE INFORMATION ABOUT A DISK 102
;       19.9.   DDSADD - ADD A DISK COMING ON-LINE. . . . . .  103
;       19.10.  STRINF - Store/check structure information. .  104
;       19.11.  STRGSB - GET STRUCTURE STATUS BLOCK (BUILD ONE IF NECESSARY) 107
;       19.12.  STRDSM - Dismount structure data base . . . .  108
;       19.13.  DDSMCH - MATCH USER REQUEST TO MOUNTS AND DISMOUNTS  109
;       19.14.  DSTDDB - Delete STructure DDB . . . . . . . .  110
;  20. Disk Routines
;       20.1.   DSKINI - Disk initialization routine. . . . .  111
;       20.2.   DSTGIV - Get status for a given unit. . . . .  112
;  21. KSDK - Set disk-drive command from OPR . . . . . . . .  113
;  22. KDSM - PROCESS DISMOUNT STRUCTURE COMMAND FROM OPR . .  114
;  23. KSHD - SHOW DISK STATUS COMMAND FROM OPR . . . . . . .  115
;  24. - DSKDSP - Print any special messages. . . . . . . . .  116
;  25. KSHS - SHOW STATUS STRUCTURE command from OPR. . . . .  117
;  26. STRDSP - Print any special messages. . . . . . . . . .  118
;  27. SHSTR - Show status for a particular structure . . . .  119
;  28. SHSMAC - Adds a user who has mounted or connected or accessing a structure to the SHO STA STR FOO: command. 120
;  29. SHWSTR - Show status for a single structure. . . . . .  121
;  30. - SHWCON
;       30.1.   Indicates structure status conflicts. . . . .  122
;  31. Process set structure (KSST)
;       31.1.   Initialize processing of command. . . . . . .  123
;       31.2.   Set the database (DDB). . . . . . . . . . . .  124
;       31.3.   Set structure correctly in monitor. . . . . .  125
;  32. KSST
;       32.1.   Data base for setable characteristics . . . .  126
;  33. STSTR - SeT STRucture. . . . . . . . . . . . . . . . .  127
;  34. KSUD - Undefine structure. . . . . . . . . . . . . . .  128
;  35. UPDSTR - Update structure. . . . . . . . . . . . . . .  129
;  36. Determine-new-string routine (NEWSTA)
;       36.1.   Determine STRFLG based on MOUNTR and disk status 131
;  37. CHKAVA - Check SSB disk drives for available/unavailable  132
;  38. SSB routines
;       38.1.   SSBINI - Initialize SSB data base . . . . . .  133
;       38.2.   SSBCRE - Create a new SSB entry (zeroed). . .  133
;       38.3.   SSBRET - Return SSB entry to free SSB pool. .  133
;       38.4.   SSBNXT - Get next SSB . . . . . . . . . . . .  134
;       38.5.   MATCHS - Match request to structure (old) . .  135
;  39. ISTDDB - Initialize structure DDB. . . . . . . . . . .  137
;  40. MESCHK - CHECK IF MESSAGE FOR STRUCTURE ALREADY SENT TO OPERATOR  138
;  41. MNTALL - MOUNT ALL STRUCTURES NOT ALREADY MOUNTED. . .  139
;  42. OPRSB - SET UP REQUEST BLOCK FOR OPR MOUNT OR DISMOUNT COMMAND  140
;  43. PSDR - PARSE OPERATOR RESPONSE TO DISMOUNT MESSAGE WHEN OTHER JOBS  141
;  44. SEVSIX - ROUTINE TO CONVERT 7-BIT ASCII TO 6-BIT . . .  142
;  45. SIXSEV - ROUTINE TO CONVERT SIXBIT TO ASCIZ. . . . . .  142
;  46. STRDMT - DISMOUNT A STRUCTURE (OPR>DISMOUNT STRUCTURE FOO:) 143
;  47. STRUNA - SET STR UNAVAILABLE . . . . . . . . . . . . .  145
;  48. Operator Communication . . . . . . . . . . . . . . . .  146
;  49. STRMNT - MOUNT A STRUCTURE . . . . . . . . . . . . . .  147
;  50. WOFRE - SET UP STRING CONTAINING INFORMATION ON FREE DRIVE  154
;  51. - WOINI
;       51.1.   Fills in the first five fields of the display  155
;  52. WOMDAV - TELL OPERATOR OF AVAILABILITY OF DISK DRIVE FOR SYSTEM USE 157
;  53. WOSM - TELL OPERATOR OF A STRUCTURE. . . . . . . . . .  158
;  54. USER TAPE MOUNT REQUEST. . . . . . . . . . . . . . . .  162
;  55. VOLUME/REQUEST ASSOCIATION LOGIC . . . . . . . . . . .  174
;  56. SUBROUTINES. . . . . . . . . . . . . . . . . . . . . .  185
;  57. STRSTT
;       57.1.   Returns the structure status. . . . . . . . .  222
SUBTTL	Edit history

Comment ^

*****	Release 4.2 -- Begin Maintenance Edits *****

154	4.2.1537	12-jan-83
	Add procedure procedure WTOCHK and calls to WTOCHK so that batch
jobs with /assistance:no will have any mount request requiring asistance 
disallowed.

155	4.2.1538	12-jan-83
	Increase number of requests allowed to 400

156	4.2.1539	13-jan-83
 	If the first mount request is canceled and the structure has not 
been mounted, make sure OPR gets mount request message on awaiting request.

157	4.2.1540	27-Jan-83
	Set or clear the correct bit in STRFLG(STR) when a change of structure
status occurs.  Also if operator refuse to dismount a structure, restore the 
structure status if there was no change.

160	4.2.1544	17-mar-83
	Add check for bad HOME or BAT blocks and inform operator.  Also check 
for disk in use by on-line diagnostic program before mount.

161	4.2.1549	14-Jun-83
	Change 1 line of edit 157 so that AC F will not get clobber if the 
structure is to be set unavailable.

162     4.2.1569	15-Mar-84
        Set the controller type field to zero in the usage records. Also set
the access type field to 1.

163	4.2.1575	3-May-84
	Do not crash if SYSTEM:INFO is not running when sending an IPCF message
message .Instead, inform the operator, sleep for 30 seconds and then attempt to
send another message.

164	4.2.1577	10-May-84
	When multiple tapes with numeric IDs are being initialized, cause 
MOUNTR to increment the next ID without asking the operator.

165	4.2.1583	25-Jul-84
	Do not abort tape mount requests if all the tape drives have been set
unavailable, instead queue the request and inform the operator that all the
tape drives are unavailable.

166	4.2.1588	21-Aug-84
	Create left justified tape numeric volume i.d.s with the OPR SET TAPE
INITIALIZE command.

167	4.2.1595	26-Sep-84
	Correct the way edit 163 searches and branches from table MTBL upon
an IPCF failure.

170	4.2.1600	10-Jan-85
	If a tape is initialized with leading zeros in its volume i.d.,
do not suppress them.

171	4.2.1606	29-Jan-85
	Do not reset the density of a tape drive when dismounting a tape.

172	4.2.1615	26-Apr-85
	Do not crash immediately upon a MUTIL% JSYS error when attempting to
get a system PID, instead try up to NTRY times before crashing.

*****	Release 5.0 -- Begin Development Edits *****

200	5.1000		3-jan-83
	Move to new development area.  Change to new edit history format.  
Change edit level designations to conform to new Galaxy standard.

201	5.1001		4-jan-83
	Support system/job default for tape drives instead of hardcoding a 
default of 1600

202	5.1005		10-jan-83
	Add version vector.

203	5.1015		4-MAR-83
	Move macro and data definitions to MTRMAC.  Add MTRCFS and MTRUSR to 
version vector.

204	5.1018		16-mar-83
	Move command table back to MOUNTR.  Add disk types for Ra80, Ra81, Ra60

205	5.1020		29-mar-83
	Due to increasing numbers of disks and tapes which are available to
TOPS-20, IPCF messages must be divided into packets with no more than wtomax 
(defined on ornmac) words of text.

206	5.1020		4-apr-83
	Need to count bytes of header as well as body of text when dividing 
ipcf messages into packets.

207	5.1022		7-apr-83
	Add check for CI port when outputting disk status display.  Abbreviate
oprtions in disk status display.

210	5.1029		24-may-83
	Add support for SET PORT command.  Enlarge filed for unit display to 4.
Make several routine labels global.

211	5.1030		22-june-83
	Modify structure dismount procedures for port operations.

212	5.1031		29-june-83
	Add calls to CFS dismount routines.

213	5.1032		30-june-83
	Add code to add or delete or replace a structure entry from the 
device-status data base.  MOUNTR will mount a structure based on status 
obtained from the device-status data base.

214	5.1033		6-july-83
	Add a call to routine CFSCHK in MTRCFS to see if we are in a CFS 
system.  The return value for CFSP is 0 for not CFS and 1 for CFS.

215	5.1040		30-Sep-83
	Redesign and rewrite the dismount code so that a dismount operation
and a dismount via a port operation can both use the common code and have each
operation handle the possible results from the dismount accordingly.

216	5,1044		14-Oct-83
	Add code to enforce the FORCE response from a port operation.  Make 
WOMDAV an external symbol.  Make sure we do not touch AC0 accidentally.

217	5.1052		31-Oct-83
	Add code to handle setting a structure exclusive.

220	5.1055		8-Nov-83
	Add code to support REMOVE/NOREMOVE function in DISMOUNT command

221	5.1056		14-Nov-83
	Fix code to handle setting a structure EXCLUSIVE while dismounting a
structure with REMOVAL in a CFS configuration and fix other bugs relating to 
DISMOUNTING a structure in a CFS configuration 	(REMOVAL/NOREMOVAL and default)

222	5.1054		15-Nov-83
	First change the above GCO# from 5.1054 to 5.1056.  Add code to set a 
structure exclusive.

223	5.1060		28-Nov-83
	Do not use SETFLG to check whether a port operation is FORCE.  Check
RSBIFL(RSB) bit R%REP.  If R%REP is set, a FORCE action is to be taken.

224	5.1062		29-Nov-83
	During start up, call a new routine, PRTINI, to check for port 
unavailability.

225	5.1065		9-Dec-83
	Fix bad test for exclusive in KSSER2.

226	5.1068		9-Dec-83
	Remove DSFxxx routines and move them to MTRDDB.  Since we
did that, a bad STOR instruction broke in PRTINI.  Fix that as well.

227	5.1079		4-Feb-84
	Lots of changes:
1.  Change all references to DDB routines to use new DDB routines.
2.  Add table of contents.
3.  Redo SHOW STATUS DISK DISPLAY
4.  Add SHOW STATUS STRUCTURE display.
5.  Add SHOW STATUS STRUCTURE FOO: display.
6.  Rearrange a number of the disk status update routines so they are together.
7.  Disable write protecting code because that gets in the way a lot.  We
    need to have storage in other modules and that is impossible with the
    current write protection scheme.
8.  Instead of using MSTRBK everywhere and having things get confused, make
    some additional locations to have MSTR argument blocks depending on the
    action occuring.
9.  For consistancy, make any bit referencing available 0 if available and 1 if
    unavailable.
10. In the DDSxxx routines, rearrange the logic to take advantage of the new
    DDB support.  In addition, make MOUNTR able to detect changes instead of
    simply accepting them, and correct some of them.  In all cases, inform
    the operator that the changes are occuring.
11. Change the management of the SSBs and create some routines to manage them:
    SSBINI - Initialize the SSB data base
    SSBCRE - Create a new SSB entry
    SSBRET - Return SSB entry to the free pool.
    SSBNXT - Get the next SSB entry.
12. Eliminate the old logic for ignore attribute.  The attribute is now
    included with the DDB entry for the structure.
13. Only mount all available structures during initialization if this is in
    CFS.
14. Rearrange the whole way we manage the unavailable attribute.  Besides a
    device being unavailable due to its attribute set, it may also be 
    unavailable due to another object that may affect it.
15. Support for new $STOP macro.

Lots of little things as well.  The above is the gist of things.

230	5.1081		6-Feb-84
	Add support for undefine structure command.

231	5.1082		6-Feb-84
	Use structure header instead of disk header for SHOW STATUS STRUCTURE.

232	5.1084		10-Feb-84
	Reformat the SHOW STA STR FOO: display. Only print one user for each
usage of the structure. Include the disk information.  The CKU is to be printed
in decimal.  Include an asterisk for dual ported disks.

233	5.1085		10-Feb-84
	Make sure the disk type field starts printing in colume 2.

234	5.1086		11-Feb-84
	If we are switching disk ports, always defer adding the new port info
until after deleting old port info.  Indicate need for second disk status pass
with flag AGAIN.  Set DSKSSA to minus one to indicate such an event is in 
progress for the disk and to prevent looping.

235	5.1087		11-Feb-84
	Unfortunatly, ABTRET takes up more than one word.  Skipping around
it doesn't make it.  JRST to it as a literal @MNTNXT+1.

236	5.1088		11-Feb-84
	Remove the code used to support MOUNTR.CMD.

237	5.1090		11-Feb-84
	Clear the pointer to the structure status block when forgetting the
structure in DDSDEL.

240	5.1091		11-Feb-84
	Add an extra CRLF to error message at DDSERR.

241	5.1096		14-Feb-84
	Add a check for offline, free and mounted before we print the state
of a disk.  Initialize TMCMSG before we print the "No disk available" message.

242	5.1097		14-Feb-84
	Write two subroutines (STRDSP, DSKDSP) to print special messages.

243	5.1100		17-Feb-84
	In routine WOMNT3 call DSFLOC to get the structure entry from the DDB.

244	5.1103		20-Feb-84
	In routine STRFND if we find the DSB pointer in the SSB already set,
then check if it is set to the current DSK before assuming a problem.

245	5.1104		20-Feb-84
	Clear STRPNT in DSTDDB.  Remove routine STRDME.  Call DSTDDB from
STRDMS.

246	5.1107		23-Feb-84
	In routine SHW1, get the conflicting bits in T1 before checking for 
status of structure.

247	5.1108		25-Feb-84
	Remove special casing in the dismount code.  Create and use ascii
string DSMHDR for dismount query.  Move test for Ignore until after the
status has been updated.  Remove confused code from WOVDS.

250	5.1109		27-Feb-84
	Add more bad bits to check for at STRIN2.  Add information to the
display to say which bad bits are set.  Move STRIN7 label down some lines to
skip over code to set up DDB info for the structure.

251	5.1110		28-Feb-84
	Add message to show status structure indicating structure
is exclusive due to port operation.  Do the STR%EP check earlier
so a public structure's exclusive bit gets set correctly.  Make MOVE
a MOVEI T1,.DVSTR.

252	5.1112		1-Mar-84
	Add routine KSMT to handle MOUNT STRUCTURE command from OPR.  Delete
all tabs at the beginning of the second line in the edit history.  Show only
one dismount message when dismounting a structure via port operation.  When 
displaying structure status and structure is not mounted, it is still
possible get a SSB on a structure if that structure is being dismounted.

253	5.1113		5-Mar-84	
	Fix KSMT so that the MOUNT command will mount structures that are not
physically mounted first and clear STR%DT correctly.  Clean up NEWSTA and 
reject the mount request based on the requestor in routine STRMNT.

254	5.1115		12-Mar-84
	Change references from CFSP to either CFSB or to a call to CHKCFS.

255     5.1117		15-Mar-84
	Check for end of TMCMSG buffer and break up IPCF packets if necessary 
at carriage returns and/or line feeds

256	5.1120		22-Mar-84
	Add code to support the MOUNT command from OPR so that the correct 
action and messages get to be printed.  Change NEWSTA back to before edit 253.

257	5.1121		26-Mar-84
	Remove path no longer exists message from SHOW STATUS DISK.  Spell
DISMOUNT correctly.  * indicates external path to drive, not simply dual
ported.

260	5.1122		28-Mar-84
	Reject dismount request if structure is set IGNORED.  Tell operator
that a structure is set IGNORED and the attributes for that structure are not
set as that of the DDB.  

261	5.1123		30-Mar-84
	Filter the "don't care bits" (MS%NTC) as well as the MS%EXC in routine
STSTR.

262	5.1125		2-Apr-84
	Add processing of controller number to disk available/un command
processing.

263	5.1127		2-Apr-84
	Change dismount message in routine WOVDS to be more clear.

264	5.1128		4-Apr-84
	In routine %K: print the CKU in decimal. In routine SHWSTR add the open
file count to the structure display.

265	5.1129		4-Apr-84
	In routine KVIRSB:+11 change the MOVEI to MOVE.

266	5.1130		5-Apr-84
	Change the dismount no-removal message so that it is in relationship
to the command.  In routine BT3:+2, change the SKIPE to SKIPLE so that it will
suppress warning messages as well as checking for text to be outputed.

267	5.1131		5-Apr-84
	Fix the dismount messages to correspond to the dismount request.

270	5.1135		11-Apr-84
	Add code in DDSCHK to check for MONITOR bug, i.e if a disk is online
there must be a structure on that disk.  Also in routine DDSDEL, delete the SSB
if and only if DSKSSA is greater than zero.

271	5.1139		25-Apr-84
	Cannot set primary public structure exclusive/shared.  In routine 
STSTR, only set the exclusive/shared attribute of the primary public structure.

272	5.1140		26-Apr-84
	Change the CALL WOMNT to CALL WOFRE in routine WOVDS to print the 
status of a disk as part of the dismount acknowledgement message to the 
operator.

273	5.1141		30-Apr-84
	In routine SCREQ2, restore MSTAL with correct structure alias.

274	5.1142		16-May-84
	Change KVIRS to KVIR2.
Add code to handle the "in the process of being dismounted/removed" state of a
structure.

275	5.1143		25-May-84
	Do not the the tape status header if no tape drives are on the system.

276	5.1145		30-May-84
	Fix KSDKER to tell the operator why it cannot set a disk drive 
unavailable if the primary public structure is mounted on that drive.

277	5.1147		7-Jun-84
	In CHKAVA loop through all the STRADD based on number of units in that 
structure.

300	5.1151		11-July-84
	Replace the constant 777777 by the assembly runtime parameter DEFPRO
when supplying the default protection for a tape being initialized.

301	5.1153		27-July-84
	Make NEWSTA and STSTR internal labels for MTRCFS.

302	5.1154		27-July-84
	In routine DISFAL, check for error code MSTX21 and reject dismount
request if so.

303	5.1156		31-Aug-84
	In routine STRINF, add code to detect errors on the disk when it comes 
online.  Change routine STRIN2 to CHKDSK and have CHKDSK return +1 errors 
found, +2 no errors found.  In DDSCHK call CHKDSK to see if the MONITOR is
returning bad data due to disk errors or due to bug.

304	5.1159		14-Sept-84
	Delete all WTORs in regards to dismount queries for a dismounted 
structure.  Also, restore the alias in MSTAL in routine STRREF.

305	5.1161		20-Sept-84
	Set STR%UD in routine STRSET rather in routine STREXC.

306	5.1163		21-Sept-84
	Include account string in display.

307	5.1164		1-Oct-84
	Create a new routine, DISREF, to handle the operator refusal to 
dismount.

310	5.1165		3-Oct-84
	Add code to display device type to SHOW STATUS TAPE/CHAR.

311	5.1178		8-Nov-84
	Add message to disk and structure displays explain "Free" is relative 
to this system and check other systems before attempting any removal.

312	5.1181		28-Nov-84
	Check for structure unique code, if given, in MATCHS.  In mount 
routines check the return from MATCHS to determine ambiguous mount request or
legitimate mount request.  Set RSBSTE to RST.WD to indicate RSB is waiting for
dismount instead of using RST.WM (waiting for mount).

313	5.1185		5-Dec-84
	Edit 311 prints the "Free" message eveytime a disk display is done.
This message is meaningless if there are no free drives.  Only print the "Free"
if there is a disk online.

314	5.1190		8-Jan-85
	In routine STSTR+5 change ERJMP to JRST.

315	5.1192		9-Jan-85
	Comment out the code pertaining to write protecting MOUNTR

316	5.1193		10-Jan-85
	No structure name in SHOW STA STR FOO: display if FOO: has not 
previously mounted and disk drive is set unavailable.

317	5.1201		4-Feb-85
	Add code to skip MSTR if we are in debug mode.

320	5.1203		21-Feb-85
	Add a SHOW CONFIGURATION (of) DISK-DRIVE command.

321	5.1203		21-Feb-85
	More on SHOW CONFIG . . .

322	5.1205		18-Mar-85
	Give the correct error message when attempting to dismount the primary
public structure.

323	5.1211		26-Mar-85
	Check for RST.WD in DDSMCH.

324	5.1212		4-Apr-85	QAR 706407
	If bit MS%OFL is on also check MS%IAC.  If both bits are on then the
disk drive is not truely offline but rather force offline due to HOM checking
on behalf of a cluster change.

325	5.1213		30-Apr-85	QAR 838245, 838231
	Add check for structure unique code change for an online structure in
routine DDSCHK.

326	5.1222		21-Jun-85	QAR 838449
	In routine WONMT3: get the alias from the DSB.
*****	Release 5.0 -- begin maintenance edits	*****
330	Increment maintenance edit level for version 5 of GALAXY.

331	5.1228		Nov-15-85
	In routine STMERR check for only one recoverable error from failure
to mount structure.

332	5.1230		Jan-10-85
	In routine MTRLS, notify the operator that a mount request for a
volume of a multi-volume set is canceled due to a dismount.

333	4.2.1623	Feb-3-86
	In routine UNLOAD, REWIND the tape before UNLOAD.

334	5.1239		May-28-86
	In routime IOXCTR, increase the time out timer from 1 minute to 3
minutes.

335	5.1245		Dec-5-86
	Remember how many dismounts are currently being performed on a
structure so that if a cancel for a dismount request is given and if there are
no more dismounts for that structure pending, MOUNTR can reset
the structure status back to its previous state prior to the dismount.
This edit must be accompanied by MTRMAC edit 41.  MOUNTR must be rebuild.

336	5.1247		Oct-13-87
	In routine STRFND: when MOUNTR detects a -1 for the address of a SSB in
the DSB, go to STRFN3 to find out why.  There are three cases that this might
happen: if two identical structures are put online, if a disk drive switches
paths while the MONITOR is doing HOM block checking on that drive, and if two
structures with identical bad HOM blocks are put online.  The first case MOUNTR
will create two structure status blocks for each structure.  The second case,
MOUNTR will delete the path (DSB) that is doing the HOM block checking.  The
third case will be treated like the first but the DSB will state that the disk
has bad HOM blocks.  Since the MONITOR will no longer returns two accessible
paths to a disk drive, MOUNTR will no longer crash.

*****	Release 6.0 -- begin development edits	*****

6000	6.1037		26-Oct-87
	Move sources from G5: to G6:

6001	6.1057		4-Nov-87
	Change PS: to BS: and PS:[SPOOL] to SPOOL: for Non PS: login feature.
	Include BS: and PS: information in disk and structure displays.

6002	6.1081		17-Nov-87
	Add support to SET STRUCTUREs DUMPABLE/NONDUMPABLE.

6003	6.1081		18-Nov-87
	Missing the "/" in CHRTBL.	

6004	6.1081		19-Nov-87
	In routine SHW4:, show whether the structure is dumpable.

6005	6.1081		20-NOV-87
	In routine SHW.4:, use the alias name from DSFE because the structure
might not be online.

6006	6.1112		2-Dec-87
	In routine SHW4:, add a check for MS%OFS and display the structure as
offline if MS%OFS is lit.

6007	6.1137		9-Dec-87
	In routine STSTR: include MS%DMP as one of the bits that cab be set.
Report any conflicts regarding MS%DMP.

6010	6.1139		13-Dec-87
	When sending a remote ACK/WTO always include the .WTNHD and .WTTYP
blocks.

6011	6.1147		17-Dec-87
	Implement automation of DISMOUNT/REMOVAL and SET EXCLUSIVE.  Add code
to handle remote MOUNTs.

6012	6.1148		18-Dec-87
	Remote systems can't mount a structure after the local system has
remounted the structure after a DISMOUNT/REMOVAL.

6013	6.1149		18-Dec-87
	MOUNTR crashes with PDL overflow when DISMOUNT/REMOVE is done in a
mix 6.1 and 7.0 TOPS-20 Cluster.

6014	6.1150		21-Dec-87
	In routine KSST.6, If the SET EXCLUSIVE requires a RSB, save the
operator's PID in RSBPID so that the operator can be notified upon completion
of command.  In KSSTEX: add code to JRST to the correct routines so that the
SET command terminates normally.  In routine STRMN1: after the structure is 
mounted, always release the structure lock.

6015	6.1151		22-Dec-87
	Rewrite STRMN8: to following the same logic as DISMOUNT/REMOVAL and
SET EXCLUSIVE when MOUNTR tries to apply the EXCLUSIVE attribute of a structure
after it has been mounted.

6016	6.1152		23-Dec-87
	In routine KSSTAB:, just return after calling UNSEXC.  SCREQ3: will
have already imform the operator that the SET EXCLUSIVE was aborted.  Also,
in routine KDSM: remember the remote node in RSBOBN and STROBN if the dismount
is a remote dismount.

6017	6.1165		7-Jan-88
	In routine BT4:, store the remote node name in .WTNHD and not the
local node name.  In CKGHDR: if the message is from NEBULA, save the remote
node name in RENODE.  In PNEDC3:+1, change the AOJG to SOJG or else MOUNTR
will loop forever.  In KSST: save the structure flag in STRFL2.

6020	6.1167		15-Jan-88
	In routine STRMNT:, change the CAME to CAMN to correctly check for
a whether the remote request node name matches the remote node name who did
the dismount.   In routine WHOEQC:, zero out the left half of TEMP so that the
user number is correctlt stored in the INFBLK:.  In routine WHOENQ:, change the
message to indicate the command failed because the structure is being dismount
with removal or set exclusive a structure from another system.

6021	6.1199		29-Feb-88
	In routine STRMNT:+4, change the MOVE to SKIPE so that remote mounts
on a structure that have not been dismount on behalf of works.

6022	6.1202		2-Mar-88
	Extend the sign bit of the terminal line number in ACCLN because the
MONITOR doesn't like 0,,-1 for a deteched terminal line number.

6023	6.1216		5-Mar-88
	Add missing RET in STRFND.

6024	6.1219		6-Mar-88
	Add conditional for enabling/disabling CLUSTER GALAXY feature.  In
routine START: add one line..SINGLE <SETOM ENQFLG> after the ENQ% call. 
ENQFLG=-1 if not 7.0 MONITOR or CLUSTER GALAXY is disabled.

6025	6.1225		8-Mar-88
	Update copyright notice.

6026	6.1228		9-Mar-88
	Change message in WODSC1: to be more clear.

6027	6.1231		28-Mar-88
	Edit 6022 is incorrect.  ACCLN is a mask (0,,-1) and not a location 
which contains the line number.  Change ACCLN to ACCNO(ACC).

6030	6.1236		21-Apr-88
	No need to check for additional pending RSBs in routine SCREQ3: because
they are already pending for a response to a WTOR.  Also, the code to do the
checking was incorrect.

6031	6.1240		27-Apr-88
	In routine NSACK: get the RSB status in AC 1 so that the check for
R%STA is correct.  In routine FAILE: make sure that the error indicator bit is
set in .OFLAG.  In routine STRDMT: set R%STA if the remote dismount fails
because the structure is set IGNORE and use ABTREQ macro to abort the request.

6032	6.1250		9-May-88
	In error table NEBERR: add [ and ] for each error string so that FNDERR
can return the correct address of a NEBULA error.
^	;End of revision history
SUBTTL PREFACE
COMMENT ^

MOUNTR - THIS PROGRAM CONTOLS MAGNETIC TAPE AND  STRUCTURE  MOUNT
REQUEST QUEUEING AND PROCESSING UNDER TOPS-20. IT INTERFACES WITH
QUASAR, ORION, NON-PRIVILEGED USER-MODE PROGRAMS  (TOPS-20  EXEC,
ET AL), AND THE SYSTEM OPERATOR.

ACCUMULATOR CONVENTIONS:

F, Q1-Q3, AND SPECIAL-PURPOSE AC'S (E.G. MTA)  ARE  PRESERVED  BY
SUBROUTINES, WHILE T1-T4 AND CX MAY BE CLOBBERED. SOME MACROS USE
CX TO LINK TO DRIVERS, SO BE  CAREFUL.  F  CONTAINS  PROGRAM-WIDE
FLAGS THAT MAY BE MODIFIED AND TESTED BY ANY ROUTINE  THAT  NEEDS
THEM. MACRO DRIVERS GENERALLY PRESERVE T1-T4.

INTERRUPT-LEVEL OPERATION:

TO  MINIMIZE  THE  POSSIBILITY  OF  TIMING  BUGS,  PROCESSING  AT
INTERRUPT LEVEL WILL BE KEPT TO AN ABSOLUTE  MINIMUM.  INTERRUPTS
FROM SOURCES EXTERNAL TO THE PROGRAM ARE  PROCESSED  AT  PRIORITY
LEVEL 3 (DEFINED BY "PRIEXT" EQUATE). TYPICALLY, THE ONLY  ACTION
TAKEN IS TO REQUEST  THAT  THE  SCHEDULER  PASS  CONTROL  TO  THE
APPROPRIATE EVENT PROCESSOR AT  NON-INTERRUPT  LEVEL  (ALL  EVENT
PROCESSOR TAGS  END  IN  "IH").  DEBRK  IS  DONE  EITHER  TO  THE
INTERRUPTED PC OR TO THE BEGINNING OF  THE  SCHEDULER,  DEPENDING
UPON THE SETTING OF THE FLAG, IRETF. ALL  PANIC-CHANNEL  ACTIVITY
OCCURS AT LEVEL 1 (DEFINED BY "PRIPAN" EQUATE).

ASSOCIATED PROCESSES:

THIS PROGRAM RELIES UPON SEVERAL OTHER SYSTEM  TASKS  TO  PERFORM
ITS FUNCTIONS. THESE ARE REFERRED TO AS  "ASSOCIATED  PROCESSES",
ABBREVIATED A/P. PARALLEL A/P  TABLES  ARE  MAINTAINED  IN  CORE,
INDEXED BY THE A/P INDEX  (A SMALL INTEGER  ASSOCIATED  WITH  THE
PROCESS).

RESTARTABILITY:

IT IS INTENDED THAT MOUNTR BE RESTARTABLE  WITH  A  MINOR  IMPACT
UPON  SYSTEM  PERFORMANCE.  SOME  OF  THE  PROBLEMS  CREATED   BY
RESTARTING THE PROGRAM ARE:

     1.	ALL STRUCTURE-MOUNT AND ACCOUNTING INFORMATION IS LOST.
     2.	ALL ACCOUNTING INFORMATION FOR CURRENTLY-MOUNTED TAPES IS
	LOST.
     3.	ALL TAPE-MOUNT REQUESTS THAT HAVE NOT BEEN ASSIGNED AN MT
	DEVICE ARE LOST.
     4. USERS WITH MT DEVICES MAY CONTINUE USING  THEM,  BUT  ANY
	ATTEMPT AT A VOLUME SWITCH WILL RECEIVE AN ERROR.

EXTENDED ADDRESSING:

THOUGH MOUNTR WILL NOT NORMALLY RUN IN A  NON-ZERO  SECTION,  ITS
CODE SHOULD NOT PRECLUDE THAT POSSIBILITY. BECAUSE OF THE VARIETY
OF JSYS'S IT EXECUTES, MOUNTR  CAN  BE  OF  GREAT  ASSISTANCE  IN
TESTING THE USER-MODE EXTENDED ADDRESSING FEATURES OF THE MONITOR.

TEST MODE:

PLACING A NON-ZERO VALUE IN LOCATION 135 (.JBOPS) BEFORE STARTING
MOUNTR  WILL  CAUSE  MOUNTR  TO  RUN  IN  A  TESTING  MODE  (THIS
CONVENTION IS ADOPTED  FROM  THE  GALAXY  WORLD).  THE  ESSENTIAL
DIFFERENCES FROM LIVE MODE ARE THAT MOUNTR WILL TALK  TO  PRIVATE
GALAXY COMPONENTS, AND IT WILL REFRAIN FROM DOING  THINGS  (E.G.,
ASSIGNING MTA DEVICES) THAT WOULD INTERFERE WITH THE OPERATION OF
THE REAL MOUNTR.

^

; TABLE OF SUPPORTED DENSITIES

DENTAB:: DENLST			;GENERATE LIST OF DENSITIES
DENMAX==:.-DENTAB-1		;MAXIMUM DENSITY INDEX

; POINTERS TO TEXT STRINGS INDEXED BY LABEL TYPE

LTTXT::	0
	[ASCIZ/Unlabeled/]
	[ASCIZ/ANSI/]
	[ASCIZ/EBCDIC/]
	[ASCIZ/TOPS-20/]
MAXLT			;CODE NEEDED HERE IF NEW LABEL TYPE ADDED

; POINTERS TO TEXT STRINGS INDEXED BY DRIVE TYPE

DRVTXT:: 0
	[ASCIZ/9-TRACK/]
	[ASCIZ/7-TRACK/]

DVTTXT:	DVTGEN <45,70,71,72,73,77,78>
	DVTLEN==:.-DVTTXT
; ASCII-TO-EBCDIC TRANSLATION TABLE

; TABLE IS COMPOSED OF 128 8-BIT BYTES, INDEXED BY THE
; ASCII CHARACTER VALUE

AETT::
BYTE (8)000,001,002,003,067,055,056,057,026,005,045,013,014,015,016,017
BYTE (8)020,021,022,023,074,075,062,046,030,031,077,047,034,035,036,037
BYTE (8)100,117,177,173,133,154,120,175,115,135,134,116,153,140,113,141
BYTE (8)360,361,362,363,364,365,366,367,370,371,172,136,114,176,156,157
BYTE (8)174,301,302,303,304,305,306,307,310,311,321,322,323,324,325,326
BYTE (8)327,330,331,342,343,344,345,346,347,350,351,112,340,132,137,155
BYTE (8)171,201,202,203,204,205,206,207,210,211,221,222,223,224,225,226
BYTE (8)227,230,231,242,243,244,245,246,247,250,251,300,152,320,241,007



; EBCDIC-TO-ASCII TRANSLATION TABLE

; TABLE IS COMPOSED OF 256 7-BIT ASCII BYTES, INDEXED BY THE
; EBCDIC CHARACTER VALUE

XXX==.CHCNZ		;VALUE OF EBCDIC CHARS WITHOUT IMAGES (^Z=SUB)

EATT::
BYTE (7)000,001,002,003,XXX,011,XXX,177,XXX,XXX,XXX,013,014,015,016
BYTE (7)017,020,021,022,023,XXX,XXX,010,XXX,030,031,XXX,XXX,034,035
BYTE (7)036,037,XXX,XXX,XXX,XXX,XXX,012,027,033,XXX,XXX,XXX,XXX,XXX
BYTE (7)005,006,007,XXX,XXX,026,XXX,XXX,XXX,XXX,004,XXX,XXX,XXX,XXX
BYTE (7)024,025,XXX,032,040,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,133
BYTE (7)056,074,050,053,041,046,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX
BYTE (7)135,044,052,051,073,136,055,057,XXX,XXX,XXX,XXX,XXX,XXX,XXX
BYTE (7)XXX,174,054,045,137,076,077,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX
BYTE (7)XXX,140,072,043,100,047,075,042,XXX,141,142,143,144,145,146
BYTE (7)147,150,151,XXX,XXX,XXX,XXX,XXX,XXX,XXX,152,153,154,155,156
BYTE (7)157,160,161,162,XXX,XXX,XXX,XXX,XXX,XXX,XXX,176,163,164,165
BYTE (7)166,167,170,171,172,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX
BYTE (7)XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,XXX,173,101,102
BYTE (7)103,104,105,106,107,110,111,XXX,XXX,XXX,XXX,XXX,XXX,175,112
BYTE (7)113,114,115,116,117,120,121,122,XXX,XXX,XXX,XXX,XXX,XXX,134
BYTE (7)XXX,123,124,125,126,127,130,131,132,XXX,XXX,XXX,XXX,XXX,XXX
BYTE (7)060,061,062,063,064,065,066,067,070,071,XXX,XXX,XXX,XXX,XXX
BYTE (7)XXX,0,0,0,0
;DISPLAY MESSAGES FOR DISK STATUS


DSKHDR::ASCIZ "
DISK DRIVE INFORMATION                   DISK PACK INFORMATION
      Chan-Cont   Disk   Mount   Mount                Usage
 Type   Drive    Status  Status  Count   Name         Options
 ---- --------- -------- ------- -----   ------------ --------------------------
"
CFGHDR::ASCIZ "
      Chan-Cont                        Mount    
 Type   Drive    Drive Serial Number   Status   Name
 ---- --------- ---------------------  -------  ------------
"

FREHDR::ASCIZ "
			FREE DRIVES
"

MNTHDR::ASCIZ "
			MOUNTED DRIVES
"

;DISPLAY MESSAGES FOR STRUCTURE STATUS

STRHDR::ASCIZ "
              Mount   Mount File
Alias  Name   State   Count Count Status         Access         Accounting
------ ------ ------- ----- ----- -------- -------------------- ---------------
"

FRESTR::ASCIZ"
		UNMOUNTED STRUCTURES
"
MNTSTR::ASCIZ"
		MOUNTED STRUCTURES
"
;  Header for a particular structure

;  Display messages for structure status change

STRCHD:	ASCIZ "Structure Status Change Detected"

;  Display message for conflicting bits

CONFLI: ASCIZ "*  The attribute(s) for this structure are inconsistent with current status
"

;  Trying to set a disk drive with PS: mounted on it

DSKPS:	ASCIZ "**Warning - Primary public structure is mounted on disk drive **
"

DSMHDR:: ASCIZ "%IDismount of structure %3S: (Alias %2S:) requested.
Other jobs are currently using it.  Should
dismount request be processed (Yes or No)?
%U"

FREEH:: ASCIZ /%7CDisk drives that are "Free" might be in use by other systems%_%7CCheck status of structure on other systems before attempting any removal/

;[6011]
RESHDR:: ASCIZ /If successful, respond PROCEED
If not successful, respond ABORT/

;[6011]
RESPRE:: BLOCK 1		;RESPRE must be right before RESNAM
RESNAM:: ASCIZ/-DSKO'MJCLFGZAPKMSACPSCBR/ ;Resource name 
;DISK UNIT TYPE TABLE

UNTYTB:! XWD .MSRP4,[ASCIZ/RP04/]	;1 - RP04
	XWD .MSRP5,[ASCIZ/RP05/]	;5 - RP05
	XWD .MSRP6,[ASCIZ/RP06/]	;6 - RP06
	XWD .MSRP7,[ASCIZ/RP07/]	;7 - RP07
	XWD .MSRM3,[ASCIZ/RM03/]	;11 - RM03
	XWD .MSR20,[ASCIZ/RP20/]	;24 - RP20
	xwd .msr80,[asciz/RA80/]	;27 - ra80
	xwd .msr81,[asciz/RA81/]	;30 - ra81
	xwd .msr60,[asciz/RA60/]	;31 - ra60
	XWD -1,[ASCIZ/Unk /]		;ENTRY IN CASE NONE OF ABOVE

	MXUTYP==:.-UNTYTB-1		;NUMBER OF KNOWN ENTRIES
SUBTTL MODIFYABLE DATA AREA

; DEFINITION OF ASSOCIATED PROCESS INDICES

DEFINE APENT (X) <.AP'X==NEXT>
NEXT$==0		;INITIALIZE VARIABLE
	APTABL		;DEFINE SYMBOLS OF FORM .APxxx AS A/P INDICES
APNUM==NEXT$		;# OF ASSOCIATED PROCESSES

; ALL DATA FROM ZROBGN TO ZROEND WILL BE SET TO ZEROS AT STARTUP

ZROBGN::			;BEGINNING OF AUTOMATIC ZERO AREA
NSR::	BLOCK 1			;# OF REQUESTS IN SCHEDULER QUEUE
TDSCF::	BLOCK 1			;.GE. 0 SCHED REQUEST EXISTS FOR TDSCIR
MYPID::	BLOCK 1			;SYSTEM MDA PID
MSGSIN:: BLOCK 1		;# OF IPCF MESSAGES RECEIVED
SHORT::	BLOCK 1			;MAXIMUM LENGTH OF NON-PAGE IPCF MESSAGE
MTAN::	BLOCK 1			;NUMBER OF MTA DEVICES ON SYSTEM
MTN::	BLOCK 1			;NUMBER OF MT DEVICES ON SYSTEM
PBACW::	BLOCK 1			;GLOBAL ADDR OF ARGUMENT COUNT WORD
PBBPT::	BLOCK 1			;ADDR OF NEXT BUILDING BLOCK TO BE BUILT
PBLFT:: BLOCK 1			;Bytes positions left in orion message
MORTXT:: BLOCK 1		;Byte pointer to remaining text
BTEXT:: BLOCK 1			;ORION communication flags
FIRST:: BLOCK 1			;Marker for wto/ack message type block
BUFLFT:: BLOCK 1		;Number of words free in TMCMSG
TMCPTR:: BLOCK 1		;BYTE POINTER INTO TMCMSG
TMCTSP:: BLOCK 1		;TMCT0 ROUTINE SOURCE STRING POINTER
TMCWDS:: BLOCK 1		;CURRENT LENGTH OF TMCMSG IN WORDS
WTRQDB:: BLOCK 1		;QDB FOR OUTSTANDING WTOR REQUESTS
ARBQDB:: BLOCK 1		;QDB FOR ACTIVE REQUEST STATUS BLOCKS
IRBQDB:: BLOCK 1		;QDB FOR INACTIVE REQUEST STATUS BLOCKS
FVSQDB:: BLOCK 1		;QDB FOR FREE VOLID SLOTS IN VOLP0
UNIQUE:: BLOCK 1		;UNIQUE VALUE WORD (ACCESSED WITH AOS)
BTFLGS:: BLOCK 1		;.OFLAG WORD FOR WTO'S AND ACK'S
TAPNAM:: BLOCK TPNMSZ/5+1	;INSTALLATION-SUPPLIED NAME FOR VOL1
CRSHAC:: BLOCK 20		;AC'S AT TIME OF CRASH
SSSDAT:: BLOCK 2		;DATA AND ROUTINE ADDRESS FOR DEBUG
LSTERR:: BLOCK 1		;LAST ERROR AT TIME OF CRASH
CSB::	BLOCK 12		;STATE BLOCK FOR COMND JSYS
APPID::	BLOCK APNUM		;A/P PID TABLE
MRPDB::	BLOCK 10		;PDB FOR MRECV OPERATIONS
TRPDB::	BLOCK 4			;MSEND PDB
PDL::	BLOCK PDLEN+1		;PUSH-DOWN STACK
PDL1::	BLOCK 4			;ALTERNATE PDL - USED BY STOPP ROUTINE
BADP::	BLOCK 1			;CONTENTS OF P WHEN STACK PROBLEM FOUND
SYRHDR:: BLOCK SYRHSZ+SYRMSZ	;SYSERR HEADER AND MESSAGE
SYRMSG==SYRHDR+SYRHSZ		;ADDRESS OF SYSERR MESSAGE
SAVEDP:: BLOCK 1		;USED TO SAVE STACK POINTER FOR REPARSES
IABQDB:: BLOCK 1		;QDB FOR INACTIVE ACCOUNT BLOCKS
AABQDB:: BLOCK 1		;QDB FOR ACTIVE ACCOUNT BLOCKS
READCL:: BLOCK 2		;DUMPI IOWD LIST FOR READING LABELS
LPC1::	BLOCK 2			;PSI LEVEL 1 FLAGS & PC
LPC2::	BLOCK 2			;PSI LEVEL 2 FLAGS & PC
LPC3::	BLOCK 2			;PSI LEVEL 3 FLAGS & PC
DAEPC::	BLOCK 1			;PC OF LAST DATA ERROR
DEFDEN:: BLOCK 1		;Default Initialization Density
PRTRSB:: BLOCK 1		;Storage for Port RSB
ANY:: BLOCK 1			;Disk marker - SET PORT CI offline 
PORTST:: BLOCK 1		;Port status word . 1=unavailable 0=unavailable
AGAIN:	BLOCK 1			;Flag word to indicate redo of status loop
UNLD:	BLOCK 1			;Tape being unloaded flag
LCNODE:	BLOCK 1			;[6010]Local node name
RENODE: BLOCK 1			;[6010]Remote node name
NEBMSG:	BLOCK 1			;[6010]Request from NEBULA flag. nonzero=NEBULA
WTNHDB: BLOCK 2			;[6010]2 Word block for .WTNHD
WTTYPA: BLOCK 1			;[6010]Address of .WTTYP
TEMPX:	BLOCK 2			;[6010]Temp storage
STNAM:	BLOCK 1			;[6011]Structure name from .STRNM from .NRDAK
NUMNOD: BLOCK 1			;[6011]Number of nodes returned from .NRDAK
DFLAG:	BLOCK 1			;[6011]Remote dismount flag from .NRDAK
ADDRBK: BLOCK 1			;[6011]Address of .STSBK block from .NRDAK
BADADR: BLOCK 1			;[6013]Address of BADNOD
BADNOD: BLOCK 7			;[6013]Nodes in the cluster that is pre 7
ZROEND==.-1			;END OF AUTOMATIC ZERO AREA

;  End of buffer flags used in TMCMSG and for IPCF packets

ENDBUF==MSGLEN-^D20		;Nearing end of TMCMSG buffer
BYTEND==^D83			;Nearing end of IPCF message buffer

;  Data for SHOW CONFIGURATION DISK-DRIVE command

CFGFLG:: BLOCK 1	;Used so SHO STA DISK knows it's a different display

;  Data for user list for SHO STa STR FOO: command

USRSIZ==101			;Max number of users on user list.
USRBIT==0			;Offset to usage bits.
USRNUM==1			;Offset to Job user number.
USRENT==2			;User entry size.
DIRNAM:: BLOCK 15		;User name who have mounted/access/connected
USRLST:: BLOCK USRSIZ		;User list for usage of structure

PNFLAG:: BLOCK 1		;[6011]Routine PNEDAC's header flag
FNDRSB:: BLOCK 1		;[6011]Routine PNEDAC's RSB flag
DSPFLG:: BLOCK 1		;Display message flag, bits define in MTRMAC
; CDFLG - DEPOSIT 0 TO DISABLE ^D, DEPOSIT 1 TO ENABLE ^D
CDFLG::	EXP -1			;CONTROL-D ENABLE/DISABLE SWITCH
CFSPEC:: ASCIZ/SPOOL:MOUNTR-CRASH.EXE/ ;[6001]CRASH FILESPEC
LBUF2::	BLOCK LB7WDS		;7-BIT ASCII REPRESENTATION OF LBUF1
OPRHSZ==12
OPRHDR:: BLOCK OPRHSZ		;TEMPORARY TEXT STORAGE
MSTRBK:: BLOCK 50		;PLACE FOR MSTR DSK STATUS ARG BLOCK
MSTNM::	BLOCK 2			;STRUCTURE NAME FOR MSTR IN 7-BIT ASCII
MSTAL::	BLOCK 2			;STRUCTURE ALIAS FOR MSTR IN 7-BIT ASCII
CFSB:: BLOCK 1			;0=NON CFS SYSTEM, -1=CFS SYSTEM
ENQFLG:: BLOCK 1		;[6010]Cluster ENQ flag -1=Not cluster ENQ
ENQBLK:: BLOCK 6		;[6010]ENQ block
ENQCBK:: Block 3		;[6010]ENQC block
CNFSIZ==:30			;[6010]CNFIG block size
NUMBLK:: BLOCK 31		;[6010]CNFIG block for CI-node number
NAMBLK:: BLOCK 31		;[6010]CNFIG block for CI-node name
INFBLK:: BLOCK 20		;[6010]INFO block

;  Argument blocks for various JSYSs

MSTRST:	BLOCK .MSGSI+1		;[6010]Block for structure status MSTR
MUTLBK:	BLOCK 3			;Block for MUTIL JSYS
TAPEBK:	BLOCK .MOIWF+1		;Block for getting info about tape drive MTOPR

;  SSB data base management

SSBFPT:	BLOCK 1			;Pointer to SSB free entries (or 0 if none)
SSBTOP:	BLOCK 1			;Top of active SSB entries
				;  Points to next SSB entry available
SUBTTL STORAGE AREA FOR USAGE DATA


JOBNO::	BLOCK 1			;JOB NUMBER
LINO::	BLOCK 1			;LINE NUMBER
USRNAM:: BLOCK 10		;ASCIZ USER NAME
ACOUNT:: BLOCK 10		;ASCIZ ACCOUNT USTING

USTCRT::			;DATE/TIME OF REQUEST CREATION
UMTCRT:: BLOCK 1		;CREATION DATE/TIME OF REQUEST

USTSCD::			;SCHEDULED TIME
UMTSCD:: BLOCK 1

USTSRV:: 			;DATE/TIME WHEN SERVICED
UMTSRV:: BLOCK 1		;SERVICED DATE/TIME

USTEUT::			;ELAPSED USAGE TIME
UMTEUT:: BLOCK 1

USTDSP::			;DISPOSITION OF REQUEST
UMTDSP:: BLOCK 1

USTTXT::			;OPERATOR/SYSTEM TEXT
UMTTXT:: BLOCK 10

USGCSZ==.-JOBNO+1

USTNM::				;STRUCTURE NAME
UMTVID:: BLOCK 1		;MAGTAPE VOLUME IDENTIFIER

USTKTP:: 			;CONTROLLER TYPE
UMTKTP:: BLOCK 1		;CONTROLLER TYPE

USTDTP:: 			;DEVICE TYPE
UMTLT::	BLOCK 1			;LABEL TYPE
				; 1 = UNLABELED, 2 = ANSI
				; 3 = EBCDIC, 4 = DEC

USTSTP::			;STRUCTURE TYPE (3=DOMESTIC,4=FOREIGN)
UMTLS::	BLOCK 1			;LABEL STATUS
				; 0 = UNLABLED VOLUME
				; 1 = PRIVATE VOLUME
				; 2 = SCRATCH VOLUME
				; 3 = SCRATCH VOLUME ASSIGNED TO USER
				;     DURING THIS MOUNT

USTTNP:: 			;NUMBER OF PACKS IN STRUCTURE
UMTMRD:: BLOCK 1		;MAGTAPE READS

USTMC::				;MOUNT COUNT BEFORE MOUNT
UMTMWR:: BLOCK 1		;MAGTAPE WRITES

USTDC::				;MOUNT COUNT AFTER MOUNT
UMTMRF:: BLOCK 1		;THOUSANDS OF FRAMES READ OF MTA

USTATP::			;ACCESS TYPE
UMTMWF:: BLOCK 1		;THOUSANDS OF FRAMES WRITTEN

UMTFSI:: BLOCK 1		;FILE SET IDENTIFIER
UMTSRE:: BLOCK 1		;NUMBER OF SOFT READ ERRORS
UMTSWE:: BLOCK 1		;NUMBER OF SOFT WRITE ERRORS
UMTHRE:: BLOCK 1		;NUMBER OF HARD READ ERRORS
UMTHWE:: BLOCK 1		;NUMBER OF HARD WRITE ERRORS
UMTVSN:: BLOCK 1		;VISUAL SERIAL NUMBER

USGSIZ==.-JOBNO+1
SUBTTL STATIC DATA AREA

;	BLOCK 1000		;GET INTO A NEW PAGE
;PURE::				;LOWEST LOCATION IN STATIC DATA AREA

; EVERYTHING BEYOND THIS POINT WILL BE WRITE-PROTECTED BY THE
; ROUTINE WRTP, WHICH IS CALLED IN THE INITIALIZATION PHASE

TSTF==:135			;Galaxy mode flag: 0=live, 1=test

; SOFTWARE INTERRUPT SYSTEM DATA AREAS
; ------------------------------------

LEVTAB:	LPC1
	LPC2
	LPC3

; MACRO TO DEFINE PANIC-CHANNEL INTERRUPT CHNTAB ENTRIES

DEFINE PANIC (PANHDL) <
	INTMSK==INTMSK+1B<.-CHNTAB> ;;SET BIT IN CHANNEL MASK
	XWD PRIPAN,PANHDL	;;GENERATE CHNTAB ENTRY
>

; MACRO TO DEFINE EXTERNAL INTERRUPT CHNTAB ENTRIES

DEFINE EXTPSI (ENAM,EADR) <
	INTMSK==INTMSK+1B<.-CHNTAB> ;;SET BIT IN CHANNEL MASK
	ENAM'CN==.-CHNTAB	;;DEFINE CHANNEL# SYMBOL
  IFB <EADR>,<
	XWD PRIEXT,[CALL EIHR	;;GENERATE CHNTAB ENTRY
		    EXP ENAM'IH] ;;ENTRY POINT FOR SCHEDULER
  > ;;END IFB EADR
  IFNB <EADR>,<
	XWD PRIEXT,EADR		;;GENERATE CHNTAB ENTRY
  > ;;END IFNB EADR
>

INTMSK==0			;INITIAL VALUE OF INTRPT CHANNEL MASK
CHNTAB:
	EXTPSI DDT		;0 - LOAD AND SCHEDULE DDT
	0,,0			;1 - ASSIGNABLE CHANNEL 1
	0,,0			;2 - ASSIGNABLE CHANNEL 2
	0,,0			;3 - ASSIGNABLE CHANNEL 3
	0,,0			;4 - ASSIGNABLE CHANNEL 4
	0,,0			;5 - ASSIGNABLE CHANNEL 5
	0,,0			;6 - ARITHMETIC OVERFLOW
	0,,0			;7 - FLOATING OVERFLOW
	0,,0			;8 - RESERVED
	PANIC PANPOV		;9 - PDL OVERFLOW
	0,,0			;10 - END OF FILE
	PANIC PANDAE		;11 - DATA ERROR
	PANIC PANQTA		;12 - QUOTA EXCEEDED
	0,,0			;13 - RESERVED
	0,,0			;14 - TIME OF DAY (RESERVED)
	PANIC PANILI		;15 - ILLEG INSTRUCTION
	PANIC PANIRD		;16 - ILLEGAL READ
	PANIC PANIWR		;17 - ILLEGAL WRITE
	0,,0			;18 - ILLEGAL EXECUTE (RESERVED)
	0,,0			;19 - INFERIOR FORK TERMINATION
	PANIC PANMSE		;20 - MACHINE SIZE EXCEEDED
	0,,0			;21 - TRAP TO USER (RESERVED)
	0,,0			;22 - NONEXISTENT PAGE REFERENCED
	0,,0			;23 - ASSIGNABLE CHANNEL 23
	EXTPSI MRCV		;24 - IPCF MESSAGE WAITING
	EXTPSI TDSC,TDSCIH	;25 - MTA DEVICE STATUS CHANGE
	EXTPSI JTO,JTOIH	;26 - JSYS TIMER EXPIRED
	EXTPSI DDSC		;27 - DISK DEVICE STATUS CHANGE
	0,,0			;28 - ASSIGNABLE CHANNEL 28
	0,,0			;29 - ASSIGNABLE CHANNEL 29
	0,,0			;30 - ASSIGNABLE CHANNEL 30
	0,,0			;31 - ASSIGNABLE CHANNEL 31
	0,,0			;32 - ASSIGNABLE CHANNEL 32
	0,,0			;33 - ASSIGNABLE CHANNEL 33
	0,,0			;34 - ASSIGNABLE CHANNEL 34
	0,,0			;35 - ASSIGNABLE CHANNEL 35
; ENTRY VECTOR

ENTVEC:	JRST START		;STARTING ADDRESS
	JRST DEBUG		;REENTER ADDRESS
LVERS::	EXP mtrVER		;PROGRAM VERSION
ENTVSZ==.-ENTVEC
; TABLE OF INITIALIZATION ROUTINE ADDRESSES FOR ASSOCIATED PROCESSES;
; ROUTINE IS CALLED DURING PROGRAM INITIALIZATION, AND POSSIBLY
; BY THE RECOVERY ROUTINE IF THE PROCESS CRASHES.

DEFINE APENT (X) <IFIW!X'INI>
APINI:	APTABL			;GENERATE LIST OF INIT ROUTINE ADDRS

; TABLE OF IPCF INPUT-MESSAGE PROCESSING ROUTINE ADDRESSES FOR A/P'S;
; ROUTINE IS CALLED WHEN AN IPCF MESSAGE IS RECEIVED FROM A PID THAT
; IS LISTED IN THE APPID TABLE

DEFINE APENT (X) <IFIW!X'MRC>
APMRC:	APTABL			;GEN LIST OF IPCF-RECEIVE HANDLER ADDRS

; Table of error codes and corresponding processing addresses upon MSEND
; failure for IPCF Send and Receive routines

MTBL:	IPCFX4,,TRAN1		;Receiver's PID is invalid
	IPCFX5,,TRAN1		;Receiver's PID is disabled
	IPCFX6,,TRAN6		;Send quota is exceeded
	IPCFX7,,TRAN5		;Receiver's quota is exceeded
	IPCFX8,,TRAN6		;IPCF free space is exhausted
	IPCF19,,TRAN7		;No PID for SYSTEM INFO
	MONX06,,TRAN6		;No swappable free space
MLEN==.-MTBL			;Length of the table
SUBTTL TEMPLATES FOR USAGE JSYS

;STRUCTURE USE RECORD

USGSTR: USENT. (.UTMNT,1,1)	;STRUCTURE USAGE RECORD TYPE
	USPNM. (<SIXBIT/MOUNTR/>,US%IMM) ;PROGRAM NAME
	USPVR. (mtrver,US%IMM)	;VERSION NUMBER
	USJNO. (JOBNO)		;JOB NUMBER
	USLNO. (LINO)		;LINE NUMBER
	USACT. (<-1,,ACOUNT>)	;ACCOUNT
	USNM2. (<-1,,USRNAM>)	;USER NAME
	USSSI. (USTNM)		;STRUCTURE NAME
	USSTP. (USTSTP)		;STRUCTURE TYPE
	USTNP. (USTTNP)		;TOTAL NUMBER OF PACKS IN FILE STRUCTURE
	USKTP. (USTKTP)		;CONTROLLER TYPE (RH20)
	USDTP. (USTDTP)		;DEVICE TYPE (RP04,ETC.)
	USDSP. (USTDSP)		;DISPOSITION
	USTXT. (<-1,,USTTXT>)	;SYSTEM/OPERATOR TEXT
	USCRT. (USTCRT)		;CREATION DATE/TIME OF REQUEST
	USSCD. (USTSCD)		;SCHEDULED TIME
	USSRV. (USTSRV)		;SERVICED DATE/TIME
	USMCT. (USTMC)		;MOUNT COUNT BEFORE MOUNT
	USDCT. (USTDC)		;MOUNT COUNT AFTER DISMOUNT
	USATP. (USTATP)		;ACCESS TYPE
	USEUT. (USTEUT)		;ELAPSED TIME OF USAGE
	0			;END OF RECORD

;TAPE MOUNT RECORD

USGMTA: USENT. (.UTMMT,2,1)	;MAGTAPE USAGE RECORD TYPE
	USPNM. (<SIXBIT/MOUNTR/>,US%IMM) ;PROGRAM NAME
	USPVR. (mtrVER,US%IMM)	;VERSION NUMBER
	USJNO. (JOBNO)		;JOB NUMBER
	USLNO. (LINO)		;LINE NUMBER
	USACT. (<-1,,ACOUNT>)	;ACCOUNT
	USNM2. (<-1,,USRNAM>)	;USER NAME
	USVID. (UMTVID)		;VOLUME IDENTIFIER IN VOL1 LABEL
	USMRF. (UMTMRF)		;THOUSANDS OF FRAMES READ
	USMWF. (UMTMWF)		;THOUSANDS OF FRAMES WRITTEN
	USDSP. (UMTDSP)		;DISPOSITION
	USTXT. (<-1,,UMTTXT>)	;SYSTEM/OPERATOR TEXT
	USCRT. (UMTCRT)		;CREATION DATE/TIME
	USSCD. (UMTSCD)		;SCHEDULED TIME
	USSRV. (UMTSRV)		;SERVICED DATE/TIME
	USKTP. (UMTKTP)		;CONTROLLER TYPE
	USMLT. (UMTLT)		;LABEL TYPE
	USMLS. (UMTLS)		;LABEL STATE
	USMRD. (UMTMRD)		;NUMBER OF TAPE READS
	USMWR. (UMTMWR)		;NUMBER OF TAPE WRITES
	USFSI. (UMTFSI)		;FILE SET IDENTIFIER
	USSRE. (UMTSRE)		;NUMBER OF SOFT READ ERRORS
	USSWE. (UMTSWE)		;NUMBER OF SOFT WRITE ERRORS
	USHRE. (UMTHRE)		;NUMBER OF HARD READ ERRORS
	USHWE. (UMTHWE)		;NUMBER OF HARD WRITE ERRORS
	USVSN. (UMTVSN)		;VISUAL SERIAL NUMBER
	USEUT. (UMTEUT)		;ELAPSED TIME OF USAGE
	0			;END OF RECORD
SUBTTL INITIALIZATION

; PROGRAM EXECUTION BEGINS HERE

START:	HLRZ T1,.JBSA		;GET UPPER BOUND OF PROGRAM
	CAIL T1,ADLOW		;PROGRAM TOO BIG?
	JRST [	TMSG <MOUNTR program overlaps ADLOW> ;YES, ERROR
		HALTF]		;MAKE ADLOW HIGHER TO CORRECT PROBLEM
	RESET			;CLOSE JFNS, CLEAR PSI, DUMP PIDS, ETC.
	MOVE P,[IOWD PDLEN,PDL]	;SET UP STACK POINTER
	MOVX F,INITF		;INITIALIZE FLAGS AC
	MOVE T1,.JBOPS		;GET GALAXY STANDARD TEST FLAG
	MOVEM T1,TSTF		;COPY TO WRITE-PROTECTED LOCATION

; ZERO OUT MODIFYABLE DATA AREA

	SETZM ZROBGN		;CLEAR FIRST WORD OF ZERO AREA
	MOVE T1,[ZROBGN,,ZROBGN+1] ;GET BLT POINTER
	BLT T1,ZROEND		;CLEAR THE REST OF THE ZERO AREA
	SETOM TDSCF		;SET NO SCHED REQUEST PRESENT FOR TDSCIR

; TURN ON INTERRUPT SYSTEM

	MOVEI T1,.FHSLF		;THIS FORK
	MOVE T2,[LEVTAB,,CHNTAB] ;TABLE ADDRESSES
	SIR			;COMMUNICATE TABLE ADDR'S TO MNTR
	EIR			;TURN ON INTERRUPT SYSTEM
	MOVX T2,INTMSK
	AIC			;ENABLE INTERRUPT CHANNELS
	SETO T3,
	EPCAP			;ENABLE ALL CAPABILITIES

; PERFORM VARIOUS INITIALIZATION OPERATIONS


;  This is one way to find out if we are running Pre 7 monitor
;  ENQFLG=0  Post 7 monitor and cluster GALAXY enabled.
;  ENQFLG=-1  Pre 7 monitor and cluster GALAXY disabled.
;  SINGLE= conditional flag for ENABLE/DISABLE CLUSTER GALAXY

	SETZM ENQFLG		;[6010]Assume cluster ENQ and 7 MONITOR
SINGLE	<SETOM ENQFLG>		;[6024]Not cluster GALAXY if SINGLE is defined
	SKIPE ENQFLG		;[6024]Do we have Cluster GALAXY?
	JRST START0		;[6024]No, skip ENQ% call
	MOVEI T1,.ENECL		;[6010]Enable cluster ENQ
	ENQ%			;[6010]Do the JSYS
	 SETOM ENQFLG		;[6010]Not cluster ENQ

START0:	CALL GCNFIG		;[6024]Get the local node name
	MOVE T1,NAMBLK+1	;[6010]Get pointer to local node name
	MOVEI T2,LCNODE		;[6010]Put SIXBIT name in LCNODE
	CALL SEVSIX		;[6010]Convert it
;	CALL WRTP		;WRITE-PROTECT MY CODE
	MOVEI T1,.SFMTA
	TMON			;TAPE-DRIVE ALLOCATION ENABLED?
	JUMPN T2,[TXO F,TALCF	;YES, SET FLAG
		MOVEI T1,POLINT	;GET POLLING INTERVAL
		MOVEI T2,POLLR	;GET ADDRESS OF POLLING ROUTINE
		CALL SRAI	;SCHEDULE MAGTAPE POLLING TASK
		JRST .+1]
	CALL PIDINI		;CREATE SYSTEM MDA PID
	CALL GTINAM		;GET INSTALLATION NAME
	CALL INAP		;MAKE FRIENDS WITH ASSOCIATED PROCESSES

	CALL DSFINI		;MAP DEVICE-STATUS FILE
	CALL DSFNUP		;Say we want no update of DDB
	SKIPN TSTF		;RUNNING LIVE?
	JRST [	TXNE F,TALCF	;Yes, SKIP MTA ASSIGN IF ALLOCATION DISABLED
		CALL ASMTA	;ASSIGN PHYSICAL MAGTAPES TO MYSELF
		CALL ASMT	;PUT LOGICAL MAGTAPES IN ALLOC POOL
		JRST .+1]
	CALL GETDEN		;Get magtape density for Initialize default
	CALL GETRSI		;INITIALIZE FREE RSB POOL
	CALL PRTINI		;Check for CI availability
	CALL DSKINI		;Initialize for disk change interrupts
	CALL SSBINI		;Initialize SSB data base
	CALL DDSCIH		;Set up DSK and STR DDB and status blocks
	SKIPE TSTF		;Debugging?
	JRST .+3		;Yes, skip mount all
	SKIPE CFSB		;Are we in CFS?
	CALL MNTALL		;Yes, mount all structures possible
	CALL DSFYUP		;We now want update of DDB

	CALL VQSPIN		;INITIALIZE VOLID-SLOT POOL
	CALL GETABI		;INITIALIZE FREE ACCOUNT BLOCK POOL
	CALL TDSCIR		;REWIND TAPES, DO AVR, ETC.
	TXZ F,INITF		;NOT INITIALIZING ANY MORE
	JRST SSS		;ENTER SCHEDULER
SUBTTL SERVICE SCHEDULER (SS)

; SCHEDULER REQUEST QUEUE ENTRY EQUATES

FLDPTR==0
  FLDDEF(RE.TIM,1)		;OFFSET TO ACTIVATION TIME
  FLDDEF(RE.ENT,1)		;OFFSET TO GLOBAL ENTRY ADDRESS
  FLDDEF(RE.ARG,1)		;OFFSET TO ARGUMENT
RE.LEN==FLDPTR			;LENGTH OF SCHEDULER ENTRY

; ONCE AGAIN INTO THE FRAY, DEAR FRIENDS

SSS:	TXZ F,IRETF		;SET NOT INTERRUPTIBLE
	CAME P,[IOWD PDLEN,PDL]	;STACK POINTER OK?
	JSP CX,STOPP		;NO, CRASH
	CALL DDCTLD		;CHECK FOR ENABLE/DISABLE ^D
	TXO F,IRETF		;SET INTERRUPTIBLE
	SKIPN NSR		;QUEUES EMPTY?
	WAIT			;YES, REG TO SLEEP
	GTAD			;GET CURRENT TIME & DATE IN T1
	MOVE T2,SRQ+RE.TIM	;GET TIME/DATE OF EARLIEST REQUEST
	SUB T2,T1		;IS IT IN THE FUTURE?
	JUMPLE T2,SSER		;NO, GET ON IT RIGHT AWAY

; SLEEP UNTIL WAKE-UP TIME OF EARLIEST REQUEST

	MOVE T1,T2		;COPY INTERNAL FORMAT SLEEP INTERVAL
	MUL T1,[DAYSEC*^D1000]	;COMPUTE # OF MILLISECONDS
	ASHC T1,^D17		; TO SLEEP IN T1
	DISMS			;SLEEP UNTIL NEEDED
	JRST SSS		;ATTEMPT SCHEDULE AGAIN

; SCHEDULE THE FIRST REQUEST IN THE QUEUE

SSER:	TXZ F,IRETF		;AIN'T IDLE NO MORE
	MOVEI T1,.FHSLF
	DIR			;INHIBIT INTERFERENCE
	MOVE T4,SRQ+RE.ENT	;GET ROUTINE ENTRY ADDRESS
	MOVE T3,SRQ+RE.ARG	;GET ARG FOR HANDLER ROUTINE
	SOS T1,NSR		;GET # OF REQUESTS REMAINING
	JUMPE T1,SSS1		;IF NONE LEFT, DON'T BLT
	IMULI T1,RE.LEN		;COMPUTE # OF WORDS TO BLT
	MOVE T2,[SRQ+RE.LEN,,SRQ] ;GET BLT SOURCE,,DESTINATION
	BLT T2,SRQ+RE.LEN-1(T1)	;DELETE HEAD OF QUEUE
SSS1:	MOVEI T1,.FHSLF
	EIR			;PERMIT INTERRUPTS
	DMOVEM T3,SSSDAT	;STORE CALLED-ROUTINE INFO FOR DEBUG
	CALL (T4)		;CALL USER ROUTINE WITH ARG IN T3
	TXZE F,ABORTF		;WERE ANY REQUESTS ABORTED?
	CALL PRQABT		;YES, PURGE THEM FROM REQUEST QUEUE
	JRST SSS		;GO SEE IF MORE WORK TO DO
; SRA - ADD SCHEDULER REQUEST TO QUEUE (2 ENTRY POINTS)
; SRAA - ABSOLUTE INTERNAL-FORMAT TIME & DATE IN T1
; SRAI - INCREMENTAL FORM: # OF SECONDS FROM NOW IN T1
; SRAN - REQUEST IS TO BE SCHEDULED AS SOON AS POSSIBLE (T1 MEANINGLESS)
;  T2/ ROUTINE ADDRESS IN RIGHT HALF
;  T3/ ARGUMENT TO BE SUPPLIED TO ROUTINE IN T3 AT TIME OF CALL
; RETURNS +1: ALWAYS

SRAI:	STAKT			;STACK T1-T4
	MUL T1,[1,,0]		;CONVERT # OF SECONDS
	DIVI T1,DAYSEC		; TO INCREMENTAL INTERNAL FORMAT
	MOVE T2,T1		;CLEAR OUT OF T1 FOR GTAD
	GTAD			;GET CURRENT INTERNAL T/D
	ADD T1,T2		;ADD INCREMENT
	JRST SRA1		;SKIP OTHER ENTRY

SRAN:	SETZ T1,		;IMMEDIATE FLAVOR - STUFF T1
SRAA:	STAKT			;STACK T1-T4

; COMMON CODE FOR SRAx

SRA1:	MOVE T4,T1		;MOVE ACTIVATION TIME TO T4
	MOVEI T1,.FHSLF
	DIR			;INHIBIT INTERFERENCE
	SETZ T2,		;INIT SCAN INDEX
	MOVNI T3,RE.LEN		;INIT QUEUE POINTER
SRA2:	ADDI T3,RE.LEN		;BUMP QUEUE POINTER
	CAMGE T2,NSR		;ANY ENTRIES LEFT TO CHECK AGAINST?
	JRST [	CAML T4,SRQ+RE.TIM(T3) ;YES, EARLIER THAN THIS ENTRY?
		AOJA T2,SRA2	;NO, CONTINUE SEARCH
		JRST .+1]	;YES, GO INSERT IT HERE
	SUB T2,NSR		;COMPUTE # OF
	MOVNS T2		; ENTRIES TO BE SHIFTED DOWN
	IMULI T2,RE.LEN		;COMPUTE # OF WORDS TO SHIFT
	MOVE T3,NSR
	IMULI T3,RE.LEN		;SET UP LOAD/STORE INDEX AT TAIL
	JUMPE T2,SRA3		;IF NONE, SKIP SHIFTING STUFF
SRA4:	MOVE T1,SRQ-1(T3)	;GET A WORD
	MOVEM T1,SRQ+RE.LEN-1(T3) ;SHIFT IT DOWN
	SOS T3			;INDEX NEXT WORD
	SOJG T2,SRA4		;LOOP TILL ALL SHIFTING DONE

; INSTALL ENTRY IN NEWLY-CREATED SLOT

SRA3:	MOVEM T4,SRQ+RE.TIM(T3)	;STUFF TIME/DATE
	XMOVEI T1,20
	HRR T1,CT2
	MOVEM T1,SRQ+RE.ENT(T3)	;STUFF GLOBAL ENTRY ADDRESS
	MOVE T1,CT3
	MOVEM T1,SRQ+RE.ARG(T3)	;STUFF ARGUMENT
	AOS NSR			;BUMP # OF ENTRIES IN QUEUE
	MOVEI T1,.FHSLF
	EIR			;PERMIT INTERRUPTS
	RET
; EIHR - SUPPORT ROUTINE FOR EXTERNAL INTERRUPTS

EIHR:	ADJSP P,5		;CREATE ROOM ON STACK FOR T1-T4, CX
	MOVEM CX,-4(P)		;SAVE CX
	DMOVEM T1,-3(P)		;SAVE T1 & T2
	DMOVEM T3,-1(P)		;SAVE T3 & T4

; REQUEST SCHEDULING AT INTERRUPT HANDLER ENTRY POINT

	MOVE T2,@-5(P)		;GET ADDRESS OF ROUTINE
	CALL SRAN		;SCHEDULE AT THIS ADDRESS IMMEDIATELY

; RESTORE AC'S AND EXIT TO INTERRUPTED PROGRAM OR SCHEDULER

	MOVE CX,-4(P)		;RESTORE CX
	DMOVE T1,-3(P)		;RESTORE T1 & T2
	DMOVE T3,-1(P)		;RESTORE T3 & T4
	ADJSP P,-6		;DELETE TEMP SPACE FROM STACK
	TXZN F,IRETF		;SCHED GOOFING OFF?
	DEBRK			;NO, GO BACK TO INTERRUPTED CODE
	MOVE CX,[PC%USR+SSS]	;YES, GET NEW PC
	MOVEM CX,@LEVTAB+PRIEXT-1 ;STUFF IT
	DEBRK			;EXIT TO SCHEDULER
SUBTTL ACCOUNTING ROUTINES

;ACCSTI - STRUCTURE COUNT BEING INCREMENTED. BUILD ACCOUNTING BLOCK FOR
;	  USER

ACCSTI:	HRRZ T1,RBUF+4		;GET STRUCTURE STATUS
	TRNE T1,(MS%NRS)	;IS IT NON-REGULATED?
	JRST ACCS3		;YES, FORGET ENTRY AND DELETE OLD BLOCK
	HLRZ T1,RBUF+2		;GET JOB NUMBER
	HRRZ T2,RBUF+3		;GET DEVICE DESIGNATOR
	HRLI T2,.DVDES+.DVDSK	;ADD DISK DESIGNATION
	CALL FNDACC		;SEE IF THERE IS A BLOCK ALREADY
	JRST ACCS1		;NO
        SKIPN ACCSVT(ACC)	;IS THERE A SERVICED TIME
	JRST ACCS2		;NO. SO STORE INFORMATION.
	AOS ACCFRK(ACC)		;YES, INCREMENT FORK COUNT
	RET			;FINISHED
ACCS1:	CALL GETACC		;GET AN ACCOUNT BLOCK
	 CALLRET DELACC		;ABORT SINCE ACC BLOCKS IN SHORT SUPPLY
ACCS2:	AOS ACCFRK(ACC)		;SET NUMBER OF FORKS USING STR TO 1

;STORE ACCOUNTING INFORMATION

	HRRZ T1,RBUF+3		;GET STRUCTURE UNIQUE CODE
	HRLI T1,.DVDES+.DVDSK	;ADD DISK DESIGNATOR
	MOVEM T1,ACCDD(ACC)	;STORE IN ACCOUNTING BLOCK
	MOVE T1,RBUF+2		;GET JOB #,,LINE #
	MOVEM T1,ACCNO(ACC)
	MOVE T2,RBUF+10		;GET USER #
	HRROI T1,ACCUSR(ACC)
	DIRST			;TRANSLATE TO NAME
	 JFCL
	MOVEI T1,ACCSTG(ACC)	;SET UP BLT POINTER
	HRLI T1,RBUF+11
	BLT T1,ACCSTG+7(ACC)	;STORE ACCOUNT STRING
	MOVE T1,RBUF+7
	SKIPN ACCSCD(ACC)	;IF NO TIME SCHEDULED
	MOVEM T1,ACCSCD(ACC)	;TIME SCHEDULED
	MOVEM T1,ACCSVT(ACC)	;AND SERVICED ARE THE SAME
	MOVE T1,RBUF+6
	MOVEM T1,ACCSTN(ACC)	;STORE STRUCTURE NAME
	HLRZ T1,RBUF+4
	STOR T1,ACCMB		;STORE MOUNT COUNT
	HLRZ T1,RBUF+5
	STOR T1,ACCNU		;STORE NUMBER OF UNITS
	HRRZ T1,RBUF+5
	STOR T1,ACCDT		;STORE DISK TYPE
	HRRZ T1,RBUF+4		;GET STRUCTURE STATUS
	MOVEI T2,4		;ASSUME STRUCTURE IS FOREIGN
	TRNE T1,(MS%DOM)	;IS IT DOMESTIC?
	MOVEI T2,3		;YES, GET DOMESTIC CODE
	STOR T2,ACCST		;STORE STRUCTURE TYPE
	SETZRO ACCKT		;SET CONTROLLER TO ALL ONES
	MOVE T1,[SIXBIT/NORMAL/] ;PRESET TO NORMAL DISPOSITION
	MOVEM T1,ACCDSP(ACC)	; SAVE IT
	RET
ACCS3:	HLRZ T1,RBUF+2		;GET JOB NUMBER
	HRRZ T2,RBUF+3		;GET DEVICE DESIGNATOR
	HRLI T2,.DVDES+.DVDSK	;ADD DISK DESIGNATION
	CALL FNDACC		;SEE IF THERE IS A BLOCK ALREADY
	RET			;NO, JUST RETURN
	SKIPE ACCSVT(ACC)	;IS IT LEFT OVER FROM A PHYSICAL MOUNT REQ?
	RET			;NO, LEAVE IT ALONE
	CALLRET DELACC		;YES, DELETE IT
;ACCSTD - STRUCTURE COUNT BEING DECREMENTED. MAKE USAGE ENTRY.

ACCSTD:	HLRZ T1,RBUF+2		;GET JOB NUMBER
	MOVE T2,RBUF+3		;GET DEVICE DESIGNATOR
	HRLI T2,.DVDES+.DVDSK	;ADD DISK DESIGNATION
	CALL FNDACC		;FIND ACCOUNT BLOCK
	 RET			;THERE WAS NONE
	SOSE ACCFRK(ACC)	;ANY OTHER FORKS HAVE IT INCREMENTED?
	RET			;YES, DON'T SEND ANY INFO, YET
	CALL STOSTR		;STORE STR INFO FROM ACCOUNT BLOCK
	HRRZ T1,RBUF+2		;GET MOUNT COUNT
	MOVEM T1,USTDC
	MOVEI T1,.UTMNT		;THIS IS STRUCTURE MOUNT INFO
	CALL SNDACC		;SEND USAGE INFO TO MONITOR
	CALLRET DELACC		;DELETE ACCOUNT BLOCK

;ACCSTR - STRUCTURE BEING REMOVED.  SEND ACCOUNT BLOCKS TO USAGE

ACCSTR:	QSCANI AABQDB		;SET UP TO SCAN ACTIVE ACCOUNT BLOCKS
	MOVE Q1,RBUF+3		;GET DEVICE DESIGNATOR
	HRLI Q1,.DVDES+.DVDSK	;ADD DISK DESIGNATION
ACCSR1:	CALL QMSCAN		;GET ADDRESS OF NEXT ACC IN T2
	 RET			;NONE LEFT
	MOVEI ACC,-ACCLNK(T2)	;LOAD ACC ADDRESS
	CAME Q1,ACCDD(ACC)	;IS THIS THE STR BEING REMOVED
	JRST ACCSR1		;NO, GET NEXT ACCOUNT BLOCK
	CALL STOSTR		;STORE STR INFO INTO USAGE BLOCK
	MOVEI T1,.UTMNT		;THIS IS STRUCTURE MOUNT INFO
	CALL SNDACC		;SEND USAGE INFO TO MONITOR
	CALL DELACC		;DELETE ACCOUNT BLOCK
	JRST ACCSR1		;GET NEXT BLOCK
;ACCMTR - TAPE BEING REQUESTED.  BUILD ACCOUNTING BLOCK FOR USER

ACCMTR:	CALL GETACC		;GET ACCOUNT BLOCK
	 JRST DELACC		;ABORT SINCE ACC BLOCKS IN SHORT SUPPLY
	MOVSI T1,RSBACT(RSB)	;BLT SOURCE
	HRRI T1,ACCSTG(ACC)	;BLT DESTINATION
	BLT T1,ACCSTG+7(ACC)	;MOVE USER'S ACCOUNT STRING TO ACC
	GTAD			;STORE TIME SCHEDULED
	MOVEM T1,ACCSCD(ACC)	;IN ACCOUNT BLOCK
	LOAD T1,RSBJNO		;GET USER'S JOB NUMBER
	STOR T1,ACCJN
	CALL STONAM		;STORE USER'S NAME
	 JRST DELACC		;USER NOT AROUND, DELETE ACC BLOCK
	MOVSI T1,.DVDES+.DVMTA	;GET DEVICE DESIGNATOR
	MOVEM T1,ACCDD(ACC)	;STORE IN ACCOUNT BLOCK
	MOVE T1,[SIXBIT/NORMAL/] ;PRESET TO NORMAL DISPOSITION
	MOVEM T1,ACCDSP(ACC)	; SAVE IT
	STOR ACC,RSBACC		;STORE ACCOUNT BLOCK ADDRESS INTO RSB
	RETSKP

;ACCMTD - TAPE BEING DISMOUNTED. MAKE USAGE ENTRY FOR USER

;ACCEPTS: MT/	ADDRESS OF MT STATUS BLOCK
;	  MTA/	ADDRESS OF MTA STATUS BLOCK
;	  RSB/  ADDRESS OF REQUEST STATUS BLOCK

ACCMTD:	SAVEAC <ACC>
	SETZM UMTKTP		;SET CONTROLLER TYPE TO ZERO
	LOAD ACC,RSBACC		;RETRIEVE ACCOUNT BLOCK ADDRESS
	MOVE T1,MTAVOL(MTA)	;GET VOLID
	MOVEM T1,UMTVID
	LOAD T1,MTALT		;GET LABEL TYPE
	MOVEM T1,UMTLT		; INTO USAGE BLOCK
	MOVEI T2,.LSUNL		;LABEL STATE, ASSUME UNLABELLED.
	CAIE T1,.LTUNL		;IS IT REALLY UNLABELLED?
	MOVEI T2,.LSPRI		;NO, MUST BE PRIVATE.
	MOVE T1,MTAFLG(MTA)	;GET FLAGS
	TXNE T1,MA%SCR		;IS IT SCRATCH?
	MOVEI T2,.LSSCR		;YES, SAY SO
	MOVEM T2,UMTLS		;LABEL STATE INTO USAGE BLOCK
	CALL MTAGJF		;GET MAGTAPE JFN
	MOVEI T2,.MOINF		;GET TAPE INFORMATION
	MOVEI T3,.MOIWF		;GET LENGTH OF INFO BLOCK
	MOVEM T3,TAPEBK
	MOVEI T3,TAPEBK		;PUT ALL INFO INTO TAPEBK
	MTOPR
	CALL MTARJF		;RELEASE JFN
	MOVE T1,TAPEBK+.MOIRD	;GET NUMBER OF PHYSICAL RECS READ
	SUB T1,ACCPR(ACC)	;SUBTRACT STARTING VALUE
	MOVEM T1,UMTMRD
	MOVE T1,TAPEBK+.MOIWT	;GET NUMBER OF PHYSICAL RECS WRITTEN
	SUB T1,ACCPW(ACC)	;SUBTRACT STARTING VALUE
	MOVEM T1,UMTMWR
	MOVE T1,TAPEBK+.MOIRF	;GET NUMBER OF FRAMES READ
	IDIVI T1,^D1000		;IN THOUSANDS
	SUB T1,ACCFR(ACC)	;SUBTRACT STARTING VALUE
	MOVEM T1,UMTMRF
	MOVE T1,TAPEBK+.MOIWF	;GET NUMBER OF FRAMES WRITTEN
	IDIVI T1,^D1000		;IN THOUDANDS
	SUB T1,ACCFW(ACC)	;SUBTRACT STARTING VALUE
	MOVEM T1,UMTMWF
	MOVE T1,TAPEBK+.MOISR	;GET NUMBER OF SOFT READ ERRORS
	SUB T1,ACCSR(ACC)	;SUBTRACT STARTING VALUE
	MOVEM T1,UMTSRE
	MOVE T1,TAPEBK+.MOISW	;GET NUMER OF SOFT WRITE ERRORS
	SUB T1,ACCSW(ACC)	;SUBTRACT STARTING VALUE
	MOVEM T1,UMTSWE
	MOVE T1,TAPEBK+.MOIHR	;GET NUMBER OF HARD READ ERRORS
	SUB T1,ACCHR(ACC)	;SUBTRACT STARTING VALUE
	MOVEM T1,UMTHRE
	MOVE T1,TAPEBK+.MOIHW	;GET NUMBER OF HARD WRITE ERRORS
	SUB T1,ACCHW(ACC)	;SUBTRACT STARTING VALUE
	MOVEM T1,UMTHWE
	MOVE T1,RSBASN(RSB)	;GET VOLUME SET NAME
	MOVEM T1,UMTFSI
	MOVE T1,ACCDSP(ACC)	; GET DISPOSITION OF REQUEST
	MOVEM T1,UMTDSP		; SAVE IT
	MOVEI T1,.UTMMT		;THIS IS TAPE MOUNT INFO
	CALLRET SNDACC		;SEND ACCOUNTING INFO TO MONITOR
;DELACC - DELETE ACCOUNT BLOCK FROM QUEUE
;ACCEPTS: ACC/	ADDRESS OF ACCOUNT BLOCK
;RETURNS: +1, NOTHING

DELACC:	SETZM ACCDD(ACC)	;SET ACC INACTIVE
	QSCANI AABQDB		;SET UP TO SCAN ACTIVE ACC QUEUE
	SAVEAC <ACC>

; SEARCH ACCOUNT BLOCK QUEUE AND EXTRACT ABORTED REQUESTS

DELAC1:	CALL QMSCAN		;GET ADDRESS OF NEXT ACC ON QUEUE
	 RET			;NONE LEFT, EXIT
	MOVEI ACC,-ACCLNK(T2)	;LOAD ACC WITH ACC BLOCK ADDRESS
	SKIPE ACCDD(ACC)	;IS REQUEST ABORTED?
	JRST DELAC1		;NO, SKIP IT
	CALL QMDQS		;DEQUEUE ACC, GET LINKAGE ADDR IN T2
	MOVEI T1,IABQDB		;GET QDB ADDRESS
	CALL QMQH		;QUEUE ACC TO HEAD OF INACTIVE QUEUE
	JRST DELAC1		;CONTINUE SCAN

;FNDACC - FIND AN EXISTING ACCOUNT BLOCK

;ACCEPTS: T1/	JOB NUMBER
;	  T2/	DEVICE DESIGNATOR

;RETURNS: +1,	FAILURE, COULD NOT FIND BLOCK
;	  +2,	SUCCESS, ACC/ ADDRESS OF ACCOUNT BLOCK

FNDACC:	SAVEQ
	DMOVE Q1,T1
	QSCANI AABQDB		;SET UP TO SCAN ACTIVE ACC QUEUE
FNDAC1:	CALL QMSCAN		;GET ADDRESS OF NEXT ACC IN T2
	 RET			;NONE LEFT
	MOVEI ACC,-ACCLNK(T2)	;LOAD ACC ADDRESS
	CAME Q2,ACCDD(ACC)	;IS THIS THE RIGHT DEVICE DESIGNATOR?
	JRST FNDAC1		;NO, GET ANOTHER ACC
	LOAD T1,ACCJN
	CAME Q1,T1		;IS THIS THE RIGHT JOB?
	JRST FNDAC1		;NO, TRY ANOTHER ACC
	RETSKP			;SUCCESS

; GETABI - INITIALIZE FREE ACC POOL FOR GETACC
; RETURNS +1: ALWAYS

GETABI:	SAVEQ
	MOVEI Q1,ACC0		;GET ADDRESS OF ACC POOL
	MOVEI Q2,MAXACC+1	;# OF ACCS IN POOL
GTABI1:	MOVEI T1,IABQDB		;GET QDB ADDRESS
	MOVEI T2,ACCLNK(Q1)	;GET ADDRESS OF ACC LINKAGE
	CALL QMQT		;QUEUE ACC TO TAIL OF FREE QUEUE
	ADDI Q1,ACCSIZ		;POINT Q1 AT NEXT ACC
	SOJG Q2,GTABI1		;LOOP THRU ALL ACCOUNT BLOCKS
	RET
; GETACC - ALLOCATE AN ACCOUNT BLOCK
; RETURNS +1: ACCOUNT BLOCK ALLOCATED, BUT IT'S THE LAST ONE
;	  +2: ACCOUNT BLOCK ALLOCATED, MORE FREE ACC BLOCK'S LEFT
;  ACC/ ADDR OF ACCOUNTING BLOCK

GETACC:	MOVEI T1,IABQDB		;POINT TO INACTIVE ACC QUEUE
	CALL QMDQH		;DEQUEUE HEAD OF QUEUE
	 CALL STOP		;QUEUE EMPTY, PROGRAM LOGIC ERROR
	MOVEI ACC,-ACCLNK(T2)	;LOAD UP ACC AC
	MOVSI T1,1(ACC)		;BLT SOURCE
	HRRI T1,2(ACC)		;BLT DESTINATION
	SETZM 1(ACC)		;CLEAR 2ND WORD OF ACC
	BLT T1,ACCSIZ-1(ACC)	;CLEAR THE REST OF THE ACC
	GTAD
	MOVEM T1,ACCCRT(ACC)	;STORE TIME WHEN REQUEST WAS RECEIVED
	MOVEI T2,ACCLNK(ACC)	;GET ADDRESS OF ACC LINKAGE WORD
	SKIPN IABQDB		;WAS THIS THE LAST FREE ACC?
	JRST [	MOVEI T1,IABQDB	;YES, CAN'T GIVE IT AWAY
		CALLRET QMQH]	;PUT ON INACTIVE QUEUE AND TAKE +1
	MOVEI T1,AABQDB		;NOT THE LAST FREE ONE
	CALL QMQT		;QUEUE TO TAIL OF ACTIVE QUEUE
	RETSKP

;SNDACC - SEND ACCOUNTING INFORMATION TO MONITOR

;ACCEPTS: T1/	TYPE OF ENTRY
;	  ACC/	ADDRESS OF ACCOUNT BLOCK

;RETURNS: +1,	ALWAYS

SNDACC:	MOVE T4,T1		;SAVE TYPE OF ENTRY
	GTAD			;GET CURRENT DATE AND TIME
	SUB T1,ACCSVT(ACC)	;SUBTRACT SERVICED TIME GIVING DAYS,,FRACTION
	MOVEM T1,ACCEUT(ACC)	; AND STORE. CHKPNT WILL CONVERT TO SECONDS.
	MOVE T1,T4		;RESTORE TYPE OF ENTRY
	MOVEI T2,USRNAM		;MOVE COMMON INFO FROM ACCOUNT BLOCK
	HRLI T2,ACCUSR(ACC)	; TO USAGE AREA
	BLT T2,USRNAM+ACCCSZ-4
	LOAD T2,ACCJN		;GET JOB NUMBER
	MOVEM T2,JOBNO
	HRRE T2,ACCNO(ACC)	;[6027]GET LINE # (use HRRE to extend sign bit)
	MOVEM T2,LINO
	MOVEI T2,USGSTR		;ASSUME STRUCTURE RECORD
	CAIE T1,.UTMNT		;IS IT A STRUCTURE?
	MOVEI T2,USGMTA		;NO, IT'S A MAGTAPE ENTRY
	MOVEI T1,.USENT		;WRITE AN ENTRY INTO SYSTEM DATA FILE
	SKIPN TSTF		;DON'T MAKE USAGE ENTRY IF TESTING
	USAGE
	 ERCAL WOUSGF		;REPORT ERROR
	SETZM JOBNO		;ZERO USAGE AREA
	MOVE T1,[JOBNO,,JOBNO+1]
	BLT T1,JOBNO+USGSIZ-2
	RET
;STONAM - STORE USER'S NAME INTO ACCOUNT BLOCK

;ACCEPTS: T1/	USER NUMBER
;RETURNS: +1,	FAILURE, COULD NOT FIND USER
;	  +2,	SUCCESS

STONAM:	MOVE T2,[-2,,Q1]
	MOVEI T3,.JITNO		;GET TERMINAL AND USER NUMBERS
	GETJI
	 RET			;USER NOT AROUND
	SKIPN Q2		;IS USER REALLY THERE?
	RET			;NO
	STOR Q1,ACCLN		;STORE LINE NUMBER
	HRROI T1,ACCUSR(ACC)	;GET USER NAME
	MOVE T2,Q2
	DIRST
	 JFCL			;CAN'T GET NAME
	RETSKP

;STOSTR - STORE STRUCTURE INFO INTO USAGE BLOCK

;ACCEPTS: ACC/	ADDRESS OF ACCOUNT BLOCK
;RETURNS: +1,	ALWAYS

STOSTR:	MOVE T1,ACCSTN(ACC)	;GET STRUCTURE NAME
	MOVEM T1,USTNM
	LOAD T1,ACCKT		;GET CONTROLLER TYPE
	MOVEM T1,USTKTP
	LOAD T1,ACCDT		;GET DEVICE TYPE
	MOVEM T1,USTDTP
	LOAD T1,ACCST		;GET STRUCTURE TYPE
	MOVEM T1,USTSTP
	LOAD T1,ACCNU		;GET NUMBER OF PACKS
	MOVEM T1,USTTNP
	LOAD T1,ACCMB		;GET MOUNT COUNT BEFORE MOUNTING
	MOVEM T1,USTMC
	MOVE T1,ACCDSP(ACC)	; GET DISPOSITION OF REQUEST
	MOVEM T1,USTDSP		; SAVE IT
	MOVEI T1,1		;GET ACCESS TYPE
	MOVEM T1,USTATP         ;SAVE IT
	RET
SUBTTL AVR - AUTOMATIC VOLUME RECOGNITION

; AVR - INITIATE AVR SEQUENCE FOR A TAPE DRIVE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

AVR:	JN MTAJCT,,R		;EXIT IF I'M ALREADY PROCESSING
	JN MTALT,,R		;EXIT IF VOLUME ALREADY RECOGNIZED
	JN MTAMT,,[LOAD T1,MTASTE ;GET STATE
		CAIE T1,S.INIT	;IN INIT MODE?
		RET		;NO, EXIT
		JRST .+1]	;YES, PROCEED
	MOVE T1,MTAFLG(MTA)	;GET FLAGS
	MOVEI T2,.LTUNL
	TXNN T1,MA%AVS		;IS AVR SUPPORTED FOR THIS DRIVE?
	STOR T2,MTALT		;NO, MUST CLASSIFY AS UNLABELED
	TXNN T1,MA%AVE		;IS AVR ENABLED FOR THIS DRIVE?
	JRST [	CALL REW	;NO, IS DRIVE LOADED?
		 RET		;NO
		CALLRET WOTMD]	;YES, TELL OPERATOR ABOUT IT
	MOVX T1,MA%UXV+MA%OPF
	ANDCAM T1,MTAFLG(MTA)	;CLEAR LABEL-RELATED FLAGS
	CALL MTAGJF		;GET JFN ON MTA DEVICE
	MOVEI T1,DENMAX
	STOR T1,MTADEN		;START AT HIGHEST DENSITY

; LOOP TO CHECK FOR LABEL AT ALL AVAILABLE DENSITIES

AVR2:	LOAD T1,MTADEN		;GET DENSITY
	CALL DRVDEN		;CAN THE DRIVE OPERATE AT THIS DENSITY?
	 JRST AVR2B		;NO, SKIP TO THE NEXT DENSITY
	MOVEI T1,AVR2A		;ENTER AT AVR2A AFTER REWIND
	CALL REWEA		;TRY TO REWIND
	 JRST AVR3		;CAN'T REWIND, WRAP UP AVR
	RET			;EXIT UNTIL REWIND COMPLETES

; END-ACTION FOR REWIND

AVR2A:	CALL CHKLT		;CHECK LABEL TYPE OF THE TAPE
	 SKIPA			;CAN'T READ TAPE AT THIS DENSITY
	JRST AVR3		;TAPE WAS IDENTIFIFED AT THIS DENSITY
AVR2B:	DECR MTADEN		;NEXT DENSITY
	JN MTADEN,,AVR2		;GO AROUND FOR ANOTHER TRY

; NOTHING CAN BE READ FROM THIS TAPE

	MOVEI T1,.SFTDF
	TMON			;GET TAPE-MOUNT CONTROLS SET BY SETSPD
	JXN T2,MT%UUT,[CALL UNLOAD ;IF UNLOAD SET BY INSTALLATION, DO IT
		CALL MTARJF	;DUMP JFN
		CALL WOLRDX	;TELL OPERATOR
		JRST AVR4]	;GO CHECK WAITING RSB'S

; MTA STATUS BLOCK NOW REFLECTS THE ATTRIBUTES OF THE AVR'ED VOLUME

AVR3:	CALL MTARJF		;DUMP JFN
	LOAD T1,MTASTE
	CAIN T1,S.INIT		;DRIVE IN INITIALIZE MODE?
	JRST [	CALLRET KVITAV]	;YES, SPECIAL EXIT
	CALL CKMPAV		;DRIVE STILL AVAILABLE?
	 CALL DACMTA		;NO, HERE IS A GOOD PLACE TO DEACTIVATE
	MOVE T1,MTAFLG(MTA)
	JXE T1,MA%LOD,AVR4	;WRAP UP IF DRIVE NOT LOADED
	CALL WOTMD		;TELL OPERATOR TAPE IS MOUNTED
	CALL WOCKSW		;IS THIS A WRITE-PROTECTED SCRATCH TAPE?
	 JRST AVR4		;YES, DRIVE UNLOADED AND MESSAGE TYPED
	SKIPN MTAVOL(MTA)	;HAS THE VOLUME BEEN IDENTIFIFED?
	RET			;NO, MUST WAIT FOR KEYIN
	CALL MATCHV		;YES, TRY FOR A MATCH

; CHECK IF NECESSARY TO TELL THE OPERATOR OF PENDING TAPE MOUNT REQUESTS

AVR4:	QSCANI ARBQDB		;SET UP TO SCAN REQUEST QUEUE
AVR41:	CALL NMTRSB		;GET NEXT TAPE REQUEST IN RSB AC
	 RET			;NONE LEFT
	CALL WOVMT		;TELL OPERATOR IF NECESSARY
	JRST AVR41		;LOOP THRU ALL REQUESTS
; CHKLT - IDENTIFY LABEL TYPE OF A TAPE AND UPDATE MTA STATUS BLOCK
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: COULD NOT READ ANY INFORMATION FROM THE TAPE
;	  +2: TAPE WAS IDENTIFIED AT DENSITY IN MTADEN

CHKLT:	SAVEQ

; Q1/	BIT 01 SET - VOL1 ACCESSIBILITY IS NOT BLANK
;	BIT 02 SET - HDR1 ACCESSIBILITY IS NOT BLANK
;	BIT 04 SET - OVERWRITE ACCESS DENIED - WORLD DP%CN IS RESET
;	BIT 10 SET - OVERWRITE ACCESS DENIED - WORLD FP%WR IS RESET
; Q2/	1 = READING CORE-DUMP MODE, 0 = READING INDUSTRY-COMPATIBLE MODE
; Q3/	CONTENTS OF MTAVOL AT TIME CHKLT WAS CALLED (USED TO RESTORE
;	MTAVOL IF TAPE HAS A VOL1 BUT NO HDR1)

	MOVE Q3,MTAVOL(MTA)	;REMEMBER CURRENT VOLID
	SETZ Q1,
	MOVEI T1,.LTUNL
	STOR T1,MTALT		;SET UNLABELED INITIALLY FOR LBLICV
	CALL MTAOPI		;OPEN MTA JFN
	 RETSKP			;OFFLINE

; CHECK FOR AND PROCESS VOL1 LABEL
; THE FIRST READ IS DONE IN CORE-DUMP MODE TO ALLOW FOR READING THE
; LARGEST POSSIBLE RECORD THAT TOPS-20 CAN WRITE (MOST LIKELY CASE
; SEEMS TO BE AN UNLABELED DUMPER TAPE WITH A LARGE BLOCKING FACTOR).
; BITS 0-31 OF THE FIRST WORD LOOK THE SAME IN CORE-DUMP AND I/C MODES,
; AND THAT'S THE FIRST 4 FRAMES OF THE RECORD (ALL I CARE ABOUT HERE).
; IF IT'S A VOL1, THEN REWIND AND READ IT AND ALL OTHER LABELS IN I/C
; MODE.  IF IT'S NOT A VOL1, THEN JUST CLASSIFY THE TAPE AS UNLABELED.

	MOVEI Q2,1		;SETUP Q2 FOR LOOPING
CHKL1:	CALL REW		;REWIND TO TEST IF DRIVE IS ONLINE
	 JRST [	CALL MTACLS	;OFFLINE, CLOSE JFN
		RETSKP]		;PREVENT CHECKING OTHER DENSITIES
	LOAD T1,MTAJFN		;GET JFN
	MOVEI T2,.MOSDM		;MTOPR FUNCTION CODE
	MOVE T3,[EXP .SJDM8,.SJDMC](Q2) ;GET DESIRED DATA MODE
	MTOPR			;SET DATA MODE
	CALL RDLBL		;TRY TO READ 1ST RECORD FROM TAPE
	 JRST [	JUMPLE T1,CHKLR1 ;TIMEOUT OR DATA ERROR
		SKIPG Q2	;SKIP IF CORE-DUMP READ
		SETZM LBUF1	;NON-LABEL READ SUCCESSFULLY
		JRST .+1]	; SO FORCE CHKV1 TO SAY IT'S UNLABELED
	SOJE Q2,[LOAD T1,MTAJFN	;FIRST READ ATTEMPT, GET JFN
		MOVEI T2,.MORDN	;FUNCTION = READ DENSITY
		MTOPR		;GET DENSITY THE TAPE WAS READ AT IN T3
		STOR T3,MTADEN	;REMEMBER IT
		CALL CHKV1A	;IS IT A VOL1?
		 JRST CHKLP	;NO, CLASSIFY AS UNLABELED
		JRST CHKL1]	;YES, REWIND AND READ IN I/C MODE
	CALL CHKV1		;CHECK FOR VOL1, FILL IN STATUS BLOCK
	 JRST CHKLP		;NOT LABELED (SHOULD NEVER GET HERE)
	CAIE T1," "		;VOL1 ACCESSIBILITY BLANK?
	TRO Q1,1		;NO, SET FLAG
	SETZM MTASET(MTA)	;LABELED TAPE - CLEAR SETNAME
	JUMPE T2,CHKL2		;JUMP IF IT CAN'T BE A TOPS-20 TAPE

; CHECK FOR AND PROCESS VOL2 LABEL

	CALL RDLBL		;YES, GET LABEL AFTER VOL1
	 JRST CHKLUN		;NO LABEL AFTER VOL1, IT'S UNLABELED
	CALL CHKV2		;IS IT A VOL2?
	 JRST CHKL3		;NO
	STOR T1,MA%SCR,MTAFLG(MTA) ;YES, STORE SCRATCH FLAG
	TRNN T2,DP%CN		;WORLD DP%CN RESET?
	TRO Q1,4		;YES, SET DP%CN ACCESS-DENIED FLAG
	MOVEI T1,.LTT20
	STOR T1,MTALT		;SET LABEL-TYPE TO TOPS-20

; CHECK FOR AND PROCESS HDR1 LABEL

CHKL2:	CALL RDLBL		;GET NEXT LABEL
	 JRST CHKLUN		;NO LABEL HERE, TAPE IS UNLABELED
CHKL3:	MOVE T1,LBUF2		;GET FIRST 5 CHARACTERS FROM RECORD
	TRZ T1,77777		;KEEP THE FIRST 3 CHARACTERS
	CAME T1,[ASCIZ/VOL/]	;IS IT A VOL
	CAMN T1,[ASCIZ/UVL/]	; OR A UVL?
	JRST CHKL2		;YES, CONTINUE SEARCH
	CALL CKHDR1		;IF HDR1, UPDATE STATUS BLOCK
	 JRST CHKLUN		;NOT HDR1, TAPE IS UNLABELED
	CAIE T1," "		;HDR1 ACCESSIBILITY BLANK?
	TRO Q1,2		;NO, SET FLAG

; CHECK FOR AND PROCESS HDR2 LABEL

	CALL RDLBL		;GET NEXT LABEL
	 JRST CHKLP		;NO LABEL
	CALL CKHDR2		;CHECK IF HDR2
	 JRST CHKLP		;NOT HDR2
	TRNN T1,FP%WR		;WORLD WRITE-ACCESS ALLOWED TO FILE?
	TRO Q1,10		;NO, SET WRITE-ACCESS DENIED
CHKLP:	CALL CHKLR1		;REWIND AND CLOSE JFN
	LOAD T1,MTALT		;GET LABEL TYPE
	CAIN T1,.LTANS		;ANSI?
	JRST [	TRNE Q1,1+2	;YES, ANY NON-BLANK ACCESSIBILITIES?
		JRST CHKLPS	;YES, SET PROTECTED
		JRST CHKLPR]	;NO, RESET PROTECTED
	CAIN T1,.LTT20		;TOPS-20?
	JRST [	TRNE Q1,4	;YES, WORLD WRITE ACCESS DENIED TO VOL?
		JRST CHKLPS	;YES, SET PROTECTED
		TRNE Q1,2	;RESET PROT IF FILE ACCESSIBILITY BLANK
		TRNN Q1,10	; OR IF WORLD WRITE ACCESS IS ALLOWED
		JRST CHKLPR
		JRST CHKLPS]	;NEITHER, SET PROTECTED
	RETSKP

CHKLPS:	SETONE MA%OPF,MTAFLG(MTA) ;SET OVERWRITE-PROTECTED FLAG
CHKLPR:	JE MA%SCR,MTAFLG(MTA),RSKP ;RETURN IF NOT SCRATCH
	MOVX T1,MA%OPF+MA%UXV	;IT'S A SCRATCH TAPE
	ANDCAM T1,MTAFLG(MTA)	;TURN OFF OVERWRITE INHIBITORS
	RETSKP

CHKLR1:	CALL REW		;GET BACK TO BOT
	 JFCL			;OFFLINE, WILL BE CAUGHT BY AVR
CHKLID:	CALL MTACLS		;CLOSE MTA
	RET

; TAPE HAS A VOL1 BUT NO HDR1 - CLASSIFY IT AS UNLABELED

CHKLUN:	MOVEI T1,.LTUNL
	STOR T1,MTALT		;SET LABEL TYPE TO UNLABELED
	MOVEM Q3,MTAVOL(MTA)	;REPLACE OLD VOLID
	JRST CHKLP		;WRAP UP AND EXIT
; CHKV1 - IDENTIFY A VOLUME WHOSE FIRST RECORD IS IN LBUF1
;  MTA/ ADDR OF MTA STATUS BLOCK
;  LBUF1/ UNMODIFIED RECORD READ FROM TAPE
; RETURNS +1: VOLUME IS UNLABELED, MTALT UPDATED
;	  +2: VOLUME IS LABELED, MTALT AND MTAVOL UPDATED
;		T1/ VOL1 ACCESSIBILITY CHARACTER
;		T2/ 1 MEANS VOL1 MEETS NECESSARY CONDITIONS FOR
;		    CLASSIFICATION AS TOPS-20 LABEL TYPE, ELSE 0

; CHKV1A - DETERMINE IF RECORD IN LBUF1 (IN CORE-DUMP FORMAT) IS A VOL1
;  LBUF1/ UNMODIFIED RECORD READ FROM TAPE IN CORE-DUMP MODE
; RETURNS +1: NOT A VOL1
;	  +2: IS A VOL1

CHKV1:	TDZA T1,T1		;REMEMBER CHKV1 ENTRY
CHKV1A:	MOVEI T1,1		;REMEMBER CHKV1A ENTRY
	SAVET			;SET UP TO RETURN VALUES TO CALLER
	SETZM CT2		;SET NOT TOPS-20
	MOVE T2,LBUF1		;GET 1ST 4 FRAMES FROM TAPE
	TRZ T2,17		;B32-B35 MEANINGLESS, SO SET TO ZERO
	CAMN T2,[713533,,237420] ;EBCDIC VOL1?
	JRST [	MOVEI T1,.LTEBC	;YES, SET LABEL TYPE TO EBCDIC
		JRST CHKV11]	;SKIP OTHER TESTS
	TDZ T2,[1B0+1B8+1B16+1B24] ;CLEAR 8TH BITS FOR ASCII CHECK
	CAMN T2,[BYTE(8) "V","O","L","1"] ;ASCII VOL1?
	JRST [	MOVEI T1,.LTANS	;YES, IS EITHER ANSI OR TOPS-20
		JRST CHKV11]	; BUT ASSUME ANSI FOR NOW...
CHKV12:	MOVEI T1,.LTUNL
	SKIPN CT1		;DON'T STORE LABEL TYPE IF CHKV1A
	STOR T1,MTALT		;SET LABEL TYPE = UNLABELED
	RET			;+1 RETURN FOR UNLABELED

; VOL1 LABEL WAS FOUND

CHKV11:	SKIPE CT1		;CHKV1A ENTRY?
	RETSKP			;YES, INDICATE RECORD WAS A VOL1
	STOR T1,MTALT		;STORE LABEL TYPE IN MTA TABLE
	CALL LBLICV		;CONVERT LABEL TO 7-BIT ASCII
	MOVE T1,[ILPTR(V1VID)]	;ADDRESS VOLID FIELD IN VOL1
	MOVEI T2,6		;6-CHARACTER FIELD
	CALL CVTA6		;CONVERT VOLID TO SIXBIT
	 JRST CHKV12		;BAD VOLID, SO ASSUME UNLABELED

; GIVE ERROR IF VOLID FROM "IDENTIFY" COMMAND DOESN'T MATCH THE
; ACTUAL VOLID THAT IS RECORDED ON THE TAPE

	MOVEM T1,MTAVOL(MTA)	;STORE ACTUAL VOLID IN MTA STATUS BLOCK
	SKIPE MTAIDV(MTA)	;DOES ALLEGED VOLID EXIST?
	CAMN T1,MTAIDV(MTA)	;YES, ALLEGED VOLID MATCH ACTUAL VOLID?
	SKIPA			;NO ALLEGED VOLID, OR IT MATCHES ACTUAL
	CALL [	TMCT <%I%M Cannot Change Volid Of Labeled Tape>
		MOVEI T3,TMCMSG	;POINT TO MESSAGE
		CALLRET BTWTON]	;TELL OPERATOR HE BLEW IT
	SETZM MTAIDV(MTA)	;CLEAR ALLEGED VOLID

; COPY VOL1 TO MTA STATUS BLOCK AND CHECK FOR TOPS-20 LABEL TYPE

	MOVSI T1,LBUF1		;BLT SOURCE
	HRRI T1,MTAV1(MTA)	;BLT DESTINATION
	BLT T1,MTAV1+LB8WDS-1(MTA) ;TRANSFER VOL1 LABEL TO STATUS BLOCK
	LDB T1,[LPTR(V1ACS)]	;GET ACCESSIBILITY CHARACTER
	MOVEM T1,CT1		;RETURN ACCESSIBILTY TO CALLER
	CAIE T1,"1"		;TOPS-20 PROTECTION?
	RETSKP			;NO, WILL CLASSIFY AS ANSI TAPE
	MOVE T1,[ILPTR(V1SCD)]	;GET POINTER TO SYS CODE IN VOL1
	MOVE T2,[POINT 7,T20SCD] ;GET POINTER TO TOPS-20 SYS CODE
CHK201:	ILDB T3,T1		;GET CHAR FROM VOL1
	ILDB T4,T2		;GET CHAR FROM TOPS-20 SYS CODE
	JUMPE T4,[AOS CT2	;MATCH SUCCESSFUL, SET TOPS-20 VOL1
		RETSKP]
	CAMN T3,T4		;MATCH SO FAR?
	JRST CHK201		;YES, CONTINUE SCAN
	RETSKP			;RETURN, NON-TOPS-20 VOL1

; TOPS-20 SYSTEM CODE

T20SCD:	ASCIZ /DECSYS20**   /
; CHKV2 - EXAMINE LABEL BUFFER FOR VOL2 RECORD
;  LBUF2/ RECORD TO BE EXAMINED
; RETURNS +1: RECORD IS NOT A VOL2
;	  +2: RECORD IS A VOL2
;		T1/ 0=NON-SCRATCH  1=SCRATCH
;		T2/ TOPS-20 VOLUME PROTECTION CODE

CHKV2:	SAVET			;SET UP TO RETURN VALUES TO CALLER
	SETZM CT1
	MOVE T1,LBUF2		;GET FIRST 5 CHARS OF LABEL
	TRZ T1,377		;MASK DOWN TO 4 CHARACTERS
	CAME T1,[ASCII/VOL2/]	;IS IT A VOL2?
	RET			;NO, RETURN +1
	MOVSI T1,LBUF1		;BLT SOURCE
	HRRI T1,MTAV2(MTA)	;BLT DESTINATION
	BLT T1,MTAV2+LB8WDS-1(MTA) ;TRANSFER VOL2 LABEL TO STATUS BLOCK

	MOVE T1,[ILPTR(V2PRO)]	;GET POINTER TO PROTECTION FIELD
	CALL PROTIN		;GET PROTECTION IN T1
	 MOVEI T1,777777	;BAD PROTECTION, ASSUME ACCESSIBLE
	MOVEM T1,CT2		;RETURN PROTECTION CODE TO CALLER

	MOVE T2,[ILPTR(V2OWN)]	;GET POINTER TO VOL2 OWNER-NAME FIELD
	MOVEI T3,V2OWNL		;GET # OF CHARACTERS TO SCAN
CHKV21:	ILDB T4,T2		;GET A CHAR FROM OWNER'S NAME
	CAIE T4," "		;SPACE?
	RETSKP			;NO, NOT SCRATCH SO RETURN
	SOJG T3,CHKV21		;CONTINUE SCAN
	AOS CT1			;SCAN COMPLETE, IT'S A SCRATCH
	RETSKP
; CKHDR1 - CHECK LBUF2 FOR HDR1 AND PROCESS HDR1 FIELDS
;  LBUF2/ LABEL TO BE EXAMINED
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: NOT HDR1 LABEL
;	  +2: WAS HDR1 LABEL, INFORMATION STORED IN MTA STATUS BLOCK
;		T1/ HDR1 ACCESSIBILITY CODE

CKHDR1:	MOVE T1,LBUF2		;GET FIRST 5 CHARS OF LABEL
	TRZ T1,377		;MASK DOWN TO 4 CHARACTERS
	CAME T1,[ASCII/HDR1/]	;IS THIS A HDR1?
	RET			;NO
	MOVE T1,[ILPTR(H1SET)]	;YES, POINT TO SETNAME FIELD
	MOVEI T2,6		;6-CHARACTER FIELD
	CALL CVTA6		;CONVERT SETNAME TO SIXBIT
	 SETZ T1,		;BAD SETNAME, ASSUME NONE
	MOVEM T1,MTASET(MTA)	;STORE SET NAME IN STATUS BLOCK
	MOVE T1,[ILPTR(H1EXP)]	;POINT AT EXPIRATION-DATE FIELD
	CALL LDATIN		;CONVERT THE DATE FROM THE LABEL
	 SETZ T1,		;BAD DATE, ASSUME EXPIRED
	SETO T2,		;SPECIFY CURRENT DATE/TIME
	MOVX T4,IC%JUD		;WANT JULIAN FORM
	ODCNV			;GET T2/ YEAR,,JULIANDAY
	MOVX T3,MA%UXV
	CAMLE T1,T2		;IS THE TAPE EXPIRED?
	IORM T3,MTAFLG(MTA)	;NO, SET NOT-EXPIRED FLAG
	LDB T1,[LPTR(H1ACS)]	;GET ACCESSIBILITY CODE FOR CALLER
	RETSKP


; CKHDR2 - CHECK LBUF2 FOR HDR2 LABEL
;  LBUF2/ LABEL TO BE EXAMINED
; RETURNS +1: NOT HDR2
;	  +2: HDR2, T1/ TOPS-20 FILE PROTECTION CODE

CKHDR2:	MOVE T1,LBUF2		;GET 5 CHARS
	TRZ T1,377		;MASK DOWN TO 4 CHARACTERS
	CAME T1,[ASCII/HDR2/]	;HDR2?
	RET			;NO
	MOVE T1,[ILPTR(H2PRO)]	;GET POINTER TO PROTECTION CODE FIELD
	CALL PROTIN		;GET PROTECTION
	 MOVEI T1,777777	;ERROR, ASSUME UNPROTECTED
	RETSKP
; LBLICV - CONVERT INDUSTRY-COMPATIBLE LABEL IN LBUF1 TO 7-BIT ASCII
;	   LABEL IN LBUF2, USING THE FOLLOWING RULES:
;		NO CONVERSION PERFORMED FOR UNLABELED TAPES
;		ANSI AND TOPS-20 LABEL TYPES ASSUMED TO BE 8-BIT ASCII
;		EBCDIC LABEL TYPE ASSUMED TO BE 8-BIT EBCDIC
;  LBUF1/ LABEL TO BE CONVERTED, 80 8-BIT BYTES
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS, LBUF2/ 7-BIT ASCII EQUIVALENT OF LABEL IN LBUF1

LBLICV:	SAVEQ
	LOAD T1,MTALT		;GET LABEL TYPE IN T1
	CAIN T1,.LTUNL		;UNLABELED?
	RET			;YES, RETURN TAKING NO ACTION
	DMOVE Q1,[POINT 8,LBUF1	;GET LOAD POINTER IN Q1
		POINT 7,LBUF2]	;GET GET STORE POINTER IN Q2
	MOVEI T2,LBLSIZ		;GET # OF FRAMES TO PROCESS
LBLCV1:	ILDB T3,Q1		;GET A BYTE FROM LBUF1
	CAIN T1,.LTEBC		;EBCDIC LABEL?
	JRST [	ADJBP T3,[POINT 7,EATT,6] ;YES, POINT AT ASCII EQUIV.
		LDB T3,T3	;GET ASCII EQUIVALENT IN T3
		JRST .+1]
	IDPB T3,Q2		;STORE CHARACTER IN LBUF2
	SOJG T2,LBLCV1		;LOOP THRU ENTIRE BUFFER
	RET
; RDLBL - READ A LABEL FROM A TAPE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: T1/ -1 = READ I/O OPERATION TIMED OUT
;	      T1/  0 = DEVICE OR DATA ERROR ON READ
;	      T1/  1 = TAPE MARK OR RECORD .LT. 80 FRAMES READ
;	  +2: RECORD OF 80 BYTES OR LONGER READ SUCCESSFULLY INTO
;	      LBUF1 IN INDUSTRY-COMPATIBLE FORMAT; ASCII EQUIVALENT
;	      LABEL IN LBUF2

RDLBL:	MOVE T1,[IOWD LBUF1W,LBUF1] ;GET IOWD FOR ENTIRE BUFFER
	SKIPN READCL		;FIRST READ SINCE I STARTED?
	MOVEM T1,READCL		;YES, SET UP TRIAL IOWD, EXPECT DUMPX3
RDLBL0:	LOAD T1,MTAJFN
	MOVEI T2,READCL		;GET ADDRESS OF COMMAND LIST
	IOXCT DUMPI,RDLBL1,RDLBL2 ;EXECUTE AND TIME OUT DUMPI JSYS
	JRST RDLBL3		;SUCCESSFUL (PROBABLY VERY RARE)

; ERROR RETURN FROM DUMPI

RDLBL1:	CALL CLRTAP		;CLEAR ERRORS AND GET ERROR INFO
	 JRST RDLBL2		;TIMED OUT
	CAIN T1,DUMPX3		;RECORD SIZE TOO LARGE?
	JRST [	MOVSI T1,1000	;YES
		ADDM T1,READCL	;REDUCE IT BY A PAGE
		JRST RDLBL0]	;TRY IT AGAIN WITH SMALLER RECORD SIZE
	CAIN T1,IOX4
	JRST [	MOVEI T1,1	;TAPE MARK, SET NON-LABEL
		RET]
	CAIE T1,IOX5		;DEVICE OR DATA ERROR?
	CALL STOP		;NO, I CAN'T HANDLE THIS ONE
	TXNE T2,MT%DVE+MT%DAE	;DEVICE ERROR OR DATA ERROR?
	JRST [	SETZ T1,	;YES
		RET]
	CAIGE T3,LBLSIZ		;IS THE RECORD LONG ENOUGH?
	JRST [	MOVEI T1,1	;NO
		RET]
RDLBL3:	CALL LBLICV		;GOOD LABEL, CONVERT IT
	RETSKP			;SUCCESSFUL RETURN

; DUMPI DID NOT COMPLETE IN TIME

RDLBL2:	CALL WOTIMO		;REPORT TIMEOUT TO OPERATOR
	SETO T1,		;RETURN -1
	RET
; POLLR - SELF-PERPETUATING PERIODIC MAGTAPE POLLING ROUTINE
;	  CHECKS FOR ONLINE-TO-OFFLINE AND OFFLINE-TO-ONLINE TRANSITIONS
; RETURNS +1: ALWAYS

POLLR:	TXO F,POLLF		;CAUSE CHECKS FOR ONLINE-TO-OFFLINE
	CALL TDSCIR		;PERFORM DRIVE SCAN
	TXZ F,POLLF
	MOVEI T1,POLINT		;GET INTERVAL BETWEEN POLLS
	MOVEI T2,POLLR		;ROUTINE ADDRESS
	CALLRET SRAI		;SCHEDULE NEXT POLL AND EXIT

; TDSCIH - CALLED AS A RESULT OF MTA STATUS CHANGE INTERRUPTS

TDSCIH:	AOSE TDSCF		;SCHEDULING REQUEST PRESENT ALREADY?
	DEBRK			;YES, EXIT
	CALL EIHR		;NO, REQUEST SCHEDULING AT TDSCIR
	EXP TDSCIR

; TDSCIR - CALLED BY SCHEDULER, REQUESTED BY TDSCIH
; RETURNS +1: ALWAYS

TDSCIR:	SAVEQ
	SAVEAC <MTA>
	SETOM TDSCF		;SET NO SCHEDULER REQUESTS FOR TDSCIR
	MOVE Q1,MTAN		;GET # OF MTA DEVICES ON SYSTEM
	MOVEI MTA,MTA0-MTASZ	;INIT MTA STATUS BLOCK POINTER

; I DON'T KNOW WHICH DRIVE DID IT, SO I HAVE TO CHECK EVERY ONE

TDSCI1:	SOJL Q1,R		;EXIT IF NO MTA DEVICES LEFT TO CHECK
	ADDI MTA,MTASZ		;GET STATUS BLOCK ADDRESS
	CALL TDSC1		;CHECK IT FOR A STATUS CHANGE
	JRST TDSCI1		;LOOP THRU ALL DRIVES
; TDSC1 - CHECK TAPE DRIVE FOR ONLINE/OFFLINE/REWIND-COMPLETE TRANSITION
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

TDSC1:	SAVEQ
	LOAD T1,MTASTE		;GET STATE
	JUMPE T1,R		;IGNORE IF NOT AVAILABLE
	CAIE T1,S.INIT		;IN INIT MODE?
	JRST [	JN MTAMT,,R	;NO, EXIT IF USER HAS THE DRIVE
		JRST .+1]
	CALL MTAGJF		;GET JFN NOW TO REDUCE GTJFN OVERHEAD
	MOVE Q1,MTAFLG(MTA)	;Q1/ MTA FLAGS
	CALL GMTADS
	MOVE Q2,T1		;Q2/ MTA STATUS BITS FROM MONITOR
	JXN Q2,SJ%OFS,[TXZE Q1,MA%LOD ;IF OFFLINE, DID I THINK SO TOO?
		CALL WOUNLW	;NO, ADMONISH OPERATOR
		MOVEM Q1,MTAFLG(MTA) ;UPDATE FLAGS
		JRST .+1]
	LOAD Q3,MTAREA		;END-ACTION ADDRESS PRESENT?
	JUMPN Q3,TDSC11		;YES
	TXNE Q1,MA%LOD		;PROCEED IF I THINK DRIVE IS UNLOADED
	TXNE Q1,MA%ULP		;PROCEED IF UNLOAD PENDING
	JRST TDSC11		;ONE OF THE ABOVE WAS TRUE
	TXNN F,POLLF		;POLLING?
	JRST [	CALLRET MTARJF]	;NO, NO NEED FOR FURTHER ANALYSIS
TDSC11:	LOAD T1,SJ%WLK,Q2	;GET WRITE-LOCKED BIT
	TRC T1,1		;COMPLEMENT TO GET WRITE-ENABLED
	STOR T1,MA%WEN,MTAFLG(MTA) ;STORE HERE FOR EASY REFERENCE

; CHECK FOR PENDING UNLOAD-REQUEST OR REWIND-ENDACTION

	TXZE Q1,MA%ULP		;WAS AN UNLOAD-REQUEST PENDING?
	JRST [	JXN Q2,SJ%REW,[CALLRET MTARJF] ;YES
		MOVEM Q1,MTAFLG(MTA) ;RESET MA%ULP IN STATUS BLOCK
		CALL UNLOAD	;UNLOAD THE DRIVE
		JRST .+1]
	JUMPN Q3,[JXN Q2,SJ%REW,[CALLRET MTARJF] ;EXIT IF REWINDING
		SETZRO MTAREA	;CLEAR END-ACTION ADDRESS
		CALL MTARJF	;DUMP JFN
		CALLRET (Q3)]	;CALL END-ACTION ROUTINE AND RETURN

; DRIVE NOT UNDER USER CONTROL AND AVR SEQUENCE NOT IN PROGRESS

	TXNN F,POLLF		;CHECK FOR ANY TRANSITION IF POLLING
	TXNN Q1,MA%LOD		;EXIT IF I THINK THE DRIVE IS LOADED
	CAIA			;POLLING OR DRIVE UNLOADED
	JRST [	CALLRET MTARJF]	;NOT POLLING AND DRIVE LOADED
	CALL REW		;IS IT LOADED NOW?
	 JRST [	TXNE Q1,MA%LOD	;NO, DID I THINK IT WAS LOADED?
		CALL WOUNLW	;YES, ADMONISH OPERATOR
		CALLRET MTARJF]	;DUMP JFN AND RETURN
	CALL MTARJF		;YES, DUMP JFN SO AVR CAN OCCUR
	TXNE Q1,MA%LOD		;HAS IT BEEN ONLINE ALL ALONG?
	RET			;YES, TAKE NO ACTION

; DRIVE IS COMING ON-LINE

	SETONE MA%LOD,MTAFLG(MTA) ;SET DRIVE-LOADED
	MOVX T1,MA%SCR+MA%UXV+MA%OPF+MA%ULP+MA%VMG
	ANDCAM T1,MTAFLG(MTA)	;CLEAR VARIOUS FLAGS
	SETZB T1,MTAVOL(MTA)	;SET VOLUME NOT IDENTIFIED (YET)
	SETZM MTAIDV(MTA)	;CLEAR OPERATOR-SUPPLIED VOLID
	STOR T1,MTALT		;SET RECOGNITION NOT ATTEMPTED (YET)
	LOAD T1,MTASTE
	CAIN T1,S.INIT		;DRIVE IN INITIALIZE MODE?
	JRST [	CALLRET KVITAV]	;YES, SPECIAL EXIT
	CALLRET AVR		;PERFORM IDENTIFICATION SEQUENCE
NOSHIP,<
SUBTTL DECTAPE SUPPORT

; RLSDTA - PROCESS RELEASE OF ALLOC'ED DECTAPE DEVICE
;  T1/ DEVICE DESIGNATOR
; RETURNS +1: ALWAYS

RLSDTA:	SAVEQ
	MOVE Q1,T1		;SAVE DESIGNATOR
	MOVE T2,T1		;COPY DESIGNATOR TO T2 FOR ALLOC
	MOVEI T1,.ALCAL		;ALLOC FUNCTION CODE
	MOVNI T3,1		;MAKE DTA AVAILABLE TO ALL USERS
	ALLOC
	 JFCL			;IGNORE FAILURE

; FIND REQUEST THAT WAS USING THIS DECTAPE AND DELETE IT

	TMCT <%I%5V Released>
	QSCANI ARBQDB		;SET UP TO SCAN REQUEST QUEUE
RDTA1:	CALL NXXRSB		;GET ADDRESS OF NEXT ACTIVE RSB
	 JRST RDTA2		;NONE LEFT
	LOAD T1,RSBTYP		;GET REQUEST TYPE
	CAIE T1,.MNTDT		;IS IT A DECTAPE-MOUNT REQUEST?
	JRST RDTA1		;NO, SKIP IT
	CAME Q1,RSBDTA(RSB)	;DOES THIS REQUEST OWN THE DECTAPE?
	JRST RDTA1		;NO
	LOAD T1,RSBJNO		;GET OWNER'S JOB #
	TMCT < by job %1D>
	ABTREQ (ABRTNR)		;FOUND THE OWNER, DELETE REQUEST
RDTA2:	MOVEI T3,TMCMSG		;GET ADDRESS OF MESSAGE
	CALLRET BTWTON		;TELL OPR'S THAT DECTAPE WAS RELEASED
; TLUDT - BUILD BLOCKS FOR SUCCESSFUL DECTAPE-MOUNT RESPONSE
;	  (CALLED BY TELUSR)
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS, T1/ FLAGS FOR GALAXY MSG HEADER

TLUDT:	STKVAR <<DVBLK,3>>
	CALL VQGCV		;GET VOLID IN T1
	TMCT <%I[DECtape volume %1S mounted]%_>
	MOVEI T1,TMCMSG		;GET ADDRESS OF TEXT
	MOVEI T2,.MNRTX		;GET ARGUMENT TYPE
	CALL PBTXT		;CREATE BUILDING BLOCK CONTAINING TEXT
	MOVE T1,[FLD(3,AR.LEN)+FLD(.MNRDV,AR.TYP)] ;GET HEADER
	MOVE T2,RSBSSN(RSB)	;GET SETNAME
	DMOVEM T1,DVBLK		;STORE HEADER AND SETNAME
	MOVE T1,RSBDTA(RSB)	;GET DECTAPE DEVICE DESIGNATOR
	MOVEM T1,2+DVBLK	;STORE DESIGNATOR IN .MNRDV BLOCK
	MOVEI T1,DVBLK		;GET ADDRESS OF BLOCK
	CALL PBBLK		;INSTALL BLOCK IN MESSAGE
	SETZ T1,		;NO FLAGS
	RET
; UDTM - PROCESS USER DECTAPE-MOUNT REQUEST RECEIVED FROM QUASAR
;  T1/ ADDRESS OF DECTAPE-MOUNT ENTRY IN IPCF MESSAGE FROM QUASAR
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

UDTM:	MOVEI T2,[[	MOVX T1,TM%WEN ;ROUTINE TO PROCESS FLAGS
			AND T1,.MEFLG(Q1)
			MOVEM T1,RSBUFL(RSB)
			RETSKP]
		BTRSET		;SETNAME
		BTRVLS		;VOLID LIST
		BTRRMK		;REMARK
		0]
	CALL BTMRSB		;BUILD RSB
	 RET			;ABORTED, EXIT
	MOVEI T1,1
	STOR T1,RSBCV		;CURRENT VOLUME = 1
	CALL PWATCH		;ABORT REQUEST IF USER DELETES PID
	MOVEI T1,RST.WM
	STOR T1,RSBSTE		;SET STATE = WAITING FOR MOUNT

; BUILD HEADER LINE

UDTM1:	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	TMCT <%IDECtape Mount Request # %1D>
	CALL CPYHDR		;COPY HEADER TO OPRHDR

; BUILD BODY OF MESSAGE

	CALL VQGCV		;GET CURRENT VOLID IN T1
	TMCT <%IMount volume %1S%_%U>
	SKIPE RSBRMK(RSB)	;DID THE USER SUPPLY A REMARK?
	JRST [	MOVEI T1,RSBRMK(RSB) ;YES, GET ADDR OF REMARK
		TMCT <%_User's remark: %1A>
		JRST .+1]
	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	TMCT <
  RESPOND msg# DTAn:
   or
  DELETE MOUNT-REQUEST %1D /REASON:reason>

; SEND MESSAGE AND GET RESPONSE

	MOVEI T2,RSBWTB(RSB)	;GET WTB ADDRESS
	MOVEI T3,OPRHDR		;GET ADDRESS OF HEADER
	JSP T1,BTWTOR		;SEND WTOR AND RECEIVE REPLY

; PROCESS RESPONSE

	MOVEI RSB,-RSBWTB(T2)	;LOAD RSB AC
	CALL COMNDI		;INIT FOR COMND PARSING
	MOVEI T2,[FLDDB. .CMDEV]
	CALL COMNDX		;PARSE DEVICE NAME
UDTM2:	 JRST [	MOVEI T3,[ASCIZ/Response Does Not Specify DECtape/]
		CALL BTACK	;REJECT IT
		JRST UDTM1]	;RE-ISSUE WTOR
	LOAD T1,DV%TYP,T2	;GET DEVICE TYPE
	CAIE T1,.DVDTA		;DECTAPE?
	JRST UDTM2		;NO, REJECT
	MOVEI T1,.ALCAL		;GET ALLOC FUNCTION CODE
	LOAD T3,RSBJNO		;GET USER'S JOB #
	ALLOC			;TRY TO ALLOC DTA TO USER
	 JRST UDTM3		;FAILED

; ALLOCATION SUCCESSFUL

	MOVEM T2,RSBDTA(RSB)	;STORE DEVICE DESIGNATOR
	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	TMCT <%I%2V Allocated To Request # %1D>
	MOVEI T3,TMCMSG
	CALL BTACK		;ACKNOWLEDGE SUCCESSFUL ALLOCATION
	MOVEI T1,RST.AC
	STOR T1,RSBSTE		;SET STATE TO ACTIVE
	CALL TELUSR		;TELL THE USER HE GOT IT
	CALLRET TCKP		;TELL QUASAR

; ALLOCATION FAILED

UDTM3:	CALL [	SAVET		;PRESERVE T1-T4
		TMCT <%ICannot Allocate %2V> ;BUILD HEADER
		CALLRET CPYHDR]	;SAVE HEADER IN OPRHDR
	CAIE T1,ALCX5		;SOMEONE ELSE HAS IT?
	JRST [	TMCT <%IError from ALLOC JSYS: %1J>
		JRST UDTM4]
	MOVE T1,T2		;ANOTHER JOB HAS IT
	DVCHR			;GET OWNER'S JOB # IN LH(T3)
	HLRZS T3		;MOVE TO RIGHT HALF
	TMCT <%IAlready in use by job %3D>
UDTM4:	MOVEI T3,OPRHDR
	CALL BTACKT		;TELL OPERATOR ABOUT ALLOC FAILURE
	JRST UDTM1		;SEND WTOR AGAIN
>;NOSHIP
SUBTTL IPCF SEND AND RECEIVE

; GSYSPD - DOES MUTIL TO GET PID FROM SYSTEM PID TABLE
;  T1/ INDEX INTO SYSTEM PID TABLE
; RETURNS +1: PID COULD NOT BE OBTAINED
;	  +2: SUCCESS, PID IN T1

GSYSPD:	SKIPE TSTF		;TESTING?
	JRST GSYSPT		;YES, SPECIAL CODE
	SAVEAC <Q1,Q2>		;Save 2 ACs
	MOVE Q1,T1		;Save T1 for possible later use
	MOVNI Q2,NTRY		;The number of MUTIL% attempts
GSYSPA:	MOVE T2,Q1		;Copy index to T2 for XMUTIL
	MOVEI T1,.MURSP		;Function = return system PID
	CALL XMUTIL		;Get it
	JRST GSYSPB		;Error, try again up to NTRY
	MOVE T1,T3		;Copy to T1 for return
	RETSKP			;Successful return
GSYSPB: AOJE Q2,GSYSPC		;Try again?
	MOVEI T1,^D2000		;Yes, but ...
	DISMS			;Wait awhile
	JRST GSYSPA		;Now try it again
GSYSPC: CAIN T1,IPCF27		;System PID table slot empty?
	RET			;Yes, take error return
	CALL STOP		;Unexpected error

GSYSPT:	STAKT
	MOVE T2,[[EXP IP%CPD,0,0,<20,,TBUF+4>,.IPCIW,0],,TBUF]
	BLT T2,TBUF+5		;MOVE PDB AND PART OF MESSAGE TO BUF
	SKIPL SYPIDS(T1)	;WANT USERNAME PREFIX?
	JRST [	HRROI T1,TBUF+6	;NO, SET UP DESTINATION POINTER
		JRST GSYSP1]	;COPY PID NAME SANS PREFIX INTO TMSG
	GJINF			;GET USER# IN T1
	MOVE T2,T1		;COPY INTO T2
	MOVE T1,[POINT 7,TBUF+6] ;GET POINTER
	MOVEI T3,"["
	IDPB T3,T1
	DIRST			;ADD USER NAME
	 JSHLT
	MOVEI T2,"]"
	IDPB T2,T1
GSYSP1:	MOVE T2,CT1		;GET SYSTEM PID TABLE INDEX
	HRRO T2,SYPIDS(T2)	;GET POINTER TO STRING
	SETZ T3,		;STOP ON NULL
	SOUT			;ADD PID NAME
	MOVEI T1,4
	MOVEI T2,TBUF
	MSEND			;SHIP OFF QUESTION TO INFO
	 JSHLT
	SETZM TBUF		;CLEAR FLAGS WORD FOR RECEIVE
	MOVE T3,TBUF+1		;GET MY PID SO I CAN RECEIVE
	MOVE T4,[20,,TBUF+4]	;SIZE,,MSGADDR
	DMOVEM T3,TBUF+2	;SET WORDS 2 & 3 OF PDB
	MRECV			;RECEIVE INFO'S REPLY
	 JSHLT
	LOAD T4,IP%CFE,TBUF+.IPCFL ;ERROR FROM INFO?
	JUMPN T4,[MOVEI T1,.MUDES ;YES, NO SUCH PID
		MOVE T2,TBUF+2	;GET THE PID WE PICKED UP
		CALL XMUTIL	;LIQUIDATE IT
		 JSHLT		;COULDN'T
		HRROI T1,TBUF+6	;RETURN POINTER TO PID NAME
		RET]
	TMSG <% MOUNTR Found PID for >
	HRROI T1,TBUF+6
	PSOUT
	 TMSG <
>
	MOVEI T1,.MUDES
	MOVE T2,TBUF+2		;GET THE PID I USED FOR THIS CRAP
	CALL XMUTIL		;LIQUIDATE IT
	 JSHLT
	MOVE T1,TBUF+5		;GET PID FOR CALLER
	RETSKP			;GIVE IT TO HIM
SYPIDS:	0
	0
	-1,,[ASCIZ/QUASAR/]
	-1,,[ASCIZ/MOUNTR/]
	-1,,[ASCIZ/ORION/]
; MRCVIH - ENTERED BY SCHEDULER WHEN INTERRUPT RECEIVED FROM PID
; RETURNS +1: ALWAYS

MRCVIH:	TXO F,MRMSF+MRPGF	;EXPECTING PAGE-MODE MESSAGE

; RECEIVE THE HEAD MESSAGE FROM THE QUEUE

MRCVI1:	TXZN F,MRMSF		;RECEIVE QUEUE EMPTY?
	RET			;YES, EXIT TO SCHEDULER
	TXCN F,MRPGF		;NON-PAGE-MODE MESSAGE COMING?
	JRST [	MOVX T1,IP%CFB+IP%TTL ;YES, GET FLAGS
		MOVE T2,[1000,,RBUF] ;SIZE,,ADDRESS
		JRST MRCVI3]	;REJOIN
	MOVX T1,IP%CFB+IP%TTL+IP%CFV ;DON'T BLOCK, TRUNCATE, PAGE MODE
	MOVE T2,[1000,,RBUF_-9]	;SIZE,,PAGE#
MRCVI3:	MOVEM T1,.IPCFL+MRPDB	;SET FLAGS
	MOVEM T2,.IPCFP+MRPDB	;SET RECEIVER BUFFER LENGTH,,ADDRESS
	MOVE T3,MYPID
	MOVEM T3,.IPCFR+MRPDB	;SET RECEIVER'S PID
	MOVEI T1,4		;LENGTH OF PDB
	MOVEI T2,MRPDB		;ADDRESS OF PDB
	MRECV			;RECEIVE THE MESSAGE
	 JRST [	CAIN T1,IPCFX2	;QUEUE EMPTY?
		RET		;YES, EXIT TO SCHEDULER
		TXO F,MRMSF	;SET DO-MRECV FLAG
		CAIN T1,IPCF16	;WRONG MODE?
		JRST MRCVI1	;YES, TRY OTHER MODE
		CALL STOP]	;CAN'T HANDLE THIS ERROR
	AOS MSGSIN		;COUNT # OF MESSAGES IN
	JUMPN T1,[TXNE T1,IP%CFV ;THERE IS ANOTHER MSG, WHAT MODE?
		TXO F,MRPGF	;PAGE-MODE
		TXO F,MRMSF	;FORCE ANOTHER MRECV
		JRST .+1]
	TXNN F,INITF		;DISCARD MESSAGE IF INITIALIZING
	CALL MRCVPM		;PROCESS MESSAGE
	JRST MRCVI1		;GO CHECK FOR MORE MESSAGES

; REFER THE MESSAGE TO THE APPROPRIATE PROCESSING ROUTINE

MRCVPM:	JN IP%CFM,MRPDB+.IPCFL,R ;DISCARD UNDELIVERED MAIL
	LOAD T1,IP%CFC,MRPDB+.IPCFL ;SENT BY <SYSTEM> ?
	JUMPN T1,[CALLRET MRSYS] ;YES, PROCESS IT
	MOVE T1,MRPDB+.IPCFS	;GET SENDER'S PID
	MOVEI T2,APNUM-1	;# OF ASSOCIATED PROCESSES - 1
MRCVAP:	CAMN T1,APPID(T2)	;FROM THIS A/P?
	JRST [	CALLRET @APMRC(T2)] ;YES, GIVE IT TO HIS HANDLER
	SOJGE T2,MRCVAP		;NO, CHECK THE OTHERS
	RET			;I DON'T KNOW THE SENDER, SO PITCH IT
; MRSYS - PROCESS IPCF MESSAGE FROM SYSTEM TASK
;  T1/ SYSTEM SENDER CODE FROM IP%CFC FIELD OF PDB
;  MRPDB, RBUF/ PDB AND MESSAGE
; RETURNS +1: ALWAYS

MRSYS:	CAIN T1,.IPCCF		;SENT BY INFO?
	JRST [	LOAD T1,IP%CFE,MRPDB+.IPCFL ;YES, GET CODE
		CAIN T1,.IPCKM	;WATCHED PID DELETED?
		JRST [	CALLRET INFOK] ;YES, GO PROCESS IT
		CAIE T1,.IPCBP	;BAD PID (RESPONSE TO .IPCIK) ?
		RET		;I DON'T RECOGNIZE IT, SO PITCH IT
		CALLRET PRQPID]	;BAD PID, CHECK REQUEST QUEUE
	CAIE T1,.IPCCC		;SENT BY SYSTEM IPCF?
	RET			;NO, PITCH IT
	HLRZ T1,MRPDB+.IPCFP	;GET SIZE OF MESSAGE
	JUMPE T1,R		;NO MESSAGE, NO WORK
	MOVE T2,RBUF		;GET SYSTEM MESSAGE CODE
	CAIN T2,.IPCSA
	JRST [	CALLRET SALMSG]	;ALLOCATED DEVICE BEING RETURNED
	CAIN T2,.IPCTR
	JRST [	CALLRET SMTMSG]	;MESSAGE ABOUT MAGTAPES
	CAIN T2,.IPCMS
	JRST [	CALLRET ACCSTI]	;STRUCTURE COUNT BEING INCREMENTED
	CAIN T2,.IPCDS
	JRST [	CALLRET ACCSTD]	;STRUCTURE COUNT BEING DECREMENTED
	CAIN T2,.IPCRS
	JRST [	CALLRET ACCSTR]	;STRUCTURE BEING REMOVED
	RET
; INFOK - PROCESS PID-KILLED MESSAGE FROM INFO
;  RBUF/ PID THAT WAS KILLED
; RETURNS +1: ALWAYS

INFOK:	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	SAVEAC <RSB>
INFOK1:	CALL QMSCAN		;GET NEXT ENTRY FROM RSB QUEUE
	 RET			;NONE LEFT, SPLIT
	MOVEI RSB,-RSBLNK(T2)	;GET RSB ADDRESS
	MOVE T1,RSBPID(RSB)	;GET PID FROM RSB
	CAMN T1,RBUF		;WAS IT KILLED?
	CALL VALPID		;YES, ABORT REQUEST IF NECESSARY
	 JFCL
	JRST INFOK1


; SALMSG - PROCESS ALLOCATED-DEVICES-RELEASED MESSAGE
; RETURNS +1: ALWAYS

SALMSG:	SAVEQ
	HLRZ Q1,MRPDB+.IPCFP	;GET # OF DEVICES PLUS 1
SALMS1:	SOJLE Q1,[CALLRET MCHWMT] ;EXIT WHEN DEVICE LIST EXHAUSTED
	MOVE T1,RBUF(Q1)	;GET DEVICE DESIGNATOR
NOSHIP,<
	LOAD T2,DV%TYP,T1	;GET DEVICE TYPE
	CAIN T2,.DVDTA		;DECTAPE?
	JRST [	CALL RLSDTA	;YES, CALL PROCESSOR
		JRST SALMS1]	;GET NEXT DEVICE
>;NOSHIP
	CALL DDMT		;CONVERT IT TO MT STATUS BLK ADDR IN MT
	 JRST SALMS1		;NOT MT DEVICE, IGNORE IT
	SETOM UNLD		;Tape being unloaded
	CALL MTRLS		;PROCESS RELEASE OF MT DEVICE
	JRST SALMS1		;ON TO NEXT DEVICE IN IPCF MESSAGE
; SMTMSG - PROCESS IPCF MESSAGES FROM MONITOR TAPE SERVICE
; RETURNS +1: ALWAYS

SMTMSG:	SAVEQ
	MOVEI Q1,RBUF+1		;GET ADDRESS OF .VMCOD WORD
	SKIPL T1,.VSMTN(Q1)	;GET MT# AND CHECK IF LESS THAN 0
	CAML T1,MTN		; OR TOO BIG
	CALL STOP		;ILLEGAL MT# FROM MONITOR
	IMULI T1,MTSZ		;EXPAND TO OFFSET
	MOVEI MT,MT0(T1)	;LOAD MT WITH ADDR OF MT STATUS BLOCK
	MOVE T1,.VMCOD(Q1)	;DISPATCH BY MESSAGE SUBCODE
	CAIN T1,.VMVSM
	JRST SMTVS		;VOLUME-SWITCH
	CALL STOP		;CODE NOT RECOGNIZED

; PROCESS VOLUME-SWITCH

SMTVS:	LOAD RSB,MTRSB		;GET REQUEST STATUS BUFFER ADDRESS
	CAIN RSB,MTNAV		;DOES USER OWN MT AND NO RSB?
	JRST [	MOVEI T1,.MTNVV	;YES
		MOVE T2,MT	;COMPUTE MT #
		SUBI T2,MT0
		IDIVI T2,MTSZ
		MOVEI T3,[EXP 3,MREQX8,0] ;GET ARGUMENT BLOCK
		MTU%		;MOUNTR CRASHED, SO YOU CAN'T VOLSWITCH
		RET]
	SKIPN RSB		;DO I OWN THE MT?
	CALL STOP		;YES, WHAT'S GOING ON HERE?
	LOAD T2,VS%COD,.VSFLG(Q1) ;TYPE OF SWITCH
	SKIPLE T2		;VALIDATE TYPE
	CAILE T2,4
	CALL STOP		;UNKNOWN TYPE
	LOAD T1,RSBCV		;GET CURRENT VOLID INDEX
	XCT [	MOVE T1,.VSCNT(Q1)	;1 - MOUNT ABSOLUTE VOLUME #
		MOVEI T1,1		;2 - MOUNT FIRST VOLUME
		CALL VQCNT		;3 - MOUNT LAST VOLUME
		ADD T1,.VSCNT(Q1)]-1(T2) ;4- MOUNT RELATIVE VOLUME
	LOAD T2,VS%WRT,.VSFLG(Q1) ;GET READ/WRITE FLAG
	LOAD T3,RSBLT		;GET LABEL TYPE
	CAIN T3,.LTUNL		;UNLABELED?
	SETZ T2,		;YES, DON'T REWRITE VOLUME LABELS
	STOR T2,R%WVL,RSBIFL(RSB) ;SET OR RESET FLAG IN RSB
	CALLRET VOLSW		;PERFORM VOLUME-SWITCH
; PIDINI - GET AND INITIALIZE PID FOR COMMUNICATION WITH THE WORLD
; RETURNS +1: ALWAYS

PIDINI:	SAVEQ

; SET JOB PID QUOTA TO A LARGE VALUE

	MOVEI T1,.MUSPQ		;FUNCTION = SET JOB PID QUOTA
	SETO T2,		;THIS JOB
	MOVEI T3,777		;NEW QUOTA
	CALL XMUTIL
	 JFCL

; TRY TO USE THE PID IN THE SYSTEM PID TABLE (IF IT EXISTS)
; IF THIS IS NOT POSSIBLE, CREATE A NEW PID AND USE IT
; Q1/ 0 IF I CREATED THE PID, 1 IF THE PID IS RECYCLED

	SETZ Q1,		;Q1/0 MEANS I CREATED THE PID
	MOVEI T1,.SPMDA		;OFFSET INTO TABLE FOR MDA PID
	CALL GSYSPD		;DOES MDA PID EXIST?
	 JRST PIN1		;NO
	MOVEM T1,MYPID		;YES, SAVE IT
	AOJA Q1,PIN2		;TRY TO RECYCLE IT

PIN1:	MOVEI T1,.MUCRE		;FUNCTION = CREATE PID
	MOVE T2,[IP%JWP+.FHSLF]	;JOB-WIDE
	CALL XMUTIL		;CREATE PID
	 CALL STOP		;CAN'T WORK WITHOUT A PID
	MOVEM T3,MYPID		;STORE MY PID
PIN2:	MOVEI T1,.MUPIC		;FUNCTION = PUT PID ON INTERRUPT CHANNEL
	MOVE T2,MYPID		;PID
	MOVEI T3,MRCVCN		;CHANNEL #
	CALL XMUTIL		;CAN PID BE PUT ON INT CHANNEL?
	 JRST [	SOJE Q1,PIN3	;NO, REPORT ERROR IF NOT MY PID
		CALL STOP]	;CAN'T PUT MY OWN PID ON INT CHANNEL

	MOVEI T1,.MUSSQ		;FUNCTION = SET SEND AND RECEIVE QUOTAS
	MOVE T2,MYPID		;PID
	MOVEI T3,777100		;SEND = 777, RECEIVE = 100
	CALL XMUTIL		;SET SEND/RECEIVE QUOTAS
	 JFCL
	SKIPE Q1		;RECYCLING OLD MDA PID?
	CALL MRCVIH		;YES, DISCARD ANY CURRENT MESSAGES

; IDENTIFY MYSELF TO THE WORLD

	SKIPE TSTF		;TESTING?
	JRST [	MOVE T2,[[EXP 0,0,0,<20,,TBUF+4>,.IPCII,0],,TBUF]
		BLT T2,TBUF+5		;MOVE PDB AND PART OF MESSAGE TO BUF
		MOVE T1,MYPID
		MOVEM T1,TBUF+.IPCFS	;SET SENDER'S PID
		GJINF			;GET USER# IN T1
		MOVE T2,T1		;COPY INTO T2
		MOVE T1,[POINT 7,TBUF+6] ;GET POINTER
		MOVEI T3,"["
		IDPB T3,T1
		DIRST			;ADD USER NAME
		 JSHLT
		MOVEI T2,"]"
		IDPB T2,T1
		HRROI T2,[ASCIZ/MDA/] 	;[6011]Get pointer to string
		SETZ T3,		;STOP ON NULL
		SOUT			;ADD PID NAME
		MOVEI T1,4
		MOVEI T2,TBUF
		MSEND
		 CALL STOP
		TMSG <% MOUNTR Becoming >
		HRROI T1,TBUF+6		;INFORM USER WE HAVE GOT PID
		PSOUT
		TMSG <
>
		JRST PIN4]
	MOVEI T1,.MUSSP		;FUNCTION = SET VALUE IN SYS PID TABLE
	MOVEI T2,.SPMDA		;OFFSET INTO TABLE
	MOVE T3,MYPID		;PID
	CALL XMUTIL		;SET MY PID AS SYSTEM MDA PID
	 CALL STOP
PIN4:

; OBTAIN AND REMEMBER MAXIMUM LENGTH OF NON-PAGE-MODE IPCF PACKETS

	MOVEI T1,.MUMPS		;FUNCTION = RETURN MAX NON-PAGE PACKET
	CALL XMUTIL
	 CALL STOP
	MOVEM T2,SHORT		;SAVE IT
	RET

; ERROR ENCOUNTERED WHILE ASSIGNING EXISTING MDA PID TO PSI CHANNEL
; THIS IMPLIES THAT ANOTHER MOUNTR IS RUNNING, SO DON'T INTERFERE

PIN3:	TMSG <?MDA PID is already defined>
	MOVEI T1,.MUFOJ
	MOVE T2,MYPID		;GET THE PID
	CALL XMUTIL		;GET JOB# OF PID'S OWNER
	 HALTF
	TMSG < by job >
	MOVEI T1,.PRIOU
	MOVE T2,T3		;COPY JOB#
	MOVEI T3,12		;BASE 10
	NOUT			;DISPLAY JOB#
	 JFCL
	HALTF
; PWATCH - TELL INFO TO WATCH THE PID IN RSBPID
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

PWATCH:	MOVEI T1,.IPCIK
	MOVEM T1,TBUF+.IPCI0	;STORE INFO FUNCTION CODE
	MOVE T1,RSBPID(RSB)
	MOVEM T1,TBUF+.IPCI2	;STORE PID TO BE WATCHED
	SETZ T1,		;SENDING TO INFO
	MOVEI T2,3		;3 WORDS
	CALLRET TRANM
; TRANG - TRANSMIT GALAXY IPCF MESSAGE TO ASSOCIATED PROCESS
; TRANU - TRANSMIT GALAXY IPCF MESSAGE TO USER PROCESS
; TRANM - TRANSMIT IPCF MESSAGE TO SPECIFIED PID
;  T1/ ASSOCIATED-PROCESS INDEX (TRANG) OR PID (TRANM, TRANU)
;  T2/ MESSAGE LENGTH IN WORDS (TRANM ONLY)
;  TBUF/ MESSAGE TO BE TRANSMITTED
; RETURNS +1: ALWAYS

TRANG:	MOVE T1,APPID(T1)	;GET PID OF ASSOCIATED PROCESS
TRANU:	LOAD T2,MS.CNT,TBUF+.MSTYP ;GET SIZE FROM GALAXY HEADER
	JUMPE T1,TRAN1		;IF RECEIVER PID IS 0, DON'T BOTHER
TRANM:	SAVEQ
	MOVEI Q1,1		;SET UP RETRY COUNTER

; BUILD PDB AND ATTEMPT TO TRANSMIT THE MESSAGE

	SETZM TRPDB+.IPCFL	;CLEAR PDB FLAGS WORD
	MOVE T4,MYPID
	MOVEM T4,TRPDB+.IPCFS	;STORE SENDER'S PID IN PDB
	MOVEM T1,TRPDB+.IPCFR	;STORE RECEIVER'S PID IN PDB
	CAMG T2,SHORT		;CAN I SEND A SHORT MESSAGE?
	JRST [	MOVSM T2,TRPDB+.IPCFP ;YES, SET SIZE IN PDB
		MOVEI T2,TBUF
		HRRM T2,TRPDB+.IPCFP ;INSTALL MSG ADDRESS IN PDB
		JRST TRAN2]	;SKIP PAGE-MODE STUFF
	MOVX T2,IP%CFV
	IORM T2,TRPDB+.IPCFL	;SET PAGE-MODE IN PDB
	MOVE T2,[1000,,TBUF_-9]
	MOVEM T2,TRPDB+.IPCFP	;SET SIZE,,PAGE#

TRAN2:	MOVEI T1,4		;PDB LENGTH
	MOVEI T2,TRPDB		;PDB ADDRESS
	MSEND			;SEND THE MESSAGE
	 JRST TRAN3		;FAILED
TRAN1:	SETZM TBUF		;CLEAR 1ST WORD OF TBUF
	MOVE T1,[TBUF,,TBUF+1]	;BLT SOURCE AND DESTINATION
	BLT T1,TBUF+777		;CLEAR TBUF FOR NEXT CALLER
	RET

; IPCF TRANSMIT FAILED, FIND OUT WHY

TRAN3:	MOVSI T2,-MLEN		;Get the length of the error table
TRAN4:	HLRZ T4,MTBL(T2)	;Get the next error code
	CAME T1,T4		;Do we match?
	AOBJN T2,TRAN4		;No, try the next one
	SKIPL T2		;Found a match?
	$STOP <MSEND Failure>	;This error can't be dealt with
	HRRZ T4,MTBL(T2)	;Get the routine address
	JRST 0(T4)		;Process the error
TRAN5:	SOJL Q1,TRAN1		;GIVE UP IF RETRY COUNT EXHAUSTED
TRAN6:	MOVEI T1,^D1000		;RETRYABLE FAILURE
	DISMS			;DELAY
	JRST TRAN2		;TRY IT AGAIN
TRAN7:	HRROI T1,[ASCIZ/SYSTEM INFO Is Not Running - MOUNTR Dismissing For 30 Seconds
/]				;The message to the operator
	PSOUT			;Tell the operator
	MOVEI T1,^D30000	;Give the operator time to restart INFO
	DISMS			;Sleep for 30 seconds
	JRST TRAN2		;Try again
SUBTTL LABELED TAPE INITIALIZATION

; LTINIT - CHECK IF LABELED TAPE MUST BE INITIALIZED, AND IF SO,
;	   WRITE VOLUME LABELS AND A DUMMY FILE ON THE TAPE
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ERROR, TAPE DISMOUNTED OR REQUEST ABORTED
;	  +2: SUCCESS, TAPE IS PROPERLY PREPARED

LTINIT:	MOVX T1,R%WVL
	TDNN T1,RSBIFL(RSB)	;SKIP IF LABELS MUST BE WRITTEN
	RETSKP			;YES, SHOULDN'T WRITE LABELS!
	CALL OWCHK		;OVERWRITE PERMITTED?
	 RET			;NO, REQUEST ABORTED
	LOAD T1,RSBDEN		;GET DESIRED DENSITY
	STOR T1,MTADEN		;OPEN MTA AT THAT DENSITY
	LOAD T1,RSBLT		;GET LABEL TYPE
	STOR T1,MTALT		;SET NEW LABEL TYPE OF TAPE
	CALL MTAOPO		;OPEN MTA FOR OUTPUT
	 JRST [	CALLRET UNLOAD]	;WRITE PROTECTED OR OFFLINE ???
	MOVEI T1,.MOREW
	MOVEI T2,1
	CALL XMTOPR		;REWIND TAPE (SHOULDN'T TAKE LONG)
	 JRST LTINI1
	LOAD T1,RSBLT
	CAIN T1,.LTUNL		;UNLABELED TAPE?
	JRST [	SETZM LBUF1	;YES
		MOVE T1,[LBUF1,,LBUF1+1]
		BLT T1,LBUF1+^D19 ;ZERO THE BUFFER
		MOVEI T1,LBUF1	;GET BUFFER ADDRESS
		CALL WRTLBL	;WRITE A RECORD OF ZEROS
		 JRST LTINI2	;ERROR
		JRST LTINI0]	;SUCCESSFUL, GO WRAP UP
	CALL BLDV1		;BUILD VOL1 LABEL
	MOVEI T1,MTAV1(MTA)	;GET ADDRESS OF VOL1
	CALL WRTLBL		;WRITE VOL1
	 JRST LTINI2		;ERROR
	SETZM MTAV2(MTA)	;ZAP VOL2 BUFFER
	LOAD T1,RSBLT		;GET LABEL TYPE
	CAIN T1,.LTT20		;IS THIS A TOPS-20 VOLUME?
	JRST [	CALL BLDV2	;YES, BUILD VOL2 LABEL
		MOVEI T1,MTAV2(MTA) ;GET ADDRESS OF VOL2
		CALL WRTLBL	;WRITE VOL2
		 JRST LTINI2	;ERROR
		JRST .+1]

; --- USER VOLUME LABELS WOULD BE WRITTEN HERE ---

	CALL BLDH1		;BUILD HDR1 FOR DUMMY FILE
	MOVEI T1,LBUF1		;GET ADDRESS OF HDR1
	CALL WRTLBL		;WRITE HDR1
	 JRST LTINI2		;ERROR
	MOVEI T1,.MOEOF
	MOVEI T2,2		;REPEAT COUNT
	CALL XMTOPR		;DOUBLE TAPE MARK FRAMING EMPTY FILE
	 JRST LTINI1
	CALL BLDEF1		;BUILD EOF1
	MOVEI T1,LBUF1		;GET ADDRESS OF EOF1
	CALL WRTLBL		;WRITE EOF1
	 JRST LTINI2
LTINI0:	MOVEI T1,.MOEOF
	MOVEI T2,2		;REPEAT COUNT
	CALL XMTOPR		;WRITE DOUBLE TAPE MARK
	 JRST LTINI1
	CALL REW		;REWIND TAPE
	 JRST LTINI2		;OFFLINE ERROR
	CALL MTACLS		;CLOSE TAPE
	RETSKP			;I DID IT!!

; DEVICE ERROR OR TIMEOUT OCCURRED

LTINI1:	CALL XMTREP		;TELL OPERATOR ABOUT ERROR OR TIMEOUT
LTINI2:	CALL UNLOAD		;UNLOAD THE TAPE FROM THE DRIVE
	CALL MTACLS		;CLOSE THE JFN
	CALLRET WOLINF		;TELL OPERATOR LABEL INIT FAILED


; WRTLBL - WRITE A LABEL TO TAPE
;  T1/ ADDRESS OF INDUSTRY-COMPATIBLE FORMAT LABEL
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: I/O ERROR OR DRIVE TIMED OUT
;	  +2: LABEL WRITTEN SUCCESSFULLY

WRTLBL:	STKVAR <<WCLIST,2>>
	SUBI T1,1		;GET BUFFER ADDRESS MINUS 1
	HRLI T1,-LBLSIZ/4	;GET MINUS # OF WORDS TO WRITE
	MOVEM T1,WCLIST		;STORE IOWD
	SETZM 1+WCLIST		;FOLLOW IOWD WITH ZERO WORD
	LOAD T1,MTAJFN		;GET JFN
	MOVEI T2,WCLIST		;GET COMMAND LIST ADDRESS
	IOXCT DUMPO,WRTLB1,WRTLB2 ;DO THE I/O
	RETSKP			;SUCCESS

WRTLB1:	CALL CLRTAP		;CLEAR ERRORS, GET ERROR CODE IN T1
	 JRST WRTLB2		;TIMED OUT
	CAIN T1,IOX5		;DEVICE OR DATA ERROR?
	RET			;YES, TELL CALLER
	CALL STOP		;I CAN'T HANDLE THIS

WRTLB2:	CALLRET WOTIMO		;TELL OPERATOR ABOUT TIMEOUT AND TAKE +1
; BLDV1 - BUILD VOL1 LABEL
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS, VOL1 LABEL IN MTAV1 IN MTA STATUS BLOCK

BLDV1:	DMOVE T1,[ASCII/VOL1      /]
	DMOVEM T1,LBUF2		;SET FIRST 2 WORDS OF VOL1
	MOVE T1,[LBUF2+1,,LBUF2+2]
	BLT T1,LBUF2+LB7WDS-1	;SET THE REST TO BLANKS
	MOVE T1,MTAVOL(MTA)	;GET VOLID
	MOVE T2,[ILPTR(V1VID)]	;GET DESTINATION POINTER
	CALL SIXASC		;PUT VOLID IN LABEL
	LOAD T1,RSBLT		;GET LABEL TYPE
	CAIN T1,.LTEBC		;EBCDIC?
	JRST BLDV11		;YES, SKIP ANSI/TOPS20 STUFF
	CAIN T1,.LTT20		;IS THIS A TOPS-20 VOLUME?
	JRST [	MOVEI T1,"1"	;YES
		DPB T1,[LPTR(V1ACS)] ;SET ACCESSIBILITY FIELD
		HRROI T1,T20SCD
		MOVE T2,[ILPTR(V1SCD)]
		CALL MOVSTR	;PUT TOPS-20 SYSTEM CODE IN VOL1
		JRST .+1]
	HRROI T1,[ASCIZ/D%K/]
	MOVE T2,[ILPTR(V1OWN)]
	CALL MOVSTR		;PUT MACHINE CODE IN OWNER-ID FIELD
	MOVEI T1,DECV
	DPB T1,[LPTR(V1DECV)]	;STORE DEC STANDARD VERSION
	MOVEI T1,ANSV
	DPB T1,[LPTR(V1ANSV)]	;STORE ANSI STANDARD VERSION
	SKIPA T2,[ILPTR(V1INAM)] ;GET POINTER TO ANSI/TOPS20 OWNER NAME
BLDV11:	MOVE T2,[ILPTR(V1INME)]	;GET POINTER TO EBCDIC OWNER NAME
	HRROI T1,TAPNAM		;POINT TO INSTALLATION NAME
	CALL MOVSTR		;COPY INSTALLATION NAME INTO LABEL
	MOVEI T1,MTAV1(MTA)	;GET DESTINATION ADDRESS
	CALLRET LBLOCV		;CONVERT TO OUTPUT FORMAT AND RETURN
; BLDV2 - BUILD VOL2 LABEL
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS, VOL2 LABEL IN MTAV2 IN MTA STATUS BLOCK

BLDV2:	DMOVE T1,[ASCII/VOL2      /]
	DMOVEM T1,LBUF2		;SET FIRST 2 WORDS OF VOL2
	MOVE T1,[LBUF2+1,,LBUF2+2]
	BLT T1,LBUF2+LB7WDS-1	;SET THE REST TO BLANKS
	MOVE T1,[ILPTR(V2PRO)]	;GET POINTER TO ACCESS CODE FIELD
	LOAD T2,RSBVPR		;GET PROTECTION CODE
	TRO T2,770000		;FORCE COMPLETE OWNER ACCESS
	TRZ T2,007700		;CLEAR WORLD ACCESS (NOT DEFINED YET)
	MOVE T3,[6,,10]		;FIELD WIDTH,,RADIX
	CALL FNOUT		;PUT NUMERIC FIELD IN LABEL
	HRROI T1,[ASCIZ/000000000000/] ;DUMMY PPN
	MOVE T2,[ILPTR(V2PPN)]
	CALL MOVSTR		;INSTALL PPN
	HRROI T1,MTAV2(MTA)	;USE MTAV2 TEMPORARILY
	MOVE T2,RSBUNO(RSB)	;USER'S USER #
	DIRST			;TRANSLATE USER # TO STRING
	 SETZM MTAV2(MTA)
	HRROI T1,MTAV2(MTA)	;(ALL THIS FUDGING IS BECAUSE DIRST
	MOVE T2,[ILPTR(V2OWN)]	; PUTS AN UNWANTED NULL AT THE END)
	CALL MOVSTR		;TRANSFER OWNER'S NAME TO LABEL
	MOVEI T1,MTAV2(MTA)	;GET DESTINATION ADDRESS
	CALLRET LBLOCV		;CONVERT TO OUTPUT FORMAT AND RETURN
; BLDH1 - BUILD DUMMY HDR1 LABEL
; BLDEF1 - BUILD DUMMY EOF1 LABEL
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS, LABEL IN LBUF1

BLDH1:	SKIPA T1,[ASCII/HDR1D/]
BLDEF1:	MOVE T1,[ASCII/EOF1D/]
	MOVEM T1,LBUF2		;SET FIRST WORD OF LABEL
	MOVE T1,[SKEL1,,LBUF2+1]
	BLT T1,LBUF2+LB7WDS-1	;SUPPLY REMAINDER OF SKELETON
	MOVE T1,MTAVOL(MTA)	;GET VOLID
	MOVE T2,[ILPTR(H1SET)]	;GET DESTINATION POINTER
	CALL SIXASC		;PUT VOLID IN FILE SET NAME FIELD
	SETO T2,		;SPECIFY CURRENT DATE/TIME
	MOVX T4,IC%JUD		;WANT JULIAN FORM
	ODCNV			;GET T2/ YEAR,,JULIANDAY
	HLRZ T1,T2		;GET YEAR
	SUBI T1,^D1900		;DROP CENTURY PART
	IMULI T1,^D1000		;DECIMAL SHIFT
	HRRZS T2		;ISOLATE DAY IN T2
	ADD T2,T1		;GET T2/ YYDDD (DECIMAL)
	MOVE T1,[ILPTR(H1CRE+1)] ;GET POINTER TO LABEL FIELD
	MOVE T3,[5,,12]		;5 CHARS WIDE, BASE 10
	CALL FNOUT		;EDIT CREATION DATE INTO LABEL
	MOVEI T1,LBUF1		;GET DESTINATION ADDRESS
	CALLRET LBLOCV		;CONVERT TO OUTPUT FORMAT AND RETURN

SKEL1:	ASCII     /UMMY-FILE-0000        0001000100010/ ;CP  6-40
	ASCII/0       00000 000000DECSYSTEM20         / ;CP 41-80


; LBLOCV - CONVERT 7-BIT ASCII LABEL IN LBUF2 TO 8-BIT ASCII OR EBCDIC
;  T1/ ADDRESS OF DESTINATION LABEL
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

LBLOCV:	SAVEQ
	HRLI T1,(POINT 8,0)	;MAKE POINTER TO DESTINATION
	MOVE T2,[POINT 7,LBUF2]	;GET POINTER TO SOURCE
	MOVEI T3,LBLSIZ		;GET # OF BYTES IN LABEL
	LOAD T4,RSBLT		;GET LABEL TYPE
LBLOC1:	ILDB Q1,T2		;GET SOURCE BYTE
	CAIN T4,.LTEBC		;EBCDIC LABEL?
	JRST [	ADJBP Q1,[POINT 8,AETT,7] ;YES, GET POINTER TO TABLE
		LDB Q1,Q1	;TRANSLATE ASCII TO EBCDIC
		JRST .+1]
	IDPB Q1,T1		;STORE BYTE IN DESTINATION
	SOJG T3,LBLOC1
	RET
; OWCHK - CHECK IF USER MAY OVERWRITE TAPE VOLUME
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: OVERWRITE NOT PERMITTED, REQUEST ABORTED
;	  +2: OVERWRITE PERMITTED

OWCHK:	JN R%PRIV,RSBIFL(RSB),RSKP ;PRIVILEGED USERS CAN DO ANYTHING
	MOVE T1,MTAFLG(MTA)	;GET FLAGS
	JXN T1,MA%UXV,[ABTRET (MREQ28)] ;ERROR IF FIRST FILE NOT EXPIRED
	JXN T1,MA%SCR,RSKP	;OK IF IT'S A SCRATCH TAPE
	LOAD T1,MTALT		;GET LABEL TYPE
	LOAD T2,MA%OPF,MTAFLG(MTA) ;GET OVERWRITE-PROTECT FLAG
	JRST @OWCDV(T1)		;DISPATCH ACCORDING TO LABEL TYPE

OWCDV:	IFIW!RSKP		;LABEL TYPE NOT KNOWN YET
	IFIW!RSKP		;UNLABELED
	IFIW!OWCANS		;ANSI
	IFIW!OWCPV		;EBCDIC (WRITE ACCESS NOT SUPPORTED)
	IFIW!OWCT20		;TOPS-20
MAXLT

OWCANS:	JUMPE T2,RSKP		;OK IF FLAG IS RESET
OWCPV:	ABTRET (MREQ29)		;OVERWRITE ACCESS VIOLATION, ABORT REQ

OWCT20:	JUMPE T2,RSKP		;OK IF FLAG RESET
	STKVAR <<OWNER,10>>
	MOVEI T1,OWNER		;PROVIDE WORK AREA FOR GETVU
	CALL GETVU		;GET TAPE-OWNER'S USER # IN T2
	CAME T2,RSBUNO(RSB)	;TAPE USER # MATCH REQUESTOR USER # ?
	JRST OWCPV		;NO, PROTECTION VIOLATION
	RETSKP			;YES, YOU OWN IT, SO YOU CAN OVERWRITE
SUBTTL OPERATOR INTERFACE

; BADOM, BADQM BADNM - TYPE A MESSAGE ON CTY INDICATING THAT I RECEIVED A BAD
; IPCF MESSAGE FROM ORION OR QUASAR OR NEBULA.  USES T4 AS A FLAG TO INDICATE 
; WHO SEND THE MESSAGE.
; RETURNS +1: ALWAYS

BADOM:	MOVEI T1,[ASCIZ/ORION/] ;From ORION 
	SETZRO T4		;-1 is from ORION
	JRST BADCOM		;Join common code
BADQM:	MOVEI T1,[ASCIZ/QUASAR/] ;From QUASAR
	SETO T4,		;0 is from QUASAR
	JRST BADCOM		;Join common code
BADNM:	MOVEI T1,[ASCIZ/NEBULA/] ;From NEBULA
	MOVEI T4,1		;1 is from NEBULA
BADCOM:	MOVE T2,[RBUF,,BADMSG]
	BLT T2,BADMSG+777	;MAKE A COPY JUST FOR THE RECORD
	TMCT <%IBad IPCF message received from %1A>
	LOAD T1,MS.TYP,RBUF+.MSTYP ;GET MESSAGE TYPE
	CAIN T1,MT.TXT		;IS THIS
	SKIPE RBUF+.OARGC	;A NULL TEXT MESSAGE?
	SKIPA			;NO
	RET			;YES, RETURN
	CAIN T1,MT.TXT		;TEXT MESSAGE?
	CALL [	MOVEI T1,RBUF+.OHDRS+ARG.DA ;YES, POINT TO TEXT
		TMCTR <%_TEXT MESSAGE: %1A>] ;DISPLAY IT
	MOVEI T3,[ASCIZ/MOUNTR System Task Error/]
	CALL BTWTO		;[6011]Out to CTY and return
	MOVE T1,RBUF+.MSFLG	;[6011]Get flag
	TXNN T1,MF.WTO		;[6017]Return status via WTO?
	TXNN T1,MF.NEB		;[6011]No, is this from NEBULA?
	RET			;[6011]No, all done

;  Have to send a dismount ACK back to NEBULA

	MOVX T1,E%BADM		;[6011]Error code
	SKIPGE T4		;[6011]From ORION
	IFSKP.			;[6011]No
         SKIPE T4		;[6011]From QUASAR
	 IFSKP.
          TXO T1,FA%QER		;[6011]Yes
	 ELSE.
	  TXO T1,FA%NER		;[6011]Must be from NEBULA
	 ENDIF.
	ELSE.
	 TXO T1,FA%OER		;[6011]Yes
	ENDIF.
	MOVE T2,RBUF+.MSCOD	;[6011]Remote ACK 
	CALLRET FAILE		;[6011]Remote, send failure
	
; TO CLEAR SOME OF THE CONFUSION HERE, AN "ACK" IS USED WHEN SENDING
; TEXT TO A PARTICULAR OPR (E.G. WHEN TELLING THE OPERATOR THAT
; HE MADE A BAD KEYIN), WHEREAS "WTO" AND "WTOR" MESSAGES ARE SEEN
; BY ALL USERS RUNNING OPR THE TIME THE MESSAGE IS RECEIVED BY ORION.
; ALL OF THE BTxxx ROUTINES RETURN +1 ALWAYS

; BTACK - BUILD AND TRANSMIT ACK MESSAGE WITHOUT TEXT
;  RBUF+.MSCOD/ ID OF OPR WHO WILL RECEIVE ACK
;  T3/ ADDRESS OF ASCIZ MESSAGE TYPE

; BTACKT - BUILD AND TRANSMIT ACK MESSAGE WITH TEXT
;  TMCMSG/ ASCIZ MESSAGE TO BE TRANSMITTED
;  T3/ ADDRESS OF ASCIZ MESSAGE TYPE

; BTWTO - BUILD AND TRANSMIT WTO MESSAGE
;  TMCMSG/ ASCIZ MESSAGE TO BE TRANSMITTED
;  T3/ ADDRESS OF ASCIZ MESSAGE TYPE

; BTWTOR - BUILD AND TRANSMIT WTOR MESSAGE
;  TMCMSG/ ASCIZ MESSAGE TO BE TRANSMITTED
;  T1/ 0 ,, ADDR OF ROUTINE TO BE SCHEDULED WHEN RESPONSE IS RECEIVED
;  T2/ ADDRESS OF WTB
;  T3/ ADDRESS OF ASCIZ MESSAGE TYPE

BTACK::	SKIPA T4,[1B0+.OMACK]	;ACK MESSAGE, NO TEXT BLOCK
BTACKT::MOVEI T4,.OMACK		;ACK MESSAGE WITH TEXT BLOCK
	JRST BT1		;ENTER COMMON CODE
BTWTON::MOVE T4,[1B0+.OMWTO]	;WTO MESSAGE WITHOUT TEXT BLOCK
	JRST BT1
BTWTOR::SKIPA T4,[.OMWTR]	;WTOR MESSAGE
BTWTO::	MOVEI T4,.OMWTO		;WTO MESSAGE
BT1:	MOVEM T4,BTEXT		;Save for text checking
	STAKT			;STACK T1-T4
	HRRZ T1,CT3		;[6010]Get the header address
	MOVEM T1,WTTYPA		;[6010]Save the .wttyp address
	AOS FIRST		;First message packet
BT2:	MOVEI T1,PBMAX		;Number of byte allowed in message
	SUBI  T1,BYTEND		;Last line in packet trigger
	MOVEM T1,PBLFT		;Initialize # bytes left in message
	SETZM BUFLFT		;Exhausted space in TMCMSG turned off

; CONSTRUCT BUILDING BLOCKS IN IPCF MESSAGE TO ORION


	MOVX T1,WT.MOR		;Get more text flag
	ANDCAM T1,BTFLGS	;Make sure it is not set
	CALL PBINIT		;SET UP TO CREATE BUILDING BLOCKS
	SKIPN FIRST		;Is it the first time
	JRST BT3		;No, check remote request

;  Object type block

	MOVEI T1,[2,,.WTOCD
		  .OTMNT]
	CALL PBBLK		;INSERT MESSAGE CLASSIFICATION BLOCK

;  Check to see whether the message is going to NEBULA or ORION or both

BT3:	SKIPE NEBMSG		;[6010]Message in response to a NEBULA reqeust
	IFSKP.
	 CAIN RSB,1		;[6010]No RSB
	 JRST BT0		;[6010]No WTNHD
	 MOVE T2,RSBIFL(RSB)	;Get the flag word	 
	 TXNN T2,R%WTO		;Nebula want WTO?
	 JRST BT0		;No
	 MOVE T2,RSBOBN(RSB)	;[6017]Get Remote node name
	 MOVEM T2,RENODE	;[6017]Save it for .WTNHD
	ENDIF.

	MOVE T1,[2,,.WTNHD]	;[6010]Node name header block
	MOVEM T1,WTNHDB		;[6010]Save it 
	MOVE T1,RENODE		;[6017]node name
	MOVEM T1,WTNHDB+1	;[6010]Save it 
	MOVEI T1,WTNHDB		;[6010]Address of arg block
	CALL PBBLK		;[6010]Insert into message
	JRST BT7		;[6010]Must add .WTTYP block

BT0:	SKIPN FIRST		;Is it the first time
	JRST BT6		;No, do text
	
BT7:	MOVE T1,WTTYPA		;ADDR OF ASCIZ MESSAGE TYPE
	MOVEI T2,.WTTYP		;TYPE CODE
	CALL PBTXT		;INSTALL MESSAGE TYPE TEXT
	SETZM FIRST		;Clear first flag

BT6:	MOVEI T1,TMCMSG		;ADDR OF FORMATTED TEXT
	MOVEI T2,.WTTXT		;TYPE CODE
	SKIPLE BTEXT		;Text Present?
	CALL PBTXT		;YES, INSTALL IT
	SKIPG MORTXT		;Any text left?
	SETZM BTEXT		;No, mark it so


; BUILD GALAXY HEADER AND SHIP THE MESSAGE OFF TO ORION
; Before calling GALHDR, T1,T2,T3 must be setup correctly with the first 3
; words of the standard GALAXY header.

BT4:	HRRZ T1,CT4		;GET MESSAGE TYPE
	CAIE T1,.OMACK		;ACK MESSAGE?
	AOSA T3,UNIQUE		;NO, GET A UNIQUE NUMBER
	MOVE T3,RBUF+.MSCOD	;YES, GET OPR PID
	MOVE T2,PBBPT
	SUBI T2,TBUF		;COMPUTE SIZE OF IPCF MESSAGE
	HRL T1,T2		;GET LENGTH,,MSGTYPE
	SKIPE NEBMSG		;[6010]Message in response to a NEBULA request
	IFSKP.
	 CAIN RSB,1		;[6010]No RSB
	 JRST BT5		;[6010]No MF.WTO
	 MOVE T2,RSBIFL(RSB)	;Get the flag word	 
	 TXNN T2,R%WTO		;Nebula want WTO?
	 JRST BT5		;No
	 MOVX T2,MF.WTO		;[6017]Yes set NEBULA WTO bit
	 MOVE T3,RSBPID(RSB)	;[6017]Get the remote operator pid
	ENDIF.

;  Remote message

	MOVE T4,BTFLGS		;[6010]Get the more data flag
	TXO T2,MF.NEB		;[6017]Set the NEBULA bit
	TXNE T4,WT.MOR		;[6010]Any more data?
	TXO T2,MF.MOR	 	;[6017]Yes, lite the more bit
	SKIPA			;[6010]
BT5:	SETZ T2,		;[6010]No flags
	CALL GALHDR		;BUILD GALAXY MESSAGE HEADER IN TBUF
	MOVE T1,BTFLGS		;GET CURRENT FLAGS 
	TXO T1,WT.SJI		;ALWAYS SUPPRESS JOB INFORMATION
	MOVEM T1,TBUF+.OFLAG	;SET FLAGS WORD OF MESSAGE TO ORION
	MOVEI T1,.APORN		;GOING TO ORION
	CALL TRANG		;QUEUE IT UP FOR TRANSMISSION
	MOVE T1,BTFLGS		;Get flags
	TXNE T1,WT.MOR		;More text?
	JRST BT2		;Yes, process it
	SETZM NEBMSG		;[6010]Clear NEBULA FLAG
	SETZM BTFLGS		;No, clear message flags
	HRRZ T1,CT4		;GET FUNCTION CODE
	CAIE T1,.OMWTR		;WHAT FUNCTION?
	RET			;NOT WTOR - ALL DONE

; WTOR - MAKE ENTRY IN RESPONSE-EXPECTED QUEUE

	MOVE T1,CT2		;GET WTB ADDRESS
	SKIPE WTBCOD(T1)	;MESSAGE OUTSTANDING?
	CALL STOP		;YES, PROGRAM LOGIC ERROR
	MOVE T2,UNIQUE
	MOVEM T2,WTBCOD(T1)	;SAVE ACK CODE
	XMOVEI T2,20
	HRR T2,CT1
	MOVEM T2,WTBENT(T1)	;SAVE CALLER'S GLOBAL ENTRY ADDRESS
	MOVEI T2,WTBLNK(T1)	;GET ADDRESS OF PACKET LINKAGE WORD
	MOVEI T1,WTRQDB		;GET QUEUE DESCRIPTOR BLOCK ADDRESS
	CALLRET QMQT		;PUT PACKET ON EXPECTED-RESPONSE QUEUE

; BTJOB - REQUEST WT.JOB BE SET IN NEXT MESSAGE TO ORION
; BTNFO - REQUEST WT.NFO BE SET IN NEXT MESSAGE TO ORION
; RETURNS +1: ALWAYS

BTJOB::	SKIPA T1,[WT.JOB]
BTNFO::	MOVX T1,WT.NFO
	IORM T1,BTFLGS		;SET APPROPRIATE FLAG
	RET
; CANWTR - CANCEL AN OUTSTANDING WTOR MESSAGE
;  T1/ ACK CODE FROM WTB
; RETURNS +1: ALWAYS

CANWTR: QSCANI WTRQDB		;SET UP TO SCAN OUTSTANDING WTOR QUEUE
	STKVAR <CANCOD>
	MOVEM T1,CANCOD		;SAVE ACK CODE

; SEARCH WTB QUEUE FOR THE WTB WITH THE SPECIFIED ACK CODE

CANWT1:	CALL QMSCAN		;GET ADDRESS OF NEXT WTB ON CHAIN
	 CALL STOP		;END OF LIST, EXPECTED WTB MISSING
	MOVE T3,WTBCOD(T2)	;GET ACK CODE FROM WTB
	CAME T3,CANCOD		;IS THIS THE ONE THE CALLER WANTS?
	JRST CANWT1		;NO, CONTINUE SEARCH

; FOUND THE WTB FOR THE WTOR REQUEST THAT'S GOING TO BE CANCELED
; BUILD AND TRANSMIT CANCEL-WTOR MESSAGE TO ORION

	CALL QMDQS		;DEQUEUE WTB
	SUBI T2,WTBLNK		;GET WTB ADDRESS IN T2
	SETZM WTBCOD(T2)	;MARK WTB AS INACTIVE
	MOVE T1,[.OARGC+1,,.OMWTR] ;BUILD GALAXY HEADER
	SETZ T2,		; FLAGS
	MOVE T3,CANCOD		; ACK CODE
	CALL GALHDR
	MOVX T1,WT.KIL+WT.SJI	;GET FLAG FOR KILL-WTOR
	MOVEM T1,TBUF+.OFLAG
	SETZM TBUF+.OARGC	;NO ARGUMENTS
	MOVEI T1,.APORN		;MESSAGE GOING TO ORION
	CALLRET TRANG		;SEND CANCEL REQUEST TO ORION


; CMDCFM - PARSE END-OF-LINE
;  CSB/ COMND STATE BLOCK
; RETURNS +1: ERROR, MESSAGE SENT TO OPERATOR
;	  +2: SUCCESS

CMDCFM:	MOVEI T2,[FLDDB. .CMCFM]
	CALL COMNDX		;PARSE IT
	 SKIPA			;ERROR
	RETSKP			;SUCCESS
	JSP T1,RSPERR
	ASCIZ/Superfluous information at end of response/
; COMNDI - SET UP COMND STATE BLOCK FOR PARSING OPERATOR RESPONSE
;  T1/ ADDRESS OF ASCIZ OPERATOR RESPONSE TEXT
; RETURNS +1: ALWAYS, CSB SET UP FOR PARSING

COMNDI::STAKT			;STACK T1-T4
	TMCT <%I>		;INIT MESSAGE COMPOSER
	MOVE T1,CT1		;GET ADDRESS OF RESPONSE TEXT
	CALL TMCRSP		;COPY TEXT TO THE WIDE OPEN SPACES
	MOVX T3,CM%RAI+CM%XIF	;RAISE INPUT, NO INDIRECT FILE
	MOVEM T3,CSB+.CMFLG
	SETZM CSB+.CMIOJ	;SET BAD JFNS TO PREVENT TTY I/O
	HRROI T3,[0]
	MOVEM T3,CSB+.CMRTY	;CTRL/R BUFFER BYTE POINTER
	HRROI T1,TMCMSG
	MOVEM T1,CSB+.CMBFP	;BEGINNING OF INPUT
	MOVEM T1,CSB+.CMPTR	;POINTER TO NEXT FIELD TO BE PARSED
	MOVEI T2,5000
	MOVEM T2,CSB+.CMCNT	;SIZE OF AREA AFTER .CMPTR
	MOVEM T2,CSB+.CMINC	;# OF UNPARSED CHARS AFTER .CMPTR
	HRROI T3,ATMBFR
	MOVEM T3,CSB+.CMABP	;POINTER TO ATOM BUFFER
	MOVEI T3,ATMSIZ*5
	MOVEM T3,CSB+.CMABC	;SIZE OF ATOM BUFFER (CHARACTERS)
	SETZM CSB+.CMGJB	;GTJFN BUFFER ADDRESS
	RET


; COMNDX - EXECUTE COMND JSYS TO PARSE OPERATOR RESPONSE IN CORE
;  T2/ ADDRESS OF FUNCTION DESCRIPTOR BLOCK CHAIN
;  CSB/ COMND JSYS STATE BLOCK SET UP BY COMNDI SUBROUTINE
; RETURNS +1: PARSE FAILED
;	  +2: PARSE SUCCEEDED, T2/ T2 RETURNED BY COMND JSYS
;			       T3/ ADDRESS OF FDB ACTUALLY USED

COMNDX::SAVEQ
	MOVE T1,CSB+.CMINC	;GET # OF UNPARSED CHARACTERS
	CAIN T1,5000		;FIRST PARSE FOR THIS COMMAND LINE?
	JRST [	MOVX Q1,FLD(.CMCFM,CM%FNC) ;YES
		HRR Q1,T2	;PREFIX CALLER'S FDB WITH CONFIRM FDB
		MOVEI T2,Q1	;SUBSTITUTE THE ADDRESS OF MY FDB
		JRST .+1]
	MOVEI T1,CSB		;GET ADDRESS OF COMND STATE BLOCK
	COMND			;CALL MONITOR
	 ERJMP R		;JSYS FAILED, MAKE LIKE PARSE ERROR
	HRRZS T3		;GET ACTUAL FDB ADDRESS IN T3
	TXNN T1,CM%NOP		;PARSE ERROR?
	CAIN T3,Q1		; OR NULL COMMAND LINE?
	RET			;YES, RETURN +1, ERROR CODE IN T2
	RETSKP
; COMNDV - PARSE A VOLID WITHIN OPERATOR RESPONSE
;  CSB/ COMND JSYS STATE BLOCK
; RETURNS +1: BAD VOLID, ERROR MESSAGE SENT TO OPERATOR
;	  +2: SUCCESS, T1/ SIXBIT VOLID

COMNDV:	MOVEI T2,[FLDDB.(.CMQST,,,,,[FLDDB.(.CMFLD)])]
	CALL COMNDX		;PARSE QUOTED STRING OR FIELD
	 SETZM ATMBFR		;SYNTACTICAL ERROR
	MOVEI T1,ATMBFR		;GET STRING ADDRESS
	CALL ASCIZL		;GET LENGTH OF VOLID IN T2
	JUMPE T2,[JSP T1,RSPERR	;ERROR IF NULL VOLID
		ASCIZ/Syntactical error in volume-id/]
	CAILE T2,6		;TOO LONG?
	JRST [	JSP T1,RSPERR	;YES
		ASCIZ/Volume identifier longer than 6 characters/]
	MOVE T1,[POINT 7,ATMBFR] ;GET POINTER TO ASCII VOLID
	CALL CVTA6R		;CONVERT VOLID TO SIXBIT
	 JRST [	JSP T1,RSPERR	;ERROR
		ASCIZ/Illegal volume identifier/]
	RETSKP			;LOOKS GOOD, RETURN IT TO CALLER
; INWTOR - PROCESS INCOMING RESPONSE TO OUTSTANDING WTOR MESSAGE
;  RBUF/ IPCF MESSAGE FROM ORION, MESSAGE TYPE = .OMRSP
; RETURNS +1: ALWAYS

INWTOR:	QSCANI WTRQDB		;SET UP TO SCAN OUTSTANDING WTOR QUEUE
	STKVAR <WTBAD>

; SCAN OUTSTANDING WTOR MESSAGE QUEUE FOR THE MESSAGE THAT
; MATCHES UP WITH THE RESPONSE I JUST GOT

INWTO1:	CALL QMSCAN		;GET ADDR OF NEXT PACKET IN QUEUE
	 RET			;RACE - OPERATOR RESPONDED TO MESSAGE
				;JUST BEFORE ORION GOT MY KILL ORDER
	MOVE T3,WTBCOD-WTBLNK(T2) ;GET ACK CODE FROM ENTRY
	CAME T3,RBUF+.MSCOD	;DOES IT MATCH CODE IN IPCF MESSAGE?
	JRST INWTO1		;NO, CONTINUE SCAN

; THE RESPONSE HAS BEEN IDENTIFIED - DEQUEUE THE WTB,
; LOAD AC'S FOR HANDLER, AND SCHEDULE IT

	CALL QMDQS		;DEQUEUE THIS ENTRY, GET ADDR IN T2
	SUBI T2,WTBLNK		;SUBTRACT LINKAGE WORD OFFSET
	MOVEM T2,WTBAD		;SAVE ADDRESS OF WTB
	SETZM WTBCOD(T2)	;MARK WTB AS INACTIVE
	MOVEI T1,.ACKID
	CALL ORNBLF		;LOOK UP OPR-IDENTIFIER BLOCK
	 SETZ T2,		;NOT THERE
	JUMPE T2,[CALLRET BADOM] ;BLOCK NOT THERE OR TOO SHORT
	MOVE T1,(T1)		;GET ID OF RESPONDING OPR
	MOVEM T1,RBUF+.MSCOD	;SET IN CASE I WANT TO CALL BTACK
	MOVEI T1,.CMTXT		;SPECIFY ARG TYPE I WANT
	CALL ORNBLF		;SCAN ARG LIST FOR RESPONSE
	 JRST [	CALLRET BADOM]	;NO RESPONSE BLOCK, BAD MSG FROM ORION
	HRLI T1,(POINT 7)	;CONSTRUCT POINTER TO RESPONSE TEXT
	MOVE T2,WTBAD		;GET WTB ADDRESS IN T2

; ENTER RESPONSE PROCESSOR WITH THE FOLLOWING AC SETUP:
;   T1/ BYTE POINTER TO ASCIZ RESPONSE FROM OPERATOR
;   T2/ ADDRESS OF WTB

	CALLRET @WTBENT(T2)	;CALL BTWTOR CLEANUP CODE
; KC ROUTINES - CHECK FOR VARIOUS TAPE DRIVE CONDITIONS
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: CONDITION NOT SATISFIED, ERROR MESSAGE SENT TO OPERATOR
;	  +2: CONDITION SATISFIED

; CHECK FOR DRIVE AVAILABLE TO USERS

KCAVL:	LOAD T2,MTASTE		;GET STATE
	CAIN T2,S.AV		;AVAILABLE?
	RETSKP			;YES
	MOVEI T1,[ASCIZ/Not Under Operator Control/]
	JUMPE T2,KC1		;JUMP IF DRIVE NOT ASSIGNED
	JSP T1,KC1		;ONLY OTHER CASE IS INITIALIZING
	ASCIZ/In INITIALIZE Mode/

; CHECK IF DRIVE IS LOADED

KCLOAD:	JN MA%LOD,MTAFLG(MTA),RSKP
	JSP T1,KC1
	ASCIZ/Not Loaded/

; CHECK IF DRIVE IS IN USE BY ME OR USER

KCUSE:	SAVEAC <MT,RSB>
	JN MTAJCT,,[TMCT <%I%M Is In Use By MOUNTR, Try Later>
		MOVEI T3,TMCMSG
		CALLRET BTACK]	;SEND REPLY AND RETURN +1
	LOAD MT,MTAMT		;MT ASSOCIATED?
	JUMPE MT,RSKP		;RETURN GOOD IF DRIVE NOT IN USE
	LOAD RSB,MTRSB		;GET RSB ADDRESS
	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	TMCT <%I%M Is In Use By Request # %1D> ;A USER HAS IT
	MOVEI T3,TMCMSG
	CALLRET BTACK		;TELL OPERATOR

; KC1 - T1/ ADDRESS OF ASCIZ ERROR MESSAGE

KC1:	TMCT <%ITape Drive %M is %1A>
	MOVEI T3,TMCMSG
	CALLRET BTACK		;SEND ACK BACK TO OPR AND TAKE +1 RET
; KDMT - PROCESS DELETE MOUNT-REQUEST COMMAND FROM OPR
; RETURNS +1: ALWAYS

KDMT:	SAVEQ
	MOVEI T1,.ORREA
	CALL ORNBLF		;LOOKUP REASON BLOCK
	 SETZ T2,		;NOT FOUND
	SKIPE Q1,T2		;REASON GIVEN?
	JRST [	MOVSS T1	;YES, GET BLT SOURCE
		HRRI T1,ATMBFR	;BLT DESTINATION
		BLT T1,ATMBFR-1(T2) ;COPY REASON TO ATMBFR FOR TELUSR
		SETZM ATMBFR(T2) ;TIE IT OFF
		JRST .+1]
	MOVEI T1,.ORREQ
	CALL ORNBLF		;LOOKUP REQUEST # BLOCK
	 JRST KDMT1		;NOT THERE, TRY STRUCTURE FORM

; DELETING SPECIFIC MOUNT REQUEST

	JUMPE T2,KBADM		;REJECT HEADER-ONLY ENTRY
	MOVE T1,(T1)		;GET REQUEST #
	CALL REQRSB		;TRANSLATE REQ# TO RSB ADDR
	 JRST KNXREQ		;REQUEST DOES NOT EXIST
	LOAD T2,RSBSTE		;GET STATE OF REQUEST
	CAIE T2,RST.WM		;WAITING FOR MOUNT?
	CAIN T2,RST.WV		; OR WAITING FOR VOLID LIST KEYIN?
	SKIPA			;IF EITHER, OK TO DELETE
	JRST [	JSP T2,KACKRQ	;CAN'T DELETE THIS REQUEST
		ASCIZ/Is Not Waiting/]
	MOVEI T2,[ASCIZ/Canceled/]
	CALL KACKRQ		;TELL OPERATOR I DELETED IT
	MOVE	Q2,RSBSTN(RSB)	;GET STR NAME
	MOVE	Q3,RSBSTA(RSB)	;GET STR ALIAS
	JUMPN Q1,[ABTREQ (MREQ15,ABT%OP) ;ABORT WITH REASON
		  JRST	KDMT0]		 ;AND CONTINUE
	ABTREQ (MREQ15)		;ABORT WITHOUT REASON
KDMT0:	QSCANI	ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
KDMT0A:	CALL	NSTRSB		;GET ADDR OF NEXT RSB
	JRST	KDMT0B		;END OF QUEUE
	CAMN	Q2,RSBSTN(RSB)	;SAME STR NAME
	CAME	Q3,RSBSTA(RSB)	;SAME ALIAS
	JRST	KDMT0A		;NO, TRY NEXT RSB
	MOVE	T1,RSBIFL(RSB)	;YES, SEE IF OPR HAS BEEN NOTIFIED
	TXNE	T1,R%ONR	;
	JRST	KDMT0A		;OPR HAS SEEN THIS ONE, TRY NEXT
	CALL	WOVMS		;OPR HAS NOT SEEN IT YET --TELL OPR
KDMT0B:	RET			;FINISHED


; DELETING ALL MOUNT REQUESTS FOR SPECIFIED STRUCTURE

KDMT1:	MOVEI T1,.STRDV		;SPECIFY BLOCK TYPE
	CALL KGTSTR		;GET STRUCTURE NAME
	 JRST KBADM		;NOT THERE, ERROR
	MOVE Q2,T1		;SAVE SIXBIT STRUCTURE NAME
	QSCANI ARBQDB		;SET UP TO SCAN REQUEST QUEUE
	SETZ Q3,		;SET ABORTED REQUEST COUNT TO ZERO

; SCAN REQUEST QUEUE ABORTING REQUESTS FOR THIS STRUCTURE

KDMT2:	CALL NSTRSB		;GET NEXT RSB
	 JRST KDMT3		;NONE LEFT
	LOAD T1,RSBTYP		;GET TYPE
	CAIE T1,.MNTST		;STRUCTURE MOUNT?
	JRST KDMT2		;NO, SKIP IT
	SKIPN T1,RSBSTN(RSB)	;STRUCTURE NAME SPECIFIED?
	MOVE T1,RSBSTA(RSB)	;NO, USE ALIAS
	CAME Q2,T1		;WANT TO CANCEL THIS REQUEST?
	JRST KDMT2		;NO, SKIP IT
	JUMPN Q1,[ABTREQ (MREQ15,ABT%OP) ;ABORT WITH REASON
		AOJA Q3,KDMT2]	;COUNT IT AND CONTINUE SCAN
	ABTREQ (MREQ15)		;ABORT WITHOUT REASON
	AOJA Q3,KDMT2		;COUNT IT AND CONTINUE SCAN

; TELL THE OPERATOR HOW MANY REQUESTS WERE DELETED

KDMT3:	JUMPE Q3,[TMCT <%INo>
		JRST KDMT3A]
	TMCT <%I%7D>		;DISPLAY # OF REQUESTS
KDMT3A:	TMCT < Mount Request>
	SOJN Q3,[TMCT <s>	;TACK ON S IF NOT 1 REQUEST
		JRST .+1]
	TMCT < Canceled>
	MOVEI T3,TMCMSG		;GET ADDRESS OF MESSAGE
	CALLRET BTACK		;RESPOND TO DELETE COMMAND
; KDIS/KENA - PROCESS ENABLE AND DISABLE COMMANDS FROM OPR
; RETURNS +1: ALWAYS

KDIS:	SKIPA T1,[[LOAD T1,MTASTE
		CAIE T1,S.AV
		RET
		MOVX T1,MA%AVE
		ANDCAM T1,MTAFLG(MTA)
		RET]]		;COROUTINE FOR DISABLE
KENA:	MOVEI T1,[LOAD T1,MTASTE
		CAIE T1,S.AV
		RET
		CALL AVRENA
		CALLRET AVR]	;COROUTINE FOR ENABLE
	JXE F,TALCF,KNALC	;REJECT IF ALLOCATION NOT ENABLED
	STAKT
	MOVEI T1,.AVREC		;CHECK FOR AVR KEYWORD
	CALL ORNBLF		;IS IT THERE?
	 JRST KBADM		;NO
	MOVE T1,CT1		;GET ADDRESS OF COROUTINE
	CALL KTXCT		;DO IT FOR SPECIFIED TAPE DRIVES
	 JRST KBADM		;BAD MESSAGE FROM QUASAR
	RET
; KGBLK - LOOK UP SPECIFIED BLOCK TYPE IN MESSAGE
;  T1/ BLOCK TYPE
;  T2/ UPPER LIMIT OF ARGUMENT (LOWER LIMIT = 0)
;      IF T2/ 0, NO LIMIT CHECKING IS DONE
;  T3/ DEFAULT, APPLIED IF (T2).NE.0 AND VALUE=0
;		OR IF ENTRY NOT PRESENT
; RETURNS +1: HEADER-ONLY ENTRY OR VALUE BEYOND LIMITS
;	  +2: T1/ VALUE (OR DEFAULT IF APPLICABLE)

KGBLK:	STAKT			;SAVE ARGS
	CALL ORNBLF		;LOOKUP ARGUMENT
	 JRST KGBLK1		;NOT THERE, TAKE THE DEFAULT
	JUMPE T2,R		;ERROR IF HEADER-ONLY
	MOVE T1,(T1)		;GET ARGUMENT
	SKIPN CT2		;LIMIT CHECK REQUESTED?
	RETSKP			;NO, JUST PASS IT BACK
	CAMG T1,CT2		;GREATER THAN UPPER LIMIT?
	SKIPGE T1		; OR BELOW 0 ?
	RET			;YES, ERROR
	SKIPN T1		;IS IT 0 ?
KGBLK1:	MOVE T1,CT3		;YES, SUBSTITUTE THE DEFAULT
	RETSKP


; KGTSTR - LOCATE AND EXTRACT STRUCTURE OR ALIAS NAME
;  T1/ ENTRY TYPE CODE (.STRDV OR .STALS)
; RETURNS +1: ENTRY NOT FOUND
;	  +2: SUCCESS, T1/ SIXBIT STRUCTURE NAME  T2,T3/ ASCIZ NAME

KGTSTR:	CALL ORNBLF		;LOOKUP SPECIFIED BLOCK TYPE
	 JRST KGSTR1		;NOT FOUND
	SAVET			;SET UP TO RETURN VALUES TO CALLER
	DMOVE T3,(T1)		;GET ASCIZ NAME FROM ENTRY
	CAIG T2,1		;ENTRY 1 WORD LONG?
	SETZ T4,		;YES, ZAP SECOND WORD
	DMOVEM T3,CT2		;RETURN ASCIZ NAME IN T2,T3
	MOVSI T1,(POINT 7)
	HRRI T1,CT2		;CONSTRUCT POINTER TO ASCIZ NAME
	MOVEI T2,CT1		;RETURN SIXBIT EQUIVALENT HERE
	CALL SEVSIX		;CONVERT NAME TO SIXBIT
	RETSKP
KGSTR1: TXNN F,PORTF		;Are we doing a port operation
	RET			;No, return failure
	SAVET			;
	MOVE T1,DSKSTN(DSK)	;Get sixbit name from status block
	MOVEM T1,CT1		;Save it for return
	MOVEI T1,CT1		;Adress of sixbit for SIXSEV
	MOVSI T2,(POINT 7)
	HRRI T2,CT2		;Construct pointer to ASCIZ name
	CALL SIXSEV		;Convert name to ASCIZ
	RETSKP

; KGTVOL - EXTRACT SIXBIT VOLID FROM .VOLID ENTRY
; RETURNS +1: ERROR, MESSAGE SENT TO OPR
;	  +2: T1/ 0 IF .VOLID ENTRY ABSENT, ELSE SIXBIT VOLID

KGTVOL:	SAVEQ
	STKVAR<TMPSIX>		;Later, to hold sixbit vol. i.d. value
	MOVEI T1,.VOLID
	CALL ORNBLF		;VOLID SPECIFIED?
	 JRST [	SETZ T1,	;NO, RETURN ZERO
		SETOM RSBIVN(RSB) ;Consider as non-numeric
		RETSKP]
	JUMPE T2,KBADV		;MUST HAVE SOMETHING AFTER HEADER
	MOVE Q1,T1		;SAVE ADDRESS OF ASCIZ VOLID
	CALL ASCIZL		;GET # OF CHARACTERS IN VOLID
	SKIPE T2		;NULL VOLID IS AN ERROR
	CAILE T2,6		;LONGER THAN 6 CHARACTERS?
	JRST KBADV		;YES, ERROR
	MOVE T1,Q1		;FETCH ADDRESS OF VOLID
	HRLI T1,(POINT 7)	;MAKE BYTE POINTER
	CALL CVTA6R		;CONVERT TO SIXBIT
	 JRST KBADV		;NOT A LEGAL VOLID
	MOVEM T1,TMPSIX		;Save for later use
	MOVE T1,Q1		;Address of vol. i.d. in ASCIZ
	CALL ASCIZL		;(T2) = number characters in vol. i.d.
	MOVE T1,Q1		;Make T1 into a pointer to the volume
	HRLI T1,(POINT 7)	;i.d. in ASCIZ
	ILDB T3,T1		;Get the 1st volume i.d. character
	CAIN T3,"0"		;Is it a zero?
	JRST NONUM		;Yes, so consider it as non-numeric
	SETZM T4		;T4 will contain the integer value
	SKIPA			;Continue to check the first character
CHKNXT: ILDB T3,T1		;Next volume i.d. character
	CAIL T3,"0"		;Less than zero in value?
	CAILE T3,"9"		;No, less or equal to nine?
	JRST NONUM		;Not numeric
	SUBI T3,"0"		;Change from ASCII to binary
	ADD T4,T3		;Add to the integer volume i.d.
	SOSLE T2		;Don't multiply the units contribution
	IMULI T4,^D10		;Multiply by base 10
	JUMPG T2,CHKNXT		;Get the next character
	MOVEM T4,RSBIVN(RSB)	;Store the integer value of the i.d.
	SKIPA			;Numeric, so skip the next
NONUM:	SETOM RSBIVN(RSB)	;Indicate that not numeric
 	MOVE T1,TMPSIX		;Restore the sixbit value of the i.d.
	RETSKP
; KIDN - PROCESS IDENTIFY COMMAND FROM OPR
; RETURNS +1: ALWAYS

KIDN:	SAVEQ
	SAVEAC <MT,MTA,RSB>
	STKVAR <<OWNER,10>>	;LOCAL WORK AREA FOR GETVU ROUTINE
; VALIDATE TAPE DRIVE

	MOVEI T1,.TAPDV
	CALL ORNBLF		;TAPE DRIVE SPECIFIED?
	 JRST KBADM		;NO, BAD MESSAGE FROM QUASAR
	JXE F,TALCF,KNALC	;REJECT IF ALLOCATION IS NOT ENABLED
	CALL STMTA		;CONVERT STRING TO MTA STATUS BLOCK ADDR
	 JRST KBADM		;NOT MTA DEVICE STRING

	MOVEI T1,.ORREQ
	CALL ORNBLF		;LOOKUP REQUEST # BLOCK
	 JRST KIDV		;NOT THERE, MAYBE ANOTHER FORM OF CMD
	JUMPE T2,KBADM		;REJECT HEADER-ONLY ENTRY
	MOVE Q3,(T1)		;GET REQUEST #

; PROCESS COMMAND:  IDENTIFY drive REQUEST-ID n

	MOVE T1,Q3		;GET REQUEST #
	CALL REQRSB		;GET RSB ADDRESS FOR THIS REQUEST
	 JRST KNXREQ		;REQUEST DOES NOT EXIST
	HRROI T2,[ASCIZ/Not Waiting For Tape Mount/]
	LOAD T3,RSBTYP
	CAIE T3,.MNTTP		;TAPE REQUEST?
	JRST KACKRQ		;NO, REJECT IT
	LOAD T3,RSBSTE		;GET STATE
	CAIN T3,RST.WV		;WAITING FOR KEYIN?
	JRST [	JSP T2,KACKRQ	;YES, REJECT WITH APPROPRIATE MESSAGE
		ASCIZ/Waiting For RESPOND Keyin/]
	CAIE T3,RST.WM		;WAITING FOR TAPE MOUNT?
	JRST KACKRQ		;NO
	CALL VQGCV		;DOES USER WANT A SCRATCH TAPE?
	JUMPE T1,KIDR1		;YES, TAKE ALTERNATE PATH
	MOVE Q1,T1		;SPECIFIC VOLID, SAVE IT
	MOVX T2,TM%BYP
	TDNE T2,RSBUFL(RSB)	;BYPASS MODE?
	SETZ T1,		;YES, KEEP KVAC FROM BARFING
	SETZ T2,		;NOT SCRATCH
	CALL KVAC		;OK TO SET NEW VOLID?
	 RET			;NO, ERROR MESSAGE SENT
	MOVEM Q1,MTAIDV(MTA)	;SET ALLEGED VOLID
	EXCH Q1,MTAVOL(MTA)	;SET NEW VOLID, SAVE OLD
	CALL VRA		;TRY TO MATCH REQUEST TO VOLUME NOW
	 SKIPA			;DIDN'T MATCH
	RET			;DID MATCH, ALL DONE
	MOVEM Q1,MTAVOL(MTA)	;RESTORE OLD VOLID
	CALL CHKAB		;REQUEST ABORTED?
	 JRST KIDR0		;YES, CLEAN UP AND LEAVE
	CALL VOLMNT		;STILL THERE, TRY TO MOUNT AGAIN
	JN MTAJCT,,R		;RETURN IF AVR IN PROGRESS
KIDR0:	SETZM MTAIDV(MTA)	;REQ ABORTED OR NOT DOING AVR
	RET

; SAME AS ABOVE, BUT USER IS REQUESTING SCRATCH VOLUME

KIDR1:	SETZ T1,		;NOT SETTING VOLID
	MOVEI T2,1		;SCRATCH
	CALL KVAC		;OK TO SCRATCH THIS VOLUME?
	 RET			;NO, ERROR MESSAGE SENT
	LOAD T1,MTALT
	CAIN T1,.LTT20		;TOPS-20 LABELED TAPE?
	JRST [	JN MA%SCR,MTAFLG(MTA),.+1 ;YES, OK IF ALREADY SCRATCH
		MOVEI T1,OWNER	;SUPPLY WORK AREA ADDRESS TO GETVU
		CALL GETVU	;GET TAPE OWNER'S USER # IN T2
		CAME T2,RSBUNO(RSB) ;OWNER AND REQUESTOR THE SAME?
		JRST KNOSCR	;NO, REJECT KEYIN
		JRST .+1]	;YES, PERMIT IT
	MOVE Q1,MTAFLG(MTA)	;SAVE FLAGS
	SETONE MA%SCR,MTAFLG(MTA) ;SET SCRATCH
	SETZRO MA%OPF,MTAFLG(MTA) ;CLEAR OVERWRITE-PROTECTED
	CALL VRA		;TRY TO MATCH REQUEST TO VOLUME
	 SKIPA			;DIDN'T MATCH
	RET			;DID MATCH, ALL DONE
	MOVX Q2,MA%SCR+MA%OPF	;RESTORE MA%SCR AND MA%OPF IN MTAFLG
	AND Q1,Q2
	ANDCAM Q2,MTAFLG(MTA)
	IORM Q1,MTAFLG(MTA)
	CALL CHKAB		;REQUEST ABORTED?
	 RET			;YES
	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	TMCT <%I%M Tape Not Compatible With Request %1D>
	MOVEI T3,TMCMSG
	CALLRET BTACK		;SEND IT OFF

; PROCESS FOLLOWING FORMS OF IDENTIFY COMMAND:
;    IDENTIFY drive VOLUME-ID volid
;    IDENTIFY drive SCRATCH-TAPE

KIDV:	CALL KGTVOL		;LOOKUP .VOLID ENTRY
	 RET			;SOME ERROR, OPERATOR NOTIFIED
	MOVE Q1,T1		;SAVE VOLID IN Q1

	MOVEI T1,.SCRTP
	MOVEI Q2,1		;ASSUME SCRATCH SPECIFIED
	CALL ORNBLF		;SCRATCH SPECIFIED?
	 JRST [	SETZ Q2,	;NO, SET NO SCRATCH
		JUMPN Q1,.+1	;ARE .SCRTP AND .VOLID BOTH ABSENT?
		JRST KBADM]	;YES, BAD MESSAGE
	JUMPN Q2,[MOVE T1,MTAFLG(MTA) ;IF SCRATCHING, GET FLAGS
		LOAD T2,MTALT	;AND LABEL TYPE
		TXNN T1,MA%SCR	;ALREADY SCRATCH?
		CAIE T2,.LTT20	;OR NOT TOPS-20 LABEL?
		JRST .+1	;YES TO EITHER, OK TO SCRATCH
		JRST KNOSCR]	;CAN'T SCRATCH TOPS-20 TAPE WITH THE
				;IDENTIFY COMMAND - MUST SET TAPE INIT
	DMOVE T1,Q1		;GET VOLID AND SCRATCH FLAG
	CALL KVAC		;OK TO DO THIS TO THIS DRIVE?
	 RET			;NO, ERROR MESSAGE SENT

; EVERYTHING LOOKS LEGAL, NOW DO WHAT THE OPERATOR WANTS

	SKIPE Q1		;SETTING VOLID?
	MOVEM Q1,MTAVOL(MTA)	;YES, DO IT
	JUMPN Q2,[SETONE MA%SCR,MTAFLG(MTA) ;SETTING SCRATCH FLAG
		SETZRO MA%OPF,MTAFLG(MTA) ;CLEAR OVERWRITE PROTECTION
		JRST .+1]
	CALLRET MATCHV		;TRY TO MATCH VOLUME WITH A REQUEST
; KSHT - PROCESS SHOW STATUS TAPE-DRIVE COMMAND FROM OPR
; ACCEPTS IPCF MESSAGE IN RBUF
; RETURNS +1: ALWAYS

KSHT:	SAVEQ
	JXE F,TALCF,KNALC	;REJECT IF ALLOCATION IS NOT ENABLED
	TMCTN <%I
Drive  State     Volid   Req#  Job#  User
-----  -----     ------  ----  ----  ---->
	MOVE T1,RBUF+.OFLAG	;GET FLAGS
	TXNE T1,ST.AVA		;/FREE
	TMCTN <%I
Drive  State    Avr  Write  Volid   Scr  Lbl Type  Density
-----  -----    ---  -----  ------  ---  --------  ------->
	TXNE T1,ST.CHR		;CHARACTERISTICS
	TMCTN <%I
Drive  Type             Supported Densities
-----  ---------------  ------------------->
	TMCTO			;INSERT HEADING
	MOVE Q1,TMCPTR		;GET CURRENT TEXT POINTER
	MOVEI T1,KSHSCR		;GET COROUTINE ADDRESS
	CALL KTXCT		;BUILD THE BODY OF THE DISPLAY
	 JRST KBADM		;BAD IPCF MESSAGE
	CAME Q1,TMCPTR		;Anything displayed?
	JRST [MOVEI T3,[ASCIZ/Tape Drive Status/] ;Yes
	      CALL BTNFO		;REQUEST NO FORMATTING
	      MOVE T4,RBUF+.MSFLG	;[6010]Get the message flag word
	      TXNE T4,MF.NEB		;[6010]From NEBULA
	      SETOM NEBMSG		;[6010]Yes
	      CALLRET BTACKT]		;SEND DISPLAY TO OPERATOR AND SPLIT

	MOVEI T3,[ASCIZ/There Are No Free Tape Drives/] ;No, assume free drives
	LOAD T2,ST.AVA,RBUF+.OFLAG ;Get the switch
	SKIPN T2		;Asking for free-drive display?
	MOVEI T3,[ASCIZ/There Are No Tape Drives/] ;No
	MOVE T4,RBUF+.MSFLG	;[6010]Get the message flag word
	TXNE T4,MF.NEB		;[6010]From NEBULA
	SETOM NEBMSG		;[6010]Yes
	CALLRET BTACK

; COROUTINE FOR SHOW STATUS

KSHSCR:	SAVEQ
	SAVEAC <MT,RSB>
	MOVE Q3,RBUF+.OFLAG	;GET MESSAGE FLAGS
	JXN Q3,ST.AVA,KSHF	;/FREE
	JXN Q3,ST.CHR,KSHC	;/CHARACTERISTICS
; SHOW STATUS TAPE-DRIVE [/ALL]

	LOAD MT,MTAMT		;GET ADDRESS OF MT STATUS BLOCK
	JE MTASTE,,[CALL GMTADD	;DRIVE UNAVAILABLE, GET DESIGNATOR
		DVCHR		;GET LH(T3)/ OWNER'S JOB#
		TLNN T3,-1	;SHOW IF PHYSICAL DEVICE EXISTS
		CALL CKMPAV	;SHOW IF SET UNAVAILABLE
		 JRST .+1
		RET]		;DON'T SHOW
	TMCT <%_%M%8C>		;DISPLAY DRIVE NAME
	LOAD Q1,MTASTE
	CAIE Q1,S.AV		;AVAILABLE TO USERS?
	JRST [	JUMPE Q1,[TMCTR <Unavailable>] ;NO
		TMCT <Initialize>
		LOAD RSB,MTRSB	;GET RSB ADDRESS
		SKIPN RSBWTB+WTBCOD(RSB) ;WAITING FOR OPER RESPONSE?
		RET		;NO
		TMCTR <, operator response wait>]
	MOVE Q1,MTAFLG(MTA)	;GET MTA FLAGS
	JXE Q1,MA%LOD,[TMCT <Unloaded>
		JRST KSHN1]
	MOVEI T1,[ASCIZ/Loaded/] ;ASSUME JUST LOADED
	SKIPE MT		;RIGHT?
	MOVEI T1,[ASCIZ/In Use/] ;NO, CHANGE TO IN USE
	TMCT <%1A%18C>		;DISPLAY STATE
	SKIPE T1,MTAVOL(MTA)	;DO I KNOW VOLID?
	CALL [	TMCTR <%1S>]	;YES, DISPLAY IT
	JUMPE MT,KSHN1		;THAT'S ALL IF NO USER
	LOAD RSB,MTRSB		;GET REQUEST STATUS BLOCK ADDRESS
	CAIN RSB,MTNAV		;MT OWNED BY PHANTOM USER?
	JRST KSHN1		;YES, THAT'S ALL
	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	LOAD T2,RSBJNO		;GET JOB #
	MOVE T3,RSBUNO(RSB)	;GET USER #
	TMCT <%26C%1D%32C%2D%38C%3U> ;SHOW USER INFO
KSHN1:	JXE Q3,ST.ALL,R		;/ALL REQUESTED?
	LOAD T1,MA%AVE,Q1	;YES, GET AVR STATUS
	TMCT <%_%8CAVR: %1Y>	;DISPLAY AVR STATE
	JXE Q1,MA%LOD,R		;EXIT IF NOT LOADED
	LOAD T1,MA%WEN,Q1	;GET WRITE-ENABLED FLAG
	TMCT <, Write: %1Y>	;DISPLAY IT
	LOAD T1,MTALT		;GET LABEL TYPE
	JUMPE T1,R		;NOT IDENTIFIED YET
	MOVE T2,LTTXT(T1)	;GET LABEL-TYPE TEXT
	MOVEI T3,[0]		;ASSUME UNLABELED
	CAIE T1,.LTUNL
	MOVEI T3,[ASCIZ/ labels/]
	TXNE Q1,MA%SCR		;SCRATCH?
	MOVEI T3,[ASCIZ/ scratch tape/]
	TMCT <, %2A%3A>		;SHOW LABEL TYPE, SCRATCH
	CAIN T1,.LTUNL		;UNLABELED?
	RET			;YES
	LOAD T2,MTADEN		;LABELED, SHOW DENSITY
	MOVE T2,DENTAB(T2)
	TMCTR <, %2D BPI>

; SHOW STATUS TAPE-DRIVE /FREE

KSHF:	LOAD T1,MTASTE		;GET STATE
	CAIE T1,S.AV		;AVAILABLE TO USERS?
	RET			;NO, SKIP IT
	JN MTAMT,,R		;DON'T SHOW IF A USER HAS IT
	MOVE T1,MTAFLG(MTA)	;GET FLAGS
	MOVEI T2,[ASCIZ/Unloaded/] ;ASSUME UNLOADED
	TXNE T1,MA%LOD		;LOADED?
	MOVEI T2,[ASCIZ/Loaded/] ;YES
	LOAD T3,MA%AVE,T1	;GET AVR FLAG
	TMCT <%_%M%8C%2A%17C%3Y> ;DISPLAY DRIVE, STATE, AVR
	JXE T1,MA%LOD,R		;END OF LINE IF DRIVE NOT LOADED
	LOAD T2,MA%WEN,T1	;GET WRITE-ENABLED FLAG
	MOVE T3,MTAVOL(MTA)	;GET VOLID
	LOAD T4,MA%SCR,T1	;GET SCRATCH FLAG
	TMCT <%23C%2Y%29C%3S%37C%4Y> ;DISPLAY WRITE, VOLID, SCRATCH
	LOAD T1,MTALT		;GET LABEL TYPE
	JUMPE T1,R		;UNKNOWN
	MOVE T2,LTTXT(T1)	;GET POINTER TO TEXT
	TMCT <%42C%2A>		;DISPLAY LABEL TYPE
	CAIN T1,.LTUNL		;LABELED?
	RET			;NO, DONE
	LOAD T2,MTADEN		;YES, GET DENSITY CODE
	MOVE T2,DENTAB(T2)	;GET DENSITY
	TMCTR <%52C%2D>		;DISPLAY AND RETURN

; SHOW STATUS TAPE-DRIVE /CHARACTERISTICS

KSHC:	JE MTASTE,,R		;DON'T SHOW DRIVE IF I DON'T CONTROL IT
	LOAD T1,MTADRV		;GET DRIVE TYPE CODE
	MOVE T1,DRVTXT(T1)	;GET ADDRESS OF TEXT
	LOAD T2,MTADVT		;Get the device
	MOVSI T3,-DVTLEN	;Get number of things in table
KSHCDV:	HRRZ T4,DVTTXT(T3)	;Get te drive type from table
	CAIN T4,(T2)		;Do they match?
	JRST KSHCD2		;Yes
	AOBJN T3,KSHCDV		;Loop to check all of them
	SKIPA T2,[EXP [ASCIZ/??/]]
KSHCD2:	HLRZ T2,DVTTXT(T3)	;Point to drive type
	TMCT <%_%M%8C%2A%15C%1A%25C>	;DISPLAY DRIVE, TYPE
	MOVSI T1,-DENMAX-1	;GET AOBJP POINTER
	MOVSI T2,(1B0)		;SET UP INTERROGATION BIT
	MOVEI T3,[0]		;NO ", " BEFORE FIRST DENSITY
KSHC1:	AOBJP T1,R		;GET OUT OF LOOP IF DONE
	LSH T2,-1		;SHIFT BIT TO NEXT POSITION
	TDNN T2,MTASDN(MTA)	;IS THIS DENSITY SUPPORTED?
	JRST KSHC1		;NO, TEST NEXT DENSITY
	MOVE T4,DENTAB(T1)	;GET DENSITY
	TMCT <%3A%4D>		;DISPLAY DENSITY
	MOVEI T3,[ASCIZ/, /]	;SEPARATE SUBSEQUENT DENS WITH A COMMA
	JRST KSHC1
; KSTP - PROCESS SET TAPE-DRIVE COMMAND FROM OPR
; RETURNS +1: ALWAYS

KSTP:	SAVEQ
	SAVEAC <MTA>
	JXE F,TALCF,KNALC	;REJECT IF ALLOCATION IS NOT ENABLED
	MOVEI T1,.TAPDV
	CALL ORNBLF		;TAPE DRIVE SPECIFIED?
	 JRST KBADM		;NO
	CALL STMTA		;CONVERT STRING TO MTA STATUS BLOCK ADDR
	 JRST KBADM		;BAD MTA STRING
	SETZ Q1,		;ASSUME SETTING UNAVAILABLE
	MOVEI T1,.DVUAV
	CALL ORNBLF		;CHECK IF SETTING UNAVAILABLE
	 JRST [	MOVEI T1,.DVAVL	;NO
		CALL ORNBLF	;SETTING AVAILABLE?
		 SKIPA		;NO
		AOJA Q1,KSTPA	;SETTING AVAILABLE
		MOVEI T1,.DVINI
		CALL ORNBLF	;SETTING INITIALIZE MODE?
		 JRST KBADM	;NO, BAD MESSAGE
		CALLRET KVI]	;YES, GO DO IT

; SETTING DRIVE UNAVAILABLE

	MOVEI T1,.ORREA
	CALL ORNBLF		;REASON BLOCK PRESENT?
	 JRST KBADM		;NO
	MOVE Q2,T1		;COPY ADDRESS OF REASON TEXT
	CALL CKMPAV		;IS DRIVE ALREADY SET UNAVAILABLE?
KSTP1:	 JRST [	MOVE T1,[[ASCIZ/Unavailable/]
			 [ASCIZ/Available/]](Q1) ;GET TEXT POINTER
		TMCT <%ITape Drive %M Is Already Set %1A>
		MOVEI T3,TMCMSG
		CALLRET BTACK]	;TELL OPRTR HIS COMMAND HAS NO EFFECT
	LOAD T1,MTASTE
	CAIN T1,S.INIT		;IN INITIALIZE MODE?
	JRST [	CALL KVICU	;YES, CAN I GET OUT OF IT NOW?
		 RET		;NO
		JRST .+1]	;YES, CONTINUE
	MOVEI T1,CS%DDV		;GET CODE FOR DETACH-DEVICE
	MOVE T2,Q2		;GET ADDRESS OF ASCIZ REASON
	CALL SYTSET		;LOG SYSERR ENTRY FOR DRIVE SET UNAVAIL
	CALL DACMTA		;DEACTIVATE THE DRIVE IF POSSIBLE
	MOVEI T1,1		;GET 1 TO SET UNAVAILABLE
	CALL SMPAV		;UPDATE DEVICE STATUS FILE
	CALL WOTDAV		;TELL ALL OPERATORS WHAT HAPPENED
	RET

; SETTING DRIVE AVAILABLE

KSTPA:	LOAD T1,MTASTE		;GET CURRENT STATE
	CAIN T1,S.INIT		;INITIALIZING VOLUMES?
	JRST [	CALL KVICU	;YES, CLEAR INITIALIZE STUFF
		 RET		;CAN'T DO IT NOW
		CALLRET KVIDAV]	;GET BACK TO AVAILABLE STATE
	SETZ Q2,		;REMEMBER INITIAL SMPAV STATE IN Q2
	SKIPE T1		;OK IF DRIVE NOT BEING SCHEDULED
	CALL CKMPAV		;OK IF DRIVE SET UNAVAILABLE
	 TDZA Q2,Q2		;ONE OF THE ABOVE CONDITIONS WAS TRUE
	JRST KSTP1		;NEITHER TRUE, THAT'S AN ERROR
	SETZ T1,
	CALL SMPAV		;SET AVAILABLE IN STATUS FILE
	MOVEI T1,S.AV		;GET DESIRED STATE
	CALL ACTMTA		;TRY TO ACTIVATE THE MTA
	 JRST KSTP3		;CAN'T, SO SEND DIAGNOSTIC TO OPR
	CALL TDSC1		;CHECK IF LOADED, DO AVR, ETC.
	JUMPE Q2,[MOVEI T1,CS%ADV ;GET CODE FOR ATTACH-DEVICE
		SETZ T2,	;NO REASON
		CALL SYTSET	;LOG SYSERR ENTRY FOR DRIVE SET AVAIL
		JRST .+1]
	CALLRET WOTDAV		;TELL OPERATORS IT'S BACK

; TAPE DRIVE WAS ASSIGNED TO ANOTHER JOB   T1/ JOB#

KSTP3:	MOVE Q2,T1		;SAVE JOB #
	TMCT <%I%M is >
	SKIPLE Q2		;ASSIGNED TO JOB 0
	CAIL Q2,4000		;OR SOME FUNNY JOB?
	JRST [	TMCT <not accessible by MOUNTR>
		JRST KSTP2]	;YES, SPECIAL MESSAGE
	MOVE T1,Q2		;GET JOB#
	TMCT <assigned to Job %1D>
KSTP2:	MOVEI T3,[ASCIZ/Cannot Set Tape Drive Available/]
	CALLRET BTACKT		;TELL OPERATOR WHY I CAN'T SET AVAIL
; KSWI - PROCESS SWITCH COMMAND FROM OPR
; RETURNS +1: ALWAYS

; VALIDATE REQUEST NUMBER AND STATE

KSWI:	SAVEQ
	SAVEAC <MT,MTA,RSB>
	MOVEI T1,.ORREQ
	CALL ORNBLF		;LOOKUP REQUEST #
	 JRST KBADM		;NOT THERE
	MOVE T1,(T1)		;GET REQ#
	CALL REQRSB		;FIND RSB
	 JRST KNXREQ		;UNKNOWN REQUEST #
	MOVEI T2,[ASCIZ/Not Using An Unlabeled Tape/]
	LOAD T3,RSBTYP		;GET REQ TYPE
	CAIE T3,.MNTTP		;TAPE-MOUNT REQUEST?
	JRST KACKRQ		;NO, REJECT IT
	LOAD T3,RSBSTE		;GET STATE
	LOAD T4,RSBLT		;GET LABEL-TYPE
	CAIN T3,RST.AC		;MUST BE ACTIVE
	CAIE T4,.LTUNL		;MUST HAVE UNLABELED TAPE
	JRST KACKRQ		;DOESN'T QUALIFY, REJECT IT
	LOAD MT,RSBMT		;GET MT STATUS BLOCK ADDRESS

; VALIDATE VOLID

	CALL KGTVOL		;LOOKUP VOLID
	 RET			;SCREWED-UP VOLID
	SKIPN Q1,T1		;WAS THERE A .VOLID ENTRY?
	JRST KBADM		;NO, BAD NEWS

; CHECK IF TAPE DRIVE SPECIFIED

	SETZ MTA,		;ASSUME NO DRIVE SPECIFIED
	MOVEI T1,.TAPDV
	CALL ORNBLF		;TAPE DRIVE SPECIFIED?
	 JRST KSWI1		;NO
	CALL STMTA		;YES, LOAD MTA AC FOR THIS DRIVE
	 JRST KBADM		;BAD DRIVE NAME FROM QUASAR
	LOAD T1,MTMTA		;GET CURRENT DRIVE
	CAMN T1,MTA		;SWITCHING TO SAME DRIVE?
	JRST [	MOVEI T3,[ASCIZ/Cannot SWITCH To Same Drive/] ;YES
		CALLRET BTACK]
	MOVE T1,Q1		;GET VOLID
	SETZ T2,		;NOT SETTING SCRATCH
	CALL KVAC		;CHECK IF I CAN USE THIS MTA
	 RET			;NO, ERROR MSG SENT
	LOAD T1,MTALT
	CAIE T1,.LTUNL		;UNLABELED TAPE?
	JRST [	TMCT <%I%M Does Not Contain An Unlabeled Tape>
		MOVEI T3,TMCMSG
		CALLRET BTACK]	;TELL OPERATOR
KSWI1:

; COMMAND HAS BEEN VALIDATED, NOW PERFORM SPECIFIED TASKS

	CALL GMTDD		;GET MT DEVICE DESIGNATOR IN T1
	LDB T2,[POINT 9,T1,35]	;GET MT UNIT# IN T2
	MOVEI T1,.MTCVV		;FUNCTION CODE = CLEAR VOLUME-VALID
	MTU%			;YANK MT AND MTA APART IN MONITOR
	 ERJMP [MOVE T1,RSBITN(RSB) ;CAN'T DO IT, GET REQUEST #
		TMCT <%ICannot SWITCH - Request %1D Has Tape Drive Open>
		MOVEI T3,TMCMSG
		CALLRET BTACK]	;TELL OPR THE BAD NEWS
	MOVX T1,TM%NUL
	MOVE Q2,RSBUFL(RSB)	;GET CURRENT SETTING OF UNLOAD FLAG
	AND Q2,T1		;EXTRACT TM%NUL FLAG
	ANDCAM T1,RSBUFL(RSB)	;MAKE SURE TAPE GETS UNLOADED
	CALL PLDISA		;DISASSOCIATE MT&MTA IN MY TABLES
	IORM Q2,RSBUFL(RSB)	;RESTORE USER SETTING OF TM%NUL
	LOAD T1,RSBCV		;GET CURRENT VOLUME #
	MOVE T2,Q1		;GET VOLID
	CALL VQSET		;SET NEW VOLID IN USER REQUEST
	 CALL STOP		;VOLID LIST SCREWED UP
	JUMPE MTA,[CALLRET VOLMNT] ;NO MTA SPECIFIED, REQUEST TAPE MOUNT

; TRY TO ASSOCIATE SPECIFIED DRIVE WITH USER REQUEST

	MOVEI T1,RST.WM
	STOR T1,RSBSTE		;SET REQUEST WAITING FOR MOUNT
	EXCH Q1,MTAVOL(MTA)	;SET NEW VOLID
	CALL VRA		;TRY TO ASSOCIATE REQUEST WITH DRIVE
	 SKIPA			;NO GO
	RET			;ASSOCIATION DONE, EXIT
	MOVEM Q1,MTAVOL(MTA)	;RESTORE OLD VOLID
	CALL CHKAB		;REQUEST ABORTED?
	 RET			;YES
	CALLRET VOLMNT		;NO, ASK FOR VOLUME
; KTXCT - IMPLEMENTS EXECUTION OF MTA FUNCTION FOR ONE OR ALL TAPE
;	  DRIVES, ACCORDING TO PRESENCE OF .TAPDV AND .ALTAP BLOCKS
;  T1/ ADDRESS OF COROUTINE TO BE CALLED; COROUTINE RECEIVES MTA
;      STATUS BLOCK ADDRESS IN MTA AC, AND RETURNS +1 ALWAYS
; RETURNS +1: ERROR IN COMMAND MESSAGE
;	  +2: SUCCESS

KTXCT:	SAVEAC <MTA>
	SAVEQ
	MOVE Q2,T1		;SAVE COROUTINE ADDRESS
	MOVEI T1,.ALTAP
	CALL ORNBLF		;LOOKUP ALL-TAPES BLOCK
	 TDZA MTA,MTA		;NOT THERE, CLEAR MTA
	MOVEI MTA,MTA0		;ALL TAPES, POINT AT MTA0 STATUS BLOCK
	MOVEI T1,.TAPDV
	CALL ORNBLF		;LOOKUP SPECIFIC-TAPE-DRIVE BLOCK
	 JRST [	JUMPE MTA,R	;NO TAPE INFO SPECIFIED, BAD MESSAGE
		MOVE Q1,MTAN	;ALL DRIVES, GET # OF DRIVES
		JRST KTXCT1]	;GO DO THEM
	JUMPN MTA,R		;CAN'T HAVE BOTH!
	CALL STMTA		;GET MTA STATUS BLK ADDR FROM STRING
	 RET			;STRING DOESN'T SPECIFY MTA DEVICE
	MOVEI Q1,1		;DOING 1 DRIVE
KTXCT1:	CALL (Q2)		;CALL COROUTINE
	ADDI MTA,MTASZ		;POINT AT NEXT MTA STATUS BLOCK
	SOJG Q1,KTXCT1		;LOOP THRU SPECIFIED # OF DRIVES
	RETSKP
; KUNL - PROCESS UNLOAD COMMAND FROM OPR
; RETURNS +1: ALWAYS

KUNL:	SAVEQ
	SAVEAC <MTA>
	MOVEI T1,.TAPDV
	CALL ORNBLF		;TAPE DRIVE SPECIFIED?
	 JRST KBADM		;NO, REJECT MESSAGE
	JXE F,TALCF,KNALC	;REJECT IF ALLOCATION IS NOT ENABLED
	CALL STMTA		;CONVERT STRING TO MTA STATUS BLK ADDR
	 JRST KBADM		;ERROR, BAD MESSAGE
	MOVE Q1,MTAFLG(MTA)	;GET FLAGS
	CALL KCAVL		;DRIVE AVAILABLE TO USERS?
	 RET			;NO
	JN MTAMT,,[CALL KCUSE	;GIVE ERROR IF A USER HAS THE DRIVE
		 JFCL		;SHOULD ALWAYS RETURN +1
		RET]
	JN MTAJCT,,[SETONE MA%ULP,MTAFLG(MTA) ;IN USE BY ME, SET UNLOAD
		JRST KUNL1]	; PENDING
	CALL UNLOAD		;NOT IN USE BY ME, UNLOAD IT
KUNL1:	TXNN Q1,MA%LOD		;DID I THINK IT WAS LOADED?
	SETZM MTAVOL(MTA)	;NO, SUPPRESS VOLID IN UNLOAD MESSAGE
	CALLRET WOUNL		;TELL OPERATORS IT'S UNLOADED
; KVAC - CHECK IF LEGAL FOR OPERATOR TO CHANGE VOLUME ATTRIBUTES
;  T1/ 0 IF NOT CHANGING VOLID, NON-ZERO IF CHANGING VOLID
;  T2/ 0 IF NOT SETTING SCRATCH, NON-ZERO IF SETTING SCRATCH
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: FUNCTION ILLEGAL, ERRROR MESSAGE SENT TO OPERATOR
;	  +2: FUNCTION IS LEGAL

KVAC:	SAVEQ
	DMOVE Q1,T1		;COPY ARGS TO A SAFE PLACE
	CALL KCAVL		;DRIVE MUST BE AVAILABLE TO USERS
	 RET
	CALL KCLOAD		;DRIVE MUST BE LOADED
	 RET
	CALL KCUSE		;DRIVE MUST NOT BE IN USE
	 RET
	LOAD Q3,MTALT		;GET LABEL TYPE
	JUMPN Q1,[JUMPE Q3,.+1	;VOLID OK IF AVR NOT PERFORMED YET
		CAIN Q3,.LTUNL	;WHAT KIND OF TAPE?
		JRST .+1	;UNLABELED, VOLID OK HERE
		JSP T1,KVAX	;CAN'T SPECIFY VOLID FOR LABELED TAPE
		ASCIZ/Cannot Change Volid Of Labeled Tape/]
	JUMPE Q2,RSKP		;OK IF NOT SETTING SCRATCH
	MOVE T1,MTAFLG(MTA)	;GET FLAGS
	JXN T1,MA%UXV,[JSP T1,KVAX ;CAN'T SCRATCH AN UNEXPIRED VOLUME
		ASCIZ/Cannot Scratch - Volume Is Not Expired/]
	JXE T1,MA%WEN,[JSP T1,KVAX ;CAN'T SCRATCH A WRITE-PROTECTED VOL
		ASCIZ/Cannot Scratch - Drive Is Write-Protected/]
	JUMPE Q3,[JSP T1,KVAX	;CAN'T SCRATCH UNTIL I'VE DONE AVR
		ASCIZ/Cannot Scratch - AVR Not Enabled/]
	RETSKP

; ERROR DETECTED, T1/ ADDR OF ERROR TEXT

KVAX:	TMCT <%I%M %1A>
	MOVEI T3,TMCMSG		;GET ADDRESS OF MESSAGE
	CALLRET BTACK		;SEND ERROR MESSAGE AND RETURN +1
; KVI - SUPPORT VOLUME INITIALIZATION UNDER OPR CONTROL
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RBUF/ "SET TAPE-DRIVE INIT" MESSAGE FROM OPR
; RETURNS +1: ALWAYS

KVI:	JE MA%AVS,MTAFLG(MTA),[LOAD T1,MTADRV
		MOVE T1,DRVTXT(T1)
		TMCT <%ICommand Illegal For %1A Drives>
		MOVEI T3,TMCMSG
		CALLRET BTACK]	;BLAST THE OPERATOR
	CALL KCAVL		;DRIVE IN S.AV STATE?
	 RET			;NO, CAN'T DO THIS
	CALL KCUSE		;DRIVE IN USE?
	 RET			;YES, ERROR
	CALL GORSB		;GET RSB FOR INITIALIZATION
	 RET			;RSB POOL EXHAUSTED, MESSAGE TYPED
	MOVEI T1,.MNTTP
	STOR T1,RSBTYP		;SET RSB TYPE = TAPE-MOUNT
	MOVEI T1,RST.AC
	STOR T1,RSBSTE		;SET RSB ACTIVE
	CALL KVIRSB		;BUILD RSB FROM USER PARAMETERS
	 RET			;ERROR, RSB ABORTED, MESSAGE SENT TO OPR
	MOVEI T1,S.INIT
	STOR T1,MTASTE		;PUT TAPE DRIVE IN PROPER STATE
	MOVEI MT,RSBIMT(RSB)	;GET PSEUDO-MT STATUS BLOCK ADDRESS
	STOR RSB,MTRSB		;LINK MT TO RSB
	STOR MT,RSBMT		;LINK RSB TO MT
	STOR MTA,MTMTA		;LINK MT TO MTA
	STOR MT,MTAMT		;LINK MTA TO MT

; GET VOLID OF VOLUME TO BE INITIALIZED

KVI0:	LOAD T1,RSBLT
	CAIE T1,.LTUNL		;UNLABELED?
	SKIPE RSBIVL(RSB)	;OR DO I KNOW THE VOLID?
	JRST KVI2A		;YES TO EITHER, PROCEED
KVI1:	JSP T1,KVIMR1		;NO, HAVE TO ASK OPERATOR
	MOVEI RSB,-RSBWTB(T2)	;GET RSB ADDRESS
	LOAD MT,RSBMT
	LOAD MTA,MTMTA		;GET MTA STATUS BLOCK ADDR
	CALL PINI		;PARSE RESPONSE
	 JRST KVI1		;ERROR, TRY IT AGAIN JACK
KVI2:	MOVEM T1,RSBIVL(RSB)	;REMEMBER VOLID

; MAKE SURE DRIVE IS READY, DO AVR IF NEEDED

KVI2A:	JN MTAJCT,,R		;WAIT IF AVR OR REWIND IN PROGRESS
	MOVE T1,MTAFLG(MTA)	;GET FLAGS
	JXE T1,MA%LOD,KVIM1	;IF TAPE NOT UP, SAY SO
	TXNE T1,MA%AVE		;WANT TO CHECK IF EXPIRED?
	JRST [	JE MTALT,,[CALLRET AVR] ;YES, DO AVR IF NOT DONE YET
		JXE T1,MA%UXV,.+1 ;AVR DONE, OK IF EXPIRED
		CALL KVIM4	;TELL OPERATOR IT'S NOT EXPIRED
		CALL UNLOAD	;UNLOAD IT
		JRST KVIM1]	;ASK HIM TO DO IT AGAIN
	CALL MTAGJF		;LOCK UP THE DRIVE
	MOVEI T1,KVI2B		;GET REWIND END-ACTION ADDRESS
	CALL REWEA		;REWIND
	 JRST KVI2B		;FAILED, MA%LOD CLEARED
	RET			;EXIT UNTIL REWIND COMPLETES

; REWIND END-ACTION

KVI2B:	CALL MTARJF		;RELEASE LOCK
	LOAD MT,MTAMT
	LOAD RSB,MTRSB		;RESTORE RSB ADDRESS
	JE MA%LOD,MTAFLG(MTA),KVIM1 ;ASK FOR TAPE IF NOT LOADED
; WRITE LABELS TO TAPE

	MOVE T1,RSBIVL(RSB)	;GET VOLID
	MOVEM T1,MTAVOL(MTA)	;STUFF IT FOR LTINIT
	SETONE R%WVL,RSBIFL(RSB) ;REQUEST LTINIT TO WRITE LABELS
	CALL LTINIT		;WRITE LABELS TO TAPE
	 JRST KVIM1		;ERROR, TELL OPERATOR TO MOUNT AGAIN
	CALL KVIM2		;TELL OPERATOR WHAT HAPPENED
	MOVX T1,TM%NUL
	TDNN T1,RSBUFL(RSB)	;UNLOAD REQUESTED?
	CALL UNLOAD		;YES, DO IT

; CHECK IF MORE INITIALIZATIONS LEFT TO DO

	SOSG RSBICT(RSB)	;ANY TAPES LEFT TO DO?
	JRST [	CALL KVICU	;NO, CLEAR INITIALIZE STUFF
		 CALL STOP
		CALLRET KVIDAV]	;GET BACK TO AVAILABLE STATE
	SETZM RSBIVL(RSB)	;YES, CLEAR VOLID
	SKIPN T1,RSBIVI(RSB)	;DOING NUMERIC VOLIDS?
	JRST KVI0		;NO, MUST ASK FOR NEXT VOLID
	ADD T1,RSBIVN(RSB)	;YES, STEP TO NEXT VOLID
	MOVEM T1,RSBIVN(RSB)	;RESTORE NUMERIC VOLID
	CALL INT26L		;Convert to sixbit
	JRST KVI2		;GO GET IT MOUNTED

; KVICU - PROCESS REQUEST TO CANCEL INITIALIZATION SERIES
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: DRIVE BUSY, OPERATOR TOLD ABOUT FAILURE
;	  +2: SUCCESS, TAPE DRIVE INITIALIZE STATE IS CLEARED

KVICU:	SAVEAC <MT,RSB>
	LOAD MT,MTAMT
	LOAD RSB,MTRSB		;GET RSB ADDRESS
	JN MTAJCT,,[JSP T1,KC1	;ERROR IF DRIVE BUSY
		ASCIZ/Busy/]
	SETZRO MTAMT		;CLEAR MTA LINK TO MT
	SETZRO RSBMT		;CLEAR RSB LINK TO MT
	SETZRO MA%LOD,MTAFLG(MTA) ;CLEAR DRIVE-LOADED
	ABTREQ (ABRTNR)		;DUMP THE RSB
	RETSKP

; KVIDAV - EXIT FROM INITIALIZE MODE TO AVAILABLE MODE

KVIDAV:	MOVEI T1,S.AV
	STOR T1,MTASTE		;SET STATE BACK TO AVAILABLE
	CALL AVRENA		;ENABLE AVR IF POSSIBLE
	CALL KVIM3		;TELL OPERATOR THE DRIVE IS AVAIL
	CALLRET TDSC1		;GO CHECK IF DRIVE OCCUPIEDPIPER

; KVITAV - REPORT TAPE DRIVE COMING ONLINE OR AVR COMPLETED
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

KVITAV:	SAVEAC <MT,RSB>
	LOAD MT,MTAMT
	LOAD RSB,MTRSB		;GET RSB ADDRESS
	JE MA%WEN,MTAFLG(MTA),[CALL UNLOAD ;WRITE-PROTECTED
		TMCT <%I%M Write Protected, Unloading Volume>
		MOVEI T3,TMCMSG	;GET ADDRESS OF TEXT
		CALLRET BTWTON]	;TELL OPERATOR THE BAD NEWS
	SKIPE RSBWTB+WTBCOD(RSB) ;WTOR OUTSTANDING?
	RET			;YES, WAIT TILL IT COMES BACK
	JN MA%LOD,MTAFLG(MTA),KVI0 ;IF TAPE IS READY, GET THINGS MOVING
	RET			;OTHERWISE, STILL HAVE TO WAIT

; KVIM1 - TELL OPERATOR TO MOUNT TAPE TO BE INITIALIZED

KVIM1:	TMCT <%IMount tape>
	SKIPE T1,RSBIVL(RSB)	;KNOW VOLID?
	JRST [	TMCT < volume %1S> ;YES
		JRST .+1]
	TMCT < for initialization on %M>
	MOVEI T3,[ASCIZ/Mount Tape To Be Initialized/]
	CALLRET BTWTO		;SEND MESSAGE TO OPERATOR

; KVIM2 - TELL OPERATOR TAPE WAS INITIALIZED SUCCESSFULLY

KVIM2:	TMCT <%I%M>		;DISPLAY DRIVE NAME
	LOAD T1,RSBLT
	CAIN T1,.LTUNL		;UNLABELED TAPE?
	JRST [	TMCT < Unlabeled Tape> ;YES, SAY SO
		JRST .+2]	;DON'T TYPE VOLID
	CALL TMCVOL		;DISPLAY VOLID
	TMCT < Initialized>
	CALL CPYHDR		;COPY HEADER TO A SAFE PLACE
	LOAD T1,RSBLT		;GET LABEL TYPE
	MOVE T1,LTTXT(T1)	;GET POINTER TO TEXT
	LOAD T2,RSBDEN
	MOVE T2,DENTAB(T2)	;GET DENSITY
	TMCT <%ILabel type: %1A%25CDensity: %2D>
	LOAD T1,RSBLT
	CAIE T1,.LTT20		;TOPS-20 TAPE?
	JRST KVIM21		;NO
	TMCT <
Owner: >			;YES, MORE INFO
	SKIPN T2,RSBUNO(RSB)	;GET OWNER USER #
	JRST [	TMCT <Scratch>	;IF ZERO, IT'S A SCRATCH TAPE
		JRST KVIM21]
	TMCT <%2U%23C  Protection: >
	MOVE T1,TMCPTR
	LOAD T2,RSBVPR		;GET PROTECTION CODE
	MOVE T3,[NO%LFL+NO%ZRO+FLD(6,NO%COL)+10]
	NOUT			;INSTALL IT
	 SKIPA
	MOVEM T1,TMCPTR		;RESTORE UPDATED POINTER
	CALL TMC1		;STANDARD TMC CLEANUP
KVIM21:	MOVEI T3,OPRHDR		;GET ADDRESS OF MESSAGE TYPE TEXT
	CALLRET BTWTO		;TELL OPERATORS WHAT HAPPENED

; KVIM3 - TELL OPERATOR DRIVE IS NO LONGER INITIALIZING

KVIM3:	TMCT <%I%M available for user tape requests>
	MOVEI T3,[ASCIZ/INITIALIZE Completed/]
	CALLRET BTWTO

; KVIM4 - TELL OPERATOR TAPE I CAN'T INITIALIZE - TAPE IS NOT EXPIRED

KVIM4:	TMCT <%I>
	CALL TMCVOL		;DISPLAY VOLID
	TMCT < on drive %M is not expired, unloading>
	MOVEI T3,[ASCIZ/Tape Volume Not Expired/]
	CALLRET BTWTO

; KVIMR1 - ISSUE WTOR TO ASK OPERATOR FOR VOLID TO BE INITIALIZED

KVIMR1:	STAKT
	TMCT <%IWhat is the volume-id of the next tape to be
initialized on drive %M ?
Respond with:
  RESPOND n volid>
	MOVE T1,CT1		;GET END-ACTION ADDRESS
	MOVEI T2,RSBWTB(RSB)	;GET WTB ADDRESS
	MOVEI T3,[ASCIZ/Key In Volume Identifier/]
	CALLRET BTWTOR
; KVIRSB - SCAN "SET TAPE INITIALIZE" IPCF MESSAGE FROM OPR AND
;	   BUILD REQUEST STATUS BLOCK
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ERROR DETECTED, OPERATOR NOTIFIED, RSB ABORTED
;	  +2: SUCCESS, INFORMATION STORED IN RSB

KVIRSB:	CALL KGTVOL		;GET VOLID
	 JRST KVIABT		;ERROR, MESSAGE SENT
	MOVEM T1,RSBIVL(RSB)	;STORE VOLID OR 0 IF NONE
	MOVE T1,RSBIVN(RSB)	;Get the integer volume i.d.
	JUMPL T1,KVIR2		;Don't increment if not an integer
	CALL INT26L		;convert to sixbit
	MOVEM T1,RSBIVL(RSB)	;set sixbit volid too
	MOVEI T1,.SIINC		;code for numeric volid increment
	SETZ T2,		;no limit
	MOVEI T3,1		;default = 1
	CALL KGBLK		;lookup increment
	 JRST KVIBM		;error
	MOVEM T1,RSBIVI(RSB)	;store increment
KVIR2:				;
	MOVEI T1,.SILBT		;CODE FOR LABEL TYPE
	MOVEI T2,.LTMAX		;LIMIT
	MOVEI T3,.LTT20		;DEFAULT
	CALL KGBLK		;LOOKUP LABEL TYPE
	 JRST KVIBM		;ERROR
	STOR T1,RSBLT		;STORE LABEL TYPE

	MOVEI T1,.SIDEN		;CODE FOR DENSITY
	MOVEI T2,DENMAX		;LIMIT
	MOVE T3,DEFDEN		;DEFAULT
	CALL KGBLK		;LOOKUP DENSITY
	 JRST KVIBM		;ERROR
	STOR T1,RSBDEN		;STORE DENSITY
	CALL DRVDEN		;CAN THE DRIVE OPERATE AT THIS DENSITY?
	 JRST [	LOAD T1,RSBDEN	;NO
		MOVE T1,DENTAB(T1) ;GET NUMERIC DENSITY
		TMCT <%I%1D BPI Is Not Supported On %M>
		MOVEI T3,TMCMSG	;GET MESSAGE ADDRESS
		CALL BTACK	;SEND ERROR MESSAGE
		JRST KVIABT]	;ABORT REQUEST

	MOVEI T1,.SICTR		;CODE FOR COUNT BLOCK
	HRLOI T2,377777		;LIMIT
	MOVEI T3,1		;DEFAULT
	CALL KGBLK		;LOOKUP COUNT
	 JRST KVIBM		;ERROR
	MOVEM T1,RSBICT(RSB)	;STORE COUNT
	MOVEI T1,.SIHLD		;REQUESTED TO KEEP TAPE ON DRIVE?
	CALL ORNBLF
	 SKIPA			;NO
	JRST [	MOVE T1,RSBICT(RSB) ;YES, GET COUNT
		MOVX T2,TM%NUL
		CAIN T1,1	;INITIALIZING 1 TAPE?
		IORM T2,RSBUFL(RSB) ;YES, OK TO KEEP ON DRIVE
		JRST .+1]

	MOVEI T1,.SIOWN		;CODE FOR OWNER-ID
	SETZB T2,T3		;NO LIMIT, DEFAULT = 0 (SCRATCH)
	CALL KGBLK		;LOOK OWNER-ID
	 JRST KVIBM		;ERROR
	MOVEM T1,RSBUNO(RSB)	;STORE OWNER-ID

	MOVEI T1,.SIPRO		;CODE FOR PROTECTION
	SETZ T2,		;NO LIMIT
	MOVEI T3,DEFPRO		;DEFAULT 
	CALL KGBLK		;LOOKUP PROTECTION
	 JRST KVIBM		;ERROR
	STOR T1,RSBVPR		;STORE PROTECTION

	MOVEI T1,.SIOVR		;OVERRIDE EXPIRATION-DATE CHECK?
	CALL ORNBLF
	 SKIPA T1,[1]		;NO
	SETZ T1,		;YES
	STOR T1,MA%AVE,MTAFLG(MTA) ;STORE OVERRIDE FLAG

	RETSKP

; ERROR CONDITIONS

KVIBM:	CALL BADQM		;ERROR IN IPCF MESSAGE FROM QUASAR
KVIABT:	ABTRET (ABRTNR)		;ABORT RSB AND RETURN +1
; ERROR HANDLERS FOR UNSOLICITED OPERATOR KEYINS ("K" ROUTINES)
; RET IS DONE THROUGH BTACK, GIVING ERROR MESSAGE TO OFFENDING OPR

KBADM:	MOVE T1,RBUF+.MSFLG	;[6011]Get flag
	TXNE T1,MF.NEB		;[6011]Is this from NEBULA?
	CALLRET BADNM		;[6011]Yes
	CALLRET BADQM		;ERROR IN MESSAGE RECEIVED FROM QUASAR


KNXREQ:	MOVEI T2,[ASCIZ/Does Not Exist/]
KACKRQ:	TMCT <%IMount Request %1D %2A> ;T1/ REQ#, T2/ ADDRESS OF TEXT
	MOVEI T3,TMCMSG
	CALLRET BTACK		;SEND IT OFF TO OPERATOR

KBADV:	MOVEI T3,[ASCIZ/Illegal Volume Identifier/]
	CALLRET BTACK

KNALC:	TMCT <%I>		;Clear message buffer 
	MOVEI T3,[ASCIZ/Tape drive allocation is not enabled/]
	CALLRET BTACK

;REJECT IDENTIFY KEYIN TO SCRATCH A TAPE

KNOSCR:	STKVAR <<OWNER,10>>
	TMCT <%ICannot Scratch %M> ;BUILD HEADING WITH DRIVE NAME
	CALL CPYHDR		;SAVE MESSAGE HEADING
	MOVEI T1,OWNER		;OWNER'S NAME GOES HERE
	CALL GETVU		;GET POINTER TO OWNER'S NAME IN T1
	MOVE T2,MTAVOL(MTA)	;GET VOLID
	TMCT <%IVolume %2S owned by user %1A>
	MOVEI T3,OPRHDR		;POINT TO HEADING
	CALLRET BTACKT		;TELL OPERATOR I REJECTED IT
; ORNBCK - CHECK BUILDING BLOCK STRUCTURE OF ORION-STYLE IPCF MESSAGE
;	   IN RBUF (ASSUMES CKGHDR HAS BEEN CALLED)
; RETURNS +1: ERROR IN BLOCK STRUCTURE
;	  +2: BLOCK STRUCTURE OK

ORNBCK:	MOVE T1,RBUF+.OARGC	;GET # OF ARGS
	MOVEI T2,RBUF+.OHDRS	;GET ADDRESS OF 1ST ARG
	LOAD T3,MS.CNT,RBUF+.MSTYP ;GET SIZE OF IPCF MESSAGE FROM HEADER
	SUBI T3,.OHDRS		;COMPUTE SIZE OF BUILDING BLOCK AREA
	CALLRET CKBSTR		;CHECK BLOCK STRUCTURE


; ORNBLF - FIND ARGUMENT BLOCK IN ORION-STYLE IPCF MESSAGE
;  T1/ TYPE CODE OF DESIRED ARGUMENT
; RETURNS +1: NO ARGUMENTS OF REQUESTED TYPE FOUND
;	  +2: SUCCESS, T1/ ADDRESS OF FIRST WORD OF ARGUMENT
;		       T2/ LENGTH OF ARGUMENT (NOT COUNTING HEADER)

ORNBLF:	MOVE T3,T1		;COPY ARG TYPE TO T3 FOR BLKFND
	MOVEI T1,RBUF+.OARGC	;GET ADDRESS OF ARG COUNT WORD
	MOVEI T2,RBUF+.OHDRS	;GET ADDRESS OF 1ST BLOCK
	CALLRET BLKFND		;CALL BLKFND TO DO LOOKUP


; ORNINI - ESTABLISH IPCF RAPPORT WITH ORION
; RETURNS +1: ALWAYS

ORNINI:	STKVAR <TSTFLG>		;FLAG USED ONLY FOR DEBUGGING
	SETOM TSTFLG		;INITIALIZE FLAG
ORNIN1:	MOVEI T1,.SPOPR
	CALL GSYSPD		;GET ORION'S PID FROM SYSTEM PID TABLE
	 JRST [	AOSN TSTFLG	;HAVE WE BEEN HERE BEFORE?
		CALL TSTWAT	;NO, INFORM USER WE ARE WAITING
		MOVEI T1,^D5000	;NOT THERE YET
		DISMS		;WAIT 5 SECONDS
		JRST ORNIN1]	; AND TRY AGAIN
	MOVEM T1,APPID+.APORN	;STUFF PID IN A/P TABLE
	GTAD			;GET FAIRLY UNIQUE VALUE IN RH(T1)
	HRLM T1,UNIQUE		;INSURE CODES UNIQUE TO SYSTEM STARTUP
	RET

; TSTWAT - INFORMS USER WHO WE ARE WAITING FOR IF DEBUGGING
; REQUIRES PONTER TO ASCII PID NAME IN T1
; RETURNS +1: ALWAYS

TSTWAT:	SKIPN TSTF		;ARE WE DEBUGGING
	 RET			;NO
	PUSH P,T1		;SAVE POINTER
	TMSG <% MOUNTR Waiting for >
	POP P,T1		;POINTER TO PID NAME STRING
	PSOUT			;TYPE IT TO TERMINAL
	TMSG <
>
	RET			;RETURN
; ORNMRC - PROCESS INCOMING IPCF MESSAGE FROM ORION
;  RBUF/ INCOMING IPCF MESSAGE
;  MRPDB/ PDB THAT WAS USED TO RECEIVE THE MESSAGE
; RETURNS +1: ALWAYS

ORNMRC:	CALL CKGHDR		;GALAXY HEADER OK?
	 JRST [	CALLRET BADOM]	;NO
	CALL ORNBCK		;BLOCK STRUCTURE OK?
	 JRST [	CALLRET BADOM]	;NO
	LOAD T1,MS.TYP,RBUF+.MSTYP ;GET MESSAGE TYPE
	CAIN T1,.OMRSP		;WHAT TYPE?
	JRST [	CALLRET INWTOR]	;RESPONSE TO WTOR
	CAIN T1,.NRDAK		;[6011]What type?
	JRST [CALLRET PNEDAC]	;[6011]Remote dismount ACK
	LOAD T2,MF.SUF,RBUF+.MSFLG ;GET SIXBIT SUFFIX
	CAIN T1,MT.TXT		;TEXT MESSAGE?
	JRST [	CAIE T2,'NMC'	;CHECK FOR - NO MESSAGE WITH THIS CODE
		CAIN T2,'ODE'	;CHECK FOR - OPR DOESN'T EXIST
		RET		;IGNORE THIS ERROR
		JRST .+1]	;CAN'T HANDLE THIS TEXT MESSAGE
	CALLRET BADOM		;BAD TEXT MESSAGE, REPORT IT
; PINI - PARSE OPERATOR RESPONSE TO REQUEST FOR VOLID TO BE INIT'ED
;  T1/ ADDRESS OF ASCIZ OPERATOR RESPONSE TEXT
; RETURNS +1: ERROR, MESSAGE SENT TO OPERATOR
;	  +2: SUCCESS, T1/ SIXBIT VOLID

PINI:	SAVET			;SETUP TO RETURN VALUE IN T1
	CALL COMNDI
	CALL COMNDV		;PARSE VOLID
	 RET			;FAILED
	MOVEM T1,CT1		;RETURN VOLID TO CALLER
	CALLRET CMDCFM		;GET CONFIRMATION AND RETURN

; PMR - PARSE OPERATOR RESPONSE TO WTOR ASKING FOR VOLID LIST
;  T1/ ADDRESS OF ASCIZ OPERATOR RESPONSE TEXT
;  RSB/ ADDRESS OF REQUEST STATUS BLOCK
; RETURNS +1: ERROR DETECTED WHILE PARSING RESPONSE, OPERATOR NOTIFIED
;	  +2: SUCCESSFUL PARSE
;	      T1/ 0 - RSB AND VOLID LIST SET UP
;	      T1/ 1 - REQUEST ABORTED

PMR:	CALL COMNDI		;INITIALIZE FOR COMND JSYS
	MOVEI T2,[FLDDB.(.CMKEY,,PMRT1)] ;SET UP FOR KEYWORD PARSE
	CALL COMNDX		;ISSUE COMND JSYS TO DO PARSE
	 JRST [	MOVEI T3,[ASCIZ/Syntactical Error In Response/]
		CALLRET BTACK]	;HE BLEW THE KEYWORD
	HRRZ T2,(T2)		;GET ADDRESS OF KEYWORD PROCESSOR
	CALLRET (T2)		;DISPATCH TO KEYWORD PROCESSOR

PMRT1:	PMRT1L,,PMRT1L		;KEYWORD TABLE
	[ASCIZ/REFUSE/],,PMRREF	;REFUSE reason
	[ASCIZ/VOLUMES/],,PMRVOL ;VOLUMES volid,...,volid
PMRT1L==.-PMRT1-1

PMRREF:	CALL PREFUS		;PARSE REFUSAL
	 RET			;OPERATOR ERROR
	ABTREQ (MREQ16,ABT%OP)	;ABORT REQUEST
	MOVEI T1,1		;SET T1 TO INDICATE ABORTION
	RETSKP


; PREFUS - COMPLETE PARSING OF REFUSAL BY OPERATOR
; RETURNS +1: ERROR, OPERATOR NOTIFIED
;	  +2: SUCCESSFUL PARSE, ATMBFR/ ASCIZ REASON GIVEN BY OPERATOR

PREFUS:	MOVEI T2,[FLDDB. .CMTXT] ;PARSE TEXT OUT TO CARRIAGE RETURN
	CALL COMNDX
	 JRST PREFU1		;ERROR
	LDB T1,[POINT 7,ATMBFR,6] ;WAS THERE A REASON GIVEN?
	JUMPN T1,RSKP		;YES, TAKE GOOD RETURN
PREFU1:	JSP T1,RSPERR		;ERROR, TELL OPERATOR
	ASCIZ/No reason given/
; PMRVOL - PARSE VOLID LIST FROM OPERATOR
;  RSB/ ADDRESS OF REQUEST STATUS BLOCK
; RETURNS +1: ERROR, T1/ ADDRESS OF ASCIZ ERROR MESSAGE FOR OPERATOR
;	  +2: T1/ 0 - RSB AND VOLID LIST SET UP
;	      T1/ 1 - REQUEST ABORTED

PMRVOL:	CALL VQDEL		;DELETE VOLID LIST (IF ANY)
	MOVEI T1,1
	STOR T1,RSBCV		;SET CURRENT VOLUME # TO 1
PMRV1:	CALL COMNDV		;PARSE VOLID
	 RET			;FAILED
	CALL VQADD		;ADD VOLUME TO LIST
	 JRST [	MOVEI T1,1	;OUT OF TABLE SPACE
		RETSKP]
	MOVEI T2,[FLDDB.(.CMCMA,,,,,[FLDDB.(.CMCFM)])]
	CALL COMNDX		;PARSE COMMA OR CARRIAGE RETURN
	 JRST [	JSP T1,RSPERR	;PARSE FAILED
		ASCIZ/Syntactical error in volume-id list/]
	HRRZS T3		;GET ADDRESS OF ACTUAL FDB
	LOAD T3,CM%FNC,(T3)	;GET FUNCTION CODE FROM FDB
	CAIN T3,.CMCMA		;WHAT DID I JUST PARSE?
	JRST PMRV1		;COMMA, GO GET ANOTHER VOLID
	SETZ T1,		;CARRIAGE RETURN, CLEAR T1
	RETSKP
; PNVR - PARSE OPERATOR RESPONSE TO "KEYIN NEXT VOLID" WTOR
;  T1/ ADDR OF ASCIZ RESPONSE TEXT
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ERROR, T1/ ADDRESS OF ASCIZ ERROR MESSAGE FOR OPERATOR
;	  +2: T1/ 0 - VOLID ADDED TO RSB VOLID LIST
;	      T1/ 1 - REQUEST ABORTED

PNVR:	CALL COMNDI		;SET UP FOR PARSING WITH COMND
	MOVEI T2,[FLDDB. .CMKEY,,PNVKT] ;GET FDB ADDRESS
	CALL COMNDX		;PARSE KEYWORD
	 JRST [	JSP T1,RSPERR	;ERROR
		ASCIZ/REFUSE or VOLUME keyword missing/]
	HRRZ T2,(T2)		;GET HANDLER ADDRESS
	CALLRET (T2)		;DISPATCH TO HANDLER

PNVKT:	PNVKTL,,PNVKTL		;KEYWORD TABLE
	[ASCIZ/REFUSE/],,PMRREF
	[ASCIZ/VOLUME/],,PNVVOL
PNVKTL==.-PNVKT-1

PNVVOL:	SAVEQ			;OPERATOR RESPONDED WITH A VOLID
	CALL COMNDV		;PARSE VOLID
	 RET			;FAILED
	MOVE Q1,T1		;SAVE VOLID
	CALL CMDCFM		;CHECK FOR EOL
	 RET			;NOT THERE
	MOVE T1,Q1		;GET VOLID
	CALL VQADD		;TACK IT ON TO THE END OF THE LIST
	 JRST [	MOVEI T1,1	;OUT OF TABLE SPACE
		RETSKP]
	SETZ T1,		;SET SUCCESSFUL COMPLETION
	RETSKP
; PSMR - PARSE OPERATOR RESPONSE TO STRUCTURE MOUNT WTOR MESSAGE
;  T1/ ADDRESS OF ASCIZ RESPONSE TEXT
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ERROR DETECTED WHILE PARSING RESPONSE, OPERATOR NOTIFIED
;	  +2: SUCCESSFUL PARSE, REQUEST ABORTED
;	      ATMBFR/ ASCIZ REASON GIVEN BY OPERATOR

PSMR:	CALL COMNDI		;INIIALIZE FOR COMND JSYS
	MOVEI T2,[FLDDB.(.CMKEY,,PSMKT)] ;SET UP FOR KEYWORD PARSE
	CALL COMNDX		;PARSE KEYWORD
	 JRST [	JSP T1,RSPERR	;BAD KEYWORD, GIVE ERROR
		ASCIZ/Response must be of the form:
REFUSE reason/]
	MOVX T2,R%OPR
	TDNE T2,RSBIFL(RSB)	;IS THIS AN OPR REQUEST?
	RETSKP			;YES, FORGET REASON
	CALL PREFUS		;PARSE REMAINDER OF REFUSAL
	 RET			;OPERATOR ERROR
	ABTREQ (MREQ15,ABT%OP)	;OPERATOR REFUSED TO MOUNT VOLUME
	RETSKP

PSMKT:	PSMKTL,,PSMKTL
	[ASCIZ/REFUSE/],,0
PSMKTL==.-PSMKT-1
; RSPERR - TELL OPERATOR THAT THERE WAS AN ERROR IN HIS RESPONSE
;  T1/ ADDRESS OF ASCIZ ERROR MESSAGE
; RETURNS +1: ALWAYS

RSPERR::TMCT <%I%1A>
	MOVEI T3,[ASCIZ/Response Error/] ;GET MESSAGE TYPE
	CALLRET BTACKT		;SEND IT OFF TO THE OPERATOR


; WOASO - TELL OPERATOR A TAPE HAS BEEN GIVEN TO A USER
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

WOASO:	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	TMCT <%I%M Given To Request %1D>
	CALL CPYHDR		;COPY HEADER TO OPRHDR
	TMCT <%I>
	CALL TMCVOL		;DISPLAY VOLID
	TMCT < now in use by%_ %U>
	MOVE T1,RSBIFL(RSB)
	TXNN T1,R%ONR		;WAS OPERATOR TOLD TO MOUNT TAPE?
	CALL BTJOB		;NO, MAKE THIS A JOB MESSAGE
	MOVEI T3,OPRHDR		;POINT TO HEADING
	CALLRET BTWTO		;SHIP IT OFF TO THE OPERATOR


; WOCKSW - IF A SCRATCH VOLUME IS WRITE-PROTECTED, DISMOUNT IT AND
;	   GIVE AN ERROR MESSAGE TO THE OPERATOR
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: WRITE-PROTECTED SCRATCH VOLUME UNLOADED
;	  +2: TAPE WAS NOT A WRITE-PROTECTED SCRATCH

WOCKSW:	MOVE T1,MTAFLG(MTA)	;GET FLAGS
	TXNE T1,MA%SCR		;TAKE +2 IF NOT SCRATCH
	TXNE T1,MA%WEN		;TAKE +2 IF WRITE-ENABLED
	RETSKP
	TMCT <%IUnloading drive %M>
	SKIPE MTAVOL(MTA)	;DO I KNOW ITS VOLID?
	CALL TMCVOL		;YES, THROW IT IN THERE TOO
	TMCT <
Remount scratch tape with write ring>
	MOVEI T3,[ASCIZ/No Ring In Scratch Tape/]
	CALL BTWTO		;TELL OPERATOR
	CALLRET UNLOAD		;UNLOAD THE TAPE


; WODISA - TELL OPERATOR A USER HAS RELEASED A TAPE DRIVE
;  T1/ ADDR OF ASCIZ DISPOSITION TEXT
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

WODISA:	STAKT
	TMCT <%I%M>
	SKIPN MTAVOL(MTA)	;TAPE HAVE A VOLID?
	JRST [	TMCT < Tape>	;NO
		JRST .+2]
	CALL TMCVOL		;DISPLAY VOLID
	MOVE T1,CT1		;GET ADDRESS OF CALLER'S TEXT
	TMCT < %1A>
	CALL BTJOB		;THIS IS A JOB MESSAGE
	MOVEI T3,[ASCIZ/Tape Drive Released By User/]
	CALLRET BTWTO		;SEND IT OFF

; WOUSGF - TELL OPERATOR THAT USAGE JSYS FAILED.
;
; RETURNS +1: ALWAYS

WOUSGF:	TMCT <%IAccount record not written. %U. Reason: %J>
	MOVEI T3,[ASCIZ/MOUNTR System Task Error/]
	CALLRET BTWTO		;OUT TO OPERATOR

; WOLINF - TELL OPERATOR THAT I FAILED TO WRITE LABELS ON A TAPE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

WOLINF:	TMCT <%IError writing labels on %M>
	CALL TMCVOL		;DISPLAY VOLID
	MOVEI T3,[ASCIZ/Tape Error Writing Labels/]
	CALLRET BTWTO		;OUT TO OPERATOR


; WOLOCF - TELL OPERATOR THAT .MOLOC MTOPR FAILED
;  MTA/ ADDR OF MTA STATUS BLOCK
;  MT/ ADDR OF MT STATUS BLOCK
; RETURNS +1: ALWAYS

WOLOCF:	TMCT <%IFailed to associate %M with %N%_Reason: %J>
	MOVEI T3,[ASCIZ/MOUNTR System Task Error/]
	CALLRET BTWTO		;OUT TO OPERATOR


; WOLRDX - TELL OPERATOR I COULDN'T READ ANYTHING FROM THE TAPE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

WOLRDX:	TMCT <%ITape on %M may be labeled at a density that
is not supported by this drive.
Tape has been unloaded.>
	MOVEI T3,[ASCIZ/Cannot Read Tape/]
	CALLRET BTWTO


; WORCAN - TELL OPERATOR A MOUNT REQUEST WAS CANCELED
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

WORCAN:	MOVE T1,RSBIFL(RSB)	;GET FLAGS
	TXNN T1,R%ONR		;DID THE OPERATOR SEE THE MESSAGE?
	RET			;NO, DON'T SAY ANYTHING WAS CANCELED
	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	TMCT <%IMount Request # %1D Canceled>
	MOVEI T3,TMCMSG		;GET ADDRESS OF TEXT
	CALLRET BTWTON		;TELL ALL OPERATORS


; WOTDAV - TELL OPERATOR OF AVAILABILITY OF TAPE DRIVE FOR SYSTEM USE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

WOTDAV:	SAVEQ
	SAVEAC <MT,RSB>
	MOVEI Q1,1		;ASSUME AVAILABLE
	CALL CKMPAV		;IS IT AVAILABLE?
	 SETZ Q1,		;NO, SET NOT AVAILABLE
	TMCT <%I%M set >
	JUMPE Q1,[TMCT <un>
		JRST .+1]
	TMCT <available for assignment by MOUNTR>
	LOAD MT,MTAMT		;MT ASSOCIATED?
	JUMPN MT,[LOAD RSB,MTRSB ;YES, GET RSB ADDRESS
		TMCT <%_%%Drive is currently in use by %U>
		JRST .+1]
	MOVE T3,[[ASCIZ/Tape Drive Set Unavailable/]
		 [ASCIZ/Tape Drive Set Available/]](Q1) ;GET HEADER
	CALLRET BTWTO		;GET MESSAGE OUT TO OPERATOR


; WOTIMO - REPORT MTA DEVICE TIMEOUT TO THE OPERATOR
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

WOTIMO:	TMCT <%I%M operation timed out>
	MOVEI T3,[ASCIZ/Tape Drive Timed Out/]
	CALLRET BTWTO		;TELL THE OPERATOR


; WOTMD - TELL OPERATOR A TAPE HAS BEEN MOUNTED ON A DRIVE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

WOTMD:	MOVX T1,MA%VMG
	TDNE T1,MTAFLG(MTA)	;HAS THE OPERATOR BEEN TOLD ALREADY?
	RET			;YES, NO ACTION THEN
	IORM T1,MTAFLG(MTA)	;NO, SET MESSAGE-GIVEN
	TMCT <%I%M>
	SKIPE MTAVOL(MTA)	;DOES IT HAVE A VOLID?
	JRST [	CALL TMCVOL	;YES, DISPLAY IT
		TMCT <,>
		JRST .+1]
	LOAD T1,MTALT		;GET LABEL TYPE
	JUMPE T1,WOTMD1		;JUMP IF LT NOT KNOWN (AVR DISABLED)
	MOVE T2,LTTXT(T1)	;GET ADDRESS OF TEXT
	TMCT < %2A>		;SPEW OUT LABEL TYPE
	CAIE T1,.LTUNL		;IS IT LABELED?
	CALL [	TMCTR < labeled>] ;YES
WOTMD1:	TMCT < tape mounted>
	MOVEI T3,TMCMSG		;GET ADDRESS OF TEXT
	CALLRET BTWTON		;BUILD AND TRANSMIT WTO MESSAGE


; WOUNL  - TELL OPERATOR THAT A TAPE HAS BEEN UNLOADED
; WOUNLW - SAME AS WOUNL, EXCEPT WARNING MESSAGE IS GIVEN TOO
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

WOUNLW:	SKIPA T1,[BTWTO]	;DISPLAY WARNING
WOUNL:	MOVEI T1,BTWTON		;SUPPRESS WARNING
	STAKT
	TMCT <%I%M>		;DISPLAY DRIVE NAME
	SKIPE MTAVOL(MTA)	;DO I KNOW THE VOLID?
	CALL TMCVOL		;YES, DISPLAY IT
	TMCT < unloaded>
	CALL CPYHDR		;COPY HEADER TO OPRHDR
	TMCT <%I%%Use the DISMOUNT TAPE command to unload tape drives>
	MOVEI T3,OPRHDR		;GET ADDRESS OF HEADER
	MOVE T1,CT1		;GET ADDRESS OF ROUTINE TO CALL
	CALLRET (T1)		;OUT TO OPERATOR AND RETURN
; WOVMT - TELL OPERATOR A TAPE VOLUME MUST BE MOUNTED
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

WOVMT:	SAVEQ
	SAVEAC <MTA>
; IN THE EVENT THAT A USER IS REQUESTING A SPECIFIC VOLUME AND
; THAT VOLUME IS UNDERGOING AVR ON A TAPE DRIVE, WE WANT TO
; INHIBIT SENDING THE WTO TO REQUEST THE TAPE UNTIL THE AVR
; SEQUENCE COMPLETES.  THIS CODE CHECKS FOR THIS CONDITION.

	LOAD T1,RSBSTE		;GET REQUEST STATE
	MOVE T2,RSBIFL(RSB)	;GET FLAGS
	CAIN T1,RST.WM		;WAITING FOR MOUNT
	TXNE T2,R%ONR		; AND OPERATOR NOT TOLD YET?
	RET			;NOT BOTH, DON'T DO ANYTHING
	CALL VQGCV		;GET CURRENT VOLID
	JUMPE T1,WOV2		;SCRATCH
	MOVE T2,MTAN		;GET # OF MTA'S TO SCAN
	MOVEI MTA,MTA0-MTASZ	;START HERE
WOV1:	ADDI MTA,MTASZ		;POINT AT NEXT MTA
	SOJL T2,WOV2		;NONE LEFT, SEND MESSAGE
	LOAD T3,MTASTE		;GET DRIVE STATE
	CAIE T3,S.AV		;AVAILABLE TO USERS?
	JRST WOV1		;NO, SKIP IT
	JE MTAJCT,,WOV1		;SKIP IF AVR NOT IN PROGRESS
	CAMN T1,MTAVOL(MTA)	;DRIVE & REQUEST VOLIDS MATCH?
	RET			;YES, MESSAGE SUPPRESSED
	JRST WOV1		;NO, CONTINUE DRIVE SCAN

; MUST TELL THE OPERATOR TO MOUNT THE TAPE, START BUILDING MESSAGE

WOV2:	SETONE R%ONR,RSBIFL(RSB) ;SET OPERATOR-NOTIFIED
	CALL WTOCHK		;IS  WTO DISABLED
	RET			;YES
	MOVE T1,RSBITN(RSB)	;GET REQUEST #
	TMCT <%ITape Mount Request # %1D>
	CALL CPYHDR		;COPY HEADER TO OPRHDR

; BUILD THE BODY OF THE MESSAGE

	TMCT <%IMount >
	CALL TRESCK		;Are any tape drives set to available
	CALL [ TMCT <%INote: All tape drives are set unavailable
Mount >				;No, include in the mount request message
	       RET ]		;Return to in stream
	CALL VQGCV		;GET VOLID IN T1
	MOVE Q1,T1		;COPY VOLID TO SAFE PLACE
	LOAD T2,RSBLT		;LABEL TYPE KNOWN?
	JUMPN T2,[MOVEI T1,[ASCIZ/Labeled/] ;YES
		CAIE T2,.LTUNL
		SKIPE Q1
		MOVE T1,LTTXT(T2) ;UNLABELED OR NOT SCRATCH
		MOVX T2,TM%BYP
		TDNE T2,RSBUFL(RSB) ;BYPASS?
		MOVEI T1,[ASCIZ/BYPASS/] ;YES, SAY SO
		TMCT <%1A >	;DISPLAY LABEL TYPE
		JRST .+1]
	JUMPE Q1,[TMCT <scratch tape> ;SCRATCH TAPE, SAY SO
		JRST .+1]
	JUMPN Q1,[TMCT <volume %5S> ;DISPLAY SPECIFIC VOLUME
		JRST .+1]
	LOAD Q1,RSBDRV		;DRIVE TYPE KNOWN?
	JUMPN Q1,[MOVE T1,DRVTXT(Q1) ;GET POINTER TO DRIVE TEXT
		TMCT <, %1A>	;DISPLAY DRIVE TYPE
		JRST .+1]
	LOAD Q1,RSBDEN		;DENSITY KNOWN?
	JUMPN Q1,[MOVE T1,DENTAB(Q1) ;YES, GET DENSITY
		TMCT <, %1D BPI>
		JRST .+1]
	MOVEI T1,[ASCIZ/, READ-ONLY/] ;ASSUME READ-ONLY
	MOVX T2,TM%WEN
	TDNE T2,RSBUFL(RSB)
	MOVEI T1,[ASCIZ/, WRITE-ENABLED/]
	TMCT <%1A%_%U>
	JE R%ONV,RSBIFL(RSB),[SETONE R%ONV,RSBIFL(RSB)
		CALL VQCNT	;MORE THAN 1 VOLID IN SET?
		SOJLE T1,.+1	;NO
		MOVE T1,RSBSSN(RSB) ;GET SETNAME
		TMCT <
Volumes in set %1S: >
		CALL TMCVLS	;DISPLAY VOLID LIST
		JRST .+1]
	SKIPE RSBRMK(RSB)	;DID THE USER SUPPLY A REMARK?
	JRST [	MOVEI T1,RSBRMK(RSB) ;YES, GET ADDR OF REMARK
		TMCT <%_User's remark: %1A>
		JRST .+1]
	MOVEI T3,OPRHDR		;GET ADDRESS OF HEADING
	CALLRET BTWTO		;SEND WTO OFF TO THE OPERATOR


; WOWDDR - REQUEST REMOUNT OF TAPE - DRIVE COULDN'T HANDLE DENSITY
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

WOWDDR:	TMCT <%I%M>
	CALL TMCVOL		;DISPLAY VOLID
	MOVE T1,MTAVOL(MTA)	;GET VOLID
	LOAD T2,RSBDEN
	MOVE T2,DENTAB(T2)	;GET NUMERIC DENSITY
	TMCT < being unloaded
Remount volume %1S on %2D BPI drive>
	MOVEI T3,[ASCIZ/Remount Tape Volume/]
	CALLRET BTWTO


; WOWPE - TELL OPERATOR THAT WRITE RING SHOULD BE INSERTED OR REMOVED
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

WOWPE:	TMCT <%I%M>
	CALL TMCVOL		;DISPLAY VOLID
	LOAD T1,MA%WEN,MTAFLG(MTA) ;GET CURRENT WRITE STATUS
	MOVE T1,[[ASCIZ/Insert/]
		 [ASCIZ/Remove/]](T1) ;GET WHAT TO DO
	TMCT <%_%1A write ring and remount tape>
	MOVEI T3,[ASCIZ/Tape Write Protect Error/]
	CALLRET BTWTO		;OUT TO OPERATOR


; WRNXTV - ASK OPERATOR FOR NEXT VOLUME OF VOLUME SET
;  T1/ ADDR OF RESPONSE HANDLER THAT WILL BE CALLED BY INWTOR
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

WRNXTV:	MOVE T2,RSBSSN(RSB)
	TMCT <%ISupply next volume-id for tape set %2S%_%U
Respond with either of:
  VOLUME volid
  REFUSE reason>
	SKIPE RSBRMK(RSB)	;DID THE USER SUPPLY A REMARK?
	JRST [	MOVEI T2,RSBRMK(RSB) ;YES, GET ADDR OF REMARK
		TMCT <%_User's remark: %2A>
		JRST .+1]
	MOVEI T2,RSBWTB(RSB)	;GET WTB ADDRESS
	MOVEI T3,[ASCIZ/Key In Next Volume Identifier/]
	CALLRET BTWTOR		;SEND IT OFF


; WRUTR - TELL OPERATOR THAT A USER TAPE MOUNT REQUEST HAS BEEN
;	   RECEIVED AND ASK HIM TO KEY IN VOLID LIST
;  T1/ ADDRESS OF RESPONSE HANDLER THAT WILL BE CALLED BY INWTOR
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

WRUTR:	MOVE T2,RSBSSN(RSB)
	TMCT <%IVolume set %2S, %U
Respond with either of:
  RESPOND n VOLUMES volid,volid,...
  RESPOND n REFUSE reason>
	SKIPE RSBRMK(RSB)	;DID THE USER SUPPLY A REMARK?
	JRST [	MOVEI T2,RSBRMK(RSB) ;YES, GET ADDR OF REMARK
		TMCT <%_User's remark: %2A>
		JRST .+1]
	MOVEI T2,RSBWTB(RSB)	;WTB ADDRESS
	MOVEI T3,[ASCIZ/Tape Set Request/] ;MESSAGE TYPE
	CALLRET BTWTOR		;SEND OFF WTOR
; TEXT MESSAGE COMPOSITION (TMC) SUBROUTINES
; ALL TMC SUBROUTINES RETURN +1 ALWAYS

TMC1:	MOVE T1,TMCPTR		;GET BUFFER POINTER
	SETZ T2,
	IDPB T2,T1		;PUT A NULL AT THE END OF THE BUFFER
	SUBI T1,TMCMSG-1	;COMPUTE BUFFER SIZE IN WORDS
	HRRZM T1,TMCWDS		;STORE IT FOR CALLING ROUTINES

; CHECK FOR END OF BUFFER

	HRRZ T1,T1		;Size of the current message
	CAIGE T1,ENDBUF		;Space for another line?
	RET			;Yes
	MOVE T1,[POINT 7,[ASCIZ/
Message Truncated - Buffer Space Exhausted
/]]
TMCLP:	ILDB T2,T1		;Pick up the next character of message
	IDPB T2,TMCPTR		;Place into the TMCMSG buffer
	SKIPE T2		;End of the ASCIZ string?
	JRST TMCLP		;No, go pick up the next character
	SETOM BUFLFT		;Set flag to indicate exhausted buffer
	MOVE T1,TMCPTR		;Get address of the end of the message
	SUBI T1,TMCMSG-1	;Calculate the message size
	HRRZM T1,TMCWDS		;Store it for calling routines
	RET

; TMCRSP - SPECIAL VERSION OF TMCASZ FOR INCOMING WTOR RESPONSES
;  T1/ 0 ,, ADDRESS OF ASCIZ WTOR RESPONSE

TMCRSP:	HRLI T1,(POINT 7)	;CONSTRUCT BYTE POINTER
TMCRS1:	ILDB T2,T1		;GET A BYTE FROM RESPONSE TEXT
	JUMPE T2,[TMCTR <%_>]	;END, APPEND CRLF AND RETURN
	CAIN T2,"F"-100
	JRST TMCRS1		;DON'T COPY CTRL/F
	CAIN T2,.CHESC
	JRST TMCRS1		;DON'T COPY ESCAPE
	CAIN T2,"?"
	JRST TMCRS1		;DON'T COPY QUESTION MARK
	CAIN T2,.CHCRT
	JRST TMCRS1		;DON'T COPY CARRIAGE RETURN
	CAIN T2,.CHLFD
	MOVEI T2," "		;CHANGE LINE FEED TO BLANK
	IDPB T2,TMCPTR		;PUT CHARACTER IN TMCMSG
	JRST TMCRS1		;LOOP UNTIL NULL

; CPYHDR - COPY CONTENTS OF TMCMSG TO OPRHDR

CPYHDR:	MOVE T1,[TMCMSG,,OPRHDR] ;BLT SOURCE,,DESTINATION
	BLT T1,OPRHDR+OPRHSZ-1
	RET


; TMCVOL - DISPLAY THE TEXT " Volume " FOLLOWED BY THE MTA VOLID
;  MTA/ ADDR OF MTA STATUS BLOCK

TMCVOL:	SKIPN T1,MTAVOL(MTA)	;GET VOLID
	JRST [	TMCTR < scratch tape>] ;ZERO, THEREFORE SCRATCH
	TMCTR < Volume %1S>	;DISPLAY AND RETURN


; TMCVLS - DISPLAY THE VOLUME-ID LIST FOR A GIVEN USER REQUEST
;  RSB/ ADDR OF REQUEST STATUS BLOCK

TMCVLS:	SAVEQ
	QSCANI <RSBVLS(RSB)>	;SET UP TO SCAN VOLID LIST
	SETO Q1,		;INIT COUNTER
TMCVL1:	CALL QMSCAN		;GET ADDRESS OF NEXT VOLID ENTRY IN T2
	 RET			;NONE LEFT, SPLIT
	AOJG Q1,[TMCT <, >	;SEPARATE VOLIDS WITH COMMAS
		JRST .+1]
	SKIPN T1,1(T2)		;GET SIXBIT VOLID
	JRST [	TMCT <scratch>	;HE'S DEAD, JIM
		JRST TMCVL1]
	TMCT <%1S>		;VOLID IS KNOWN
	JRST TMCVL1		;LOOP UNTIL ALL VOLIDS ARE DISPLAYED
; DRIVER FOR TMCT AND TMCTR MACROS
;  CX/ ADDRESS OF FORMATTING STRING

TMCT0:: HRL  CX,BUFLFT		;Load end of buffer flag
	SKIPGE CX		;Any space left in TMCMSG?
	RET			;No
	HRLI CX,(POINT 7)	;MAKE BYTE POINTER TO SOURCE STRING
	MOVEM CX,TMCTSP		;SAVE POINTER
	SAVET			;ALL AC'S PRESERVED (EXCEPT 15,16)
	TRVAR <TMCTAR,<TMCTAC,4>>
	DMOVEM T1,TMCTAC	;SAVE T1-T4
	DMOVEM T3,2+TMCTAC
TMCT1:	ILDB T1,TMCTSP		;GET NEXT CHARACTER FROM STRING
	JUMPE T1,TMC1		;END OF STRING
	CAIE T1,"%"		;TRIGGER CHARACTER?
	JRST [	IDPB T1,TMCPTR	;NO, JUST COPY IT
		JRST TMCT1]	;LOOP THRU STRING
	TXZ F,ARGF		;SAY NO ARGUMENT (YET)
	SETZM TMCTAR		;ZERO ARGUMENT ACCUMULATOR
TMCT2:	ILDB T1,TMCTSP		;GET NEXT CHARACTER
	CAIG T1,"9"		;NUMERIC?
	CAIGE T1,"0"
	JRST TMCT3		;NO
	SUBI T1,"0"		;YES, CONVERT ASCII TO INTEGER
	MOVE T2,TMCTAR		;GET CURRENT ACCUMULATOR
	IMULI T2,12		;DECIMAL SHIFT
	ADD T2,T1		;ADD IN NEXT DIGIT
	MOVEM T2,TMCTAR		;STORE UPDATED ACCUMULATOR
	TXO F,ARGF		;SET ARG-SEEN
	JRST TMCT2		;CONTINUE ARGUMENT SCAN

TMCT3:	MOVSI T2,-TMCDTL	;GET AOBJN POINTER TO DISPATCH TABLE
TMCT4:	HLRZ T3,TMCDT(T2)	;GET CHARACTER FROM DISPATCH TABLE
	CAME T1,T3		;MATCH FUNCTION CHARACTER?
	JRST [	AOBJN T2,TMCT4	;NO, CONTINUE SCAN
		JRST TMC1]	;NO MATCH??? ERROR IN FORMAT STRING
	HRRZ T1,TMCDT(T2)	;FOUND IT, GET ROUTINE ADDRESS
	CALL (T1)		;CALL HANDLER
	MOVE T1,TMCPTR		;GET BUFFER POINTER
	SETZ T2,
	IDPB T2,T1		;PUT A NULL AT THE END OF TEXT
	SUBI T1,TMCMSG-1	;COMPUTE TEXT SIZE IN WORDS
	HRRZM T1,TMCWDS		;STORE IT FOR CALLERS
	JRST TMCT1		;FUNCTION DONE, CONTINUE STRING SCAN
; TMCT DISPATCH TABLE

TMCDT:	"A",,%A		;ASCIZ STRING, ARG = AC CONTAINING ADDRESS
	"C",,%C		;ADVANCE TO COLUMN, ARG = COLUMN#
	"D",,%D		;DECIMAL #, ARG = AC CONTAINING #
	"I",,%I		;INITIALIZE TMC FORMATTED STRING
	"J",,%J		;JSYS ERROR MESSAGE, ARG = AC CONT. ERROR CODE
			;NO ARG MEANS USE MOST RECENT MOUNTR ERROR
	"K",,%K		;TYPE DRIVE NUMBERS, ARG = CKU NUMBER
	"M",,%M		;DISPLAY "MTAn:" (NEEDS MTA AC)
	"N",,%N		;DISPLAY "MTn:" (NEEDS MT AC)
	"O",,%O		;OCTAL NUMBER, ARG = AC CONTAINING #
	"S",,%S		;SIXBIT, ARG = AC CONTAINING SIXBIT VALUE
	"U",,%U		;USER NAME, ARG = AC CONTAINING USER#
			;NO ARG MEANS DO NAME/JOB/LINE FOR CURRENT RSB
	"V",,%V		;DEVICE NAME, ARG = AC CONTAINING DESIGNATOR
	"Y",,%Y		;ARG = AC CONTAINING NON-0 FOR Yes OR 0 FOR No
	"%",,%%		;PERCENT SIGN
	"_",,%CRLF	;CRLF
TMCDTL==.-TMCDT		;NUMBER OF ENTRIES IN TABLE
GETREG:	JXE F,ARGF,[ADJSP P,-1	;IF NO ARG PRESENT
		RET]		;RETURN TO CALLER'S CALLER
	MOVE T1,TMCTAR		;GET ARGUMENT
	CAIG T1,T4		;IN T1-T4?
	ADDI T1,-1+TMCTAC	;YES, ADD OFFSET TO STORED AC'S
	MOVE T1,(T1)		;GET CONTENTS OF REGISTER
	RET

;Returns - +1 always 
;	   T2/The current location of the message
;	   This routine clobbers T2

TMCNT:	SAVEQ

	MOVE Q1,[POINT 7,TMCMSG] ;GET POINTER TO EXISTING MESSAGE
TMCNT1:	SETZ T2,		;# OF CHARACTERS SINCE LAST LINEFEED
TMCNT2:	ILDB Q2,Q1		;GET NEXT CHARACTER FROM MESSAGE
	CAIN Q2,.CHLFD		;IS IT A LINEFEED?
	JRST TMCNT1		;YES, RESET COUNTER AND CONTINUE SCAN
	SKIPE Q2		;END OF STRING?
	AOJA T2,TMCNT2		;NO, COUNT CHARACTER AND LOOP
	RET
%CRLF:	SKIPA T1,[[ASCIZ/
/]]
%A:	CALL GETREG		;GET ADDRESS OF TEXT
%A0:	HRLI T1,(POINT 7)	;MAKE STRING POINTER
%A1:	ILDB T2,T1		;GET NEXT CHARACTER FROM STRING
	JUMPE T2,R		;EXIT IF END OF STRING
	IDPB T2,TMCPTR		;COPY CHARACTER TO OUTPUT STRING
	JRST %A1		;LOOP THRU INPUT

%C:	CALL TMCNT		;Get the current location of pointer to msg
	MOVE T1,TMCTAR		;GET DESIRED COLUMN POSITION
	SUB T1,T2		;GET # OF SPACES PLUS 1
	MOVEI T2," "		;GET SPACE
TMCC3:	SOJLE T1,TMC1		;EXIT IF NO MORE SPACES NEEDED
	IDPB T2,TMCPTR		;INSERT A SPACE
	JRST TMCC3		;LOOP UNTIL POSITION IS REACHED

%D:	CALL GETREG		;GET NUMBER
	MOVEI T3,12		;BASE 10
	JRST %DO		;MERGE
%O:	CALL GETREG		;GET NUMBER
	MOVEI T3,10		;BASE 8
%DO:	MOVE T2,T1		;# TO T2 FOR NOUT
	MOVE T1,TMCPTR		;GET DESTINATION STRING POINTER
	NOUT			;OUTPUT NUMBER
	 SKIPA
	MOVEM T1,TMCPTR		;STORE UPDATED POINTER
	RET

%I:	MOVE T1,[POINT 7,TMCMSG] ;GET PTR TO TEXT STRING
	MOVEM T1,TMCPTR		;INITIALIZE IT
	RET

%J:	MOVEI T1,-1		;ASSUME NO ARGUMENT
	TXNE F,ARGF		;ARG PRESENT?
	CALL GETREG		;YES, GET ERROR CODE FROM AC
	MOVE T2,T1		;CODE TO T2 FOR ERSTR
	HRLI T2,.FHSLF		;FORK HANDLE ,, ERROR CODE
	MOVE T1,TMCPTR		;DESTINATION STRING POINTER
	SETZ T3,		;NO LIMIT ON LENGTH
	ERSTR			;GET ERROR STRING
	 JFCL
	 JFCL
	MOVEM T1,TMCPTR		;STORE UPDATED POINTER
	RET

%K:	CALL GETREG		;READ ARGUMENT
	MOVE T4,T1		;REMEMBER IT
	MOVE T1,TMCPTR		;GET BYTE POINTER
	HRROI T2,[ASCIZ/Channel /]	;TEXT
	SETZ T3,		;ALL OF IT
	SOUT			;TYPE IT
	LOAD T2,DOP%C2,T4	;GET CHANNEL
	MOVEI T3,^D10		;Decimal
	NOUT			;TYPE IT
	 JFCL
	TXC T4,DOP%K2		;GET READY
	TXCN T4,DOP%K2		;ANY CONTROLLER TO TYPE?
	JRST %K2		;NO, SKIP ON
	HRROI T2,[ASCIZ/ Controller /]	;YES
	SETZ T3,		;ASCIZ
	SOUT			;TYPE THIS
	LOAD T2,DOP%K2,T4	;GET CONTROLLER NUMBER
	MOVEI T3,^D10		;Decimal
	NOUT			;TYPE IT
	 JFCL
%K2:	HRROI T2,[ASCIZ/ Drive /]	;MORE TEXT
	SETZ T3,		;ASCIZ
	SOUT			;TYPE IT
	LOAD T2,DOP%U2,T4	;GET DRIVE NUMBER
	MOVEI T3,^D10		;Decimal AGAIN
	NOUT			;TYPE IT
	 JFCL
	MOVEM T1,TMCPTR		;REMEMBER NEW POINTER
	RET			;DONE


%M:	CALL GMTADD		;GET MTA DEVICE DESIGNATOR
	SKIPA
%N:	CALL GMTDD		;GET MT DEVICE DESIGNATOR
%V1:	MOVE T2,T1		;DESIGNATOR TO T2 FOR DEVST
	MOVE T1,TMCPTR		;GET DEST STRG PTR
	DEVST			;GET DEVICE NAME
	 CALL STOP
	MOVEM T1,TMCPTR		;STORE UPDATED POINTER
	MOVEI T1,":"
	IDPB T1,TMCPTR		;PUT A COLON AT THE END
	RET

%S:	CALL GETREG		;GET SIXBIT QUANTITY
%S1:	SETZ T2,		;CLEAR T2 FOR SHIFT
	ROTC T1,6		;GET NEXT CHARACTER IN T2
	ADDI T2,40		;CONVERT TO ASCII
	IDPB T2,TMCPTR		;STORE IT
	JUMPN T1,%S1		;LOOP IF MORE NON-BLANKS REMAINING
	RET

%U:	JXE F,ARGF,%UNA		;JUMP IF NO ARGUMENT
	CALL GETREG		;GET USER#
	MOVE T2,T1		;USER# TO T2 FOR DIRST
	MOVE T1,TMCPTR		;GET DEST POINTER
	DIRST			;GET USER NAME
	 SKIPA
	MOVEM T1,TMCPTR		;STORE UPDATED POINTER
	RET

%UNA:	PUSH P,TMCTSP		;SAVE CURRENT INPUT POINTER
	TMCT <User>
	CAIN RSB,MTNAV		;RSB AVAILABLE?
	JRST %U1		;NO, THAT'S ALL
	LOAD T1,RSBJNO		;GET JOB #
	MOVE T2,RSBUNO(RSB)	;GET USER #
	TMCT < %2U, Job %1D>
	MOVSS T1		;MOVE JOB # TO LEFT HALF
	HRRI T1,.JOBTT		;GET TABLE # IN RIGHT HALF
	GETAB			;GET LINE # FROM JOBTTY TABLE
	 CALL STOP
	HLRES T1		;DETACHED?
	JUMPE T1,%U1		;IF ZERO, USER PROBABLY LOGGED OUT
	JUMPL T1,[TMCT <, DETACHED> ;IF DETACHED, SAY SO
		JRST %U1]
	TMCT <, Terminal %1O>	;SHOW LINE # AND RETURN
%U1:	MOVEI T2,RSBACT(RSB)	;Get address of account string in mount request
	MOVX T1,R%OPR		;Check for OPR request
	TDNN T1,RSBIFL(RSB)	;Skip if OPR request
	TMCT <, Account %2A>	;Indicate the account string
	POP P,TMCTSP		;RESTORE PREVIOUS STRING POINTER
	RET

%V:	CALL GETREG		;GET DESIGNATOR IN T1
	JRST %V1		;GO DISPLAY IT

%Y:	CALL GETREG		;GET ARG IN T1
	JUMPN T1,[JSP T1,%A0	;NON-ZERO, SAY YES
		ASCIZ/Yes/]
	JSP T1,%A0		;ZERO, SAY NO
	ASCIZ/No/

%%:	MOVEI T1,"%"
	IDPB T1,TMCPTR		;STORE PERCENT CHARACTER
	RET
SUBTTL QUASAR INTERFACE

; GETRSB - ALLOCATE A REQUEST STATUS BLOCK
; RETURNS +1: RSB ALLOCATED, BUT IT'S THE LAST ONE
;	  +2: RSB ALLOCATED, MORE FREE RSB'S LEFT
;  RSB/ ADDR OF REQUEST STATUS BLOCK

GETRSB:	MOVEI T1,IRBQDB		;POINT TO INACTIVE RSB QUEUE
	CALL QMDQH		;DEQUEUE HEAD OF QUEUE
	 CALL STOP		;QUEUE EMPTY, PROGRAM LOGIC ERROR
	MOVEI RSB,-RSBLNK(T2)	;LOAD UP RSB AC
	MOVS T1,RSB		;BLT SOURCE
	HRRI T1,1(RSB)		;BLT DESTINATION
	SETZM (RSB)		;CLEAR 1ST WORD OF RSB
	BLT T1,RSBSIZ-1(RSB)	;CLEAR THE REST OF THE RSB
	MOVEI T2,RSBLNK(RSB)	;GET ADDRESS OF RSB LINKAGE WORD
	MOVEI T1,ARBQDB
	CALL QMQT		;QUEUE TO TAIL OF ACTIVE QUEUE
	SKIPN IRBQDB		;WAS THIS THE LAST FREE RSB?
	RET			;YES, RETURN +1
	RETSKP


; GETRSI - INITIALIZE FREE RSB POOL FOR GETRSB
; RETURNS +1: ALWAYS

GETRSI:	SAVEQ
	MOVEI Q1,RSB0		;GET ADDRESS OF RSB POOL
	MOVEI Q2,MAXMRQ+1	;# OF RSBS IN POOL
GTRSI1:	MOVEI T1,IRBQDB		;GET QDB ADDRESS
	MOVEI T2,RSBLNK(Q1)	;GET ADDRESS OF RSB LINKAGE
	CALL QMQT		;QUEUE RSB TO TAIL OF FREE QUEUE
	ADDI Q1,RSBSIZ		;POINT Q1 AT NEXT RSB
	SOJG Q2,GTRSI1		;LOOP THRU ALL RSBS
	RET

; GORSB - GET RSB FOR FUNCTION REQUESTED VIA OPR COMMAND
;  T1/ REQUEST TYPE CODE
; RETURNS +1: RSB POOL EMPTY, ACK MESSAGE SENT TO OPERATOR
;	  +2: SUCCESS, RSB/ ADDR OF REQUEST STATUS BLOCK

GORSB:	STAKT
	CALL GETRSB		;TRY TO ASSIGN RSB
	 TDZA T4,T4		;SET SHORTAGE FLAG
	MOVEI T4,1		;SET NO SHORTAGE
	MOVE T1,CT1
	STOR T1,RSBTYP		;SET TYPE IN RSB
	MOVX T1,R%OPR+R%PRIV	;SET FROM-OPERATOR AND PRIVILEGED
	IORM T1,RSBIFL(RSB)
	JUMPN T4,RSKP		;TAKE +2 IF NO FREESPACE SHORTAGE
	ABTREQ (ABRTNR)		;SHORTAGE, ABORT REQUEST
	CALL PRQABT		;PUT RSB BACK ON INACTIVE QUEUE
	MOVEI T3,[ASCIZ/Space exhausted, try later/]
	CALLRET BTACK		;TELL OPERATOR ABOUT BUMMER
; MATR - PROCESS USER REQUEST FOR ATTRIBUTES OF MOUNTED DEVICE
;	 (CURRENTLY VALID ONLY FOR TAPES)
;  RBUF/ ATTRIBUTE-REQUEST MESSAGE
;  T1/ SIZE OF MESSAGE (WORDS)
; RETURNS +1: ALWAYS

MATR:	SAVEQ
	SAVEAC <MT,RSB>
	CAIE T1,.MATQS		;CHECK SIZE
	JRST [	CALLRET BADQM]	;NOT WHAT IT SHOULD BE
	MOVE T1,RBUF+.MATDV	;GET DEVICE DESIGNATOR
	CALL DDMT		;GET MT STATUS BLOCK ADDRESS
	 TDZA RSB,RSB		;BAD MT DEVICE, FORCE ERROR RETURN
	LOAD RSB,MTRSB		;GET RSB ADDRESS
	SKIPE RSB
	CAIN RSB,MTNAV
	JRST [	TMCT <%IInvalid device> ;BAD MT OR NO REQ ASSOCIATED
		MOVE T1,RBUF+.MATPD ;GET USER'S PID
		MOVX T2,MF.FAT	;GET FATAL-ERROR FLAG
		MOVE T3,RBUF+.MSCOD ;GET USER'S ACK CODE
		CALLRET TXTMSG]	;RESPOND TO USER WITH GLX TEXT MESSAGE

; CONSTRUCT RESPONSE, BUILDING-BLOCK STYLE

	CALL PBINIT		;INITIALIZE BUILDING-BLOCK STRUCTURE
	MOVE Q1,[2,,.MATDD]	;CONSTRUCT DEVICE-DESIGNATOR BLOCK
	MOVE Q2,RBUF+.MATDV
	MOVEI T1,Q1		;GET ADDR OF SOURCE BLOCK
	CALL PBBLK		;INSTALL IT
	HRRI Q1,.TMSET		;GET SIZE AND TYPE FOR SETNAME
	MOVE Q2,RSBSSN(RSB)	;GET SETNAME
	MOVEI T1,Q1		;GET ADDR OF SOURCE BLOCK
	CALL PBBLK		;INSTALL IT
	CALL VQCNT		;GET # OF VOLIDS
	MOVSI Q1,1(T1)		;BLOCK LENGTH = # OF VOLIDS + 1
	HRRI Q1,.TMVOL		;GET BLOCK TYPE
	MOVEI T1,Q1		;GET ADDR OF SOURCE BLOCK
	HRRZ Q2,PBBPT		;GET ADDRESS OF DESTINATION BLK HEADER
	CALL PBBLK		;INSTALL IT
	HLRZS Q1		;GET # OF VOLIDS + 1
MATR3:	SOJG Q1,[AOBJN Q2,	;BUMP INDICES (NEVER JUMPS)
		HLRZ T1,Q2	;GET VOLID INDEX
		CALL VQGET	;GET VOLID
		 JFCL		;SHOULD NEVER FAIL
		MOVEM T1,(Q2)	;STORE VOLID INTO MESSAGE
		JRST MATR3]	;LOOP THRU ALL VOLIDS
	MOVE T1,PBBPT		;MESSAGE IS COMPLETE, GET HIGH ADDRESS
	SUBI T1,TBUF		;COMPUTE LENGTH OF MESSAGE
	MOVSS T1		;TO LEFT HALF
	HRRI T1,.QOMAR		;GET MESSAGE CODE
	SETZ T2,		;NO FLAGS
MATR2:	MOVE T3,RBUF+.MSCOD	;GET ACK CODE FOR USER
	CALL GALHDR		;BUILD GALAXY HEADER IN MESSAGE
	MOVE T1,RBUF+.MATPD	;GET USER'S PID
	CALLRET TRANU		;SEND MESSAGE TO USER
; QMNT - PROCESS USER MOUNT REQUEST MESSAGE FROM QUASAR
;  RBUF/ IPCF MOUNT MESSAGE
;  T1/ SIZE OF MESSAGE (WORDS)
; RETURNS +1: ALWAYS

QMNT:	SAVEQ
	CAIE T1,1000		;DID I GET A PAGE OF DATA?
	JRST [	CALLRET BADQM]	;NO, QUASAR BLEW IT

; GET RSB AND COPY USER-DESCRIPTOR INFORMATION INTO IT

	SETZ Q2,		;ASSUME NO PROBLEMS WITH RSB POOL
	CALL GETRSB		;ALLOCATE STATUS BLOCK FOR THIS REQUEST
	 SETO Q2,		;FREE RSB POOL IS NOW EMPTY
	MOVE T1,RBUF+.MMNAM
	MOVEM T1,RSBRNM(RSB)	;MOVE REQUEST NAME TO RSB
	MOVE T1,RBUF+.MMITN
	MOVEM T1,RSBITN(RSB)	;MOVE QUASAR INTERNAL TASK # TO RSB
	MOVE T1,RBUF+.MMUCD
	MOVEM T1,RSBCOD(RSB)	;MOVE USER'S ACK CODE TO RSB
	MOVE T1,RBUF+.MMPID
	MOVEM T1,RSBPID(RSB)	;MOVE USER'S PID TO RSB
	LOAD T1,MD.PJB,RBUF+.MMCAP
	STOR T1,RSBJNO		;MOVE USER'S JOB # TO RSB
	MOVE T1,RBUF+.MMUNO
	MOVEM T1,RSBUNO(RSB)	;MOVE USER'S USER # TO RSB
	MOVX T1,MD.PWH+MD.POP
	MOVX T2,R%PRIV
	TDNE T1,RBUF+.MMCAP	;DOES USER HAVE WHEEL OR OPERATOR?
	IORM T2,RSBIFL(RSB)	;YES, MARK HIM AS PRIVILEGED
	MOVSI T1,RBUF+.MMACT	;BLT SOURCE
	HRRI T1,RSBACT(RSB)	;BLT DESTINATION
	BLT T1,RSBACT+7(RSB)	;MOVE USER'S ACCOUNT STRING TO RSB

; IDENTIFY REQUEST TYPE AND DISPATCH TO THE APPROPRIATE PROCESSOR

	JUMPN Q2,[ABTREQ (MREQ31) ;ABORT IF RSB'S IN SHORT SUPPLY
		TXZ F,ABORTF	;CLEAR ABORTED-REQUESTS-PRESENT
		CALLRET PRQABT]	;MAKE SURE AT LEAST 1 FREE RSB IS LEFT
	MOVE T1,RBUF+.MMARC	;GET ENTRY COUNT
	CAIE T1,1		;IS IT 1?
	JRST MSERR		;NO, FORMAT ERROR
	MOVEI T2,RBUF+.MMHSZ	;GET ADDRESS OF FIRST ENTRY
	MOVE T3,RBUF+.MMUMS	;GET SIZE OF USER IPCF MESSAGE
	SUBI T3,.MMHSZ		;COMPUTE SIZE OF MOUNT-ENTRY REGION
	CALL CKBSTR		;CHECK BUILDING-BLOCK STRUCTURE
MSERR:	 JRST [	ABTRET (MREQ13)] ;STRUCTURAL ERROR IN MOUNT MESSAGE
	MOVEI T1,RBUF+.MMHSZ	;GET ADDRESS OF FIRST ENTRY
	LOAD T2,AR.TYP,(T1)	;GET TYPE OF ENTRY
	STOR T2,RSBTYP		;STORE REQUEST TYPE IN RSB
	CAIN T2,.MNTTP		;IS IT A USER TAPE MOUNT?
	JRST [	CALLRET UTM]	;YES, GO PROCESS IT
	CAIN T2,.MNTST		;USER STRUCTURE MOUNT?
	JRST [	CALLRET USM]	;YES, GO PROCESS IT
	CAIN T2,.DSMST		;DISMOUNT STRUCTURE?
	JRST [	CALLRET USD]	;YES
NOSHIP,<
	CAIN T2,.MNTDT		;DECTAPE MOUNT?
	JRST [	CALLRET UDTM]	;YES
>;NOSHIP
	ABTRET (MREQ21)		;I CAN'T HANDLE ANYTHING ELSE
; QSRINI - ESTABLISH IPCF RAPPORT WITH QUASAR
; RETURNS +1: ALWAYS

QSRINI:	STKVAR <TSTFLG>		;FLAG USED ONLY FOR DEBUGGING
	SETOM TSTFLG		;INITIALIZE FLAG
QSRIN1:	MOVEI T1,.SPQSR
	CALL GSYSPD		;GET QUASAR'S PID FROM SYSTEM PID TABLE
	 JRST [	AOSN TSTFLG	;HAVE WE BEEN HERE BEFORE?
		CALL TSTWAT	;NO, INFORM USER WE ARE WAITING
		MOVEI T1,^D5000	;NOT THERE YET
		DISMS		;WAIT 5 SECONDS
		JRST QSRIN1]	; AND TRY AGAIN
	MOVEM T1,APPID+.APQSR	;STUFF PID IN A/P TABLE

; BUILD AND TRANSMIT HELLO MESSAGE TO QUASAR

	MOVE T1,[HEL.SZ,,.QOHEL] ;MESSAGE LENGTH ,, MESSAGE TYPE
	SETZB T2,T3		;NO FLAGS, NO ACK CODE
	CALL GALHDR		;CONSTRUCT GALAXY HEADER IN TBUF
	MOVE T1,[SIXBIT/MOUNTR/]
	MOVEM T1,TBUF+HEL.NM	;MY NAME
	MOVX T1,FLD(%%.QSR,HEFVER)
	MOVEM T1,TBUF+HEL.FL	;QSRMAC VERSION #
	MOVX T1,FLD(1,HENNOT)+FLD(HENMAX,HENMAX)
	MOVEM T1,TBUF+HEL.NO	;# OF OBJ TYPES, MAX # OF JOBS
	MOVX T1,.OTMNT
	MOVEM T1,TBUF+HEL.OB	;I HANDLE MAGTAPE MOUNT REQUESTS

	MOVEI T1,.APQSR		;GOING TO QUASAR
	CALL TRANG		;TRANSMIT MESSAGE
	RET
; QSRMRC - DISPATCH IPCF MESSAGES FROM QUASAR TO APPROPRIATE ROUTINES
;  MRPDB, RBUF/ PDB AND MESSAGE
; RETURNS +1: ALWAYS

QSRMRC:	SAVEQ
	CALL CKGHDR		;CHECK OUT GALAXY HEADER
	 JRST [	CALLRET BADQM]	;BAD HEADER

; T1/ MESSAGE LENGTH (WORDS)   T2/ MESSAGE TYPE

	MOVSI T4,-QDTABL	;GET AOBJN POINTER
QSRMR1:	HLRZ T3,QDTAB(T4)	;GET MESSAGE TYPE FROM TABLE
	CAME T2,T3		;DOES IT MATCH THE MESSAGE I JUST GOT?
	JRST [	AOBJN T4,QSRMR1	;NO, LOOP
		CALLRET BADQM]	;DOESN'T MATCH ANYTHING IN THE TABLE
	HRRZ T2,QDTAB(T4)	;GET ADDRESS OF DISPATCH WORD
	MOVE T2,(T2)		;GET DISPATCH WORD
	TLZE T2,1		;HAVE TO CALL ORNBCK?
	JRST [	DMOVE Q1,T1	;YES, SAVE T1 & T2
		CALL ORNBCK
		 JRST [	CALLRET BADQM] ;ERROR, REPORT IT AND RETURN
		DMOVE T1,Q1	;COPY 'EM BACK
		JRST .+1]
	CALLRET (T2)		;DISPATCH TO HANDLER, T1/ MSG LENGTH

; DISPATCH TABLE FOR MESSAGE TYPES RECEIVED FROM QUASAR

; 1 IN LEFT HALF OF LITERAL MEANS ORNBCK MUST BE CALLED BEFORE DISPATCH

QDTAB:	.QOMNT,,[0,,QMNT]	;MOUNT REQUEST FROM USER
	.QOMTA,,[0,,TCAN]	;TAPE MOUNT CANCEL
	.QOMAT,,[0,,MATR]	;ATTRIBUTE REQUEST FROM USER
	.ODDMT,,[1,,KDMT]	;OPR COMMAND - DELETE MOUNT-REQUEST
	.ODENA,,[1,,KENA]	;OPR COMMAND - ENABLE
	.ODDIS,,[1,,KDIS]	;OPR COMMAND - DISABLE
	.ODDSM,,[1,,KDSM]	;OPR COMMAND - DISMOUNT
	.ODSDK,,[1,,KSDK]	;OPR COMMAND - SET DISK-DRIVE
	.ODIDN,,[1,,KIDN]	;OPR COMMAND - IDENTIFY
	.ODSTP,,[1,,KSTP]	;OPR COMMAND - SET TAPE-DRIVE
	.ODSHD,,[1,,KSHD]	;OPR COMMAND - SHOW STATUS DISK
	.ODSHT,,[1,,KSHT]	;OPR COMMAND - SHOW STATUS TAPE
	.ODSTR,,[1,,KSHS]	;OPR COMMAND - SHOW STATUS STRUCTURE
	.ODSST,,[1,,KSST]	;OPR COMMAND - SET STRUCTURE
	.ODSWI,,[1,,KSWI]	;OPR COMMAND - SWITCH
	.ODUNL,,[1,,KUNL]	;OPR COMMAND - UNLOAD
	.ODSPO,,[1,,KSPT##]	;OPR Command - Set Port
	.ODUDS,,[1,,KSUD]	;OPR Command - Undefine Structure
	.ODMTS,,[1,,KSMT]	;OPR command - Mount Structure
	.ODSCD,,[1,,KSCD]	;OPR COMMAND - Show configuration disk
QDTABL==.-QDTAB
; REQRSB - TRANSLATE REQUEST NUMBER INTO RSB ADDRESS
;  T1/ REQUEST NUMBER
; RETURNS +1: UNKNOWN REQUEST #, T1/ REQUEST #
;	  +2: SUCCESS, RSB/ RSB ADDR,  T1/ REQUEST #

REQRSB:	QSCANI ARBQDB		;SET UP TO SCAN RSB QUEUE
	SAVET			;PRESERVE T1 AS ADVERTISED
REQR1:	CALL QMSCAN		;GET NEXT RSB
	 RET			;NONE LEFT, REQUEST # UNKNOWN
	MOVEI RSB,-RSBLNK(T2)	;LOAD RSB AC WITH ADDRESS OF RSB
	MOVE T1,CT1		;GET REQ# FROM RSB
	CAME T1,RSBITN(RSB)	;DOES IT MATCH WHAT THE CALLER GAVE?
	JRST REQR1		;NO, CONTINUE SCAN
	RETSKP			;YES, SUCCESS


; RLSMSG - SEND RELEASE MESSAGE TO QUASAR
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

RLSMSG:	MOVE T1,RSBITN(RSB)	;GET ITN
	MOVEM T1,TBUF+REL.IT	;STORE IN MESSAGE
	MOVE T1,[REL.SZ,,.QOMTR] ;GET GALAXY HEADER
	SETZB T2,T3
	CALL GALHDR		;BUILD HEADER
	MOVEI T1,.APQSR
	CALLRET TRANG		;SEND RELEASE MESSAGE TO QUASAR
; TCAN - PROCESS USER TAPE REQUEST CANCEL MESSAGE FROM QUASAR
;  RBUF/ IPCF TAPE MOUNT CANCEL MESSAGE
;  T1/ SIZE OF MESSAGE (WORDS)
; RETURNS +1: ALWAYS

TCAN:	SAVEQ
	MOVE T3,T1		;COPY SIZE OF MESSAGE
	SUBI T3,.OHDRS		;GET SIZE OF BLOCK REGION OF MESSAGE
	JUMPLE T3,TCANQE	;NO BLOCK REGION, ERROR BY QUASAR
	MOVE T1,RBUF+.OARGC	;GET # OF BLOCKS
	MOVEI T2,RBUF+.OHDRS	;GET ADDRESS OF 1ST BLOCK
	CALL CKBSTR		;CHECK BLOCK STRUCTURE
TCANQE:	 JRST [	CALLRET BADQM]	;BAD STRUCTURE, QUASAR GOOFED
	DMOVE T1,[EXP RBUF+.OARGC,RBUF+.OHDRS]
	MOVEI T3,.MTPID		;GET TYPE OF BLOCK BEING SOUGHT
	CALL BLKFND		;LOOK UP USER'S PID
	 JRST TCANQE		;PID BLOCK NOT THERE
	JUMPE T2,TCANQE		;MAKE SURE THERE'S ROOM FOR A PID
	MOVE Q2,(T1)		;GET PID SO I CAN REPLY TO THE USER
	DMOVE T1,[EXP RBUF+.OARGC,RBUF+.OHDRS]
	MOVEI T3,.MTITN		;GET BLOCK TYPE
	CALL BLKFND		;LOOK UP ITN LIST
	 JRST TCANQE		;NOT THERE
	SETZ Q1,		;CLEAR COUNTER OF CANCELED REQUESTS
	JUMPE T2,TCAN2		;NO SCAN IF NOTHING TO CANCEL
	MOVN Q3,T2		;GET NEGATIVE NUMBER OF ITN'S
	MOVSS Q3		;OVER TO LEFT HALF FOR AOBJN
	HRR Q3,T1		;MAKE AOBJN POINTER TO ITN LIST

; LOOP THROUGH ITN LIST, TRYING TO CANCEL EACH ONE

TCAN1:	MOVE T1,(Q3)		;GET AN ITN
	CALL TCITN		;TRY TO CANCEL IT
	 SKIPA			;CAN'T CANCEL
	AOS Q1			;COUNT CANCELED REQUEST
	AOBJN Q3,TCAN1		;LOOP
	; ..
	; ..

; BUILD TEXT REPLY TO CANCEL MESSAGE IN TMCMSG

TCAN2:	JUMPG Q1,[TMCT <%I%5D>	;AT LEAST 1 REQUEST CANCELED
		JRST TCAN3]
	TMCT <%INo>		;NO REQUESTS CANCELED
TCAN3:	TMCT < mount request>
	SOJN Q1,[TMCT <s>	;IF NOT 1 REQUEST, TACK ON AN "S"
		JRST .+1]
	TMCT < canceled>

; BUILD IPCF MESSAGE AND SEND IT TO THE CANCELER

	MOVE T1,Q2		;GET USER'S PID
	SETZ T2,		;NO FLAGS
	MOVE T3,RBUF+.MSCOD	;GET CANCELER'S ACK CODE
	CALLRET TXTMSG		;RESPOND TO CANCEL WITH GLX TEXT MESSAGE
; TCKP - SEND A STATUS UPDATE FOR A MOUNT REQUEST TO QUASAR
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

TCKP:	SAVEQ
	SAVEAC <MT,MTA>
	MOVE T1,RSBITN(RSB)
	MOVEM T1,TBUF+CHE.IT	;STORE ITN IN MESSAGE
	SETZM TBUF+CHE.FL	;SET NO SPECIAL FLAGS
	MOVEI Q1,TBUF+CHE.IN	;GET ADDR OF START OF CKPT INFO AREA

	LOAD Q2,RSBTYP		;GET REQUEST TYPE
	MOVEM Q2,.MTTYP(Q1)	;STORE IT
	CAIE Q2,.MNTTP		;TAPE REQUEST?
	CAIN Q2,.MNTDT		; OR DECTAPE REQUEST?
	SKIPA			;YES
	JRST TCKP0		;NO, SKIP VOLID STUFF

	CALL VQGCV		;GET VOLID OF CURRENT VOLUME IN T1
	SKIPN T1		;SCRATCH?
	MOVEI T1,%VOLSC		;YES, GET 1 TO DISPLAY "Scratch"
	LOAD T2,RSBSTE		;GET CURRENT STATE OF REQUEST
	CAIGE T2,.ERBAS		;ABORTED OR
	CAIN T2,RST.WV		; WAITING FOR VOLID LIST?
	MOVEI T1,%VOLBL		;YES, DON'T DISPLAY ANYTHING
	MOVEM T1,.MTVOL(Q1)	;STORE VOLID
TCKP0:

	CAIN T2,RST.AC		;REQUEST HAVE MTA OR DTA?
	JRST [	MOVE T1,RSBDTA(RSB) ;YES, ASSUME DECTAPE
		CAIN Q2,.MNTDT	;DECTAPE?
		JRST TCKP1	;YES, T1/ DECTAPE DEVICE DESIGNATOR
		LOAD MT,RSBMT	;MAGTAPE REQUEST
		LOAD MTA,MTMTA	;LOAD MTA AC
		CALL GMTADD	;GET MTA DESIGNATOR IN T1
		JRST TCKP1]	;GO STORE IT
	MOVEI T1,%STAWT		;ASSUME WAITING FOR SOMETHING
	CAIL T2,.ERBAS		;ABORTED?
	MOVEI T1,%STAAB		;YES, SAY SO THEN
TCKP1:	MOVEM T1,.MTSTA(Q1)	;STORE STATE FIELD OF MESSAGE

	MOVE T1,[CHE.IN+EQCKSZ,,.QOMTC] ;GET SIZE AND MESSAGE TYPE
	SETZB T2,T3		;NO FLAGS OR ACK CODE
	CALL GALHDR		;BUILD GALAXY HEADER
	MOVEI 1,.APQSR
	CALLRET TRANG		;SEND CHECKPOINT MESSAGE TO QUASAR
; TXTMSG - SEND GALAXY IPCF TEXT-MESSAGE
;  T1/ RECEIVER'S PID
;  T2/ FLAGS FOR GALAXY MESSAGE HEADER
;  T3/ ACK CODE FOR MESSAGE HEADER
;  TMCMSG/ ASCIZ MESSAGE TO BE SENT
; RETURNS +1: ALWAYS

TXTMSG:	STAKT
	AOS TBUF+.OARGC		;SET ARGUMENT COUNT TO 1
	MOVE T1,TMCWDS		;GET LENGTH OF MESSAGE (WORDS)
	MOVSI T2,1(T1)		;CONSTRUCT
	HRRI T2,.CMTXT		; ARGUMENT HEADER WORD
	MOVEM T2,TBUF+.OHDRS	;STORE ARG HEADER
	MOVE T2,[TMCMSG,,TBUF+.OHDRS+1] ;GET BLT SOURCE,,DESTINATION
	BLT T2,TBUF+.OHDRS(T1)	;COPY TEXT INTO IPCF MESSAGE
	MOVSI T1,.OHDRS+1(T1)	;GET SIZE OF ENTIRE MESSAGE
	HRRI T1,MT.TXT		;BUILD SIZE,,TYPE
	MOVE T2,CT2		;GET FLAGS
	MOVE T3,CT3		;GET ACK CODE
	CALL GALHDR		;BUILD GALAXY HEADER FOR MESSAGE
	MOVE T1,CT1		;GET RECEIVER'S PID
	CALLRET TRANU		;TRANSMIT MESSAGE AND RETURN
SUBTTL STRUCTURE ROUTINES

;BSRALI - GET STRUCTURE ALIAS FROM QUASAR MSSG INTO RSB

;ACCEPTS: T1/ ADDRESS OF SUBENTRY COUNT WORD
;	  T2/ ADDRESS OF FIRST SUBENTRY
;	  RSB/ ADDR OF REQUEST STATUS BLOCK

;RETURNS: +1,	FAILURE
;	  +2,	SUCCESS

BSRALI: MOVEI T3,.SMALI		;GET STRUCTURE ALIAS CODE
	CALL BLKFND		;LOOKUP ALIAS
	 JRST [	ABTRET(MREQ22)]	;ERROR, CAN'T MOUNT STR IF NO ALIAS
	JUMPE T2,[ABTRET(MREQ22)] ;TREAT ZERO-LENGTH NAME LIKE NO NAME
	MOVE T1,(T1)		;GET ALIAS IN T1
	MOVEM T1,RSBSTA(RSB)	;STORE ALIAS IN RSB
	RETSKP


;BSRNAM - GET STRUCTURE NAME FROM QUASAR MSSG INTO RSB

;ACCEPTS: T1/ ADDRESS OF SUBENTRY COUNT WORD
;	  T2/ ADDRESS OF FIRST SUBENTRY
;	  RSB/ ADDR OF REQUEST STATUS BLOCK

;RETURNS: +1,	FAILURE
;	  +2,	SUCCESS

BSRNAM:	MOVEI T3,.SMNAM		;GET STRUCTURE NAME CODE
	CALL BLKFND		;LOOKUP NAME
	 JRST BSRNA1		;NAME NOT GIVEN
	JUMPE T2,BSRNA1		;TREAT ZERO-LENGTH NAME AS NO NAME
	MOVE T1,(T1)		;GET NAME IN T1
	CAME T1,RSBSTA(RSB)	;IS NAME SAME AS ALIAS
	JRST [	MOVX T2,R%PRIV	;NO, IS USER PRIVILEGED?
		TDNE T2,RSBIFL(RSB)
		JRST .+1	;YES, LET IT GO
		ABTRET (CAPX1)]	;NOT PRIVLEGED, ABORT REQUEST
	SKIPA
BSRNA1:	SETZ T1,		;STORE ZERO IF NO NAME MENTIONED
	MOVEM T1,RSBSTN(RSB)	;STORE NAME IN REQUEST BLOCK
	RETSKP
SUBTTL Update all disks -- Flow of update
COMMENT %

                        +----------+
                        |  DDSCIH  |
                        +----------+
                             |
      ------------------------------------------------
      |               |               |              |
+----------+    +----------+    +----------+    +----------+
|  DDSNXT  |    |  DSTSRC  |    |  DDSNEW  |    |  DDSCHK  |  Add or check
+----------+    +----------+    +----------+    +----------+  DSK
 Get next        Search for           |           |    |
 CKU             DSK with CKU         -------------    |
                 (Also called          |               |
                  by KSDK)       +----------+    +----------+
                                 |  DDSADD  |    |  DDSDEL  |  Delete structure
                        Add disk +----------+    +----------+  info. about disk
                                  |        |       |
                            +----------+   ---------
           Store structure  |  STRINF  |       |
            info. for disk  +----------+   +----------+
                                  |        |  DDSMCH  |  Match user requests
                            +----------+   +----------+  with disk change
             Get/build SSB  |  STRGSB  |
                            +----------+
% ; END OF COMMENT
SUBTTL Update all disks -- DDSCIH - Update all disk drives

;DDSCIH - ENTERED BY SCHEDULER WHEN PSI INTERRUPT RECEIVED
;	  INDICATING THAT A DISK STATUS CHANGE HAS OCCURRED
;	Also called whenever disks need to be updated

;ACCEPTS: NOTHING
;RETURNS: +1,	ALWAYS


DDSCIH::SAVEQ			;SAVE ACS
	CALL DSFNUP		;Set no update
DDSC.0:	CALL DSTINI		;INITIALIZE TO LOOP OVER ALL DISKS

DDSC.1:	CALL DSTNXT		;GET STATUS OF NEXT DISK
	 JRST DDSC.2		;Done go finish up
	CALL DSTSRC		;LOOK FOR UNIT IN TABLES
	 JRST [	CALL DDSNEW	;Not found, go do a new disk drive
	 	JRST DDSC.1]	;And continue
	CALL DDSCHK		;Otherwise, go check on it
	JRST DDSC.1		;THEN LOOK AT NEXT ONE

DDSC.2:	SKIPN AGAIN		;Do we need to do again?
	JRST DDSC.3		;No, go clean up
	SETZM AGAIN		;Clear flag
	JRST DDSC.0		;Go try again

DDSC.3: CALL DSFYUP		;Want to update
	RET			;And return
SUBTTL Update all disks -- DSTINI - Initialize MSTR block for scanning units

;  Called only by DDSCIH

;ACCEPTS: NOTHING
;RETURNS: +1,	ALWAYS


DSTINI:	SETOM MSTRBK		;SET UP MSTR TO LOOK AT FIRST CHANNEL
	SETOM MSTRBK+1		; FOR FIRST CONTROLLER
	SETOM MSTRBK+2		; FOR FIRST DISK
	RET			;DONE


SUBTTL Update all disks -- DSTNXT - Get status of the next disk

;  Called only by DDSCIH

;ACCEPTS: MSTRBK BLOCK FOR MSTR JSYS
;RETURNS: +1,	FAILURE
;	  +2,	SUCCESS, STATUS RETURNED IN MSTRBK BLOCK
;		  T1/	CKU NUMBERS FOR UNIT


DSTNXT:	MOVE T1,[POINT 7,MSTNM] ;GET POINTER TO STRUCTURE NAME
	MOVEM T1,MSTRBK+.MSRSN	; AND STORE IN MSTR ARGUMENT BLOCK
	MOVE T1,[POINT 7,MSTAL]	;DO SAME FOR STRUCTURE ALIAS
	MOVEM T1,MSTRBK+.MSRSA
	MOVE T1,[50,,.MSRNU]	;Set up call to monitor to get status
	MOVEI T2,MSTRBK		;PUT STATUS IN MSTR BLOCK
	SETZM MSTNM		;CLEAR NAME IN CASE NOT PART OF STRUCTURE
	SETZM MSTAL		;CLEAR ALIAS ALSO
	MSTR			;GET STATUS
	 ERJMP R		;END OF DISKS
	SETZ T1,		;START WITH ZERO AC
	MOVE T2,MSTRBK+.MSRCH	;GET CHANNEL NUMBER
	STOR T2,DOP%C2,T1	;STORE INTO AC
	MOVE T2,MSTRBK+.MSRCT	;GET CONTROLLER NUMBER
	STOR T2,DOP%K2,T1	;STORE WITH CHANNEL
	MOVE T3,MSTRBK+.MSRUN	;FINALLY GET UNIT NUMBER
	STOR T3,DOP%U2,T1	;STORE WITH REST
	RETSKP			;DONE
SUBTTL Update all disks -- DSTSRC - LOOK FOR THE DISK ENTRY MATCHING SPECIFIED CKU NUMBERS

;ACCEPTS: T1/	CKU NUMBER (CHANNEL, CONTROLLER, UNIT NUMBERS)
;RETURNS: +1,	UNIT WAS NOT IN TABLES
;		   DSK/	ADDRESS OF FIRST FREE SLOT OR ZERO IF NONE
;	  +2,	UNIT FOUND
;		  DSK/	ADDRESS OF DISK STATUS BLOCK FOR UNIT



DSTSRC:	MOVE DSK,[-MAXDSK,,DSKSTB]	;GET AOBJN POINTER READY
	SETZ T2,		;NO FREE ENTRY FOUND YET

DSTSRL:	SKIPN DSKFLG(DSK)	;THIS ENTRY IN USE?
	JRST DSTSRF		;NO, GO REMEMBER FREE ENTRY
	CAME T1,DSKCKU(DSK)	;IS THIS THE UNIT?
	JRST DSTSRN		;NO, TRY NEXT ONE
	ANDI DSK,-1		;FOUND THE UNIT, REMOVE JUNK
	RETSKP			;SUCCESSFUL RETURN

DSTSRF:	SKIPN T2		;HAVE FREE ENTRY REMEMBERED YET?
	MOVE T2,DSK		;NO, THEN REMEMBER THIS ONE
DSTSRN:	ADDI DSK,DSKSZ-1	;MOVE TO NEXT ENTRY
	AOBJN DSK,DSTSRL	;GO DO IT
	HRRZ DSK,T2		;UNIT NOT FOUND, GET FREE BLOCK IF ANY
	RET			;AND RETURN IT
SUBTTL Update all disks -- DDSNEW - Add new disk to data bases

;  Called only by DDSCIH

;HERE WHEN A NEW UNIT HAS TO BE ADDED TO THE DISK TABLES:
;  DSK/	ADDRESS OF FREE ENTRY, OR ZERO IF NO MORE ROOM
;  T1/	CKU NUMBERS FOR UNIT


DDSNEW:	SKIPN DSK		;Room for the entry?
	 CALL STOP		;No, must be room

;  Initialize the disk status block

	MOVSI T2,0(DSK)		;SETUP BLT POINTER
	IORI T2,1(DSK)		;TO CLEAR THE DISK STATUS BLOCK
	SETZM (DSK)		;CLEAR FIRST WORD
	BLT T2,DSKSZ-1(DSK)	;THEN THE REST

	MOVEM T1,DSKCKU(DSK)	;REMEMBER CKU NUMBERS
	MOVE Q2,MSTRBK+.MSRST	;GET STATUS OF DISK
	MOVEM Q2,DSKFLG(DSK)	;REMEMBER IN BLOCK
	MOVE T2,MSTRBK+.MSDSH	;Get serial number of disk (HIGH ORDER)
	MOVEM T2,DSKSNH(DSK)	;Remember in block
	MOVE T2,MSTRBK+.MSDSN	;Get serial number of disk (LOW ORDER)
	MOVEM T2,DSKSNL(DSK)	;Remember in block

;  Add/create DDB for entry

	MOVEI T2,.DVDSK		;Get the disk type
	MOVEM T2,DSFE+DSFTYP	;Save it
	MOVEM T1,DSFE+DSFSPC	;Save the CKU
	SETZM DSFE+DSFFLG	;Default to no flags
	CALL DSFCRE		;Go create it
	 JRST DDSN.1		;Skip this, it already exists

;  Here check whether to set DSF%PO in the disk entry of the DDB base on PORTST
;  PORTST=0 indicates port available, 1=unavailable, -1=No port

	SKIPG PORTST		;Is the port available
	JRST DDSN.1		;Available, skip port stuff
	MOVE T2,MSTRBK+.MSRCH	;Get the channel number
	CAIE T2,CIPORT		;For now test for channel 7
	TXNE Q2,MS%2PT		;Port unavailable, is it dual ported?
	CALL [SETONE DSF%PO,DSFE+DSFFLG ;Set disk unavail due to port operation
	      RET]
DDSN.1:	MOVEM DSK,DSFE+DSFPNT	;Save the DSB address
	CALL DSFUDE		;Update the entry
	 $STOP <Update of previously known DDB with DSFUDE failed>
	MOVEM T1,DSKPNT(DSK)	;Save address of DDB in DSB

	TXNE Q2,MS%OFL		;Is pack off-line?
	TXNE Q2,MS%IAC		;Yes, but is it due to HOM checking?
	CALL DDSADD		;No, add structure information
	RET			;DONE WITH UNIT
SUBTTL Update all disks -- DDSCHK - Check disk already existing

;  Called only by DDSCIH

;HERE TO CHECK ON A DISK WHICH WAS ALREADY IN OUR TABLES.  UPDATE
;THE DATA FOR IT.
;  DSK/	ADDRESS OF THIS DRIVE'S DATA


DDSCHK:	MOVE Q2,MSTRBK+.MSRST	;Get status of disk unit
	MOVE Q1,Q2		;Make copy of status
	XOR Q1,DSKFLG(DSK)	;Get changed bits
	MOVEM Q2,DSKFLG(DSK)	;Save new state in any case

;  First, if online, check the name of the structure with the old name.
;  If different, then delete the old and set the new structure information.

	TXNE Q2,MS%OFL!MS%IAC	;Offline?
	JRST DDSCH1		;Yes, skip the name test

;  Online, make sure we have a structure
	
	SKIPN MSTNM		;Do we have a structure
	JRST [CALL CHKDSK	;[336]Is it due to disk errors?
	      RET		;[336]Yes, bad data on disk drive
	      LOAD STR,DSKSSA,(DSK) ;[336]No structure,
	      JUMPE STR,R	;[336]If no pointer forget about this disk
	      MOVE T1,DSKCKU(DSK) ;No errors, MONITOR bug, get the CKU
	      TMCT <%IWarning disk (%1K) is online
but can not find structure on disk%_>
	      MOVEI T3,[ASCIZ/DISK PROBLEM/] 
	      CALLRET BTWTO]	;Online, but no structure!!!!
	MOVE T1,MSTRBK+.MSMID	;Get the unique code
	CAME T1,DSKUNQ(DSK)	;Is it the same
	JRST DDSCH0		;No, must be a new structure
	MOVE T1,[POINT 7,MSTNM] ;Online, get pointer to name
	MOVEI T2,Q3		;Want to put it in Q3
	CALL SEVSIX		;Convert name to sixbit
	CAMN Q3,DSKSTN(DSK)	;Same as before?
	JRST DDSCH1		;Yes, go check on other things

;  The name (disk) has changed

DDSCH0:	CALL DDSDEL		;Delete old structure information
	CALL DDSADD		;Add new structure information
	RET			;Nothing else to do this time

;  The name is the same or don't care.  Any reason to check further?

DDSCH1:	LOAD T1,DSKSSA,(DSK)	;Get the structure address field
	CAIN T1,-1		;Is it special, indicating a need to add?
	JRST DDSADD		;Yes, go do it

	SKIPN Q1		;Anything changed in status?
	JRST [TXNN Q2,MS%MNT	;No, is it mounted?
	      RET		;No, nothing further to check
	      LOAD STR,DSKSSA,(DSK) ;Get the SSB address
	      SKIPN STR		;Is there one?
	      RET		;No. done
	      SKIPE T1,STRPNT(STR) ;Get the DDB address
	      CALL UPDSTR	;Go try to update it
	      RET]		;Done

;  If the offline status has changed we either need to add or delete

	TXNE Q1,MS%OFL		;Offline status change?
	JRST [TXNE Q2,MS%IAC	;Yes, but is it HOM checking?
	      RET		;Yes, no need to do anything
	      TXNE Q2,MS%OFL	;How did the offline status change?
	      JRST DDSDEL	;  became offline
	      JRST DDSADD]	;  became online

;  If the mount status changed, add structure again
;  Also, if on f the error status changed, then also add structure again.

	TXNE Q1,MS%MNT!MS%WLK!MS%HBB!MS%BBB!MS%DIA ;Mount or error change?
	JRST DDSADD		;Yes.

	RET			;Whatever changed, we don't understand...
SUBTTL Update all disks -- DDSDEL - DELETE STRUCTURE INFORMATION ABOUT A DISK

;  Called only by DDSCHK

;ACCEPTS: DSK/	DISK NUMBER
;RETURNS: +1,	ALWAYS

DDSDEL:	LOAD STR,DSKSSA,(DSK)	;Get structure block address
	JUMPLE STR,DDSDE2	;If no STR then return after zeroing dsk entry

	CALL STRDSM		;Dismount structure data base if needed
	LOAD T1,STRMCT,(STR)	;Get number of disks mounted in structure
	SOJN T1,[STOR T1,STRMCT,(STR) ;If still more, save the number left
		LOAD T1,DSKLUN,(DSK) ;Get disk logical number
		ADD T1,STR	;Add base
		SETZM STRADD(T1) ;Clear this entry
		JRST DDSDE2]	;Continue to clear disk entry

	QSCANI ARBQDB		;Setup to scan active RSB queue
	SAVEAC <RSB,DSK>
	CALL PRQPID		;CLEAN UP REQUEST QUEUE FIRST
	MOVX T1,R%DSM		;CHECK DISMOUNT QUEUES
	CALL DDSMCH		;MATCH AND FINISH ACTIVE RSB'S
	MOVE T1,STRFL1(STR)	;[6011]Get flag
	TXNN T1,STR%LE+STR%LD	;[6011]Locked?
	IFSKP.
	 TXNN T1,STR%MT		;[6011]Yes, is it still mounted?
	 CALL RELLOC		;[6011]No, have to unlock structure
	ENDIF.
	CALL SSBRET		;Return the SSB

DDSDE2:	SETZM DSKSTN(DSK)	;ZERO STRUCTURE NAME
	SETZM DSKSTA(DSK)	;ZERO STRUCTURE ALIAS
	SETZM DSKNS(DSK)	;Zero structure unit information
	SETZM DSKP2(DSK)	;Clear pointer to SSB (zeros DSKSSA)
	RET
SUBTTL Update all disks -- DDSADD - ADD A DISK COMING ON-LINE

;  Called only by DDSNEW and DDSCHK

;ACCEPTS: DSK/	Address of Disk Status Block
;RETURNS: +1,	ALWAYS

DDSADD:	CALL STRINF		; YES, STORE STRUCTURE INFORMATION
	RET			;Do not want to continue right now
	LOAD T1,STRUNI,(STR)	;GET NUMBER OF DISKS IN STR
	LOAD T2,STRMCT,(STR)	;GET NUMBER OF DISKS MOUNTED IN STR
	CAME T1,T2		;ARE ALL DISK PACKS MOUNTED?
	RET			;NO, RETURN

;TRY TO MATCH STRUCTURE COMING ON-LINE TO USER REQUEST

	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	SAVEAC <RSB,DSK>
	CALL PRQPID		;CLEAN UP REQUEST QUEUE FIRST
	MOVE Q2,DSKFLG(DSK)	;GET DISK STATUS
	TXNE Q2,MS%MNT		;IS IT MOUNTED ALREADY?
	JRST [	CALLRET DDSMC0]	;YES, CHECK MOUNT QUEUES
DDSAD1:	CALL NSTRSB		;GET ADDRESS OF NEXT RSB
	 RET			;NONE LEFT
	LOAD T1,RSBSTE		;GET STATE OF REQUEST
	CAIE T1,RST.WM		;IS USER WAITING FOR STRUCTURE
	JRST DDSAD1		;NO, TRY NEXT REQUEST
	SKIPN T1,RSBSTN(RSB)	;GET STRUCTURE NAME IN REQUEST
	MOVE T1,RSBSTA(RSB)	;THERE IS NONE, GET ALIAS FOR NAME
	CAME T1,STRNAM(STR)	;IS IT SAME AS STRUCTURE COMING ON-LINE
	JRST DDSAD1		;NO, TRY NEXT REQUEST
	CALL STRMNT		;MOUNT THE STRUCTURE
	JRST DDSAD2		;ERROR IN MOUNTING STRUCTURE
	SETZ T1,		;CHECK MOUNT REQUESTS
	CALLRET DDSMCH		;STRUCTURE IS NOW READY FOR USERS. TELL THEM

;DDSAD2 - Return according to request.  If it was a MOUNT command from OPR
;         go to KSMTE2 for error message.

DDSAD2:	SKIPGE RSBITN(RSB)	;Is it from operator
	CALLRET KSMTE2		;Yes, let KSMTE2 handle the error
	RET			;No, STRMNT should have given the error message
SUBTTL Update all disks -- STRINF - Store/check structure information

;  Called only by DDSADD

;ACCEPTS: Q2/	STATUS OF UNIT
;	  DSK/  Address of Disk Status Block
;	  MSTRBK/ BLOCK FROM MSTR CALL

;RETURNS: +1 if processing requires second pass
;	  +2 if ok.

STRINF:	MOVE T1,[POINT 7,MSTNM]	;GET POINTER TO STRUCTURE NAME
	MOVEI T2,DSKSTN(DSK)	;GET WORD IN WHICH TO STORE NAME
	CALL SEVSIX		; CONVERT FROM 7-BIT TO 6-BIT
	TXNN Q2,MS%MNT		;DOES DRIVE HAVE MOUNTED STRUCTURE
	JRST STRIN1		;NO, STORE REST OF INFORMATION
	MOVE T1,[POINT 7,MSTAL]	;GET POINTER TO ALIAS NAME
	MOVEI T2,DSKSTA(DSK)	;GET WORD IN WHICH TO STORE ALIAS
	CALL SEVSIX		;CONVERT FROM 7-BIT TO 6-BIT
STRIN1:	MOVE T3,MSTRBK+.MSRNS	;GET LOGICAL UNIT,,NUMBER OF UNITS
	MOVEM T3,DSKNS(DSK)	; AND STORE
	MOVE T4,MSTRBK+.MSMID	;Get the unique code
	MOVEM T4,DSKUNQ(DSK)	;Save it in DSB
	MOVE T1,DSKSTA(DSK)	;GET STRUCTURE ALIAS IN SIXBIT
	MOVE T2,DSKSTN(DSK)	;GET STRUCTURE NAME
	CALL STRGSB		;BUILD STR STATUS TABLE & GET STR ADDR
	RET			;Done for now
	STOR STR,DSKSSA,(DSK)	;STORE STR STATUS BLOCK ADDRESS

;  If the structure is not mounted, was it previously, and if so, clean
;  some stuff up.

	TXNE Q2,MS%MNT		;Is disk part of a mounted structure?
	JRST [CALL CHKDSK	;Is the disk error free
	      JRST STRIN6	;No
	      JRST STRIN3]	;Yes, no errors found
	CALL CHKDSK		;Disk is not mounted, any errors
	SKIP
	CALL STRDSM		;Dismount structure data base if needed
	RETSKP			;And done

;  Continued on next page
;Continued from previous page

;  Since there are no error bits, are there any to clear?

STRIN3:	MOVE T1,STRFL1(STR)	;Get the flags
	TXZN T1,STR%DE		;Any device errors previous? (And clear bit)
	JRST STRIN6		;No, skip this

;  Want to loop on all the disks to verify that the bit should still be set.

	LOAD T2,STRUNI,(STR)	;Get the number of units
	MOVNS T2		;Set number of units negative
	MOVSS T2		;Switch halves
	HRRI T2,STRADD(STR)	;Get start of pack list

;    Beginning of loop

STRIN4: MOVE T3,(T2)		;Get address of DSB
	MOVE T3,DSKFLG(T3)	;Get the flags for this one
	TXNE T3,MS%WLK+MS%HBB+MS%BBB+MS%DIA+MS%ERR+MS%16B ;Any bad bits set?
	JRST STRIN6		;Yes, cannot clear bit at this time
	AOBJN T2,STRIN4		;Go try for more

;    End of loop

	MOVEM T1,STRFL1(STR)	;We win! Clear the bit
	MOVE T2,DSKSTA(DSK)	;Get Alias
	TMCT <%IDevice error cleared%_Structure %2S: can be used>
	MOVEI T3,STRCHD		;Get general purpose structure header
	CALL BTWTO		;Tell everyone

;  Continued on next page
;Continued from previous page

;  Structure is mounted.
;  Check to see if SSB knows about all of the disks of the structure.

STRIN6:	LOAD T1,STRUNI,(STR)	;Get number of units in structure
	LOAD T2,STRMCT,(STR)	;Get the number found so far
	CAME T1,T2		;The whole thing mounted?
	RETSKP			;No, don't do anything else for now

;  All the packs are mounted.  Build/find DDB entry.

	MOVE T1,STRFL1(STR)	;Get the other structure flags
	TXNE T1,STR%MT		;Was it previously mounted?
	JRST STRIN7		;Yes, skip this stuff
	MOVEI T2,MSTAL		;Get the structure alias ascii
	TMCT <%IPreviously mounted structure %2A: detected>
	MOVEI T3,STRCHD		;Get header
	CALL BTWTO
	MOVX T2,STR%MT		;Get mounted bit
	IORM T2,STRFL1(STR)	;Say it is so
	MOVE T1,DSKSTA(DSK)	;Get the structure alias
	MOVEM T1,STRALI(STR)	;Save it

	SKIPA			;Don't need to get alias again
	MOVE T1,STRALI(STR)	;Get the alias
	CALL ISTDDB		;Go build/find DDB
	  CALL [SKIPE DSFE+DSFPNT ;Already exists, does it point at an SSB?
		CALL STOP	;Yep.  Shouldn't happen
		RET]		;Rejoin code
	HRRM STR,DSFE+DSFPNT	;Save SSB address as pointer
	CALL DSFUDE		;Update DDB entry
	 $STOP <Update of previously known DDB with DSFUDE failed>
	MOVEM T1,STRPNT(STR)	;Save DDB pointer

;  Now want to UPDATE structure if needed including telling everyone
;  about what happened.

STRIN7:	MOVE T1,STRPNT(STR)	;Get pointer to DDB back
	CALL UPDSTR		;Go update structure
	RETSKP			;And done
SUBTTL Update all disks -- STRGSB - GET STRUCTURE STATUS BLOCK (BUILD ONE IF NECESSARY)

;  Called only by STRINF

;ACCEPTS: T1	SIXBIT STRUCTURE ALIAS
;	  T2	SIXBIT STRUCTURE NAME
;	  T3	LOGICAL UNIT # OF CURRENT DISK,,# OF UNITS IN STRUCTURE
;	  T4	Structure Unique Code
;	  DSK	DISK STATUS BLOCK ADDRESS

;RETURNS: +1 if processing requires 2nd pass
;	  +2 if ok.
;		STR/ CURRENT STRUCTURE BLOCK ADDRESS

STRGSB:	STAKT
	CALL MATCHS		;DOES THIS STRUCTURE EXIST?
	SKIPA			;NO
	JRST STRFND		;YES, DON'T NEED TO BUILD NEW BLOCK
STRGS0:	CALL SSBCRE		;[336]Get a new SSB entry
	MOVE T2,CT2		;RESTORE STR NAME
	MOVEM T2,STRNAM(STR)	;SAVE STR NAME
	HRRZ T2,CT3		;GET NUMBER OF UNITS
	STOR T2,STRUNI,(STR)	;AND STORE
	MOVE T1,DSKUNQ(DSK)	;Get unique code
	MOVEM T1,STRUNQ(STR)	;Save it

;STORE DISK STATUS BLOCK ADDRESS

STRFND:	HLRZ T3,CT3		;GET UNIT NUMBER
	ADD T3,STR		;GET OFFSET TO
	SKIPN T2,STRADD(T3)	;[6023]Do we have a previous address?
	IFSKP.			;[336][6023]Change to IFSKP
	 CAMN T2,DSK		;[336]Yes, is it the same as this one?
	 JRST STRFN0		;Yes, still ok.
	 LOAD T1,DSKSSA,(DSK)	;Get the disk structure address
         CAIN T1,-1		;Have we already been here?
	 JRST STRFN3		;[336]Yes, go do some analyz
         SETONE DSKSSA,(DSK) 	;Set the case
         SETOM AGAIN		;Say we should try again
	 RET			;[6023]Add missing RET from [336]
	ENDIF.			;[336]
STRFN0:	HRRZM DSK,STRADD(T3)	; SAVE DISK STATUS BLOCK ADDRESS

	LOAD T2,STRUNI,(STR)	;Get the number of units
	MOVNS T2		;Set number of units negative
	MOVSS T2		;Switch halves
	HRRI T2,STRADD(STR)	;GET START OF PACK LIST
	SETZ T4,		;LOOP THRU TO GET # OF PACKS

STRFN1:	SKIPE (T2)		;IS THIS A PACK
	AOS T4			;YES, COUNT IT
	AOBJN T2,STRFN1		;LOOK FOR ALL OF THEM

	STOR T4,STRMCT,(STR)	; AND STORE
	RETSKP

;[336] STRFN3 - Find out why we have a -1 in DSKSSA.
;Accepts T2/disk status block
;	 DSK/disk status block with -1 for SSB address.  
;	 STR/SSB
STRFN3:	MOVE T1,DSKFLG(DSK)	;[336]Get status flag of coming online disk
	TXNE T1,MS%IAC+MS%OFL	;[336]HOM block checking?
	 IFNSK.
	  MOVE T2,DSK		;[336]Move DSB into AC T2
	  JRST STRFN5		;[336]Delete DSB
	 ENDIF.
	MOVE T3,DSKFLG(T2)	;[336]Get disk status flag of existing disk
	TXNE T3,MS%IAC+MS%OFL	;[336]HOM block checking?
	 JRST STRFN5		;[336]Yes, delete DSB
;  Not result from a force offline due to HOM block checking
;  Is it due to bad HOM block informaton
	TXNN T1,MS%HBB		;[336]Bad HOM block?
	 IFSKP.		        ;[336]Yes
	  SETZM DSKP2(DSK)	;[336]Clear pointer to SSB (zeros DSKSSA)
	  RET			;[336]Yes, no need to add SSB
	 ENDIF.
	
;  Not result from bad HOM block
;  Must be identical structures coming online
	JRST STRGS0		;[336]Go create a new SSB

;T2/DSB address
STRFN5:	SETZM DSKSTN(T2)	;[336]Zero structure name
	SETZM DSKSTA(T2)	;[336]Zero structure alias
	SETZM DSKNS(T2)		;[336]Zero structure unit information
	SETZM DSKP2(T2)		;[336]Clear pointer to SSB (zeros DSKSSA)
	RET
SUBTTL Update all disks -- STRDSM - Dismount structure data base

;  Called only by STRINF and DDSDEL

;  This routine checks the mount bit for the structure and if lit, then
;  delete DDB, clear the mount bit, and clear the alias.  It also sends
;  an error message because the dismount is not normal

;  Accepts: STR / address of SSB

;  Returns: +1 always

STRDSM:	MOVE T1,STRFL1(STR)	;No, get the structure flags
	TXNN T1,STR%MT		;Was the structure previously mounted?
	RET			;No, all done
	CALL DSTDDB		;Get rid of DDB entry
	MOVE T1,STRALI(STR)	;Get the old structure alias
	TMCT <%IPreviously mounted structure %1S: no longer mounted>
	MOVEI T3,STRCHD		;Get general purpose structure header
	CALL BTWTO		;Tell everyone
	SETZM STRALI(STR)	;Alias only has meaning if structure mounted
	RET			;All to do with this structure
SUBTTL Disk status check -- CHKDSK -- Check for disk errors

;  Disk is online, check out if any error bits are set
;	accepts Q2/disk status
;		STR/structure status block
;		DSK/disk status block
;	return 	+1 found error 
;		+2 no error found
CHKDSK:	TXNN Q2,MS%WLK+MS%HBB+MS%BBB+MS%DIA+MS%ERR+MS%16B ;Any bad bits set?
	RETSKP			;No, skip setting the problem
	MOVE T1,DSKCKU(DSK)	;Get CKU
	TMCT <%IDevice error on %1K%_Drive cannot be used>
	TXNE Q2,MS%WLK		;Write locked?
	CALL [TMCT <%_Unit is write locked>
	      RET]		;And return
	TXNE Q2,MS%HBB		;Home block problem?
	CALL [TMCT <%_Unit has bad home block>
	      RET]		;And return
	TXNE Q2,MS%BBB		;Bad bit block problem?
	CALL [TMCT <%_Unit has bad bat block>
	      RET]		;And return
	TXNE Q2,MS%DIA		;Diagnostics?
	CALL [TMCT <%_Unit currently in use by on-line diagnostic>
	      RET]		;And return
	TXNE Q2,MS%ERR		;Device error?
	CALL [TMCT <%_Error reading this unit>
	      RET]		;And return
	TXNE Q2,MS%16B		;16 Bit format?
	CALL [TMCT <%_Unit written in 16 bit mode>
	      RET]		;And return
	MOVEI T3,STRCHD		;Get general purpose structure header
	CALL BTWTO		;Tell everyone
	LOAD STR,DSKSSA,(DSK)	;[336]No structure,
	JUMPE STR,R		;[336]If no pointer forget about this disk
	SETONE STR%DE,STRFL1(STR) ;[336]Yes, set the disk error flag
	RET			;Error return
SUBTTL Update all disks - DDSMCH - MATCH USER REQUEST TO MOUNTS AND DISMOUNTS

;  Called only by DDSADD and DDSDEL

;ACCEPTS: T1/	0=LOOK AT MOUNT REQUESTS
;		R%DSM=LOOK AT DISMOUNT REQUESTS
;	  QSB/ ADDRESS OF QUEUE SCAN BLOCK
;	  STR/ ADDRESS OF STRUCTURE BLOCK
;RETURNS:  +1,	ALWAYS

DDSMC0:	SAVEQ			;ALTERNATE ENTRY FOR MOUNT REQUESTS
	SETZ Q1,
	JRST DDSMC1

DDSMCH:	SAVEQ
	MOVE Q1,T1
	JUMPE Q1,DDSMC2		;GO TO DDSMC2 FOR MOUNT REQUESTS
DDSMC1:	CALL NSTRSB		;GET NEXT USER REQUEST
	 RET			;NONE LEFT
	LOAD T1,RSBSTE		;GET STATE OF REQUEST
	CAIE T1,RST.WM		;Is user waiting for mount?
	JRST [CAIE T1,RST.WD	;No, is user waiting for dismount?
	     JRST DDSMC1	;Neither, try next request
	     JRST .+1]		;Waiting for dismount
	MOVE T1,RSBSTA(RSB)	;GET STRUCTURE ALIAS
	CAME T1,STRALI(STR)	;IS IT SAME AS THIS ONE
	JRST DDSMC1		;NO, TRY NEXT REQUEST
	SKIPN T1,RSBSTN(RSB)	;GET STRUCTURE NAME
	JRST DDSMC2		;NONE SPECIFIED. ALLOW THIS MOUNT
	CAME T1,STRNAM(STR)	;IS THIS THE SAME AS CURRENT STR
	JRST DDSMC1		;NO, GET NEXT REQUEST
DDSMC2:	MOVE T1,RSBIFL(RSB)	;GET INTERNAL FLAGS
	XOR T1,Q1		;ARE WE LOOKING AT RIGHT REQUEST TYPE
	TXNE T1,R%DSM
	JRST DDSMC1		;NO
	LOAD ACC,RSBACC		;GET ACC IF ANY ASSOCIATED.
	JUMPE ACC,DDSMC3	;NO ASSOCIATED ACC
	SETZRO RSBACC		;DELINK ACC AND RSB
	MOVEI T1,RSBSTA(RSB)	;POINT TO SIXBIT ALIAS
	MOVE T2,[POINT 7,MSTAL]	;ASCII GOES HERE
	CALL SIXSEV		;CONVERT ALIAS TO ASCII
	HRROI T1,MSTAL		;POINT TO ASCII ALIAS
	STDEV			;GET DEVICE DESIGNATOR
	 CALL STOP		;ERROR NO SUCH DEVICE?
	JRST [	HLRZ T1,T2	;GET LEFT HALF OF DESIGNATOR
		CAIE T1,.DVDES+.DVDSK ;IS IT A DISK?
		 CALL STOP	;NOT A DISK?
		MOVEM T2,ACCDD(ACC) ;SAVE IT FOR FNDACC.
		JRST .+1 ]
DDSMC3:	MOVX T1,R%OPR
	TDNN T1,RSBIFL(RSB)	;DID OPERATOR REQUEST THIS?
	CALL TELUSR		;NO, LET USER KNOW HE HAS STRUCTURE
	ABTREQ (ABRTNR)		;ABORT RSB WITH NO REPLY TO USER
	JRST DDSMC1
SUBTTL Update all disks -- DSTDDB - Delete STructure DDB

;  Called only by STRDSM and STRDMS

;  This routine deletes the structure DDB and sets the STR as dismounted.

;  Accepts: STR / address of SSB

;  Returns +1 always

DSTDDB:	SKIPN T1,STRPNT(STR)	;Do we have DDB entry?
	JRST DSTDD0		;No, skip this

;  Delete DDB entry and mark the structure as not mounted

	CALL DSFGET		;Yes, go get it
	 SKIPA			;Shouldn't happen
	CAME STR,DSFE+DSFPNT	;Does pointer match SSB address?
	 $STOP <Incorrect DDB pointer detected in SSB>
	SETZM DSFE+DSFPNT	;Get rid of pointer
	CALL DSFUDE		;Update entry
	 $STOP <Update of previously known DDB with DSFUDE failed>
	SETZM STRPNT(STR)	;Clear pointer

DSTDD0:	SETZRO STR%MT,STRFL1(STR) ;Clear structure mounted flag
	RET
SUBTTL Disk Routines -- DSKINI - Disk initialization routine

;ACCEPTS: NOTHING
;RETURNS: +1, ALWAYS


DSKINI:

;  Turn on interrupts for disk status changes

	MOVEI T1,33		;GET INTERRUPT CHANNEL FOR DISK
	MOVEM T1,T3		; STATUS CHANGE
	MOVE T1,[1,,.MSOFL]	;TELL MONITOR TO INTERRUPT US IF
	MOVEI T2,T3		; THERE IS DISK CHANGE
	SKIPN TSTF		;DON'T DO MSTR IF TESTING
	MSTR
	 ERCAL STOP		;Should not fail
	RET
SUBTTL Disk Routines -- DSTGIV - Get status for a given unit

;  Called only by STRMNT

;DSTGIV - GET STATUS FOR GIVEN DISK UNIT

;ACCEPTS: DSK/	ADDRESS OF DISK STATUS BLOCK
;RETURNS: +1	ERROR, INVALID UNIT
;	  +2	SUCCESS, STATUS IN MSTRBK BLOCK
;	  T1 /  Unit status returned by MSTR

DSTGIV: LOAD T1,DSKCTR,(DSK)	;GET CONTROLLER NUMBER
	LOAD T2,DSKCHN,(DSK)	;GET CHANNEL NUMBER
	LOAD T3,DSKDRV,(DSK)	;GET UNIT NUMBER
	CAIN T1,<.RTJST(-1,DOP%K2)>	;ALL ONES?
	SETO T1,		;YES, MAKE IT A FULL WORD
	MOVEM T1,MSTRBK+.MSRCT
	MOVEM T2,MSTRBK+.MSRCH
	MOVEM T3,MSTRBK+.MSRUN	;STORE VALUES FOR MSTR JSYS
	MOVE T1,[.MSRST+1,,.MSRUS] ;RETURN STATUS OF THE GIVEN UNIT
	MOVEI T2,MSTRBK		;GIVE ADDRESS OF ARGUMENT BLOCK
	MSTR
	 ERJMP R		;FAILURE RETURN
	MOVE T1,MSTRBK+.MSRST	;Get flags
	RETSKP
SUBTTL KSDK - Set disk-drive command from OPR

;KSDK - PROCESS SET DISK-DRIVE COMMAND FROM OPR
;***  NOTICE:  THIS CANNOT HANDLE RP20'S UNTIL GALAXY REDEFINES
;***  THEIR ARGUMENT BLOCK TO INCLUDE CONTROLLER NUMBERS
;Local AC use
;	Q1/New disk state. 1=unavailable  0=available
;	Q2/CKU,,Channel
;	Q3/
;RETURNS +1,	ALWAYS

KSDK:	SAVEQ
	SAVEAC <DSK>
	STKVAR <REASON>

;  Check for valid arguments

	MOVEI T1,.DSKDV
	CALL ORNBLF		;DISK DRIVE SPECIFIED?
	 JRST KBADM		;NO

	MOVE T2,0(T1)		;GET CHANNEL NUMBER
	DPB T2,[POINTR Q2,DOP%C2]	;PUT INTO AC
	MOVE T2,1(T1)		;Get controller number
	DPB T2,[POINTR Q2,DOP%K2] ;Put into AC
	MOVE T2,2(T1)		;GET DRIVE NUMBER
	DPB T2,[POINTR Q2,DOP%U2]	;STORE ALSO
	CALL DDSCIH		;MAKE SURE TABLES UP-TO-DATE
	MOVE T1,Q2		;COPY CKU NUMBER TO RIGHT AC
	CALL DSTSRC		;FIND THIS DISK DRIVE
	 JRST [	TMCT <%ICommand ignored.  Unknown %1K>	;NOT FOUND, COMPLAIN
		MOVEI T3,TMCMSG
		CALLRET BTACK]	;TELL OPERATOR NO SUCH DRIVE

;  Q1 contains the state of the disk to be changed. unavailable=1 available=0

	MOVEI Q1,1		;ASSUME SETTING UNAVAILABLE
	MOVEI T1,.DVUAV
	CALL ORNBLF		;CHECK IF SETTING UNAVAILABLE
	 JRST [ MOVEI T1,.DVAVL	;NO
		CALL ORNBLF	;SETTING AVAILABLE?
		 JRST KBADM	;NO
	        SOJA Q1,KSDK0]	;Yes, make Q1 zero and join common code

;  We are setting the disk to unavailable, get the reason block

	MOVEI T1,.ORREA
	CALL ORNBLF		;REASON BLOCK PRESENT
	 JRST KBADM		;No, bad message
	MOVEM T1,REASON		;Save the reason 

;  If a structure is mounted on this disk, set up to set the correct str bits 

KSDK0:	TMCT <%I>
	MOVE T1,DSKFLG(DSK)	;GET DISK STATUS
	TXNN T1,MS%MNT		;IS IT LOGICALLY MOUNTED?	
	JRST KSDK1		;No, skip setup stuff for set structure status
	LOAD STR,DSKSSA,(DSK)	;Get str status block address for disk drive

;  Check to see if primary PS: is mounted on this disk

	LOAD T1,MS%PPS,STRFLG(STR) ;Get the PS: bit
	JUMPN T1,KSDKER		;Error if PS:

	MOVEI T1,STRALI(STR)	;Get alias
	MOVE T2,[POINT 7,MSTAL]	;Alias goes here
	CALL SIXSEV		;Convert to asciz
	SKIPE T1,STRPNT(STR)	;Get address of DDB
	CALL DSFGET		;Get it
	  CALL STOP		;Not there, someone else must have mounted it

;  We have a structure, now see if the status is consistent with monitor

	CALL UPDSTR		;Update status

;  Find the disk entry in DDB

KSDK1:	MOVE T1,DSKPNT(DSK)	;Get the dsk pointer to DDB
	CALL DSFGET		;Go look for it
	 CALL STOP		;Not there,SHOULDN'T HAPPEN

;  T2 contains previous DSF%AV.  on if unavailable, of if unavailable

	LOAD T2,DSF%AV,DSFE+DSFFLG ;Load the available unavailable bit

	CAMN Q1,T2		;See if we have to change status? 
        JRST KSDKA		;No, no need to update DDB 
	STOR Q1,DSF%AV,DSFE+DSFFLG ;store the bit

	MOVE T1,DSKPNT(DSK)	;Get pointer to DDB entry
	CALL DSFUDE		;Go update
	 $STOP <Update of previously known DDB with DSFUDE failed>
	MOVEM T1,DSKPNT(DSK)	;In case it is updated


;  If Q1 is 0  log SYSERR for available else log for unavailable

	JUMPE Q1,[MOVEI T1,CS%ADV ;GET CODE FOR ATTACH-DEVICE
	          SETZ T2,	;NO REASON     
		  JRST KSDK2]	;Go log it
	MOVEI T1,CS%DDV		;Get code for detach-device
	MOVE T2,REASON		;Get adrress of ASCIZ reason

;  SYSSET should be called after DDB has been updated

KSDK2:	CALL SYMSET		;LOG SYSERR ENTRY FOR DRIVE SET UNAVAIL
	CALL WOMDAV		;TELL ALL OPERATORS WHAT HAPPENED

;  Check to see if a structure is mounted on this disk

	MOVE T1,DSKFLG(DSK)	;GET DISK STATUS
	TXNN T1,MS%MNT		;IS IT LOGICALLY MOUNTED?	
	RET			;NO


;  Here we want to determine what we would like STRFLG to be.  Compare that
;  with the current STRFLG value.  If they are equal, nothing to do but clean
;  up and exit.  If they are unequal, we would like to set the structure
;  to the new value and then set STRFLG appropriatly.  If we fail, analyze
;  the error.

	TMCT <%I >
	MOVE T1,STRPNT(STR)	;Get address of DDB
	CALL DSFGET		;Get it
	  CALL STOP		;Should not happen
	CALL NEWSTA		;Determine a new proposed STRFLG
	  JFCL			;Do not care if unmounted
	CAMN T1,STRFLG(STR)	;Is the proposed STRFLG anything new?	
	RET			;No.  Done.

;  Set the new strflg

	CALL STSTR		;Try to set the new strflg
	SKIPA			;Error need to do some more
	JRST KSDK4		;All done.

;  Failed to set the new strflg characteristics.  T1 contains the attempt.

	MOVE T2,STRALI(STR)	;Get structure alias
	TMCT <Unable to change structure %2S: status as part of disk operation>
	JRST KSDK5		;Send the message	

KSDK4:	MOVE T2,STRALI(STR)	;Get structure alias
	JUMPN Q1,[TMCT <Structure %2S: UNAVAILABLE due to disk operation>
	          JRST KSDK5]
	TMCT <Structure %2S: is AVAILABLE due to disk operation>	
KSDK5:	MOVEI T3,[ASCIZ/Structure status changed due to disk operation/]
	CALLRET BTWTO

;  Exit routine for setting a disk that already has that characteristic.

KSDKA:	MOVE T1,[[ASCIZ/Available/]
		[ASCIZ/Unavailable/]](Q1) ;GET TEXT POINTER
	MOVE T2,DSKCKU(DSK)		;GET UNIT ADDRESS
	TMCT <%I%2K Is Already Set %1A>
	MOVEI T3,TMCMSG
	CALLRET BTACK	;TELL OPRTR COMMAND HAS NO EFFECT

;  Exit routine for trying to set a disk drive with PS: mounted on it

KSDKER:	MOVEI T1,DSKPS		;Get error message
	TMCT <%8C%1A>
  	MOVEI T3,[ASCIZ/Set disk drive command failed/]
	CALL BTNFO		;Ask for no formatting
	CALLRET BTACKT	;TELL OPRTR COMMAND HAS NO EFFECT
SUBTTL KDSM - PROCESS DISMOUNT STRUCTURE COMMAND FROM OPR
;RBUF/
;RETURNS +1,	ALWAYS

KDSM:	CALL DDSCIH		;MAKE SURE TABLES UP-TO-DATE
	MOVEI T1,.DSMST		;GET RSB TYPE
	CALL OPRSB		;SET UP RSB FOR THIS OPR REQUEST
	 JRST KNORSB		;[6011]No RSB available
	MOVX T2,R%RNR		;Get the bit
	MOVE T1,RBUF+.OFLAG	;Get the REMOVE/NOREMOVE bit
	TXNE T1,.DMNRV		;Noremove specified ?
	JRST KDSM.1		;Do not have to set the bit
	TXNE T1,.DMRMV		;Remove specified ?
	JRST [ IORM T2,RSBIFL(RSB)	;Yes, set it 
		JRST KDSM.1]		;Skip default
	CALL CFSCHK		;Check on CFS status
	SKIPA			;Not cfs
	JRST KDSM.1		;CFS system, default to NOREMOVE
	MOVX T1,R%RNR		;Get the bit	
	IORM T1,RSBIFL(RSB)	;Set it 
KDSM.1:	MOVX T1,R%DSM		;GET DISMOUNT FLAG
	IORM T1,RSBIFL(RSB)	;AND SET INTO RSB
	SETZM RSBSTN(RSB)	;ZERO STRUCTURE NAME FOR MATCHS
	MOVEI T1,RST.WD
	STOR T1,RSBSTE		;SET STATE TO WAITING FOR DISMOUNT
	MOVE T1,RSBSTA(RSB)	;GET STRUCTURE ALIAS
	MOVE T2,RSBSTN(RSB)	;GET STRUCTURE NAME
	SETZ T4,		;No unique code
	CALL MATCHS		;MATCH REQUEST TO STRUCTURE
	 JRST KDSM.2		;[6011]Structure not mounted. nothing to do.
	STOR STR,RSBSS		;STORE THE STRUCTURE ADDR INTO RSB
	SKIPG STR		;IS STRUCTURE MOUNTED?
	IFSKP.
	 SKIPN T1,RSBOBN(RSB)	;[6016]Get node name
	  IFSKP.
           MOVEM T1,STROBN(STR)	;[6011]Save it
	   SETONE STR%OB,STRFL1(STR) ;[6011]Set bit in STRFL1
	  ENDIF.
	 MOVEI T1,RSBSTA(RSB) 	;YES, DISMOUNT IT
	 MOVE T2,[POINT 7,MSTAL]
	 CALL SIXSEV
	 CALLRET STRDMT		;Dismount the structure
	ENDIF.

KDSM.2:	CALL NSACK		;[6011]Tell Nebula or not
	MOVE T2,RSBSTA(RSB)	;Get the name
	TMCT <%IStructure %2S: is not mounted%_> ;Build common message 
	MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE STATUS/] ;Default case
	LOAD T1,R%LOR,RSBIFL(RSB) ;[6011]Get the status bit
	SKIPE T1		;[6011]Local request, use local header
KDSM.3:	MOVEI T3,[ASCIZ/REMOTE DISMOUNT STRUCTURE STATUS/] ;Else use remote
KDSM.4:	CALL BTWTO		;Tell the operator
	ABTRET (ABRTNR)		;Delete RSB and return

;[6011]
;Error routine for KDSM when MOUNTR runs out of RSBs. It will inform the
;operator of the error.  If the request is remote then a DISMOUNT
;ACK (failure ACK) is sent to NEBULA via ORION.  The content of AC RSB will
;determine whether the error is no RSB or somthing else.
;RSB/1 no RSB.
;RBUF/MESSAGE

KNORSB:	CAIE RSB,1		;[6014]We have a RSB
	RET			;[6011]No, just return
	MOVE T2,RBUF+.MSFLG	;[6011]Get the Galaxy flag word
	TXNE T2,MF.NEB		;[6011]Remote or local
	TXNN T2,MF.WTO		;[6011]Direct or indirect request
	JRST KNORS1		;[6011]Local/Indirect no need to send ACK

	MOVX T1,E%NRSB		;[6011]Error code
	TXO T1,FA%MER		;[6011]MOUNTR error type
	MOVE T2,RBUF+.MSCOD	;[6011]Remote ACK 
	CALL FAILE		;[6011]Remote, send failure
	MOVEI T1,.STRDV		;[6011]Get block type code
	CALL KGTSTR		;[6011]Get structure name
	 JRST KBADM		;[6011]Not there, reject message
	MOVE T3,T1		;[6011]Save the name
	MOVEI T1,.NDENM		;[6011]Want node name
	CALL ORNBLF		;[6011]Look for it in RBUF
	 JFCL			;[6011]None
	MOVE T4,(T1)		;[6011]Get the node name
	TMCT <%IInsufficient MOUNTR resources needed to dismount
structure%3S: for node %4S::%_>
	MOVEI T3,[ASCIZ/REMOTE DISMOUNT STRUCTURE FAILED/]
	CALLRET BTWTO		;[6011]Tell the operator

KNORS1:	TMCT <%IInsufficient MOUNTR resources needed to dismount
structure%3S:>
	MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE FAILED/]
	CALLRET BTWTO		;[6011]Tell the operator
;[6011]
;MOUNTR must send a dismount ACK back to Nebula for a remote dismount
;Checks R%LOR for local or remote request.
;If the request is a remote request then this routine will check bit R%STA
;in RSBIFL and send a success or failure dismount ACK back to Nebula.  
;RSB/ request status block

NSACK:	MOVE T1,RSBIFL(RSB)	;[6031]Get the status
	TXNN T1,R%LOR		;[6031]Local request?
	RET			;[6031]Yes, no need to tell NEBULA
	MOVE T2,RSBRAC(RSB)	;[6011]Get remote ACK
	TXNN T1,R%STA		;[6011]Success or failure?
	IFNSK.
 	 CALL SUCCE		;[6011]Success
	ELSE.
	 MOVE T1,RSBERR(RSB)	;[6011]Get error type,, error code
	 CALL FAILE		;[6011]Fail
	ENDIF.
	RET	

;SUCCE builds the success ACK
;Accepts T2/ACK code

SUCCE:	MOVE T1,[.OARGC+1,,.NFDAK] ;[6011]BUILD GALAXY HEADER
	MOVE T3,T2		;[6011]ACK code
	MOVX T2,MF.NEB		;[6011]Nebula message
	CALL GALHDR		;[6011]Build the Galaxy header
	SETONE SU%NOE,TBUF+.OFLAG ;[6011]Set the success bit 
	SETZM TBUF+.OARGC	;[6011]NO ARGUMENTS
	MOVEI T1,.APORN		;[6011]MESSAGE GOING TO ORION
	CALLRET TRANG		;[6011]SEND CANCEL REQUEST TO ORION

;FAILE builds the failure ACK
;Accepts T1/error type,,error code
;	 T2/ACK Code
;Returns +1 always

FAILE:	CALL PBINIT		;[6011]Set up for creating building blocks
	MOVE T3,T2		;[6011]Ack code in T3
	HRRZM T1,T2		;[6011]Save error code for later 
	HLLM T1,TBUF+.OFLAG	;[6031]Error indicator goes here
	MOVE T1,[.ERRSZ,,.ERRBK] ;[6011]length,, error block
	DMOVEM T1,TEMPX		;[6011]Goes here
	MOVE T1,[.OARGC+3,,.NFDAK] ;[6011]BUILD GALAXY HEADER
	MOVX T2,MF.NEB		;[6011]Nebula message
	CALL GALHDR		;[6011]Build the Galaxy header
	MOVEI T1,TEMPX		;[6011]Address of .ERRBK
	CALL PBBLK		;[6011]Add it
	MOVEI T1,1
	MOVEM T1,TBUF+.OARGC	;[6011]for this message
	MOVEI T1,.APORN		;[6011]MESSAGE GOING TO ORION
	CALLRET TRANG		;[6011]SEND CANCEL REQUEST TO ORION
E%NRSB==1B0
E%BADM==1B1

MTRERR:	[ASCIZ/Insufficient MOUNTR resources/]
	[ASCIZ/Bad IPCF message/]
SUBTTL KSCD - SHOW CONFIGURATION DISK-DRIVE COMMAND FROM OPR

;RETURN: +1,	ALWAYS

KSCD:	SETOM	CFGFLG		;Set CONFIG command flag
	CALLRET	KSHD		;Use SHOW STATUS DISK code checking for flag
SUBTTL KSHD - SHOW DISK STATUS COMMAND FROM OPR

;RETURN: +1,	ALWAYS

KSHD:	SAVEQ

	SETZM DSPFLG		;Start of clean, no special messages yet
	CALL DDSCIH		;MAKE SURE TABLES UP-TO-DATE
	TMCT <%I>

;  Q3 is a flag which indicates the kind of display
;  -1=all disk drives.  0=free disk drives.  1=mounted disk drives.

	SETO Q3,		;Say it is for all drives, for now
	MOVE Q1,RBUF+.OFLAG	;GET COMMAND TYPE
	CAMN Q1,[ST.MNT]	;IS IT ASKING FOR MOUNTED DISKS?
	JRST [CALL KSHDM	;Yes, print the mounted header
		MOVEI Q3,1	;Say it is for mounted drives
		JRST KSHDA]	;Go join common stuff for STATUS
	CAMN Q1,[ST.AVA]	;WERE WE ASKED ONLY FOR FREE DRIVES?
	JRST [CALL KSHDF	;Yes, print the free header
		SETZ Q3,	;Say it is for free drives
		JRST KSHDA]	;Go join common stuff for STATUS
KSHDA:	MOVEI T1,DSKHDR		;Get common header for STATUS
	SKIPE CFGFLG		;Unless it is from CONFIG...
	MOVEI T1,CFGHDR		;Get common header for CONFIG
	TMCT <%1A>

;  Loop through all disk drives in DDB
	
KSHDA1:	MOVEI T1,.DVDSK		;Get the disk type
	MOVEM T1,DSFE+DSFTYP	;Save it in DSFE
	SETZ T1,		;Go for the first
KSHDA2:	CALL DSFGNX		;Go get an entry
	 JRST KSHDE		;No more, go do mounted disk if needed
	PUSH P,T1		;Save pointer
	SKIPN DSK,DSFE+DSFPNT	;Get disk status block address
	JRST KSHDA4		;Not there, not in use, skip this entry
	LOAD T1,MS%MNT,DSKFLG(DSK) ;Get mount bit
	SKIPN T1		;Is it mounted?
	JRST [SKIPG Q3		;No, are we asking for mounted drives only?
	       CALL WOFRE	;No, display the unit's status.
              JRST KSHDA4]	;Get the next disk drive.
	SKIPE Q3		;Are we asking for free drives?
	 CALL WOMNT		;No

;  Before we get the next disk make sure that DSFE contains the correct type

KSHDA4:	MOVEI T1,.DVDSK		;Get the disk type
	MOVEM T1,DSFE+DSFTYP	;Save it in DSFE
	POP P,T1		;Get the pointer back
	JRST KSHDA2		;Get the next

KSHDE:	CALL DSKDSP		;Print any special messages

KSHDEX:	MOVEI	T3,[ASCIZ/Disk Drive Status/]
	SKIPE	CFGFLG
	 MOVEI	T3,[ASCIZ/Disk Drive Configuration/]
	SETZM	CFGFLG		;Re-set CONFIG command flag
	CALL	BTNFO		;ASK FOR NO FORMATTING
	MOVE T4,RBUF+.MSFLG	;[6010]Get the message flag word
	TXNE T4,MF.NEB		;[6010]From NEBULA
	SETOM NEBMSG		;[6010]Yes
	CALLRET	BTACKT		;END OF DISKS, SEND STATUS TO OPR

KSHDM:	MOVEI T1,MNTHDR		;Get header for mounted drives
	SKIPA			;Only wanted mounted header
KSHDF:	MOVEI T1,FREHDR		;GET HEADER FOR MOUNTED DRIVES
	TMCT <%1A>
	RET
SUBTTL - DSKDSP - Print any special messages
;Accepts - Nothing
;Returns +1 always

DSKDSP::MOVE T1,DSPFLG		;Get the display message flag
	TXNN T1,MSG%AN		;Any disk to print 
	JRST [TMCT <%I%15CCurrently there are no free disk drives%_>
	      JRST DSKDEX]	;No
	TXNE T1,MSG%CI		;Any channel 7 CI disks?;
	CALL [TMCT <%7CNOTE: Channel 7 indicates CI channel%_>
	      RET]
	TXNE T1,MSG%DU		;Any dual ported disks
	CALL [TMCT <%7C(*) indicates potential external port%_>
	      RET]
	TXNE T1,MSG%FR		;Any free drives
	CALL [TMCTI <FREEH>
	      RET]

DSKDEX:	RET
SUBTTL KSHS - SHOW STATUS STRUCTURE command from OPR

;  Returns: +1 always

KSHS:	SAVEQ
	CALL DDSCIH		;First go update things
	SETZM DSPFLG		;Clear display flags 
	TMCT <%I>

	MOVEI T1,.STRDV		;GET BLOCK TYPE CODE
	CALL KGTSTR		;GET STRUCTURE NAME
	 SKIPA			;Not there, go do all purpose display
	JRST SHSTR		;Go display the particular structure and skip
				; this stuff

;  Q3 is a flag which indicates the kind of display
;  -1=all disk drives.  0=free disk drives.  1=mounted disk drives.

	SETO Q3,		;Say it is for all drives, for now
	MOVE Q1,RBUF+.OFLAG	;GET COMMAND TYPE
	CAMN Q1,[ST.MNT]	;IS IT ASKING FOR MOUNTED DISKS?
	JRST [CALL KSHSM	;Yes, print the mounted header
		MOVEI Q3,1	;Say it is for mounted structure
		JRST KSHSA]	;Go join common stuff
	CAMN Q1,[ST.AVA]	;WERE WE ASKED ONLY FOR FREE DRIVES?
	JRST [CALL KSHSF	;Yes, print the free header
		SETZ Q3,	;Say it is for dismounted structure 
		JRST KSHSA]	;Go to join common code



KSHSA:	MOVEI T1,STRHDR
	TMCT <%1A>
	SETZ T1,		;Go for the first one

	MOVEI T2,.DVSTR		;Get structure type
	MOVEM T2,DSFE+DSFTYP	;Set it

KSHS.0:	CALL DSFGNX		;Go get an entry
	  JRST KSHS.9		;Done
	PUSH P,T1		;Save the pointer

;  What do we want to print out

	SKIPN STR,DSFE+DSFPNT	;Structure mounted?
	JRST [SKIPG Q3		;No, are we asking for mounted drives only?
	      CALL SHWSTR	;No, display the unit's status.
	      JRST KSHS8]	;Yes, get the next
	SKIPE Q3		;Yes, Can this drive be printed
	CALL SHWSTR		;Yes, output structure status

KSHS8:	MOVEI T2,.DVSTR		;Get structure type
	MOVEM T2,DSFE+DSFTYP	;Set it
	POP P,T1		;Get back the pointer
	JRST KSHS.0		;Go for another

KSHS.9:	CALL STRDSP		;Go print any special messages


KSHSEX:	MOVEI T3,[ASCIZ/Structure Status/]
	CALL BTNFO		;No formatting
	MOVE T4,RBUF+.MSFLG	;[6010]Get the message flag word
	TXNE T4,MF.NEB		;[6010]From NEBULA
	SETOM NEBMSG		;[6010]Yes
	CALL BTACKT		;Send status
	RET			;And done
SUBTTL STRDSP - Print any special messages
;Accepts - nothing

STRDSP:	MOVE T1,DSPFLG		;Get the display message flag
	TXNN T1,MSG%AN		;Any disk to print 
	JRST [TMCT <%I%15CCurrently there are no unmounted structures%_>
	      JRST STRDEX]	;No

	TXNE T1,MSG%CO		;Conflict messge?
	CALL [MOVEI T2,CONFLI	;Get the message 
	      TMCT <%2C%2A>	;Print it
	      RET]
STRDEX:	RET
SUBTTL SHSTR - Show status for a particular structure

;Accepts - T1/Structure name in sixbit
;	 - T2 and T3/Structure name in ASCIZ

SHSTR:	SAVEQ

	DMOVEM T2,MSTAL		;Save the ASCIZ structure name
	MOVEM T1,DSFE+DSFSPC	;Save the SIXBIT structure name
	MOVEI T1,.DVSTR		;Get structure type
	MOVEM T1,DSFE+DSFTYP
	CALL DSFLOC
	 JRST [MOVEI T1,MSTAL	;No entry, must not be mounted
	      TMCT <%20CNo such Structure %1A:%_>
	      JRST SHEX]	;Go to common exit

;  Print the structure information on this structure

	MOVEI T1,STRHDR		;Get all purpose header
	TMCT <%1A>		;Add it to display
	CALL SHWSTR		;Print structure information first
	CALL STRDSP		;Go print any special messages

;  Print the disk information on this structure

	JUMPE STR,[TMCT <%_Structure is not mounted on a disk drive%_>
	      JRST SHEX]		;If structure is not mounted, all done
	CALL [TMCT <%_%10CDisk information pertaining to mounted structure>
	      RET]
	MOVEI T1,DSKHDR		;Get all purpose disk header
	TMCT <%1A>		;Add it to the display

;  Loop through all the disks on which this structure is mounted on.

	LOAD Q3,STRUNI,(STR)	;Get the number of units
	MOVNS Q3		;Negate number of units
	MOVSS Q3		;And switch halves
	HRRI Q3,STRADD(STR)	;Setup address of first disk status block

SHS.0:	MOVE DSK,(Q3)		;Get the disk address
	JUMPE DSK,SHS.01	;No DSB, try next
	MOVE T1,DSKFLG(DSK)	;Get the status of the disk
	TXNE T1,MS%MNT		;Is it mounted?
	JRST [CALL WOMNT	;Yes, display the unit's status.
	      JRST SHS.01]	;Get the next.
	CALL WOFRE		;No, display the unit's status.

SHS.01:	AOBJN Q3,SHS.0		;Get the next disk
SHS.02:	CALL DSKDSP		;Print any special messages
	JUMPLE STR,SHEX		;Structure is not mounted

;  Get list of users on structure

	MOVE T1,[POINT 7,MSTAL]	
	MOVEM T1,MSTRBK+.MSUAL	;Put alias in mstr block 
	MOVX T1,MS%GTA+MS%GTM+MS%GTC ;We want all users
	MOVEM T1,MSTRBK+.MSUFL	;Put it in mstr block 
	MOVE T1,[50,,.MSGSU]	;
	MOVEI T2,MSTRBK	
	MSTR
	 ERJMP SHSERR
	HRRZ Q1,MSTRBK+.MSUFL	;Get number of users currently using this str
	JUMPE Q1,[TMCT <There are currently no users using this structure%_>
	          JRST SHEX]	;No users all done

;  Initialize some things

	SETZM USRLST
	MOVE T1,[USRLST,,USRLST+1] ;Zero out the user list
	BLT T1,USRLST+USRSIZ-1

	MOVEI Q3,USRLST+1	;Get the beginning of the user list

	MOVEI Q2,MSTRBK+.MSUJ1	;Get the address of first user

;  Get ready to do GETJI and add users on to the list.

SHS.1:	HRRZ T1,(Q2)		;Get the job number
	MOVE T2,[-1,T4]		;Lets save the job user number in T4
	MOVEI T3,.JIUNO		;We only want the job user number
	GETJI
	 ERJMP SHSERR
	MOVEI T1,1		;Looking at the first user entry
	MOVEI T3,1		;Use T3 as an index to the current user list

;  Loop through user list to see if user already exist.

SHS.2:	CAMLE T1,USRLST		;Are we at the end of the list
	JRST SHS.3		;Yes 
	CAMN T4,USRLST+USRNUM(T3) ;Is it in the table?
	JRST SHS.4		;Yes, get the next
	AOS T1			;Increment counter
	ADDI T3,USRENT		;Go to the next entry 
	JRST SHS.2

;  User is not on list, add user

SHS.3:	HLLZ T2,(Q2)		;Get the mounted/connected/access bit
	MOVEM T2,USRBIT(Q3)	;Save it in the first word
	MOVEM T4,USRNUM(Q3)	;Save the job user number in the second word
	ADDI Q3,USRENT		;Now the next entry
	AOS USRLST		;One more user using this structure
	JRST SHS.5		;Next

;  Same user but is it the same usage

SHS.4:	LOAD T2,MS%GTM,(Q2)	;Get the mounted bit
	SKIPE T2		;Not mounted
	STOR T2,MS%GTM,USRLST+USRBIT(T3) ;Mounted, include it for this user
	LOAD T2,MS%GTC,(Q2)	;Get the connected bit
	SKIPE T2		;Not connected
	STOR T2,MS%GTC,USRLST+USRBIT(T3) ;Connected, include it for this user
	LOAD T2,MS%GTA,(Q2)	;Get the connected bit
	SKIPE T2		;Not access
	STOR T2,MS%GTA,USRLST+USRBIT(T3) ;Access, include it for this user
			
SHS.5:	AOS Q2			;Point to the next user
	SOJG Q1,SHS.1		;Jump if more

;  Check each user to see what their usages are.

	TMCT <%_Users who have MOUNTed this structure:%_>
	MOVX T3,MS%GTM		;Show users who have mounted this structure
	CALL SHSMAC		;Add users to message
	CALL [TMCT <None.%_>
	      RET]
	TMCT <%_Users who are ACCESSing this structure:%_>	
	MOVX T3,MS%GTA		;Show users who are connected to this structure
	CALL SHSMAC		;Add users to message
	CALL [TMCT <None.%_>
	      RET]
	TMCT <%_Users who are CONNECTed to this structure:%_>	
	MOVX T3,MS%GTC		;Show users who are connected to this structure
	CALL SHSMAC		;Add users to message
	CALL [TMCT <None.%_>
	      RET]

SHEX:	JRST KSHSEX		;All done

;  Error routine for JSYS when doing SHSTR

SHSERR:	TMCT <%_Can't determine users using this structure because of the following error: %_%J>
	JRST SHEX		;Go to common exit
SUBTTL SHSMAC - Adds a user who has mounted or connected or accessing a structure to the SHO STA STR FOO: command.

;Accepts - T3/Usage bit (MS%GMT,MS%GTA,MS%GTC)
;Returns - +1 No users 
;	 - +2 with users added on to display

SHSMAC:	MOVE Q2,USRLST		;Get the number of users using this structure
	MOVEI Q3,USRLST+1	;Get the address of user list
	SETO T4,		;Flag to indicate whether we have a user
SHSM.1:	HLLZ T2,USRBIT(Q3)	;Get the user's usage of structure.
	AND T2,T3		;Get the bit that we are interested in 
	SKIPN T2		;If set, user belongs to this list
	JRST SHSM.6		;User does not belong to this list
	MOVE T2,USRNUM(Q3)	;Get the job user number
	HRROI T1,DIRNAM		;Put the string here
	DIRST
	 ERJMP SHSMEX
	CALL TMCNT		;Get the current location in the line
	MOVE Q1,[POINT 7,DIRNAM] ;Pointer to user name

SHSM.2:	ILDB T1,Q1		;Get the character
	SKIPN T1		;End of string
	JRST SHSM.3		;Yes, all done
	AOS T2			;Add another character
	JRST SHSM.2		;Get the next character	

SHSM.3:	MOVEI T1,DIRNAM		;Get the user name
	CAIL T2,^D78		;Can we add it to this line (78 , and space)
	JRST [TMCT <,%_%1A>	;No, start at new line
	      JRST SHSM.6]	;and continue
	SKIPE T4		;The first user?
	JRST [TMCT <%1A>	;Yes
	      SETZ T4,		;Say we have at least one user therefore
	      JRST SHSM.6]	; The next user should have a , and a space
	TMCT <, %1A>	 	;No, lets add a comma and a space to message


SHSM.6:	ADDI Q3,USRENT		;Point to the next user
	SOJG Q2,SHSM.1 		;If we have more

SHSMEX:	SKIPE T4		;Do we have at least one user?
	RET			;No 
	TMCT <.%_>		;Finish off the line
	RETSKP			;We have at least one user
SUBTTL SHWSTR - Show status for a single structure

;  Accepts: DSFE containing DDB for structure

SHWSTR:	SAVEQ

;  Q2 contains the structure status from DDB

	MOVE Q2,DSFE+DSFFLG	;Save the status flag
	MOVX T2,MSG%AN		;Get bit to say we have at least one
	IORM T2,DSPFLG		;Say we have one
	MOVE T1,DSFE+DSFSPC	;Get the alias
	TMCT <%1S >
	SKIPN STR,DSFE+DSFPNT	;Do we have SSB?
	JRST SHW0		;No, continue
	MOVE T1,STRNAM(STR)	;Get name
	TMCT <%8C%1S >
	JRST SHW0.1		;skip this if DDB has a SSB

;  Structure might have SSB but no DDB link.

SHW0:	SETZ T2,		;Don't have structure name. T1 has the alias
	SETZ T4,		;Don't have unique code
	CALL MATCHS		;Do we have a SSB for this structure
	JFCL			;No, STR should be zero

;  If STR/0 structure is not mounted, STR/less than 0 means structure is 
;  spinning or being dismounted, STR/ greater than 0 means mounted.

SHW0.1:	SKIPG STR		;Again do we have SSB?
	JRST SHW1		;No, not mounted

	MOVE Q1,STRFL1(STR)	;Get flags
	TXNN Q1,STR%MT		;Mounted?
	JRST SHW1		;No, not mounted

	TMCT <%15CMounted >

;  Print the mount count

	MOVE T2,[POINT 7,MSTAL];SET UP POINTER FOR ALIAS
	MOVEI T1,STRALI(STR)
	CALL SIXSEV		;CONVERT SIXBIT ALIAS TO NEEDED 7-BIT
	MOVEI T1,MSTAL		;Get address of alias
	CALL STRSTT		;Go get the status
	 JRST SHW1		;NO STRUCTURE?
	TMCT <%24C%3D>		;Print the mount count

;  Open file count field

	TMCT <%30C%4D>		;Print the open file count

SHW1:	TMCT <%35C>

	SKIPG STR		;Mounted?
	JRST SHW2		;No, no need to check for conflicting status
	CALL NEWSTA		;Get the real status
	 JFCL			;Shouldn't really happen
	XOR T1,STRFLG(STR)	;Get the changed bits

;  T1 contains the conflicting bits if structure is mounted, else there is no 
;  check for conflict.

	TXZ T1,MS%NTC		;Get rid of don't care bits

SHW2:	TXNE Q2,DSF%IG		;Ignored for real?
	JRST [TMCT <Ignored>	;Assume ignored
	      JRST SHW3]	;Skip avail/unavailable

	TXNE Q2,DSF%AV		;Unavailable for real?
	JRST [TMCT <Unavail>	;Assumption
	      JRST SHW2.1]
	TMCT <Avail>		;No 

SHW2.1:	SKIPG STR		;Mounted?
	JRST SHW3		;No

	TXNE T1,MS%DIS		;Is the available/unavailable bit in conflict?
	CALL SHWCON		;Yes print * and set bit in display flag word

SHW3:	TXNE Q2,DSF%EX		;Exclusive for real?
	JRST [TMCT <%44CExclusive> ;Assume exclusive
	      JRST SHW3.1]
	TMCT <%44CShared>

SHW3.1:	SKIPG STR		;Mounted?
	JRST SHW3.2		;No

	TXNE T1,MS%EXC		;Is the exclusive/shared bit in conflict?
	CALL SHWCON		;Yes print * and set bit in display flag word

SHW3.2:	SKIPG STR		;Mounted?
	JRST SHW3.3		;No
	MOVE T2,STRFLG(STR)	;Get flags
	TXNN T2,MS%PS!MS%BS	;[6001]Is either bit lit?
	JRST SHW3.3		;[6001]No.
	TXNE T2,MS%PS		;[6001]At least one lit. Is MS%PS lit
	TXNN T2,MS%BS		;[6001] along with MS%BS?
	IFSKP.			;[6001]If both are lit...
	  TMCT <%55C## Primary Public Str. ##> ;[6001]Both. Old message
	ELSE.			;[6001]If only one..
	  TXNN T2,MS%PS		;[6001]Is MS%PS lit?
	  IFSKP.		;[6001]If yes...
	    TMCT <%55C## Login Structure ##> ;[6001]Login Structure
	  ELSE.			;[6001]Then must be MS%BS
	    TMCT <%55C## Boot Structure ##> ;[6001]Boot structure
	  ENDIF.		;[6001]
	ENDIF.			;[6001]
	JRST SHW4		;[6001]Go to common exit

SHW3.3:	TXNE Q2,DSF%DO		;Domestic for real?
	JRST [TMCT <%55CDomestic> ;Assume domestic 
	      JRST SHW3.4]
	TMCT <%55CForeign>

SHW3.4:	SKIPG STR		;Mounted?
	JRST SHW3.5		;No, no need to check for conflict

	TXNE T1,MS%DOM		;Is the domestic/foreign bit in conflict?
	CALL SHWCON		;Yes print * and set bit in display flag word


SHW3.5:	TXNE Q2,DSF%RG		;Regulated for real?
	JRST [TMCT <%65CUnregulated>	;Assume regulated
	      JRST SHW3.6]
	TMCT <%65CRegulated>

SHW3.6:	SKIPG STR		;Mounted?
	JRST SHW4		;No
	TXNE T1,MS%NRS		;Is the regulated/unregulated bit in conflict?
	CALL SHWCON		;Yes print * and set bit in display flag word

;  Before we check for disk status, make sure there is a SSB

SHW4:	TMCT <%_>		;End the line
	TXNE Q2,DSF%DP		;[6007]DUMPABLE?
	CALL [TMCT <%4CStructure is Dumpable%_> ;[6007]Yes
	      RET]		;[6007]
	JUMPE STR,SHWSEX	;No SSB means all done
	MOVE Q1,STRFL1(STR)	;Get mount state
	TXNE Q1,STR%DT		;Is structure being dismounted
	CALL [MOVE T1,STRALI(STR) ;Get the alias
              TMCT <%4CCan't use structure %1S: - structure being dismounted%_>
	      RET]
	TXNE Q1,STR%UD		;[335]Is structure unavail due to dismount?
	TMCT <%4CStructure is set unavailable due to dismount%_> ;[335]
	TXNE Q1,STR%EP		;[335]Is str exclusive due to port operation?
	TMCT <%4CStructure is exclusive due to port operation%_> ;[335]
	TXNE Q1,STR%OB		;[6011]Dismount on behalf of another node?
	CALL [MOVE T1,STROBN(STR) ;[6011]Get "on behalf node name"
	      TMCT <%4CStructure is dismounted on behalf of %1S::%_>
	      RET]
	MOVE T1,STR		;Get the SSB address
	CALL CHKAVA		;Is the disk available/unavailable
	CALL [SKIPN T1,STRALI(STR) ;Structure might not be mounted
	      MOVE T1,STRNAM(STR) ;Use structure name
		TMCT <%4CCan't use structure %1S: - drive is unavailable for system use%_>
		RET]		
	MOVE T1,STRFLG(STR)	;[6006]Get the structure flag
	TXNE T1,MS%OFS		;[6006]Offline due to outstanding IORB?
	CALL [MOVE T1,STRALI(STR) ;[6006]Get the alias
	      TMCT <%4CCan't use structure %1S: - structure is offline%_>
	      RET]
SHWSEX:
	RET
SUBTTL - SHWCON -- Indicates structure status conflicts


;Accepts nothing
;Returns +1 always

SHWCON: SAVET
	TMCT <*>		;Yes
	MOVX T1,MSG%CO		;Get the CONFLICT MESSAGE BIT
	IORM T1,DSPFLG		;Set it so it can be printed 
	RET

;  Routine to print the correct header

KSHSM:	MOVEI T1,MNTSTR		;Get the mounted structure header
	SKIPA			;We want mounted header not free header
KSHSF:	MOVEI T1,FRESTR		;Get the free structure header
	TMCT <%1A>
	RET
SUBTTL Process set structure (KSST) -- Initialize processing of command

;ACCEPTS: MRPDB, RBUF/ PDB AND MESSAGE FROM OPR
;	  +1,	ALWAYS

KSST:
;  Do some initial validation

	CALL DDSCIH		;MAKE SURE TABLES UP TO DATE
	MOVEI T1,.STRDV		;GET BLOCK TYPE CODE
	CALL KGTSTR		;GET STRUCTURE NAME
	 JRST KBADM		;NOT THERE, REJECT MESSAGE
				; wrong routine, calling BADOM probably better
	MOVEM T1,DSFE+DSFSPC	;Save the sixbit structure name
	DMOVEM T2,MSTAL		;STORE ASCII STRUCTURE NAME	
	MOVEI T1,.STCHR
	CALL ORNBLF		;WAS A CHARACTERISTIC SPECIFIED?
	 JRST KBADM		;NO, REJECT MESSAGE
	MOVE Q3,(T1)		;Save the characteristic for later

;  Lets see what we have in the DDB for this structure

	MOVE T1,DSFE+DSFSPC	;Get the alias back
	CALL ISTDDB		;Go try to create DDB entry based on alias
	  JFCL			;What a suprise, we already have it!
				;  DSFE now contains the correct stuff
	MOVE Q1,T1		;Save the pointer to the DDB for later

;  Update status of structure if needed

	CALL UPDSTR		;Go do it

;  Find the characteristic.

	HRLZI Q2,-CHRTL		;Form index into CHRTBL
KSST.1:	HLRZ T1,CHRTBL(Q2)	;Get characteristic
	CAMN Q3,T1		;Found characteristic?
	JRST KSST.2		;Yes, go process characteristic
	AOBJN Q2,KSST.1		;No, go try next
	JRST KBADM		;NO SUCH CHARACTERISTIC, REJECT MESSAGE
				; wrong routine, calling BADOM probably better

;  Continued on next page
SUBTTL Process set structure (KSST) -- Set the database (DDB)

;  Continued from preceeding page

KSST.2: STKVAR <SAVPNT>		;[6011]Save DDB pointer
	TMCT <%I >		;Initialize the operator message

;  Found characteristic to be set.  Check the attributes of the set with
;  existing attributes.

	MOVE T1,Q1		;Get pointer to DDB
	CALL DSFGET		;Get DDB
	  CALL STOP		;Should not happen

	MOVEM T1,SAVPNT		;Save DDB pointer
	HRRZ Q2,CHRTBL(Q2)	;Get address of attributes
	MOVE T1,(Q2)		;Get the bit
	AND T1,DSFE+DSFFLG	;Get rid of everything but the bit in question
	HLRZ T2,1(Q2)		;Get on/off flag
	SKIPE T1		;Equal to zero?
	MOVEI T1,1		;No, bit is set
	CAME T1,T2		;Compare for both on or off
	JRST KSST.3		;Not equal, need to do some setting

;  Here the characteristic is already correctly set in DDB.
;  Add error message.

	CAIE Q3,S.SHAR		;[6017]Shared?
	IFSKP.
	 MOVE T1,DSFE+DSFFLG	;[6017]Get the flag word again
	 MOVEM T1,STRFL2(STR)	;[6017]Save IT
	 JRST KSST.S		;[6017]Yes, have to do some work
	ENDIF.			;[6017]
	MOVEI T1,MSTAL		;Get structure alias
	HRRZ T2,1(Q2)		;Get ASCII attribute
	TMCT <Structure %1A already set %2A%_>
	JRST KSSEN1		;Go and finish up

;  Set new characteristic in DSFFLG, but don't write it back on disk until
;  the characteristic is set.

KSST.3:	MOVE T1,DSFE+DSFFLG	;Get the flag word again
	SKIPE T2		;Want to set the bit?
	 TDOA T1,(Q2)		;Yes, do it and skip next
	TDZ T1,(Q2)		;No, clear the bit
	MOVEM T1,DSFE+DSFFLG	;Put value back

;  Continued from previous page
;  Now want to determine the correct structure status block

	TXNE T1,DSF%IG		;Is it IGNORED?
	JRST [TMCT <Structure is currently set IGNORED.%_>
	      TMCT <Attributes will be applied when 
structure is set to ACKNOWLEDGED.%_>
	      JRST KSSEND]	;Yes
	SKIPG STR,DSFE+DSFPNT	;Do we have SSB?
	JRST KSSEND		;No.  Done.
	MOVE T1,STRFL1(STR)	;Get other structure flags
	TXNN T1,STR%MT		;Structure mounted?
	JRST KSSEND		;No.  Done.
	MOVE T2,DSFE+DSFFLG	;[6011]Get value back
	MOVEM T2,STRFL2(STR)	;[6011]Save IT
	TXNN T1,STR%UD		;Structure unavailable due to dismount?
	JRST KSST.6		;No

;  Structure is in the process of being dismounted

	CAIN Q3,S.AVAL		;Setting available?
	JRST KSSEN2		;Yes, cannot do it right now

;  Set the new strflg

KSST.6:	CALL NEWSTA		;Get the proposed STRFLG
	 JRST KSST.4		;Not mounted
	CALL STSTR		;Try to set the new strflg
	 JRST KSSERR		;Failed. find out if it was set exclusive
	JRST KSST.4		;[6011]No
;  Setting a structure from exclusive to shared
;tbd  This might not ever happened
KSST.S:	CALL UNSEXC		;Unlock the structure

;Get RSB
;[6011]

 	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	CALL PRQPID		;CLEAN UP REQUEST QUEUE FIRST

KSST.7:	CALL QMSCAN		;GET ADDRESS OF NEXT RSB
	 JRST KSST.4		;No more all done
	MOVEI RSB,-RSBLNK(T2)	;Load RSB ac
	LOAD T1,RSBTYP		;Get type
	CAIE T1,.DSEXC		;Exclusive
	JRST KSST.7		;No,, continue scan
	MOVE T1,RSBSTA(RSB)	;Get the alias
	CAME T1,STRALI(STR)	;Are they the same
	JRST KSST.7		;No, get the next
	MOVE T1,RSBIFL(RSB)	;Get request status flag
	MOVE T2,STRFL1(STR)	;Get structure status flag
	TXNN T1,R%SDM		;Did this request send a remote dismount?
	IFSKP.			;Yes,
	 TXNN T2,STR%LD		;Are there any pending dismount/remove request
	 CALL NEBCAN		;No, tell Nebula to cancel
	ENDIF.
	ABTREQ (ABRTNR)		;Delete RSB and return

KSST.4:	MOVE T1,Q1		;Get the pointer to the structure entry in DDB
	CALL DSFGET		;Get the entry
	 $STOP <Structure entry not in DDB>
	MOVE T1,STRFL2(STR)	;[6011]Get the new STRFLG
	MOVEM T1,DSFE+DSFFLG	;Put it the status word
SUBTTL Process set structure (KSST) -- Set structure correctly in monitor

;  All is done write DDB back on disk and tell operator of success.

KSSEND:	MOVE T1,Q1		;Get pointer to DDB back
	CALL DSFUDE		;Update entry
	 $STOP <Update of previously known DDB with DSFUDE failed>
	HRRZ T1,1(Q2)		;Get address of string indicating change
	MOVEI T2,MSTAL
	TMCT <Structure %2A: set %1A>

;  Here we want to output messages.

KSSEN1:	MOVEI T3,[ASCIZ/Set Structure Command/] ;Header line for message
	CALL BTACKT		;Send the message we built with TMCT
	RET
SUBTTL	SET Structure EXCLUSIVE failure.  Send remote dismount

;[6011]
;  Failed to set the new strflg characteristics.  T1 contains the attempt.
;  Check to see if the failure was due to a SET EXCLUSIVE.  If so, we have
;  to send a remote dismount to all the systems that have the structure mounted
;  
;Accepts T1/error type

KSSERR:	CAIE T1,-1		;Is the error exclusive?
	JRST KSSER		;No
	MOVEI T1,.DSEXC		;Set up exclusive switch request
	CALL OPRSB		;Get RSB
	 JRST [TMCT <%IFailed to acquire RSB for exclusive procedure>
	       MOVEI T3,[ASCIZ/SET STRUCTURE COMMAND/] 
	       CALLRET BTACKT]	;Error abort
	MOVE T1,RBUF+.MSCOD	;[6014]Get operator's PID
	MOVEM T1,RSBPID(RSB)	;[6014]Save it for later
	STOR STR,RSBSS		;[6011]Save SSB address in RSB
	SKIPE ENQFLG		;[6011]Cluster ENQ enabled?
	JRST KSSER		;No
KSSER1:	CALL GETLOC		;[6011]Lock the structure
	 JRST [CALL WHOENQ	;[6011]Failed, find out who has it
	       JRST KSSER1	;[6011]No one lets try again
	       MOVEI T3,[ASCIZ/SET STRUCTURE COMMAND/]
	       CALLRET BTACKT]	;[6011]failed
	MOVEI T1,KSSTEX 	;[6011]Get continue address for success
	MOVEM T1,RSBCON(RSB)	;[6011]Save it
	MOVEI T1,KSSTAB		;[6014]Get continue address for abort
	MOVEM T1,RSBABO(RSB)	;[6011]Save it
	JRST SCREQ1		;[6011]Failed get cfs compliance

;Upon receiving the dismount ACK, KSSTEX will setup MOUNTR in the correct
;context.  DSFE must be setup with the correct structure DDB, Q1 must have
;the pointer to the DDB, Q2/EXCLUSIVE entry in CHRTBL, RBUF+.MSCOD contains
;the operator PID.

;Accepts RSB and STR

KSSTEX:	TMCT <%I>		;[6014]Initialize TMCMSG
	MOVE T1,RSBPID(RSB)	;[6014]Get the operator PID
	MOVEM T1,RBUF+.MSCOD	;[6014]Save it
	MOVE Q1,STRPNT(STR)	;[6014]Get address of DDB
	SKIPE T1,Q1		;[6014]Get address of DDB
	CALL DSFGET		;Setup DSFE
	 JRST KSSTE1		;[6014]Not here, must have been deleted

;  Set up Q2 to contain CHRTBL attributes

	HRR Q2,CHRTBL+3		;[6014]Get the ASCIZ for EXCLUSIVE

;RSB,STR and DSFE must be setup

	CALL NEWSTA		;Get status 
	 JRST KSSTE1		;[6014]Not mounted, clean up
	TXO T1,MS%EXC		;[6014]Lite the EXCLUSIVE bit
	CALL STSTR		;Try to set the new strflg
	 JRST [CAIN T1,-1	;Failed. find out if it was set exclusive
	       CALLRET KSSER1	;Yes, try again
	       JRST KSSER]	;[6014]No clean up

;  Finaly, we set the structure exclusive.

	CALL UNSEXC		;[6014]Unlock 
	HRR Q2,CHRTBL+3		;[6014]Get the entry for EXCLUSIVE
	JRST KSST.4		;[6014]Go join common success exit

KSSTE1: CALL UNSEXC		;[6014]Unlock 
	JRST KSST.4		;[6014]All done 	

KSSTAB:	CALL UNSEXC		;[6014]Unlock 
	RET			;[6016]Just return
SUBTTL	Error handler for SET EXCLUSIVE

KSSER:	MOVEI T2,MSTAL		;Get the alias
	HRRZ T3,1(Q2)		;Get the characteristic that failed
	TMCT <Can't set structure %2A: %3A%_>
	CALL GETERR		;Get the last error
	TMCT <- error - %1J>
	JRST KSSEN1		;Go send the message

KSSEN2:	TMCT <Dismounted currently in progress.%_>
	HRRZ T1,1(Q2)		;Get address of string indicating change	
	TMCT <Structure attribute %1A will be applied 
at completion of dismount.%_>
	JRST KSST.4		;[6014]Join common routine
SUBTTL KSST -- Data base for setable characteristics

COMMENT /
  CHRTBL contains characteristic to be changed in the left half and address
of attributes in the right half.  The first attribute is the bit in the
structure DDB flag word.  The left half of the second word indicates whether
the bit is on or off.  Finally the right half of the second attribute word
contains a pointer to the ASCIZ string describing the characteristic.
/

CHRTBL:	S.ACKN,,[DSF%IG
		0,,[ASCIZ/ACKNOWLEDGED/] ]
	S.AVAL,,[DSF%AV
		0,,[ASCIZ/AVAILABLE/] ]
	S.DOMS,,[DSF%DO
		1,,[ASCIZ/DOMESTIC/] ]
	S.EXCL,,[DSF%EX
		1,,[ASCIZ/EXCLUSIVE/] ]
	S.FORN,,[DSF%DO
		0,,[ASCIZ/FOREIGN/] ]
	S.IGNO,,[DSF%IG
		1,,[ASCIZ/IGNORED/] ]
	S.REGU,,[DSF%RG
		0,,[ASCIZ/REGULATED/] ]
	S.SHAR,,[DSF%EX
		0,,[ASCIZ/SHARED/] ]
	S.UAVL,,[DSF%AV
		1,,[ASCIZ/UNAVAILABLE/] ]
	S.UREG,,[DSF%RG
		1,,[ASCIZ/UNREGULATED/] ]
	S.DUMP,,[DSF%DP				;[6002]
		1,,[ASCIZ/DUMPABLE/] ]		;[6002]
	S.NODP,,[DSF%DP				;[6002]
		0,,[ASCIZ/NONDUMPABLE/] ]	;[6002][6003]

CHRTL==.-CHRTBL

;UNSEXC - Unlock structure due to reversing SET EXCLUSIVE

UNSEXC: MOVE T1,STRFL1(STR)	;[6011]Get flag
	TXZN T1,STR%LE		;[6011]Is it locked for set exclusive?
	IFSKP.
	 TXNN T1,STR%LD		;[6011]Yes, how about for dismount?
	 CALL RELLOC		;[6011]No, time to unlock
	ENDIF.
	MOVEM T1,STRFL1(STR)	;[6011]Restore flag
	RET
;UNDREM - Call to only  unlock a structure due to dismount/remove

UNDREM:	LOAD T2,STRDLK,STRELC(STR) ;[6011]Get the # of locks for this structure
	JUMPE T2,R		;[6014]No lock! just return
	SOJG T2,UNDRE0		;[6014]One less, any more dismount pending?
	MOVE T1,STRFL1(STR)	;[6011]No, Get flag
	TXZN T1,STR%LD		;[6011]Is it locked for dismount?
	IFSKP.
	 TXNN T1,STR%LE		;[6011]Yes, how about for set exclusive?
	 CALL RELLOC		;[6011]No, time to unlock
	ENDIF.
	MOVEM T1,STRFL1(STR)	;[6011]Update the flag word

;  no need to unlock because the are outstanding dismount/removals  pending.

UNDRE0:	STOR T2,STRDLK,STRELC(STR) ;[6011]Update lock counter
UNDRE1:	RET
SUBTTL STSTR - SeT STRucture

;  This routine sets the new structure characteristics based on T1.
;  Accepts: T1 / New STRFLG value
;	    STR / Pointer to SSB.
;	    MSTAL / Two words containing structure name in ASCII
;  Uses: MSTRST for the MSTRs needed
;  Returns: STRFLG updated in STR data base to correct state
;	    +1 on error T1/-1 for exclusive failure
;	    +2 on success

;  First we need to determine if exclusive or shared is to be set because
;  that is not set in a normal way.

STSTR::	TRVAR <NEWSTF,STRERR>	;NEWSTF - Saved T1, new structure flags
				;STRERR - Error flag.  0 if no error encounter
	SETZM STRERR		;No errors yet
	MOVEM T1,NEWSTF		;Save the new STRFLG to be

;  Do set for domestic/regulated/dismounted, but first check if it is PS:

	MOVEI T1,MSTAL		;Get address of alias
	CALL STRSTT		;Go get the status
	JRST [SETOM STRERR	;Set the error code
				;Would like to set error message
	       JRST STSTR2]	;And skip success setting 
	TXNE T1,MS%PPS		;[6001]Is this the primary public structure?
	JRST STSTR1		;Yes, only can set exclusive/share
	MOVE T1,NEWSTF		;Restore the new STRFLG to be
	TXZ T1,MS%EXC+MS%NTC	;Forget about exclusive and other bits for now
	HRROI T2,MSTAL		;Build pointer to alias
	MOVEM T2,MSTRST+.MSSSN	;Save it
	MOVEM T1,MSTRST+.MSSST	;Save the new state
	MOVX T2,MS%DIS+MS%DOM+MS%NRS+MS%DMP ;[6007]The bits that can be set
	MOVEM T2,MSTRST+.MSSMW	;Save the bits being changed
	MOVE T1,[3,,.MSSSS]	;Get block size,,function code
	MOVEI T2,MSTRST		;Get the argument block
	SKIPN TSTF		;Don't set if debugging
	MSTR
	ERJMP [SETOM STRERR	;Set the error code
				;Would like to set error message
	       JRST STSTR1]	;And try to set exclusive/shared

;  Since we have just set some bits, lets say so in STRFLG

	LOAD T1,MS%DIS,NEWSTF	;Get the new unavail/avail bit
	STOR T1,MS%DIS,STRFLG(STR) ;And save it

	LOAD T1,MS%DOM,NEWSTF	;Get the new domestic/foreign bit
	STOR T1,MS%DOM,STRFLG(STR) ;And save it

	LOAD T1,MS%NRS,NEWSTF	;Get the new unregulated/regulated bit
	STOR T1,MS%NRS,STRFLG(STR) ;And save it

;  Now to set EXCLUSIVE/SHARED

STSTR1:	MOVE T1,NEWSTF		;Get the new strflg back
	SETZ T4,		;Assume shared
	TXNE T1,MS%EXC		;Clear exclusive bit, was it set?
	MOVX T4,MS%EXC		;Yes, say we want exclusive
	HRROI T3,MSTAL		;Build pointer to alias
	MOVE T1,[2,,.MSCSM]	;Say we want to set exclusive/shared
	MOVEI T2,T3		;And where the arguments are
	SKIPN TSTF		;Don't set if debugging
	MSTR			;Try to set it
	 ERJMP [SETOM STRERR	;[6014]Set the error flag
		CALL GETERR	;[6014]Get error
		CAIE T1,MSTX48	;[6011]CFS error?
		JRST STSTR2	;[6014]No
		TXNE T4,MS%EXC	;Were we doing exclusive? 
	        MOVEI T1,-1	;[6011]Yes, set error for exclusive failure
	        JRST STSTR2]	;And skip success setting 

;  Set STRFLG to indicate change

	LOAD T1,MS%EXC,NEWSTF	;Get the exclusive stuff
	STOR T1,MS%EXC,STRFLG(STR) ;Update STRFLG

;  Here to do cleanup and analysis.

STSTR2:	SKIPE STRERR		;Any errors?
	RET			;Yes. return telling the world
	RETSKP			;All done.
SUBTTL KSUD - Undefine structure

;  This routine processes the UNDEFINE STRUCTURE command from OPR.

KSUD:	
;  Do some initial validation

	CALL DDSCIH		;Make certain tables up to date

	MOVEI T1,.STRDV		;Get block type code
	CALL KGTSTR		;Get structure name
	 JRST KBADM		;Not there, reject message

	DMOVEM T2,MSTAL		;Save the ascii name
	MOVEI T2,MSTAL		;Get the address
	TMCT <%IStructure %2A: > ;Start the message
	MOVEM T1,DSFE+DSFSPC	;Save SIXBIT structure name
	MOVEI T1,.DVSTR		;Get the structure type
	MOVEM T1,DSFE+DSFTYP	;Save it
	CALL DSFLOC		;Go try to locate this one
	 JRST [TMCT <is currently not defined> ;Not there
	       JRST KSUD.9]	;Go to the cleanup
	SKIPE DSFE+DSFPNT	;Do we have an SSB currently?
	 JRST [TMCT <cannot be undefined%_The structure is currently in use.>
	       JRST KSUD.9]	;Yes, go to the cleanup
	CALL DSFDLE		;Delete the entry
	  $STOP <Deletion of previously known DDB with DSFDLE failed>
	TMCT <deleted from data base> ;Tell of success

KSUD.9:	MOVEI T3,[ASCIZ/Undefine Structure Command/] ;Header for message
	CALL BTACKT		;Send the message we built with TMCT
	RET			;And fini
SUBTTL KSMT - Mount Structure x:/Structure-id:z: command from OPR
;KSMT - Mount a structure if possible else allow the structure to be mounted if
;       possible.

;Accepts MRPDB, RBUF/ PDB AND MESSAGE

KSMT:	CALL DDSCIH		;Update disk table
	MOVEI T1,.MNTST		;We want mount RSB
	CALL OPRSB		;Get mount RSB 
	 JRST KSMTNR		;[6011]No RSB, no mount
	MOVE T1,RSBIFL(RSB)	;[6011]Get flag word
	TXNN T1,R%LOR		;[6011]Remote or local?
	JRST KSMT0		;[6011]Local
	MOVEI T1,.NDENM		;[6011]Want node name block
	CALL ORNBLF		;[6011]Is there one?
	 JRST KBADM 		;[6011]No, bad remote mount messge
	MOVE T4,0(T1)		;[6011]Get the node name
	MOVEM T4,RSBOBN(RSB)	;[6011]Save it
	MOVE T1,RBUF+.MSCOD	;[6017]Get operator's PID
	MOVEM T1,RSBPID(RSB)	;[6017]Save it for later

KSMT0:	SETOM RSBITN(RSB)	;[6011]Indicate request is from operator
	MOVEI T1,RST.WM
	STOR T1,RSBSTE		;Set state to waiting for mount
	MOVE T1,RSBSTA(RSB)	;Alias name in T1
	MOVE T2,RSBSTN(RSB)	;Structure name in T2
	SETZ T4,		;For now no unique code
	CALL MATCHS		;Go find SSB
	 JRST [JUMPE T1,KSMTE1	;Not there, go ask to be mounted
	       JRST DUPSTA]	;More than one found

	SKIPE T2,STRPNT(STR)	;Do we have a pointer to DDB
	 JRST [TMCT <%IStructure %1S: is already mounted%_>
	       JRST KSMTEX]	;No need to do anything but tell operator
	SETZRO STR%DT,STRFL1(STR) ;Clear the being dismount bit

	LOAD T1,STRUNI,(STR) 	;No, get # of disks in str
	LOAD T2,STRMCT,(STR) 	;Get # of disk on-line in str
	CAME T1,T2		;Are all disks on-line?
	JRST KSMTE1		;No, ask operator
	CALL STRMNT		;Go mount the structure
	 JRST KSMTE2		;Can't mount structure 
	RET

KSMTE:	MOVE T1,RSBSTA(RSB)	;Alias name in T1
	MOVE T2,RSBSTN(RSB)	;Structure name in T2
	TMCT <%IStructure %2S: mounted as alias %1S:%_>
KSMTEX:	ABTREQ (ABRTNR)		;Get rid of RSB
	MOVEI T3,[ASCIZ/Mount request by operator completed/]
	CALLRET BTWTO		;Tell operator
	 	
;  Exit routines for KSMT

KSMTE1:	CALLRET WOVMS		;TELL OPERATOR TO MOUNT STRUCTURE	

KSMTE2:	MOVE T3,RSBSTA(RSB)	;Alias name in T1
	MOVE T2,RSBSTN(RSB)	;Structure name in T2
	TMCT <%ICan't mount structure %2S: (alias %3S:)
Check status of structure and disk drive.%_>
	MOVEI T3,[ASCIZ/Mount request by operator failed/]
	CALLRET BTWTO		;Tell operator of failure
;[6011]
;No RSB.  from KSMT
;RSB/1
;RBUF/MESSAGE

KSMTNR:	CAIE RSB,1		;[6014]We have a RSB
	RET			;[6011]NO, just return
	MOVEI T1,.STALS	
	CALL KGTSTR		;[6011]an alias specified?
	 JRST KBADM		;[6011]Reject message
	MOVE T2,T1		;[6011]Save alias
 	MOVE T3,T2		;[6011]Structure name same as alias for now
	MOVEI T1,.STRDV		;[6011]Get block type
	CALL KGTSTR		;[6011]Get structure name
	SKIPA			;[6011]No name use alias
	MOVE T3,T1		;[6011]Save name
	MOVEI T1,.NDENM		;[6011]Want node name
	CALL ORNBLF		;[6011]Look for it
	 JRST KBADM		;[6011]No there
	MOVE T4,0(T1)		;[6011]Save it

	MOVE T1,RBUF+.MSFLG	;[6011]Get the Galaxy flag word
	TXNN T1,MF.NEB		;[6011]Remote or local
	JRST KSMTN1		;[6011]Local

	TMCT <%IInsufficient MOUNTR resources needed to mount
structure%3S: (Alias %2S:) for node %4S::%_>
	MOVEI T3,[ASCIZ/REMOTE MOUNT STRUCTURE FAILED/]
	CALLRET	 BTWTO		;[6011]Tell the operator

KSMTN1:	
	TMCT <%IInsufficient MOUNTR resources needed to mount
structure%3S: (Alias %2S:) %_%U%_>
	MOVEI T3,[ASCIZ/MOUNT STRUCTURE FAILED/]
	CALLRET BTWTO		;[6011]Tell the operator
; Found two structures with same structure name. Need operator help. 

DUPSTA:	SKIPN T1,RSBSTN(RSB)	;Use structure name if there is one
	MOVE T1,RSBSTA(RSB)	;else use alias
	TMCT <%ICan not satisfy mount request because
there is more than one structure with 
the name %1S: online.
Structures are online on disk drives%_>
	SETZ STR,		;Start at the beginning
DUPST1:	CALL SSBNXT		;Go get the next one
	JRST DUPST7		;All done go send message
	MOVE T3,STRFL1(STR)	;Get structure state flags
	TXNE T3,STR%MT		;Is the structure mounted?
	JRST DUPST1		;Already mounted, go get next
	CAME T1,STRNAM(STR)	;Is this the one we want
	JRST DUPST1		;no, get next
	LOAD T3,STRUNI,(STR)	;Get number of disks in structure
	MOVNS T3
	HRRI T3,STRADD(STR)	;Setup address of first disk status block

DUPST2: HRRZ T4,(T3)		;Get the DSB
	JUMPE T4,DUPST3		;Get next if zero
	MOVE T2,DSKCKU(T4)	;Get the CKU
	TMCT <%7C%2K%_>		;Add it to message
DUPST3:	AOBJN T3,DUPST2		;Increment pointer 
	JRST DUPST1		;Next structure
DUPST7:	TMCT <Mount request >
	MOVE T1,RSBITN(RSB)	;Get request #
	SKIPL T1		;No request ID must be from operator
	CALL [TMCT < # %1D > 
	      RET]
	TMCT <rejected.
Please spin down conflicting structure(s)
and resubmit the mount request%_>
	MOVEI T3,[ASCIZ/AMBIGUOUS MOUNT REQUEST DETECTED/]
	CALL BTWTO		;Tell operator
	MOVE T2,RSBIFL(RSB)	;GET INTERNAL REQUEST FLAGS
	TXNE T2,R%OPR		;DON'T REPLY TO OPR-ORIGINATED REQUEST
	JRST [ABTRET (ABRTNR)]	;and abort 
	ABTRET (NPXAMB)		;But do tell user
SUBTTL UPDSTR - Update structure

;  This routine updates the status of a structure by comparing the state
;  of the structure as determined from the DDB and STRFLG with the state
;  of the structure determined from the monitor.

;  Accepts T1 / pointer for DDB containing structure
;	MSTAL / ascii alias contained in DSFE

;  Uses MSTRBK for MSTR call

UPDSTR:	STKVAR <INIPNT,STRSTA>	;Some locals
				;INIPNT - place to save pointer
				;STRSTA - place to save prop. structure status

	MOVEM T1,INIPNT		;Save argument
	CALL DSFGET		;Go get DDB
	  CALL STOP		;Someone lied

	SKIPN STR,DSFE+DSFPNT	;Get pointer to SSB, is there one?
	JRST UPDSEX		;No, cannot need updating

;  Now get the monitor state for the structure

	MOVEI T1,MSTAL		;Get pointer to alias
	CALL STRSTT		;Go get the state
	 JRST [CALL GETERR	;Get the error
		CAIN T1,MSTX21	;Was it not mounted?
		JRST UPDSEX	;Yes, just return for now
		MOVEI T2,MSTAL	;Get structure name
		TMCT <%IError in structure status for structure %2A, error is %1J>
		JRST UPDS.9]	;Send to all OPRs

	MOVEM T1,STRFLG(STR)	;Save the status from the MONITOR

	MOVE T1,DSFE+DSFFLG	;Get the flags
	TXNN T1,DSF%IG		;Is it ignore?

	CALL NEWSTA		;Go check on current status
	JRST UPDSEX		;Not mounted, don't need updating

;  Continued on next page
;  Continued from previous page
;  Now, do we match?

	MOVE T2,STRFL1(STR)	;Get the other structure flag
	TXNE T2,STR%UD+STR%ME	;[6011]Is it unavail due to dismount and
				;[6011]failure to exclusive as part of mount?
	TXO T1,MS%DIS		;Yes, it must be unavailable
	MOVEM T1,STRSTA		;Save the proposed structure status for a bit
	XOR T1,STRFLG(STR)	;Get the changed bits
	TXZ T1,MS%NTC		;Get rid of don't care bits
	SKIPN T1		;Has it changed?
	JRST UPDSEX		;No, all done

	MOVEI T2,MSTAL		;Get structure name
	TMCT <%IStructure state for structure %2A is incorrect%_>

	TXZE T1,MS%DOM		;Domestic bit set incorrectly?
	CALL [TMCT <  DOMESTIC/FOREIGN attribute set incorrectly%_>
	      RET]

	TXZE T1,MS%NRS		;Regulated bit set incorrectly?
	CALL [TMCT <  REGULATED attribute set incorrectly%_>
	      RET]

	TXZE T1,MS%EXC		;Exclusive bit set incorrectly?
	CALL [TMCT <  EXCLUSIVE/SHARED attribute set incorrectly%_>
	      RET]

	TXZE T1,MS%DIS		;Dismount bit set incorrectly?
	CALL [TMCT <  Available status is set incorrectly%_>
	      RET]

	TXZE T1,MS%DMP		;[6007]Dumpable bit set incorrectly?
	CALL [TMCT <  Dumpable status is set incorrectly%_>
	      RET]

	SKIPE T1		;Cleared everything?
	CALL [TMCT <  Unknown status -- word is - %1O%_> ; No
	      RET]

	MOVE T1,STRSTA		;Get new STRFLG based on DDB and disk
	CALL STSTR		;Try to update things	
	  CALL [TMCT <Unable to update structure status correctly%_> ;Thing bad
		RET]

;  Tell operator what bits were set or not set.

	MOVEI T1,MSTAL		;Get alias 
	TMCT <Status of structure %1A: is set:%_> 
	CALL STRSTT		;Go get the state
	 JRST [	MOVEI T1,MSTAL	;Get alias 
	        TMCT <Error in getting structure status for structure %1A:
error is %J%_>
		JRST UPDS.9]	;Send to all OPRs

	TXNE T1,MS%DOM		;Foreign or domestic?
	JRST [TMCT <Domestic>
	      JRST UPD1]
	TMCT <Foreign>

UPD1:	TXNE T1,MS%NRS		;Regulated on unregulated
	JRST [TMCT <, Unregulated>
	      JRST UPD2]
	TMCT <, Regulated>

UPD2:	TXNE T1,MS%EXC		;Exclusive or shared?
	JRST [TMCT <, Exclusive>
	      JRST UPD3]
	TMCT <, Shared>

UPD3:	TXNE T1,MS%DIS		;Available or unavailable?
	JRST [TMCT <, Unavailable> ;[6007]
	      JRST UPD4]	;[6007]
	TMCT <, Available>	;[6007]

UPD4:	TXNE T1,MS%DMP		;[6007]
	JRST [TMCT <, Dumpable%_> ;[6007]
	      JRST UPDS.9]	;[6007]
	TMCT <, Nondumpable%_>	;[6007]

;  Structure check message output

UPDS.9:	MOVEI T3,STRCHD		;Get structure error header
	CALL BTWTO		;Tell the operator

UPDSEX:	RET		;All done
SUBTTL Determine-new-string routine (NEWSTA) -- Determine STRFLG based on MOUNTR and disk status

;This routine determines new STRFLG(STR) based on DDB, disk drive status used 
;by this structure and structure mount status.

;Accepts - DSFE / structure DDB  (will NOT be preserved!)
;Returns - always with T1 containing the new structure status flags.
;	   +1 if structure is not mounted
;	   +2 if structure is mounted

NEWSTA::SAVEAC <Q1>			;Save some ACs
	SETZ Q1,			;Q1 contains the building STRFLG

;  Structure status DSFE+DSFFLG, lets set the corresponding bits in STRFLG 

	LOAD T1,DSF%EX,DSFFLG+DSFE	;Get the share/exclusive bit

;  This bit counts if the structure is primary PS.

	MOVE T2,DSFE+DSFPNT		;Is there a pointer to the SSB?
	JUMPE T2,NEWST0			;If no pointer, continue normal stuff

	LOAD T3,STR%EP,STRFL1(T2)	;Get exclusive due to port bit
	SKIPE T3			;Is it?
	MOVE T1,T3			;Yes, set for exclusive anyway

	MOVE T3,STRFLG(T2)		;Get the structure flags
	TXNN T3,MS%PPS			;Is it primary PS?
	JRST NEWST0			;No, continue normal stuff
	STOR T1,MS%EXC,T3		;Store the share/exclusive bit with
					;  STRFLG since nothing else changable
	MOVE T1,T3			;Move the new STRFLG over
	RETSKP				;And return only the PS case

NEWST0:	STOR T1,MS%EXC,Q1		;Save it

	LOAD T1,DSF%DO,DSFFLG+DSFE	;Get the foreign/domestic bit
	STOR T1,MS%DOM,Q1		;Save it

	LOAD T1,DSF%RG,DSFFLG+DSFE	;Get the regulate/unregulate bit
	STOR T1,MS%NRS,Q1		;Save it

	LOAD T1,DSF%AV,DSFFLG+DSFE	;Get the available/unavailable bit
	STOR T1,MS%DIS,Q1		;Save it

	LOAD T1,DSF%DP,DSFFLG+DSFE	;[6002]DOB Get the dumpable/nondumpable
	STOR T1,MS%DMP,Q1		;[6002]Save it

	SKIPG T2,DSFE+DSFPNT		;SSB?
	JRST NEWEX			;No, Can't have anything else to do
	PUSH P,T2			;Save the SSB

	MOVE T1,STRFL1(T2)		;Get other structure bits
	TXNE T1,STR%DT+STR%DE		;Structure being dismounted or error
	JRST NEWST1			;Yes, set structure as unavailable

	MOVE T1,T2			;Move over the SSB address
	CALL CHKAVA			;Go check on status based on disks
	SKIPA				;Skip if want unavailable
	JRST NEWST2			;Otherwise go to finish

NEWST1:	SETONE MS%DIS,Q1		;Set things unavailable

NEWST2:	MOVE T1,Q1			;Get the new strflg in any case
	POP P,T2			;Get the SSB
	MOVE T2,STRFL1(T2)		;Get the internal status flags
	TXNE T2,STR%MT			;Structure mounted?
	RETSKP				;Yes
	SKIPA				;Don't need to set strflg again

NEWEX:	MOVE T1,Q1			;Get the STRFLG
	RET				;And return unmounted.
SUBTTL CHKAVA - Check SSB disk drives for available/unavailable

;  Accepts: T1 / Address of SSB

;  Returns: +1 Structure is on a disk drive unavailable
;	    +2 Structure can be available

CHKAVA:	SAVEQ
	MOVE Q1,T1		;Get address of SSB

;  Set according to the disk which this structure is mounted.

	LOAD Q3,STRUNI,(Q1)	;Get the number of units
	MOVNS Q3		;Negate number of units
	MOVSS Q3		;And switch halves
	HRRI Q3,STRADD(Q1)	;Setup address of first disk status block

;  Loop through all disks belonging to this structure

CHKAV1:	MOVE T2,(Q3)		;Get the disk status block address
	JUMPE T2,CHKAV2		;No address, go try the next
	MOVE T1,DSKPNT(T2)	;Get pointer to disk DDB
	CALL DSFGET		;Get DSFE for disk	
	  CALL STOP		;Should never happen
	MOVE T2,DSFE+DSFFLG	;Get the flag bits
	TXNE T2,DSF%AV+DSF%PO	;Any reason to be unavailable?
	RET			;Yes, return unavailable

CHKAV2:	AOBJN Q3,CHKAV1		;Get the next disk address and loop back	

;  End of loop

	RETSKP			;Must be ok
SUBTTL SSB routines -- SSBINI - Initialize SSB data base

;  Returns +1 always

SSBINI:	SETZM SSBFPT		;No free entries
	MOVEI T1,STRSTB		;The bottom is the top
	MOVEM T1,SSBTOP		;And remember it
	RET


SUBTTL SSB routines -- SSBCRE - Create a new SSB entry (zeroed)

;  Returns +1 always
;		STR / address of new entry

SSBCRE:	SKIPE STR,SSBFPT	;Any already existing free entries?
	JRST [MOVE T1,STRALI(STR) ;Yes, get pointer to next free entry
	      MOVEM T1,SSBFPT	;Set it as address of free entry list
	      JRST SSBC.5]	;go to finish up
	MOVE STR,SSBTOP		;Get top as new entry
	MOVE T1,STR		;Copy of new entry address
	ADDI T1,STRSZ		;Bump to the new limit
	CAIL T1,MAXSSB		;Room for more?
	CALL STOP		;No.  Too bad
	MOVEM T1,SSBTOP		;Save the new next entry 

;  Clear new entry

SSBC.5:	MOVSI T1,0(STR)		;Setup BLT pointer
	IORI T1,1(STR)		;  to clear Structure status block
	SETZM (STR)		;Clear first word
	BLT T1,STRSZ-1(STR)	;And the rest
	RET


SUBTTL SSB routines -- SSBRET - Return SSB entry to free SSB pool

;  Accepts:	STR / Address of entry to be returned to free

;  Returns +1 always

SSBRET:	MOVE T1,SSBFPT		;Get pointer to first entry
	MOVEM T1,STRALI(STR)	;Save it
	MOVEM STR,SSBFPT	;Save new pointer to new first entry
	SETZM STRNAM(STR)	;Say entry is free
	SETZ STR,		;Clear the SSB pointer just in case
				;  someone tries to use it
	RET
SUBTTL SSB routines -- SSBNXT - Get next SSB

;  Accepts: STR / Address of the current SSB or 0 if initializing search

;  Returns: +1 if no more SSBs
;	    +2 if successful
;	    STR / Address of next SSB

SSBNXT:	SKIPE STR		;Do we have a previous?
	JRST SSBN.2		;Yes, go to bump to the next one
	MOVEI STR,STRSTB	;No.  Initialize

SSBN.1:	SKIPE STRNAM(STR)	;Is this one in use?
	RETSKP			;Yes, done
SSBN.2:	ADDI STR,STRSZ		;Bump to the next one
	CAMGE STR,SSBTOP	;Any more to look at?
	JRST SSBN.1		;Yes, go try this one
	RET			;No, no more
SUBTTL SSB routines -- MATCHS - Match request to structure (old)

; The caller determines what to match by passing arguements in T ACs.

;  Accepts:	T1 / SIXBIT structure alias
;		T2 / SIXBIT structure name
;		T4 / Unique Code
;	    +1 Unsuccessful in finding a match
;		STR /  0
;		T1  /  0 if structure not found
;		T1  / -1 if ambiguity found
;	    +2 Structure spinning
;		STR / -1,,SSB address if not mounted
;		STR /  0,,SSB address if mounted
;  Caller should check return

MATCHS:: SAVEQ			;Save the Q acs
				;Q1 will have structure Alias
				;Q2 will have structure name
				;Q3 will have successful unmounted name match
	STKVAR <UNQCOD>		;Storage for unique code
	SETZ Q3,		;No name matchs
	DMOVE Q1,T1		;Save the arguments
	MOVEM T4,UNQCOD		;Save the unique code
	SETZ STR,		;Starting place

;  Loop on all structure entries till match or run out

MATC.1:	CALL SSBNXT		;Get the next entry
	JRST MATC.8		;No more entries

;  Want to check for match with the following logic:
;  If the structure is mounted, alias matching is required.
;	if the alias matches, then so must the unique code,
;	or the request cannot be satisfied.  (ambiguous)
;  If the structure is not mounted name matching and unique code matching
;  is acceptable (The alias in SSB is invalid and should be 0)
;  But matching with a mounted structure is preferred.

	MOVE T4,STRFL1(STR)	;Get structure flags with mount flag
	TXNN T4,STR%MT		;Is this structure mounted?
	JRST MATC.3		;No, go try for match another way

;  Here if mounted

	CAME Q1,STRALI(STR)	;Match the alias
	JRST MATC.1		;No, go try for another
	SKIPN T2,UNQCOD		;Unique code provided
	JRST MATC.2		;No, check structure name
	CAME T2,STRUNQ(STR)	;Yes, do they match
	JRST MATC.1		;No, get the next
MATC.2:	SKIPE Q2		;Name provided
	CAMN Q2,STRNAM(STR)	;Yes, does it match
	JRST MATC.9		;Yes, go tell of success
	JRST MATC.7		;No, give up on this one
				;  (indicates ambiguity)

;  Loop continued on next page
;  Loop continued from previous page

;  Here if structure being examined is not mounted

MATC.3:	SKIPN T4,Q2		;Skip if structure name given
	MOVE T4,Q1		;Otherwise, match on alias against name
	CAME T4,STRNAM(STR)	;Do we have a match
	JRST MATC.1		;No, go try for another
	SKIPN T2,UNQCOD		;Unique code given?
	JRST MATC.4		;No, skip this check. 
	CAME T2,STRUNQ(STR)	;Yes, do they match?
	JRST MATC.7		;Unique code doesn't match, ambiguity

MATC.4:	JUMPN Q3,MATC.7		;If already have a name match, then go bad
				;  (Indicates ambiguity)
	SETO Q3,		;Remember this one
	HRRI Q3,(STR)		;  unmounted as it is
	JRST MATC.1		;  and continue to look for something better

;  End of loop

;  Returns:
;  Here on ambiguous return

MATC.7:	SETO T1,		;Set the problem
	SETZ STR,		;Clear the pointer
	RET

;  Here on exhausted loop

MATC.8:	SETZ T1,		;Say at least not bad
	SKIPN STR,Q3		;Any non-mount match?
	RET			;No.

;  For whatever reason, we think we succeeded

MATC.9:	RETSKP
SUBTTL ISTDDB - Initialize structure DDB

;  Accepts: T1 / Structure alias in sixbit

;  Returns: T1 / Pointer for found/created entry
;	    DSFE containing found/created entry
;	    +1 if alias already exists
;	    +2 if entry created
;	    DSFE containing entry

ISTDDB:	MOVEM T1,DSFE+DSFSPC	;Save the alias
	MOVEI T1,.DVSTR		;Get structure type
	MOVEM T1,DSFE+DSFTYP	;Set it
	SETZM DSFE+DSFPNT	;No pointer yet
	SETZM DSFE+DSFFLG	;Set for default flags
	CALL DSFCRE		;Go create
	  RET			;Already exists, what a suprise
	RETSKP			;Successfully created!
SUBTTL MESCHK - CHECK IF MESSAGE FOR STRUCTURE ALREADY SENT TO OPERATOR

;ACCEPTS:  RSB/	ADDRESS OF RSB
;RETURNS:  +1,	OPERATOR ALREADY NOTIFIED OF STRUCTURE
;	   +2,	OPERATOR NOT NOTIFIED

MESCHK:	SAVEQ
	MOVE Q1,RSBSTN(RSB)	;GET STRUCTURE NAME
	MOVE Q2,RSBSTA(RSB)	;GET STRUCTURE ALIAS
	MOVE Q3,RSB		;SAVE ADDRESS OF RSB
	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	SAVEAC <RSB>
	CALL PRQPID		;CLEAN UP REQUEST QUEUE FIRST
MESCH1:	CALL NSTRSB		;GET ADDRESS OF NEXT RSB
	RETSKP			;NONE LEFT
	CAMN Q3,RSB		;IS THIS THE CURRENT RSB?
	JRST MESCH1		;YES, FORGET IT
	CAMN Q1,RSBSTN(RSB)	;SAME STRUCTURE NAME?
	CAME Q2,RSBSTA(RSB)	;YES, SAME ALIAS?
	JRST MESCH1		;NO, TRY NEXT RSB	
	MOVE T1,RSBIFL(RSB)	;SEE IF OPR TOLD ABOUT THIS ONE
	TXNN T1,R%ONR		; 
	JRST MESCH1		;NO, DO NOT STOP HERE
	RET			;SAME NAME AND ALIAS
SUBTTL MNTALL - MOUNT ALL STRUCTURES NOT ALREADY MOUNTED

;ACCEPTS:  NOTHING
;RETURNS:  +1,	ALWAYS

MNTALL:	CALL GORSB		;Create a fake RSB since everything else
				;  depends on it
	JFCL			;Got the last one

;  loop on all the structures around

	SETZ STR,		;Start at the beginning
MNTNXT:	CALL SSBNXT		;Go get the next one
	JRST [ABTRET (ABRTNR)]	;No more.  Get rid of RSB and return
	MOVE T1,STRFL1(STR)	;Get structure state flags
	TXNE T1,STR%MT		;Is the structure mounted?
	JRST MNTNXT		;Already mounted, go get next
	MOVE T1,STRFLG(STR)	;Get the structure flags
	TXNE T1,MS%PPS		;Public structure?
	JRST MNTNXT		;Public structure, go get next

	LOAD T1,STRUNI,(STR)	;Get number of disks in structure
	LOAD T2,STRMCT,(STR)	;Get number of disks on-line
	CAME T1,T2		;Is it all there?
	JRST MNTNXT		;No, go get next one
	PUSH P,STR		;Save the SSB we are working at
	SETZ T1,		;No alias
	MOVE T2,STRNAM(STR)	;Get structure name
	MOVEM T2,RSBSTA(RSB)	;Alias of structure will be physical name
	SETZ T4,		;No unique code
	CALL MATCHS		;Find SSB
	JRST MNTNX2		;Skip mount if more than one str with that name
	CALL STRMNT		;Mount the structure
	  JFCL			;Failed for some reason, who cares
MNTNX2:	POP P,STR		;Restore the SSB
	JRST MNTNXT		;Go try for the next one
SUBTTL OPRSB - SET UP REQUEST BLOCK FOR OPR MOUNT OR DISMOUNT COMMAND

;ACCEPTS: T1/	REQUEST TYPE (.MNTST,.DSMST, .PTSET, .SETST)
;	  MRPDB, RBUF/ PDB AND MESSAGE FROM OPR IPCF REQUEST

;RETURNS: +1,	FAILURE.  RSB/1
;	  +2,	SUCCESS, RSB/ ADDR OF REQUEST STATUS BLOCK

OPRSB::	CALL GORSB		;GET A STATUS BLOCK FOR REQUEST
	 JRST [MOVEI RSB,1	;[6011]No RSB's available, set RSB to 1
	       RET]		;[6011]Take error return
	MOVE T1,RBUF+.MSFLG	;[6011]Get the Galaxy header flag word
	TXNN T1,MF.NEB		;[6011]Is the request from Nebula (remote)?
	JRST OPRSB0		;[6011]No need to get node name

;  Remote request must have a node block

	SETONE R%LOR,RSBIFL(RSB);[6011]Yes, say so in the RSB
	TXNE T1,MF.WTO		;Want WTO?
	SETONE R%WTO,RSBIFL(RSB) ;Yes, remember to send WTO to NEBULA
	MOVE T1,RBUF+.MSCOD	;[6011]Get the ACK code
	MOVEM T1,RSBRAC(RSB)	;[6011]Store it for return message
	MOVEI T1,.NDENM		;[6011]Want node name block
	CALL ORNBLF		;[6011]Is there one?
	 JRST OPRSBE		;[6011]No go to error routine
	MOVE T4,0(T1)		;[6011]Get the node name
	MOVEM T4,RSBOBN(RSB)	;Save it

OPRSB0:	MOVEI T1,.STRDV		;GET BLOCK TYPE
	CALL KGTSTR		;GET STRUCTURE NAME
	SKIPA			;Not there, lets try alias
	MOVEM T1,RSBSTN(RSB)	;STORE SIXBIT STRUCTURE NAME IN RSB
	MOVEI T1,.STALS	
	CALL KGTSTR		;WAS AN ALIAS SPECIFIED?
	 JRST [	SKIPE T1,RSBSTN(RSB) ;No alias, how about structure name?
		JRST OPRSB1	;We have a structure name but no alias
	        JRST OPRSBE]	;[6011]Bad message from NEBULA
	SKIPN RSBSTN(RSB)	;Do we have a structure name?
	MOVEM T1,RSBSTN(RSB)	;No, lets use the alias
OPRSB1:	MOVEM T1,RSBSTA(RSB)	;YES, STORE IT IN RSB
	MOVE T1,MRPDB+.IPCFS	;GET PID OF SENDER
	MOVEM T1,RSBPID(RSB)	;STORE IN RSB
	MOVEM T1,MUTLBK+1
	MOVEI T1,.MUFOJ		;GET SENDER'S JOB NUMBER
	MOVEM T1,MUTLBK
	MOVEI T1,3		;3 WORDS IN ARGUMENT BLOCK
	MOVEI T2,MUTLBK		; WHICH IS MUTLBK
	MUTIL
	 JRST [	ABTRET (ABRTNR)] ;SOMETHING HAPPENED TO REQUESTER
	MOVE T1,MUTLBK+2	;GET JOB NUMBER
	STOR T1,RSBJNO
	MOVE T2,[-1,,T4]	;GET USER NUMBER
	MOVEI T3,.JIUNO
	GETJI
	 JRST [	ABTRET (ABRTNR)] ;SOMETHING HAPPENED TO REQUESTER
	MOVEM T4,RSBUNO(RSB)	;STORE USER NUMBER
	RETSKP

;  Error routine when MOUNTR receives a bad message from NEBULA

OPRSBE: ABTREQ (ABRTNR)		;[6011]No, abort the request
	MOVX T1,E%NEB		;[6011]Error code=NEBULA error
	TXO T1,FA%NER		;[6011]Set bit NEBULA error
	MOVE T2,RSBRAC(RSB) 	;[6011]Need ACK code 
	MOVE T3,RSBIFL(RSB) 	;[6011]Get flag
	TXNN T3,R%WTO		;[6011]Just send WTO?
	CALL FAILE		;[6011]No, send ACK first
	JRST KBADM		;[6011]Then tell local operator
SUBTTL PSDR - PARSE OPERATOR RESPONSE TO DISMOUNT MESSAGE WHEN OTHER JOBS
;	USING STRUCTURE

;ACCEPTS: T1/	ADDRESS OF ASCIZ RESPONSE TEXT
;	  RSB/	ADDRESS OF REQUEST STATUS BLOCK

;RETURNS: +1,	ERROR DETECTED WHILE PARSING RESPONSE, OPERATOR TOLD
;	  +2,	SUCCESSFUL PARSE
;		IF ANSWER IS YES, T1/	0
;		IF ANSWER IS NO,  T1/	-1

PSDR::	CALL COMNDI		;INITIALIZE FOR COMND JSYS
	MOVEI T2,[FLDDB.(.CMKEY,,PSDKT)] ;SETUP FOR KEYWORD PARSE
	CALL COMNDX		;PARSE KEYWORD
	 JRST [	MOVEI T1,[ASCIZ/Response must be YES or NO/]
		CALLRET RSPERR]	;DIDN'T SAY YES OR NO, GIVE ERROR
	HRRZ T1,(T2)		;GET 0 FOR NO, 1 FOR YES
	SOJA T1,RSKP		;RETURN -1 FOR NO, 0 FOR YES

PSDKT:	PSDKTL,,PSDKTL
	[ASCIZ/NO/],,0
	[ASCIZ/YES/],,1
PSDKTL==.-PSDKT-1
SUBTTL SEVSIX - ROUTINE TO CONVERT 7-BIT ASCII TO 6-BIT

;ACCEPTS: T1	POINTER TO ASCIZ STRING
;	  T2	ADDRESS OF WORD IN WHICH TO STORE 6-BIT STRING

;RETURNS: +1, ALWAYS

SEVSIX:	SAVET			;[6010]Save T ACs
	HRLI T2,(POINT 6,0)	;SET UP SIXBIT POINTER
	SETZM (T2)		;CLEAR THE DESTINATION WORD
	MOVEI T4,6		;MAXIMUM OF 6 CHARACTERS

;LOOP OVER CHARACTERS

SEVLOP:	ILDB T3,T1		;GET 7-BIT CHARACTER
	JUMPE T3,R		;RETURN IF END OF STRING
	CAIL T3,"a"		;IS IT LOWER CASE?
	TRZ T3,40		;MAKE SURE IT IS UPPER CASE
	SUBI T3,40		;CONVERT TO 6-BIT
	IDPB T3,T2		;STORE CHARACTER
	SOJG T4,SEVLOP		;JUMP IF MORE CHARACTERS
	RET

SUBTTL SIXSEV - ROUTINE TO CONVERT SIXBIT TO ASCIZ

;ACCEPTS: T1	ADDRESS OF WORD CONTAINING SIXBIT CHARACTERS
;	  T2	POINTER TO WORDS FOR STORING ASCIZ STRING (2 WORDS)

;RETURNS: +1, ALWAYS

SIXSEV::SAVET			;[6010]Save T ACs
	HRLI T1,(POINT 6)	;SET UP BYTE POINTER FOR SIXBIT WORD
	MOVEI T4,6		;MAXIMUM OF 6 CHARACTERS

;LOOP OVER CHARACTERS

SIXLOP:	ILDB T3,T1		;GET CHARACTER
	JUMPE T3,SIXEND		;IF ZERO, THEN END OF STRING
	ADDI T3,40		;MAKE 7-BIT
	IDPB T3,T2		;STORE WORD
	SOJG T4,SIXLOP		;JUMP IF MORE CHARACTERS
SIXEND:	ADDI T4,4		;ZERO OUT REST OF WORD(S)
	SETZ T3,
	IDPB T3,T2		;DEPOSIT ZERO
	SOJG T4,.-1		;JUMP BACK IF MORE CHARACTERS
	RET
SUBTTL STRDMT - DISMOUNT A STRUCTURE (OPR>DISMOUNT STRUCTURE FOO:)
;	  This is the superior dismount routine.  It calls the appropriate 
;	  routines to do the task.

;ACCEPTS: RSB/	ADDR OF REQUEST STATUS BLOCK
;	  MSTAL/ ASCIZ ALIAS OF STRUCTURE
;	  STR/ STRUCTURE STATUS BLOCK

;RETURNS: +1,	ALWAYS

STRDMT: 

;  First, make sure we are allowed to dismount structure.

	MOVE T1,STRPNT(STR)	;Get the pointer to the DDB
	CALL DSFGET		;Go find it
	 $STOP <TRYING TO DISMOUNT A STR THAT DOESN'T HAVE A STRUCTURE ENTRY IN DDB>
	MOVE T1,DSFE+DSFFLG	;Get the status flag
	TXNE T1,DSF%IG		;Is it IGNORED?
	JRST [MOVEI Q1,MREQ27	;Yes, get the error code
	      MOVE T1,STRALI(STR) ;Get the alias
	      TMCT <%ICan't dismount structure %1S:-%5J%_%U%_>
              MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE FAILED/]
	      CALL BTWTO	;SEND MSSG TO OPERATORS
	      ABTREQ (MREQ27)	;[6031]Abort the dismount request
	      TXO Q1,FA%TER	;[6011]Monitor error
	      MOVEM Q1,RSBERR(RSB) ;[6011]Save it
	      SETONE R%STA,RSBIFL(RSB) ;[6031]Set status of request as fail
	      JRST STREXT]	;[6011]Go to common failure exit

;  Are we in the middle of a dismount for this structure and is it from OPR

	MOVE T2,RSBIFL(RSB)	;Get the request status flag
	TXNN T2,R%LOR		;[6011]From Nebula?
	TXNN T2,R%OPR		;No, local OPR request?
	JRST STRDM0		;From Nebula, go do the dismount
	MOVE T1,STRFL1(STR)	;Get the structure status
	TXNN T1,STR%UD		;Are we already dismounting?
	JRST STRDM0		;No, go dismount structure 
	
;  Tell operator we are already dismounting this structure

	MOVE T1,STRALI(STR) 	;Get the alias
        TMCT <%IStructure %1S: is already in the process of being dismounted%_%U%_>
        MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE ABORTED/]
	CALL BTACKT		;Send message to operator

	ABTREQ (ABRTNR)		;[6011]Abort rsb with no reply to operator
	JRST STREXT		;[6011]Common exit

;  Start procedures for dismount.

STRDM0:	CALL STRSET		;Set up for dismount
	JRST STRER1		;An error or some one connected to str
STREX0:	MOVE T1,RSBIFL(RSB)	;Get the flag word
	TXNE T1,R%RNR		;Is it remove
	SKIPA			;yes, but is it CFS?
	JRST STRDMC		;No remove specified go to dismount
	SKIPN CFSB		;Is it CFS system?
	JRST STRDMC		;No, just go dismount str
	SKIPE ENQFLG		;[6011]Yes, but is Cluster ENQ enabled?
	JRST STREX2		;[6011]No, do it the old way
STREX1:	CALL GETLOC		;[6011]Lock the structure
	 JRST [CALL WHOENQ	;Failed, find out who has it
	       JRST STREX1	;No one lets try again
	       MOVEI T3,[ASCIZ/DISMOUNT STATUS/]
	       CALL BTWTO
	       CALL STSTBK
	       JRST STREXT]	;[6011]failed
STREX2:	MOVE T3,[POINT 7,MSTAL]	;Get pointer to alias of str
	MOVX T4,MS%EXC		;say we want it exclusive
	MOVE T1,[2,,.MSCSM]	;Get length,,function
	MOVEI T2,T3		;Get the address of the arguments
	SKIPN TSTF		;Skip if debugging
	MSTR			;Go try to set exclusive
	 ERJMP [CALL GETERR	;[6011]Get the error
	        CAIE T1,MSTX48 ;[6011]CFS access error?
		JRST STEXER	;[6011]No, abort the dismount
		MOVEI T1,STREX2 ;[6012]Get continue address for success
	        MOVEI T2,STREXT ;[6011]Get continue address for abort
		MOVEM T1,RSBCON(RSB) ;[6011]Save it
		MOVEM T2,RSBABO(RSB) ;[6011]Save it
		JRST SCREQ1]	;[6011]Failed get cfs compliance
STRDMC:	CALL STRDMS		;Dismount the str
	CALLRET DISFAL		;An error, tell operator what happened
	CALL NSACK		;[6011]Tell NEBULA or not?
	CALL WOVDS		;Tell operator to remove or not to remove
	SETZM STRNDM(STR)	;Set number of pending dismounts to zero

;  Just dismounted a structure, Do we have any more dismount queries for this 
;  structure.  Loop through all RSB and kill outstanding WTORs

 	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	SAVEAC <RSB,DSK>
	CALL PRQPID		;CLEAN UP REQUEST QUEUE FIRST

STRDRB:	CALL NSTRSB		;GET ADDRESS OF NEXT RSB
	 RET			;NONE LEFT
	SKIPE T1,RSBSUP(RSB)	;Is this a dismount due to port operation
	JRST STRDR2		;Yes, leave it alone!!
	LOAD T1,RSBTYP		;Get the type
	CAIE T1,.DSMST		;Is it a dismount?
	JRST STRDR2		;No
	MOVE T1,RSBSTA(RSB)	;Yes, get alias in request
	CAME T1,STRALI(STR)	;Is it same as dismounted structure? 
	JRST STRDR2		;No
	SKIPN T2,RSBSTN(RSB)	;Yes, do we have a structure-id?
	JRST STRDR1		;No, one more check
	CAME T2,STRNAM(STR)	;Yes, is it the same as dismounted structure?
	JRST STRDR2		;No
STRDR1:	SKIPE T1,RSBWTB+WTBCOD(RSB) ;Do we have ack code?
 	CALL CANWTR		;Yes, Get rid of WTOR for this RSB
STRDR2:	JRST STRDRB		;Get the next one

;STEXER - Routine to handle set exclusive error when doing a dismount/removal
;that is not MSTX48.

STEXER:	CALL SAVERR		;[6011]Report the error
	CALL STSTBK		;[6011]Set the structure back
	CALLRET DISFAL		;[6011]Abort the dismount
SUBTTL GETLOC - Obtain a structure lock for dismount/removal or set/exec

;[6011]
;GETLOC - Routine to lock the structure for setting a structure exclusive due
;to the SET or DISMOUNT/REMOVE commands.  This routine only locks a structure
;once and updates STRFL1 (bits STR%LE and STR%LD) to indicate why it is locked.
;Also, STRDLK is incremented for DISMOUNT/REMOVE to indicate how many dismounts
;are pending.
;The resource name is the structure unique code
;plus an arbitrary ASCIZ string.  Cluster ENQ at this point must be enabled.
;If cluster ENQFLG is set (cluster ENQ is disabled) then there means that we
;are running a pre 7 monitor.
;Accepts RSB and STR
;T4 is only used as a counter for the number of locks in this routine.  Do not
;use T4 for anything else.
;Returns ENQBLK
;	+1 failed to lock. Error code in T1
;	+2 Success

GETLOC:	LOAD T4,STRDLK,STRELC(STR) ;[6011]Get the number of locks
	MOVE T1,STRFL1(STR)	;[6011]Get flag
	SKIPG T4		;No need to lock if already locked for dismount
	TXNE T1,STR%LE		;or lock for set exclusive
	JRST GETLO1		;No need to lock

;Build header

	MOVE T1,[20001,,6]	;Header length,# resource block,,length
	MOVEM T1,ENQBLK+.ENQLN  ;Into arg block
	SETZM ENQBLK+.ENQID	;No PSI and no ID

;Build request block

	MOVX T1,EN%BLN+EN%NST	;Ignore level number and allow nesting
	HRRI T1,-2		;Only allow locking by this job
	MOVEM T1,ENQBLK+.ENQLV	;Say so in arg block
	MOVE T1,STRUNQ(STR)	;Structure unique code
	MOVEM T1,RESPRE		;Resources prefix
	HRROI T1,RESPRE		;Make it a pointer
	MOVEM T1,ENQBLK+.ENQUC	;Add it to arg block
	SETZM ENQBLK+.ENQRS	;Only one resource
	SETZM ENQBLK+.ENQMS	;Save it
	MOVEI T1,.ENQAA		;Get function code
	MOVEI T2,ENQBLK		;Address of argument block
	SKIPN TSTF		;Debugging?
	ENQ%			;No, get the lock
	 ERJMP R		;Error
GETLO1:	SETONE R%LOC,RSBIFL(RSB) ;This request locked the structure
	LOAD T1,RSBTYP		;Get the type
	CAIE T1,.DSMST		;Dismount?
	IFSKP.			
	 SETONE STR%LD,STRFL1(STR) ;Lock for dismount
	 AOS T4			;Add one more
	 STOR T4,STRDLK,STRELC(STR) ;Store it 
	ELSE.
	 SETONE STR%LE,STRFL1(STR) ;No, then it must be exclusive
	ENDIF.
	RETSKP			;Got it

;RELLOC - Release the structure lock
;RELLOC is called when:
;A structure goes offline and is not mounted.
;A structure is set from exclusive to shared.
;A dismount/remove is canceled.
;Operator aborts a dismount/remove request.
;
;Accepts STR/
;Return +1 always

RELLOC:	SAVET			;Save T ACs

;Build header

	MOVE T1,[20001,,6]	;Header length,# resource block,,length
	MOVEM T1,ENQBLK+.ENQLN  ;Into arg block
	SETZM ENQBLK+.ENQID	;No PSI and no ID

;Build request block

	MOVX T1,EN%BLN+EN%NST	;Ignore level number and allow nesting
	HRRI T1,-2		;Only allow locking by this job
	MOVEM T1,ENQBLK+.ENQLV	;Say so in arg block
	MOVE T1,STRUNQ(STR)	;Structure unique code
	MOVEM T1,RESPRE		;Resources prefix
	HRROI T1,RESPRE		;Make it a pointer
	MOVEM T1,ENQBLK+.ENQUC	;Add it to arg block
	SETZM ENQBLK+.ENQRS	;Only one resource
	SETZM ENQBLK+.ENQMS	;No mask
	MOVEI T1,.DEQDR		;Get function code
	MOVEI T2,ENQBLK		;Address of argument block
	SKIPN TSTF		;Debugging?
	DEQ%			;No, get the lock
	 ERCAL RELOC1		;Error
	SETZRO STR%LE+STR%LD,STRFL1(STR) ;Clear lock for dismount/set exclusive
	RET			;All done

;Error handling routine for RELLOC
;T1/DEQ error code

RELOC1:	CAIE T1,ENQX7		;No ENQ on this lock
	$STOP <DEQ error in RELLOC >
	RET

;WHOENQ - Called when an ENQ (function .ENQAA) fails to lock a structure
;resource.  WHOENQ Checks for error code ENQX6 to see if it is already locked
;by another system then calls WHOEQC to find the node that has the lock.
;WHOEQC returns in T1 the SIXBIT node name
;WHOENQ builds the message why it couldn't lock the structure
;Accepts T1/ERROR CODE
;       STR/structure status block
;returns +1 No one has it locked
;	 +2 Someone has it or some other ENQ error.

WHOENQ:	CAIE T1,ENQX6		;Already locked?
	JRST [MOVE T2,STRALI(STR);Some other error.  Get the structure name
	      TMCT <%IUnable to lock structure %2$:%_Reason - %1J%_>
	      JRST WHOEN3]	;Add header
	CALL WHOEQC		;Who has it
	 RET			;No one
	SETONE R%STA,RSBIFL(RSB) ;Set status of request as fail
	MOVE T2,STRALI(STR)	;Get the name
	TMCT <%IUnable to lock structure %2S:
Structure %2S: is in the process of being DISMOUNTED with REMOVAL or
SET EXCLUSIVE by node %1S::%_> ;[6020]T1 contains  node name from WHOEQC
WHOEN3:	RETSKP			;No one has it

;WHOEQC - Routine to find out which system in the cluster has locked a
;particular structure resource via the ENQC JSYS.  Since the ENQC JSYS only
;returns the job number, WHOEQC will call GCNFIG to get the CI node number of
;each system in the cluster and do a INFO (function GETJI) on each node to find
;out if the job number belongs to this node.  If it is found WHOEQC returns
;back to the caller the node name in T1.
;Accepts STR
;	 ENQBLK set up
;Returns +1 no one has it
;	 +2 T1/sixbit node name

WHOEQC:	STKVAR <TEMP>		;Allocate space for job number and node name

;Build header

	MOVE T1,[20001,,6]	;Header length,# resource block,,length
	MOVEM T1,ENQBLK+.ENQLN  ;Into arg block
	SETZM ENQBLK+.ENQID	;No PSI and no ID

;Build request block

	MOVX T1,EN%BLN+EN%NST	;Ignore level number and allow nesting
	HRRI T1,-2		;Only allow locking by this job
	MOVEM T1,ENQBLK+.ENQLV	;Say so in arg block
	MOVE T1,STRUNQ(STR)	;Structure unique code
	MOVEM T1,RESPRE		;Resources prefix
	HRROI T1,RESPRE		;Make it a pointer
	MOVEM T1,ENQBLK+.ENQUC	;Add it to arg block
	SETZM ENQBLK+.ENQRS	;Only one resource
	SETZM ENQBLK+.ENQMS

;Do ENQC

	MOVEI T1,.ENQCS		;Function code
	MOVEI T2,ENQBLK		;Arg block
	MOVEI T3,ENQCBK		;Return Info goes here
	ENQC%			;Get the node that has the structure locked
	 ERJMP STOP		;(tbd)
	MOVE T1,ENQCBK		;Get the flag and job number 
	TXNN T1,EN%QCE		;Any errors?
	IFSKP.			;Yes
	 HRRZS T1		;Get error code
	 CAIE T1,ENQX7		;No ENQ on this lock?
	  $STOP <ENQC JSYS failed at WHOEQC:>
	 RET			;No one has it
	ELSE.
	 CAIN T1,-1		;Lock is not owned?
	 RET			;That's right
	 HRR T1,ENQCBK		;Get the job number
	 HRRZM T1,TEMP		;[6020]Save job number
	ENDIF.
	CALL GCNFIG		;Get node and CI number
	SOJLE T3,R		;No one has it

;  Who has it.  Use INFO% (GETJI) to find out who has it.

	MOVEI T4,2		;Start at the second CI-node number
WHOEQ1:	HLRZ T1,NUMBLK(T4)	;Get the CI-node number
	MOVEM T1,INFBLK+.INCID	;Store it in INFO arg block
	MOVE T1,[.INGJI,,.INAC3+2] ;Function,,Length
	MOVEM T1,INFBLK+.INFUN	;Store it 
	MOVE T1,TEMP 		;job number
	MOVEM T1,INFBLK+.INAC1	;Store it in INFO block	
	MOVE T1,[-2,,TEMPX]	;Just want to see if its there
	MOVEM T1,INFBLK+.INAC2	;Address goes here 
	SETZM INFBLK+.INAC3	;Start at the beginning
	MOVEI T1,INFBLK		;
	INFO%
	 ERJMP [AOS T4		;Not this node
		SOJN T3,WHOEQ1	;Get the next node
		RET]		;No one has it
	TXNN T1,IN%RER		;INFO% encounter a remote error?
	SKIPGE TEMPX		;Does the job belong to this node?
	JRST WHOEQ2		;Get the next node
	MOVE T1,NAMBLK(T4)	;Yes, get pointer to node
	MOVEI T2,TEMP		;Store node name here
	CALL SEVSIX		;Convert to SIXBIT
	MOVE T1,TEMP		;Return it in T1
	RETSKP

WHOEQ2:	AOS T4			;Not this node
	SOJN T3,WHOEQ1		;Get the next node
	RET
;Failure exit point
;Accepts RSB

STREXT:	CALL UNDREM		;[6011]UNLOCK?
	CALL NSACK		;Remote, tell Nebula
	RET			;Lets continue
	
;STRSET - Set up for dismount. 
;	  This routine sets the status of a structure and indicates whether
;	  an error has occurred.
;  For local dismounts:
;  If the structure is in used, a dismount query will be sent to the operator.
;  For remote dismounts:
;  It will not check for structure use

;ACCEPTS RSB and STR already setup
;RETURNS +1 If error occurs LSTERR contains error code
;	  or LSTERR is zero indicates user is connected or files open.
;	 +2 Ready to continue to dismount.

STRSET::SETZM LSTERR
	MOVEI T1,MSTAL		;Get address of alias string
	CALL STRSTT		;Try to get the status
	 JRST SAVERR		;Go save error
	TXNE T1,MS%PPS		;Is this the primary public str?
	JRST [	MOVEI T1,MSTX24 ;Say it is a ps:
		MOVEM T1,LSTERR	;Save the error
		RET]
	SETZ T2,		;Clear
	TXNE T1,MS%DIS		;Is this str unavailable
	MOVEI T2,1		;Yes, set the bit
	STOR T2,MS%DIS,STRFLG(STR) ;Store it
	CALL STRUNA		;Set it unavailable
	CALLRET SAVERR		;Error return back
	MOVEI T1,MSTAL		;Get address of alias string again
	CALL STRSTT		;Get the status again
	 JRST SAVERR		;Go get the error
	SETONE STR%UD,STRFL1(STR) ;Say it is unavailable due to dismount
	MOVE T1,RSBIFL(RSB)	;[6011]Get Local or remote bit
	TXNE T1,R%LOR		;[6011]Remote?
	RETSKP			;[6011]Yes, no need to query the operator
	AOS STRNDM(STR)		;[335]Up the # of dismount requests
	SKIPN T3		;Has anyone mounted this str?
	SKIPE T4		;No, are any files open?
	SKIPA			;Yes
	RETSKP			;No one connected & no files open

; WHILE WE WAIT FOR OPERATOR RESPONSE ALLOW OTHERS TO USE STRUCTURE
	MOVE T1,STRFLG(STR)	;Get the previous status
	TXNE T1,MS%DIS		;Was it unavailable
	RET			;Yes leave it unavailable
	CALL STRAVA		;Set it available
	CALLRET SAVERR		;Error in LSTERR
	RET			;No errors but someone is connected.

;STRER1 - Check to see if we have an error
;	 or if we need to ask operator what to do

STRER1: SKIPE LSTERR		;Any errors 
	CALLRET DISFAL		;Yes, tell operator what happened
STRER2:	MOVEI T1,STRER3		;Get end-action address
	CALLRET WRDSC		;Ask operator if ok to process request
STRER3:	MOVEI RSB,-RSBWTB(T2)	;Load rsb ac
	LOAD STR,RSBSS		;Get structure status block again
	CALL PSDR		;Parse operator response
	 JRST STRER2		;Bad response, try it again
	JUMPN T1,STRREF		;Operator refused
	CALL STRDM2		;No, set str unavailable
	CALLRET DISFAL		;Can not set str unavailable
	JRST STREX0		;Str unavailable, now check to see EXCLUSIVE

;;STRDM2 - Set str unavailable
;RETURNS +1 Any errors will be saved in LSTERR
;	 +2 O.K

STRDM2::MOVEI T1,RSBSTA(RSB)	;Get alias again
	MOVE T2,[POINT 7,MSTAL]	
	CALL SIXSEV		;Convert to asciz
	CALL STRUNA		;Set str unavailable
	CALLRET SAVERR		;Structure is gone!!!!
	RETSKP			;Back to caller

;STRDMS - Dismount the structure

;  Accepts: MSTAL / name of structure in ASCII

;  RETURNS +1 On error, error code in LSTERR
;	   +2 On success

STRDMS:: HRROI T3,MSTAL		;Set pointer to structure name
	MOVE T1,[1,,.MSDIS]	;Dismount structure
	MOVEI T2,T3		;Get address of only argument
	SKIPN TSTF		;Skip if debugging
	MSTR
	 ERJMP SAVERR		;Save the error and tell operator
	CALL DSTDDB		;Clear structure DDB info
	SETONE STR%DT,STRFL1(STR) ;Say unavailable due to dismount
	SETZRO STR%UD,STRFL1(STR) ;Say all done with dismount
	TXNE F,PORTF		;Are we engaged in a port operation
	JRST STRDM1		;Yes, tell operator and return skip
	MOVEI T1,STRNAM(STR)	;Get sixbit structure name and
	MOVE T2,[POINT 7,MSTNM]	; And convert to asciz
	CALL SIXSEV
	CALL WOSDM		;Tell operator of dismount
	RETSKP			;Have to check for removal/no removal 

STRDM1:	MOVE T1,STRNAM(STR)	;Get the structure name
	MOVE T2,STRALI(STR)	;Get the structure alias name
	TMCT <%IStructure %1S: (alias %2S:) dismounted %_%U%_>
	MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE SUCCEEDED AS PART OF PORT OPERATION/]
	CALL BTWTO		;SEND MSSG TO OPERATORS
	RETSKP			;All done back to who ever called STRDMS

;STRREF - Operator refuses to dismount structure
;Accepts STR/SSB address
;	 RSB/Request status block address
;Returns +1 always through STSTBK

STRREF::MOVE T1,STRALI(STR)	;Get the structure alias name
	MOVE T2,STRNAM(STR)	;Get the structure name
	TMCT <%IOperator refused to dismount structure %2S: (Alias %1S:)%_ for %U%_>
	MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE FAILED/]
	CALL BTWTO		;SEND MSSG TO OPERATORS
	CALL STSTBK		;[335]Set structure back to previous state
	ABTRET (MREQ23,ABT%OP)  ;[335] and abort the request
;**;[335]At DISREF:+0 rename the routine to STSTBK 
SUBTTL STSTBK - Set STR back to previous state, before the DISMOUNT.
;Accepts STR/structure status block address
;Returns +1 always

STSTBK:	SOSLE STRNDM(STR)	;[335]One less, any more dismounts?
	JRST STSTB1		;[335]Yes, better not set it back yet.
	SETZRO STR%UD,STRFL1(STR) ;[335]Say all done with dismount	
	MOVEI T1,RSBSTA(RSB)	;[335]Get SIXBIT alias
	MOVE T2,[POINT 7,MSTAL]	;[335]This is place to store 7-bit
	CALL SIXSEV		;[335]CONVERT IT
	MOVE T1,STRFLG(STR)	;[335]Get structure status
	TXNN T1,MS%DIS		;[335]Was it originally unavailable?
	JRST STSTB2		;[335]It was available so set it 
	CALL STRUNA		;[335]Set str unavailable
	CALL DISFA1		;[335]Can not set structure unavailable

STSTB1:	RET			;[335]Common exit point 

STSTB2:	CALL STRAVA		;[335]Set it available
	CALL DISFA1		;[335]Can not set structure unavailable
	CALLRET STSTB1		;[335]Back to previous, join common exit
SUBTTL STRUNA - SET STR UNAVAILABLE

;RETURNS +1 On error
;	 +2 Ok
STRUNA::MOVE T1,[POINT 7,MSTAL]	;Get pointer to structure alias
	MOVEM T1,MSTRST+.MSSSN
	MOVX T1,MS%DIS
	MOVEM T1,MSTRST+.MSSST	;Change only the bit to say the str
	MOVEM T1,MSTRST+.MSSMW	;Is being dismounted
	MOVE T1,[3,,.MSSSS]	;Changing structure status
	MOVEI T2,MSTRST
	SKIPN TSTF		;Skip if debugging
	MSTR
	 ERJMP R		;Get error in lsterr
	RETSKP

;STRAVA - SET STR AVAILABLE

;RETURNS +1 On error
;	 +2 Ok

STRAVA::MOVE T1,[POINT 7,MSTAL]	;Get pointer to structure alias
	MOVEM T1,MSTRST+.MSSSN
	MOVX T1,MS%DIS
	MOVEM T1,MSTRST+.MSSMW	;Change only the bit to say the str
	SETZM MSTRST+.MSSST	;Is being dismounted
	MOVE T1,[3,,.MSSSS]	;Changing structure status
	MOVEI T2,MSTRST
	SKIPN TSTF		;Skip if debugging
	MSTR
	 ERJMP R		;Get error in lsterr
	RETSKP

;STDERR - RECOVER FROM AN ERROR WHEN TRYING TO DISMOUNT A STRUCTURE

STDERR:	MOVEI T1,MSTNM
	TMCT <%IProblem with structure %1A: %J%_%U>
	MOVEI T3,[ASCIZ/DISMOUNT PROBLEM/]
	CALLRET BTWTO		;SEND MESSAGE TO OPERATOR

;SAVERR - Error routine, reports the error to the operator
;	  and saves the error in LSTERR.
;RETURNS +1 Always

SAVERR::MOVE T1,STRNAM(STR)	;Get the structure name
	MOVE T2,STRALI(STR)	;Get the structure alias
	TMCT <%IProblem with structure %1A: (Alias %2A:) %J%_%U>
	MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE FAILED/]
	CALL BTWTO		;SEND MSSG TO OPERATORS
	CALL GETERR		;Get the error
	MOVEM  T1,LSTERR	;Save the error
	RET			;After saving the error we return

;DISFAL - Tell the operators that a dismount structure failed and abort

DISFAL::MOVE T1,LSTERR		;Get the last error	
	CAIN T1,MSTX21		;Was it structure no longer mounted
	JRST DISFA0		;[6011]Go to common exit
	CAIN T1,MSTX24		;Trying to dismount PS:?
	JRST [MOVE T2,STRALI(STR) ;Yes, get the alias
	     TMCT <%I%1J %2S:%_%U>
	     MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE FAILED/]
	     CALL BTWTO		;Send msg to operators
	     JRST .+1]		;[6011]Set it back to previous state
	TXO T1,FA%TER		;[6011]MONITOR error type
	MOVEM T1,RSBERR(RSB)	;[6011]Save error type,,code
	MOVE T1,STRPNT(STR)	;Get the pointer to the DDB
	CALL DSFGET		;Go find it
	 $STOP <STRUCTURE NOT FOUND IN DDB..DISFAL::+2>
	MOVE T1,DSFE+DSFFLG	;Get the status
	TXNE T1,DSF%AV		;Should we set it available/unavailable
	JRST [CALL STRUNA	;Unavailable
	      CALL DISFA1	;On error say so
	      SETONE MS%DIS,STRFLG(STR) ;Should be unavailable
	      JRST DISFA]	;Just continue
	CALL STRAVA		;Set it available
	CALL DISFA1		;On error say so
	SETZRO MS%DIS,STRFLG(STR) ;Should be available
DISFA:	SETZRO STR%UD,STRFL1(STR) ;No longer unavailable due to dismount
	SETONE R%STA,RSBIFL(RSB) ;[6011]Set failure bit
	MOVE T1,RSBIFL(RSB)	;[6011]Get lock bit
	TXZE T1,R%LOC		;[6011]Did this request locked the structure
	CALL UNDREM		;[6011]Go unlock
DISFA0:	ABTREQ (LSTERR,ABT%IN)  ;[6011]Abort the dsk request
	JRST STREXT		;[6011]

;  Only called when the resulting error is due to a local event

DISFA1:	MOVE T1,STRNAM(STR)	;Get the structure name
	MOVE T2,STRALI(STR)	;Get the structure alias
	TMCT <%IProblem with structure %1S: (Alias %2S:) %J%_%U>
	MOVEI T3,[ASCIZ/CANNOT SET STRUCTURE TO ORIGINAL STATE/]
	CALLRET BTWTO		;SEND MSSG TO OPERATORS
SUBTTL	Operator Communication When set EXCLUSIVE fails

; SCREQ1 - SCS Request - dismount structure on all processors
;	   Until this procedure is set, the following
;	   temporary local operator request will be the request mechanism
;Must have a continue address in RSBCON

SCREQ1::MOVEI T1,SCREQ2		;get end action request
	CALLRET WODSCI		;Notify operator

SCREQ2:	MOVEI RSB,-RSBWTB(T2)	;Load RSB ac
	LOAD STR,RSBSS		;Get str status block
	CALL RSDR		;Parse answer
	 JRST SCREQ1		;Error, try again
	JUMPN T1,SCREQ3		;[6011]Refused
	MOVEI T1,RSBSTA(RSB)	;Get SIXBIT alias
	MOVE T2,[POINT 7,MSTAL]	;This is the place to store 7-bit
	CALL SIXSEV		;Convert it
	SKIPE ENQFLG		;[6011]Cluster ENQ enabled?
	JRST @RSBCON(RSB)	;[6011]No, do it the old way
	JRST SENNEB		;[6011]Send remote dismount message to NEBULA

;  Operator refused to continue with dismount

SCREQ3:	MOVE T1,STRALI(STR)	;Get the structure alias name
	MOVE T2,STRNAM(STR)	;Get the structure name
	TMCT <%IOperator refused to dismount structure %2S: (Alias %1S:)
from the other system for %_%U%_>
	MOVEI T3,[ASCIZ/CANNOT SET STRUCTURE EXCLUSIVE/]
	CALL BTWTO		;SEND MSSG TO OPERATORS
	CALL STSTBK		;[335] Abort the disk request and return
	ABTREQ (MREQ23,ABT%OP) ;[335][6011] and abort the request
	SKIPE ENQFLG		;[6011]Pre 7 MONITOR?
	RET			;[6011]Yes, just return
	SETONE R%STA,RSBIFL(RSB) ;[6011]Set failure bit
	MOVE T1,RSBIFL(RSB)	;[6011]Get status
	TXZN T1,R%LOC		;[6011]Did this request locked the structure
	JRST SCREQ4		;[6011]No
	MOVE T2,STRFL1(STR)	;[6011]Get the status
	LOAD T3,RSBTYP		;[6011]Get the type
	CAIN T3,.DSMST		;Dismount?
	CALL RELLOC		;[6011]Unlock

SCREQ4:	CALLRET @RSBABO(RSB)	;[6030]Continue at failure address and return
SUBTTL	Send a DISMOUNT Message to NEBULA

;[6011]SENNEB Send dismount message to Nebula.  Send only one remote dismount
;message.
;Accepts RSB and STR
;Returns back to scheduler

SENNEB:	MOVE T1,STRFL1(STR)	;Get the flag word
	TXNE T1,STR%SN		;Did we send a dismount message?
	JRST SCSNE0		;Yes, no need to send another

;Build Structure name block

	STKVAR <<DVBLK,3>>
	CALL PBINIT		;Set up for creating building blocks
	MOVE T1,[3,,.STRDV] ;length,, structure name block
	MOVEM T1,DVBLK		;Save it in the message
	MOVE T2,[POINT 7,MSTAL];Set up pointer for alias
	MOVEI T1,STRALI(STR)
	CALL SIXSEV		;CONVERT SIXBIT ALIAS TO NEEDED 7-BIT
	DMOVE T1,MSTAL		;Get the ASCIZ name
	MOVEM T1,1+DVBLK	;Put it in the message
	MOVEM T2,2+DVBLK	;Put it in the message
	MOVEI T1,DVBLK		;Get address of the structure name block 
	CALL PBBLK		;Add it

;Build Node name block
;Get node name from RSB

	LOAD T4,RSBNSM		;Get the number of nodes
	MOVEI T1,RSBRND(RSB)	;Start at the beginning
SCSNE:	MOVE T2,[.NDESZ,,.NDENM] ;Size,,node block
	MOVE T3,(T1)		;Get the node name
	DMOVEM T2,TEMPX		;Goes here
	PUSH P,T1		;Save address of node name 
	MOVEI T1,TEMPX		;Add it to the node block
	CALL PBBLK
	POP P,T1		;Restore address
	ADDI T1,2		;Go to the next node
	SOJG T4,SCSNE		;Get the next node

;Build Galaxy header

	MOVE T2,PBBPT		;Get the end of the message
	SUBI T2,TBUF		;Compute size of IPCF message
	HRL T1,T2		;Get length,,msgtype
	HRRI T1,.NRDSM		;
	MOVX T2,MF.NEB 		;Nebula message
	AOS T3,UNIQUE		;ACK code
	CALL GALHDR		;Build the Galaxy header
	MOVX T1,.DMDIS		;Assume it is for dismount
	LOAD T2,RSBTYP		;Get the type
	CAIN T2,.DSMST		;Dismount?
	SKIPA
	MOVX T1,.DMSEX		;Set exclusive
	MOVEM T1,TBUF+.OFLAG	;Save it
	MOVEI T1,.APORN		;ORION'S PID
	PUSH P,T3		;Save the ACK code 
	CALL TRANG		;Send it
	POP P,T3		;Restore ACK code
	SETONE STR%SN,STRFL1(STR) ;Say we have send a dismount message
SCSNE0:	MOVEM T3,RSBRAC(RSB)	;Save ACK code in RSB
	LOAD T1,STRSEN,STRSMN(STR) ;Get the number of dismount msg sent
	AOS T1			;Add one more
	STOR T1,STRSEN,STRSMN(STR) ;Save it 
	RET
SUBTTL	Build and Send a Cancel Remote Dismount Message to NEBULA


;[6011]
;Build and send cancel remote dismount message
;Accepts T1/Type of cancel (NC%CDM or NC%CSE)  and RSB

NEBCAN:	MOVEM T1,TBUF+.OFLAG	;Set the cancel type
	MOVE T1,[.OARGC+1,,.NCDSM] ;BUILD GALAXY HEADER
	MOVX T2,MF.NEB 		;Nebula message
	MOVE T3,RSBRAC(RSB)	;Get remote ACK
	CALL GALHDR		;Build the Galaxy header
	SETZM TBUF+.OARGC	;No arg count word
	MOVEI T1,.APORN		;MESSAGE GOING TO ORION
	CALLRET TRANG		;SEND CANCEL REQUEST TO ORION
SUBTTL	Process NEBULA Dismount ACK 

;[6011]
; PNEDAC - Process DISMOUNT ACK from NEBULA.
;The ACK can be in response to a SET EXCLUSIVE or a DISMOUNT/REMOVE command.
;PNEDAC translates the ACK to an ASCIZ text and informs the operator what the
;results of the remote dismounts were.  If there was a failure, a QUERY will be
;sent to the operator.  If all the remotes are successful
;or the operator RESPOND with PROCEED, PNEDAC will continue processing at
;@RSBCON on success and at RSBABO on abort.
;  RBUF/ IPCF MESSAGE FROM NEBULA via ORION, MESSAGE TYPE = .NTDAK
; RETURNS +1: ALWAYS

;Build status WTO about remote dismounts

PNEDAC:	SETZM PNFLAG		;Clear PNEDAC FLAG
	MOVEI T1,.STRNM		;Get the structure name block
	CALL ORNBLF		;
	 JRST KBADM		;Bad message from NEBULA (BUG)
	MOVE T2,0(T1)		;Get the structure name
	MOVEM T2,STNAM		;Save it
	MOVEI T1,.STSBK		;Get node name
	CALL ORNBLF
	 JRST KBADM		;No node block, bad message from NEBULA (BUG)

;  Uses T2/the arg block length and T1/address of block

	MOVEM T1,ADDRBK		;Save address of block
	IDIVI T2,2		;Two words/entry 
	MOVEM T2,NUMNOD		;Save number of nodes
	MOVE T4,RBUF+.OFLAG	;Get the flag
	MOVEM T4,DFLAG		;Save it
	SETZM FNDRSB		;Initialize found RSB flag

;  Continued on next page
;Continued from previous page

;  Get exclusive pending RSB

PNEDA: 	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	CALL PRQPID		;CLEAN UP REQUEST QUEUE FIRST

PNEDA0:	CALL QMSCAN		;GET ADDRESS OF NEXT RSB
	 JRST [SETOM FNDRSB	;No RSB found
	       SKIPE PNFLAG	;First time through?
	       JRST PNEDER	;No, all done
	       JRST PNEDA7]	; must have been canceled
	MOVEI RSB,-RSBLNK(T2)	;Get RSB adddress
	MOVE T3,RSBRAC(RSB)	;Get ACK code from entry
	CAME T3,RBUF+.MSCOD	;Does it match code in IPCF message?
	JRST PNEDA0		;No,, continue scan
	LOAD STR,RSBSS		;Get str status block
	HRL T3,ADDRBK		;Get the source
	HRRI T3,RSBRND(RSB)	;Destination
	BLT T3,RSBRND+15(RSB) 	;Do the transfer
	LOAD T1,STRSEN,STRSMN(STR) ;[6011](TBD)Get message sent counter
	SOS T1			;[6011]One less
	STOR T1,STRSEN,STRSMN(STR) ;Put it back
	SETZRO STR%SN,STRFL1(STR) ;Clear send dismount message to NEBULA
	JRST PNEDA1

;Print the success nodes first

PNEDA7:	MOVE T1,ADDRBK		;Get the nodes status block
	SKIPA

PNEDA1:	MOVEI T1,RSBRND(RSB)	;Point to remote node status
	MOVEM T1,ADDRBK		;Save it for later
	SETZM PNFLAG		;Clear the header flag
	MOVE T2,NUMNOD		;Get the number of nodes in message
	TMCT <%I>		;Initialize TMCMSG buffer
PNEDA2:	MOVE T4,.STNST(T1)	;Get status word
	TXNN T4,ST%SSD		;Success?
	 JRST PNEDA3		;No
	SKIPE PNFLAG		;Did we print the header?
	IFSKP.			;No
	 MOVE T3,STNAM		;Get the structure name
 	 TMCT <Structure %3S: dismounted from >
	 SETOM PNFLAG		;Set the header flag
	ELSE.
	 TMCT <, >
	ENDIF.
	MOVE T3,.STNNE(T1)	;Yes, get the node name
	TMCT <%3S::>		;Add it to the message
PNEDA3:	ADDI T1,.STRLN		;Go to the next block
	SOJN T2,PNEDA2		;Get the next block if there is one
	TMCT <%_>

;  Continued on next page
;Continued from previous page

	MOVE T1,DFLAG		;Get status flag word
	TXNE T1,DS%SUC		;All success?
	JRST PNEDA6		;Yes no need to send WTOR

;Print the failure nodes

	MOVE T1,ADDRBK		;Get the nodes status block
	MOVE T2,NUMNOD		;Get number of nodes

PNEDA4:	MOVE T4,.STNST(T1)	;Get status word
	TXNE T4,ST%SSD		;Success?
	JRST PNEDA5		;Yes, get the next node
	MOVE T3,STNAM		;Get the structure name
	MOVE T4,.STNNE(T1)	;Yes, get the node name
 	TMCT <Structure %3S: failed to be dismounted from %4S::%_Error - >
	MOVE T3,.STNST(T1)	;Get the error word
	TXZN T3,ST%TER		;From MONITOR
	IFSKP.			;Yes
	 TMCT <%3J>
	ELSE.
	 CALL FNDERR		;Find the address of the error string
	 TMCTI <T3>
	ENDIF.
	SKIPN FNDRSB		;No RSB means request canceled
	TMCT <%_Correct the problem indicated on %4S::%_>
PNEDA5:	ADDI T1,.STRLN		;Go to the next block
	SOJN T2,PNEDA4		;Get the next block

	MOVE T1,RBUF+.OFLAG	;Get the flag
	TXNN T1,DS%SUC		;Dismount from all?
	SKIPE FNDRSB		;Don't have a request
	JRST PNEDA6		;No need for WTOR
	TMCTI <RESHDR>		;Add tail of message
	MOVEI T3,[ASCIZ/DISMOUNT QUERY/]
	TXNE T1,DS%SEX		;Is this a dismount ACK via SET EXCLUSIVE?
	MOVEI T3,[ASCIZ/SET STRUCTURE QUERY/] ;Yes
	MOVEI T1,PNERSP		;Continue here
	MOVEI T2,RSBWTB(RSB)	;Get WTB address
	CALLRET BTWTOR		;Send WTOR

;  Continued on next page
;Continued from previous page

;Here there is no need to send a WTOR because either the request was canceled
;or all the remote dismounts were successful

PNEDA6:	MOVEI T3,[ASCIZ/REMOTE DISMOUNT STATUS/]
	CALL BTWTO		;Tell the operator
	SKIPN FNDRSB		;Do we have a request for this ACK
	JRST PNEDEX		;Yes, continue with the request

;Tell operator to remotely mount the structure that just got remotely
;dismounted.

	MOVE T1,ADDRBK		;Get the address of structure block
	MOVE T2,NUMNOD		;Get number of nodes
	MOVE T3,STNAM		;Get the structure name
	TMCT <%IDismount request has been canceled.
However, structure %3S: has been dismounted from nodes:%_>

PNEDC1:	MOVE T4,.STNST(T1)	;Get status word
	TXNN T4,ST%SSD		;Success?
	JRST PNEDC3		;No, get the next node
	MOVE T3,.STNNE(T1)	;Yes, get the node name
	TMCT <%3S::  >		;Add it
PNEDC3:	ADDI T1,.STRLN		;Next
	SOJG T2,PNEDC1		;[6017]
	MOVEI T3,[ASCIZ/DISMOUNT STATUS/]
	CALLRET BTWTO

;  Continue with the request.  Could be a set exclusive command or a dismount
;  with removal.

PNEDEX:	LOAD STR,RSBSS		;Get str status block
	MOVEI T1,RSBSTA(RSB)	;Get SIXBIT alias
	MOVE T2,[POINT 7,MSTAL]	;This is the place to store 7-bit
	CALL SIXSEV		;Convert it
	CALL @RSBCON(RSB)	;Yes, continue from where we left of
PNEDER:	RET

;Parse response from operator

PNERSP: MOVEI RSB,-RSBWTB(T2)	;Load RSB ac
	LOAD STR,RSBSS		;Get str status block
	SETZM FNDRSB		;We have a request 
	CALL RSDR		;Parse answer
	 JRST PNEDA1		;Error, try again
	JUMPN T1,SCREQ3		;Abort 
	MOVEI T1,RSBSTA(RSB)	;Get SIXBIT alias
	MOVE T2,[POINT 7,MSTAL]	;This is place to store 7-bit
	CALL SIXSEV		;Convert it
	JRST PNEDEX		;Go to common code
SUBTTL	Process NEBULA Remote Dismount Errors

;[6011]
;Accepts T3/error bit
;Returns T3/address of error text string

FNDERR:	SAVET			;Save T ACs
	JFFO T3,.+1		;Pickup displacement into error table
	CAIL T4,STLOW		;Check for legal error
	CAILE T4,STHIGH		;Check for legal error
	SETZ T4,
	MOVE T3,NEBERR(T4)	;[6032]Return address of error string in T3
	RET

NEBERR:	[ASCIZ/Unknown error/]
	[ASCIZ/STRUCTURE SUCCESSFULLY DISMOUNTED/]
	[ASCIZ/SENDER WAITING FOR A HELLO RESPONSE/]
	[ASCIZ/LISTENER HAS NOT RECEIVED HELLO MSG/]
	[ASCIZ/SENDER LISTENER ARE CRASHED/]
	[ASCIZ/NO SUCH NODE/]
        [ASCIZ/PRE-7 MONITOR/]
	[ASCIZ/NO DECNET IN MONITOR/]
        [ASCIZ/SCS% DETECTED NODE LEFT THE CLUSTER/]
        [ASCIZ/INFO% UNABLE TO OBTAIN SOFTWARE ENVMEN/]
        [ASCIZ/DISMOUNT CANCELLED IN TIME/]
        [ASCIZ/MONITOR ERROR DISMOUNTING STRUCTURE/]
 	[ASCIZ/ORION ERROR/]
	[ASCIZ/QUASAR ERROR/]
 	[ASCIZ/NEBULA ERROR/]
 	[ASCIZ/MOUNTR ERROR/]
; WODSCI - Tell Operator to find all other processors having
;	   the specified structure mounted so that they can dismount it.
;RSB and STR

WODSCI:	STKVAR <CONADR,TRSB>	;Allocate room for continue address, RSB
	MOVEM T1,CONADR		;Save continue address for CALL BTWTOR
	MOVEM RSB,TRSB		;[6011]Save RSB
	MOVE T2,STRNAM(STR)	;Get structure name
	MOVE T3,STRALI(STR)	;Get structure alias
	TMCT <%IStructure %2S: (Alias %3S:) is in use by%_>
	SKIPN ENQFLG		;[6011]Cluster ENQ enabled?
	IFSKP.			;[6011]No, must be a pre 7 release
	 TMCT <another processor in the cluster>
	 JRST WODSC1		;[6011]Go finish of WTOR message text
	ENDIF.
	CALL GETNOD		;[6011]Get the systems which have it mounted
	 JRST WODSC2		;[6013]No one has it????
	LOAD T2,RSBNSM		;Get number of nodes which has it mounted
	SKIPN T2		;If no node
	JRST STREX2		;[6013]Try to set it exclusive again
WODSC0:	MOVE T1,RSBRND(RSB)	;Get the node name
	TMCT <%1S::>		;Add it to the message
	SOJLE T2,WODSC1		;Any more?
	TMCT <, >		;Yes, add a comma
	ADDI RSB,2		;Next node
	JRST WODSC0		;Get the next node

WODSC2:	SETZ T1,		;[6013]Start at the beginning 
	SKIPE T2,BADNOD(T1)	;[6013]Do we have a bad node?
	IFSKP.
	 TMCT <another processor in the cluster>
	 JRST WODSC1		;[6013]No one
	ENDIF.

	TMCT <the following nodes which were unreachable for structure
information:%_>
WODSC4:	TMCT <%2S::>		;[6013]Display BAD node
	AOS T1			;[6013]Next BAD node
	SKIPN T2,BADNOD(T1)	;[6013]Do we have one?
	IFSKP.			;[6013]Yes
	 TMCT <, >
	 JRST WODSC4
	ENDIF.

WODSC1:	TMCT <%_and can't be removed from the cluster unless it's dismounted
with NO-REMOVAL from the systems.
Respond with PROCEED to dismount the structure from the 
above systems or
Respond with ABORT to terminate the dismount request%_ > ;[6026]
	MOVE RSB,TRSB		;Get back RSB 
	MOVEI T2,RSBWTB(RSB)	;Get WTB address
	LOAD T3,RSBTYP		;Get the type
	CAIE T3,.DSMST		;Dismount? 
	IFSKP.
	 MOVEI T3,[ASCIZ/DISMOUNT QUERY/]
	ELSE.
 	 MOVEI T3,[ASCIZ/SET STRUCTURE COMMAND QUERY/]
	ENDIF.
	MOVE T1,CONADR		;Get the continue address
	CALL BTWTOR		;Query the operator
	RET
SUBTTL	Find Out Which Node(s) in the Cluster has the Structure Mounted

;[6011]
;Do config%
;Accepts STR
;	 RSB
;Returns +1 on failure
;	 BADNOD/Nodes in the Cluster that might have the structure mounted
;	        but we don't know
;Returns +2 on success
;	 NAMBLK/ASCIZ node name
;	 NUMBLK/CI-node number
;	 RSBRND+n/SIXBIT node names
;	 RSBNNM/number of node
;	 +2 on success 

GETNOD:	STKVAR <NCOUNT,TRSB>	;Allocate space for which node mounted the str
				;and RSB.
	SETZM NCOUNT		;Make sure we start at zero
	MOVEM RSB,TRSB		;Save RSB
	SETZM BADNOD		;[6013]Clear BAD node block
	MOVE T1,[BADNOD,,BADNOD+1] ;[6013]Get source,,destination 
	BLT T1,BADNOD+6		;[6013]Clear it
	SETZM RSBNNM(RSB)	;No one has it mounted yet
	CALL GCNFIG		;Get the node and their CI node number
	SOJLE T3,RSKP		;We are the only one, set it exclusive
	STOR T3,RSBNO1		;Remember how many node in cluster
	MOVEI T4,BADNOD		;[6013]Get address of BAD nodes in the cluster
	MOVEM T4,BADADR		;[6013]Save it

;Can't use T3.  T3 must be perserved when routines are called from this routine
;Check which systems have the structure mounted.  RSB is saved in TRSB because
;it gets trashed.  Make sure RSB is strored before leaving this routine

	MOVEI T4,2		;Start at the second CI-node number
GETNO1:	HLRZ T1,NUMBLK(T4)	;Get the CI-node number
	MOVEM T1,INFBLK+.INCID	;Store it in INFO arg block
	MOVE T1,[.INMSR,,.INAC2+2] ;Function,,Length
	MOVEM T1,INFBLK+.INFUN	;Store it 
	MOVE T1,[.MSGSI+1,,.MSGSS] ;Get length,,function	
	MOVEM T1,INFBLK+.INAC1	;Store it in INFO block	
	MOVEI T1,MSTRST		;MSTR block
	MOVEM T1,INFBLK+.INAC2	;Address goes here 
	MOVEI T1,STRALI(STR)	;Make pointer to alias
	MOVE T2,[POINT 7,MSTAL]	;DO SAME FOR STRUCTURE ALIAS
	MOVEM T2,MSTRST+.MSGSN	;Store it in MSTR block
	CALL SIXSEV		;Convert into ASCIZ 
	MOVEI T1,INFBLK		;Get the INFO arg block
	INFO%
	 ERJMP GETNO3		;Local error, get the next node
	TXZE T1,IN%RER		;[6013]Any remote error?
	JRST GETNO4		;Yes, skip this and onward
	MOVE T1,NAMBLK(T4)	;Get pointer to node
	MOVEI T2,RSBRND(RSB)	;Store name here
	CALL SEVSIX		;Convert to SIXBIT
	MOVE T1,NCOUNT		;Get counter for who has it mounted
	AOS T1			;Increment it
	MOVEM T1,NCOUNT		;Store it back
	ADDI RSB,2		;Next RSBNNM
GETNO2:	AOS T4			;Next node number
	SOJG T3,GETNO1		;Next node name
	MOVE RSB,TRSB		;Get RSB
	MOVE T1,NCOUNT		;Get who has it mounted counter
	STOR T1,RSBNSM		;Store it in RSB
	SKIPG T1		;[6013]Do we have at least one node
	RET			;[6013]No
	RETSKP			;No more all done

;  Detected that a node in the Cluster is running a 7 Monitor.  Save the SIXBIT
;  node name in BADNOD and display them in WODSCI:

GETNO4:	CAIN T1,MSTX21		;[6013]Structure is not mounted?
	JRST GETNO2		;[6013]Yes, no need to add this node
GETNO3:	MOVE T2,BADADR		;[6013]Get address of BAD nodes
	MOVE T1,NAMBLK(T4)	;Get pointer to node
	MOVEI T2,(T2)		;Store name here
	CALL SEVSIX		;Convert to SIXBIT
	AOS T2			;[6013]Increment to next word
	MOVEM T2,BADADR		;[6013]Save it
	JRST GETNO2		;[6013]Get the next node
SUBTTL	Get The Cluster Node Name and CI Node Number
;[6010]
;GCNFIG - returns the number of nodes in the cluster.
;Returns +1 Success T3/number of nodes in the cluster
;	    NAMBLK/Node name block
;   	    NUMBLK/CI node number block


GCNFIG:	MOVEI T1,CNFSIZ		;Size of CNFIG block 
	MOVEM T1,NAMBLK+.CFNND	;Store it in the arg block

	MOVEI T1,.CFCND		;Get function code
	MOVEI T2,NAMBLK		;Get the arg address
	CNFIG%			;Get the node name
	 ERJMP STOP		;Shouldn't fail

	MOVEI T1,CNFSIZ		;Size of CNFIG block 
	MOVEM T1,NUMBLK+.CFLEN	;Store it in the arg block
	MOVEI T1,.CFCSE		;Get function code
	MOVEI T2,NUMBLK		;Get the arg address
	CNFIG%			;Get the node number
	 ERJMP STOP		;Shouldn't fail
	HLRZ T2,NUMBLK		;Get number of words returned
	SOS T2			;Don't count the first word
	HLRZ T3,NAMBLK		;Get number of node in the cluster
	CAME T3,T2		;Are the number and name the same?
	JRST GCNFIG		;No, try again
	RET
;RSDR - Parse operator response to request for other processor dismount
;
RSDR:	CALL COMNDI		;Initialize for COMND jsys
	MOVEI T2,[FLDDB. .CMKEY,,RSDRKS] ;Setup keyword parse
	CALL COMNDX		;Parse keyword
	 JRST [ MOVEI T1,[ASCIZ/Response must be PROCEED or ABORT/]
		CALLRET RSPERR] ;Incorrect response, give error
	HRRZ T2,(T2)		;Get address of keyword processr
	CALLRET (T2)		;Dispatch 

RSDRKS: RSDRSE,,RSDRSE
	[ASCIZ/ABORT/],,RSDRNO
	[ASCIZ/PROCEED/],,RSDRSI
RSDRSE==.-RSDRKS-1		

RSDRNO::SETO T1,
	RETSKP

RSDRSI::SETZ T1,
	RETSKP
SUBTTL STRMNT - MOUNT A STRUCTURE

;ACCEPTS: RSB/	CURRENT REQUEST BLOCK
;	  STR/	STRUCTURE TO MOUNT

;RETURNS: +1/	FAILURE
;	  +2/	SUCCESS

;  It is assumed the structure specified is not logically mounted...

STRMNT:	SKIPE ENQFLG		;[6011]Pre 7 monitor?
	JRST STRMN		;[6011]Yes, no need to check locking

;  Check to see if we are doing a remote mount.  If we are, the mount request
;  must be from the same node that did the remote dismount.

	MOVE T1,RSBIFL(RSB)	;[6011]Get flag
	TXNN T1,R%LOR		;[6011]Local or remote
	IFSKP.			;[6011]Remote
	 SKIPE T1,STROBN(STR)	;[6021]No need to check if no node name
	 CAMN T1,RSBOBN(RSB)	;[6020]Is the node we are doing the remote
				;mount the same as the node we did a remote
				;dismount
  	 JRST STRMN		;Yes, by pass locking check
	 SKIPN T2,RSBSTN(RSB)	;Get the structure name
	 MOVE T2,RSBSTA(RSB)	;No name, use the alias 
	 MOVE T3,RSBSTA(RSB)	;and alias
	 TMCT <%IUnable to mount structure %2S: (Alias %3S:)
Structure %2S: (Alias %3S:) is currently being dismounted
with removal by node %1S::>
	MOVEI T3,[ASCIZ/MOUNT STATUS/]
	CALLRET BTWTO 		;[6011]Inform operator
	ENDIF.
	 
; Check and see if it is reasonable to mount this structure

	MOVE T1,STRFL1(STR)	;[6011]Get status
	TXNE T1,STR%LE+STR%LD	;[6011]Do we have it locked?
	JRST STRMN		;[6011]Yes, no need to check who has it locked
	CALL WHOEQC		;[6011]Anyone has it locked
	JRST STRMN		;[6011]No one has it
	SKIPN T2,RSBSTN(RSB)	;Get the structure name
	MOVE T2,RSBSTN(RSB)	;Get the structure name
	MOVE T3,RSBSTA(RSB)	;and alias
	TMCT <%IUnable to mount structure %2S: (Alias %3S:)
Structure %2S: is locked by node %1S::>
	MOVEI T3,[ASCIZ/MOUNT STATUS/]
	CALL BTWTO 		;[6011]Inform operator
	MOVEI Q1,
	JRST STRMEX

STRMN:	MOVE T1,RSBSTA(RSB)	;Get alias in request
	MOVEM T1,DSFE+DSFSPC	;Set it in test DDB
	MOVEI T1,.DVSTR		;Get structure type
	MOVEM T1,DSFE+DSFTYP	;Set it
	CALL DSFLOC		;Go look for it
	  JRST STRMN0		;Don't have DDB.  Have no reason not to mount

	MOVE T2,DSFE+DSFFLG	;Get the flags
	TXNE T2,DSF%IG		;Is it ignore?
	JRST [MOVEI Q1,MREQ27	;Get the error code
	      JRST STRMEX]	;Yes, reject request based on caller
	SKIPE DSFE+DSFPNT	;Get address of SSB for structure
	JRST [ABTRET (ABRTNR)]	;Already mounted, reject the request
	CALL NEWSTA		;Get new status of the structure based on DDB
	  JFCL			;Not mounted
	TXNE T1,MS%DIS		;Is this structure available to be mounted?
	JRST [MOVEI Q1,MSTX33	;Get the error code
	      JRST STRMEX]	;No, reject request based on caller
	
	MOVE T1,STRFL1(STR)	;Get the other status word
	TXNE T1,STR%DT		;Is it being dismounted?
	JRST [MOVEI Q1,MSTX33	;Yes, get the error code
	      JRST STRMEX]	;Reject request based on requestor

STRMN0:	MOVE T1,STR		;Get the address of the SSB
	CALL CHKAVA		;Check availability status of the SSB
	JRST [MOVEI Q1,MSTX33	;Get the error code
	      JRST STRMEX]	;Not available, reject request based on caller

;  Now we want to set up the MSTR to mount the structure
;  First argument word is to contain pointer to ASCIZ string for structure name

	MOVE T2,[POINT 7,MSTNM]	;GET PTR TO CONVERT STR NAME TO ASCIZ
	MOVEM T2,MSTRBK+.MSTNM	;STORE POINTER FOR LATER MSTR CALL
	MOVEI T1,RSBSTN(RSB)
	SKIPN (T1)		;IF NO PHYSICAL NAME WAS SPECIFIED,
	MOVEI T1,RSBSTA(RSB)	; USE ALIAS
	CALL SIXSEV

;  Second argument word is pointer to ASCIZ string for structure alias

	MOVE T2,[POINT 7,MSTAL]	;DO SAME FOR STRUCTURE ALIAS
	MOVEM T2,MSTRBK+.MSTAL
	MOVEI T1,RSBSTA(RSB)
	CALL SIXSEV

;  Third argument word is to contain number of units in structure

	LOAD T1,STRUNI,(STR)	;GET NUMBER OF UNITS IN STRUCTURE
	HRRZM T1,MSTRBK+.MSTFL	; AND DON'T SET ANY SPECIAL ACTION FLAGS

;  Beginning with the 4th argument word build three word blocks, one block for
;  each disk in the structure.  The three word block contains the CKU for the
;  disk drive.
;  For this loop, T1 pointers to the current STRADD and controls the loop
;		  T2 points to the destination in the MSTR block for the CKU.

	MOVNS T1		;NEGATE NUMBER OF UNITS
	MOVSS T1		;SET UP INDEX FOR DISK ADDRESS
	HRRI T1,STRADD(STR)	;Point to the first disk drive status block
	MOVEI T2,MSTRBK+.MSTUI	;SET UP INDEX FOR STORING DISK INFO

STRMN1:	MOVE DSK,(T1)		;GET ADDRESS OF DISK STATUS BLOCK

	LOAD T3,DSKCHN,(DSK)	;GET DISK CHANNEL
	MOVEM T3,.MSTCH(T2)	;STORE FOR MSTR CALL

	LOAD T3,DSKCTR,(DSK)	;GET CONTROLLER
	CAIN T3,<.RTJST(-1,DOP%K2)> ;ALL ONES?
	SETO T3,		;YES, MAKE FULL-WORD
	MOVEM T3,.MSTCT(T2)	;STORE IT

	LOAD T3,DSKDRV,(DSK)	;Get drive unit number
	MOVEM T3,.MSTUN(T2)	;Store for MSTR call

	ADDI T2,1+.MSTUN	;Increment destination for next try
	AOBJN T1,STRMN1		;Go for another disk drive if any

	SUBI T2,MSTRBK		;GET LENGTH OF ARGUMENT BLOCK

	MOVEI T1,.MSMNT		;Get MSTR function type (mount a structure)
	HRL T1,T2		;Get length
	MOVEI T2,MSTRBK		;GET ADDRESS OF ARGUMENT BLOCK
	MSTR			;FINALLY, MOUNT IT
	 ERJMP STMERR		; SOMETHING WENT WRONG

	CALL RELLOC		;[6014]Unlock the structure
	SETZM STRELC(STR)	;[6012]No longer locked for dismount
	SETZRO STR%LD+STR%OB,STRFL1(STR) ;[6016]Clear lock bit 
	MOVE T1,RSBSTA(RSB)	;GET STRUCTURE ALIAS
	MOVEM T1,STRALI(STR)	; AND STORE

;  We should also create a str entry in DDB for this structure

	CALL ISTDDB		;Go try to create
	  CALL [SKIPE DSFE+DSFPNT ;Already have one, already pointing at SSB?
		$STOP <Detected previously set pointer in DDB during STR mount>
		RET]		;No, continue
	HRRZM STR,DSFE+DSFPNT	;Need to update pointer
	CALL DSFUDE		;Update the entry pointer
	 $STOP <Update of previously known DDB with DSFUDE failed>
	SKIPE STRPNT(STR)	;Already pointing at DDB?
	$STOP <Detected previously set pointer in SSB during STR mount> ;Yes
	MOVEM T1,STRPNT(STR)	;Save the pointer to the DDB

	SETONE STR%MT,STRFL1(STR) ;Set structure mounted

STRMN3:	LOAD T4,STRMCT,(STR)	;GET NUMBER OF DISKS IN STRUCTURE
	MOVNS T4
	HLRZS T4
	HRRI T4,STRADD(STR)
STRMN4:	MOVE DSK,(T4)
	CALL DSTGIV		;GET STATUS OF GIVEN UNIT
	 CALL STOP		;THERE IS AN INCONSISTENCY
	MOVEM T1,DSKFLG(DSK)	;STORE STATUS OF UNIT
	MOVE T1,STRALI(STR)	;GET ALIAS
	MOVEM T1,DSKSTA(DSK)	; AND STORE
	AOBJN T4,STRMN4
	SKIPGE RSBITN(RSB)	;Is the MOUNT from operator?
	IFSKP.
	 CALL WOSMT		;[6015]Tell operator of success
	ELSE.
	 CALL KSMTE		;[6015]Let KSMT handle the message
	ENDIF.

STRMN5:	CALL NEWSTA		;Get the new status
	 JFCL			;Don't care
	CALL STSTR		;Set the structure
	 JRST [CAIE T1,-1	;[6011]Couldn't set exclusive
	       JRST STRMNE	;[6015]No
	       SETONE STR%ME,STRFL1(STR) ;[6011]Set bit in flag word
	       JRST STRMN6]
STRMNE:	RETSKP			;[6015]Common exit point
SUBTTL	Apply Structure Exclusive Attribute after it mounted

;[6011]  Fail to set the structure exclusive attribute.
;  We get here only if we can't set the structure exclusive as part of the
;  mount.
;  At this point there is no RSB for the set exclusive.

STRMN6:	SKIPE CFSB		;CFS?
	SKIPE ENQFLG		;[6011]Cluster ENQ enabled?
	JRST STRMNE		;[6015]No
	MOVEI T1,.DSEXC		;[6015]Set up exclusive switch request
	CALL OPRSB		;[6015]Get RSB
	 JRST [TMCT <%IFailed to acquire RSB for exclusive procedure>
	       MOVEI T3,[ASCIZ/APPLYING STRUCTURE ATTRIBUTE STATUS/]
	       CALLRET BTACKT]	;Error abort
	MOVE T1,RBUF+.MSCOD	;[6014]Get operator's PID
	MOVEM T1,RSBPID(RSB)	;[6014]Save it for later
	STOR STR,RSBSS		;[6011]Save SSB address in RSB
STRMN7:	CALL GETLOC		;Lock the structure
	 JRST [CALL WHOENQ	;Failed, find out who has it
	       JRST STRMN7	;No one lets try again
	       MOVEI T3,[ASCIZ/APPLYING STRUCTURE ATTRIBUTE STATUS/]
	       CALL BTACKT	;[6011]Tell operator
	       ABTREQ (ABRTNR)	;[6015]Get rid of RSB
	       JRST STRMNE]	;[6011]failed
	MOVEI T1,STRMNP 	;[6015]Get continue routine address
	MOVEM T1,RSBCON(RSB) 	;[6011]Save it
	MOVEI T1,STRMNA		;[6015]Get abort routine address 
	MOVEM T1,RSBABO(RSB)	;[6011]
	CALL SCREQ1		;[6015]Failed get cfs compliance
	JRST STRMNE		;[6015]Go to common exit 

;  STRMNP continue with setting the structure exclusive after receiving the
;  dismount ACK.
;  Accepts RSB and STR.
;  Returns via STRMN3.

STRMNP:	SKIPE T1,STRPNT(STR)	;Get address of DDB
	CALL DSFGET		;Get it
	 JRST STRMNA		;[6015]Not here, must have been UNDEFINE

	CALL NEWSTA		;Get the new status
	 JFCL			;Don't care
	CALL STSTR		;Set the structure
	 JRST [CAIE T1,-1	;[6011]Couldn't set exclusive
	       JRST .+1		;[6011]No
	       SETONE STR%ME,STRFL1(STR) ;[6011]Set bit in flag word
	       JRST STRMN6]

;  Finally, we have applied the structure's exclusive attribute.
;  Now, lets see if we can unlock the structure.

STRMNA:	SETZRO STR%ME,STRFL1(STR) ;[6015]Clear can't set exclusive bit
	CALL UNDREM		;[6011]Unlock if we can
	ABTRET (ABRTNR)		;[6015]Get rid of RSB
;STMERR - ERROR IN MOUNTING A STRUCTURE

STMERR:	SAVEQ
	MOVEI T1,.FHSLF		;GET THE ERROR
	GETER
	HRRZS T2		;GET ERROR ONLY
	MOVE Q1,T2		;[331] Copy error code to safe place
	CALL DDSERR		;[331] Tell operator of problem
	CAIN Q1,MSTRX5		;[331] Is error drive offline?
	RET			;[331] Yes, don't abort the request

;  STRMEX - Exit routine for STRMNT for a structure which can't be mounted 
;           because of its disk or structure attributes.  The purpose of this 
;	    routine is to reject the request based on the caller i.e from user
;	    or operator.
;Accepts - RSB/Request status block
;	   Q1/error code.
;Returns - +1 to caller of STRMNT.  Indicates failure

STRMEX: SKIPL RSBITN(RSB)	;Is it from operator
	JRST [ABTRET (Q1,ABT%IN)] ;No, must be from user, reject the request
	RET			;Yes, let KSMT handle the error

;DDSERR - RECOVER FROM AN ERROR WHEN TRYING TO MOUNT A STRUCTURE

DDSERR:	MOVEI T1,MSTNM
	TMCT <%IProblem with structure %1A:%_%J%_%U>
	MOVEI T3,[ASCIZ/MOUNT PROBLEM/]
	CALLRET BTWTO		;SEDN MESSAGE TO OPERATOR
;SUBTTL SYMSET - BUILD AND LOG SYSERR ENTRY FOR DISK DRIVE STATUS CHANGE

;ACCEPTS: T1/ FUNCTION CODE (CS%ADV = SET AVAILABLE, CS%DDV = SET UNAVAILABLE)
;	  T2/ ADDRESS OF ASCIZ REASON, OR 0 IF NO REASON GIVEN
;	  Q2/ CHANNEL,,DRIVE
;	  DSK/ ADDR OF DISK STATUS BLOCK
;RETURNS: +1, ALWAYS

SYMSET:	SAVEQ
	SETZM SYRMSG		;ZERO OUT SYSERR MESSAGE AREA
	MOVE T4,[SYRMSG,,SYRMSG+1]
	BLT T4,SYRMSG+SYRMSZ-1

; TRANSFER OPERATION CODE AND REASON TO MESSAGE

	STOR T1,CS%OPR,SYRMSG+CS%OPW ;STORE OPERATION CODE INTO MESSAGE
	MOVEI Q1,SYRHSZ+CS%SIZ	;ASSUME NO REASON GIVEN
	SKIPN T1,T2		;REASON GIVEN?
	JRST SYMSE1		;NO
	MOVS Q3,T1		;YES, COPY ADDRESS OF STRING FOR BLT
	CALL ASCIZL		;GET # OF CHARACTERS
	IDIVI T2,5		;GET # OF WORDS MINUS 1
	CAIL T2,SYRMSZ		;TOO LONG?
	MOVEI T2,SYRMSZ-1	;YES, TRUNCATE
	MOVEI Q1,SYRHSZ+CS%SIZ+1(T2) ;SAVE SIZE OF ENTIRE MESSAGE
	HRRI Q3,SYRMSG+CS%SIZ	;GET BLT DESTINATION
	BLT Q3,SYRMSG+CS%SIZ(T2) ;TRANSFER STRING TO MESSAGE
	MOVEI T1,CS%SIZ
	STOR T1,CS%RSN,SYRMSG+CS%RSW ;STORE POINTER TO REASON
SYMSE1:	MOVEI T1,SEC%CS		;GET CONFIGURATION STATUS CHANGE CODE
	DPB T1,[POINT 9,SYRHDR,8] ;STORE INTO SYSERR ENTRY HEADER

;BUILD AND STORE SIXBIT DEVICE NAME

	MOVE T1,[SIXBIT/DP000 /]
	MOVE T2,[POINT 6,1,11]
	HLRZ T3,Q2		;GET CHANNEL
	ADDI T3,20		;MAKE IT A SIXBIT NUMBER
	IDPB T3,T2		;SET CHANNEL INTO NAME
	HRRZ T3,Q2		;GET DRIVE NUMBER
	ADDI T3,20
	IDPB T3,T2		;SET DRIVE INTO NAME
	MOVEM T1,SYRMSG+CS%DNM	;STORE SIXBIT DEVICE NAME
	SETZM SYRMSG+CS%ADS	;CAN'T GET THE SERIAL NUMBER
	LOAD T1,DSKTYP,(DSK)	;GET DISK TYPE
	STOR T1,CS%UTP,SYRMSG+CS%HTP

;LOG THE MESSAGE

	MOVEI T1,SYRHDR		;GET ADDRESS OF SYSERR MESSAGE
	MOVE T2,Q1		;GET # OF WORDS IN MESSAGE
	SKIPN TSTF		;DON'T LOG SYSERRS IF TESTING
	SYERR			;LOG IT
	 ERJMP R		;IGNORE ERRORS
	RET
;TLUSR - BUILD BLOCK FOR SUCCESSFUL STRUCTURE REMOVAL RESPONSE

;ACCEPTS: RSB/	ADDRESS OF REQUEST STATUS BLOCK

;RETURNS:  +1,	ALWAYS

TLUSR:	MOVE T1,RSBSTA(RSB)	;GET STRUCTURE NAME
	TMCT <%IStructure %1S: removed
>
	MOVEI T1,TMCMSG		;GET ADDRESS OF ASCIZ TEXT
	MOVEI T2,.MNRTX		;GET ARGUMENT TYPE
	CALL PBTXT		;CREATE TEXT BUILDING BLOCK
	SETZ T1,		;SET NO FLAGS IN GALAXY HEADER
	RET
;TLUSS - BUILD BLOCKS FOR SUCCESSFUL STRUCTURE MOUNT RESPONSE

;ACCEPTS: RSB/	ADDRESS OF REQUEST STATUS BLOCK

;RETURNS: +1:	ALWAYS

TLUSS:	STKVAR <<DVBLK,2>>
	TMCT <%I>		;NEED THIS?
	MOVE T1,[FLD(2,AR.LEN)+FLD(.MNSDV,AR.TYP)] ;GET HEADER
	MOVE T2,RSBSTA(RSB)	;GET STRUCTURE ALIAS
	DMOVEM T1,DVBLK		;STORE HEADER AND STRUNCTURE NAME
	MOVEI T1,DVBLK		;GET ADDRESS OF DEVICE BLOCK
	CALL PBBLK		;ADD IT TO BUILDING BLOCK LIST
	SETZ T1,		;SET NO FLAGS IN GALAXY HEADER
	RET
;USD - PROCESS USER STRUCTURE DISMOUNT REQUEST RECEIVED THRU QUASAR

;ACCEPTS: T1/	ADDR OF STRUCTURE MOUNT ENTRY IN IPCF MSSG FROM QUASAR
;	  RSB/	ADDR OF REQUEST STATUS BLOCK

;RETURNS: +1,	ALWAYS

USD:	SAVEQ
	MOVEI T2,BSRRTA		;SET UP ANALYSIS TABLE FOR BTMRSB
	CALL BTMRSB		;BUILD RSB FROM QUASAR MESSAGE
	 RET			;REQUEST ABORTED, EXIT
	MOVX T1,R%DSM+R%RNR	;GET DISMOUNT and REMOVAL FLAG
	IORM T1,RSBIFL(RSB)	;AND SET INTO RSB
	CALL DDSCIH		;MAKE SURE TABLES UP-TO-DATE
	CALL CHKAB		;REQUEST ABORTED?
	 RET			;YES, MADE UNCORRECTABLE MOUNT ERROR
	MOVE T1,RSBSTA(RSB)	;GET STRUCTURE ALIAS
	MOVE T2,RSBSTN(RSB)	;GET STRUCTURE NAME
	SETZ T4,		;No unique code
	CALL MATCHS		;MATCH REQUEST TO STRUCTURE
	 JRST [ABTRET(MREQ25)]	;STRUCTURE NOT FOUND
	STOR STR,RSBSS		;STORE STRUCTURE STATUS BLOCK ADDR

;MAKE SURE USER ISN'T CONNECTED TO STRUCTURE TO DISMOUNT

	LOAD T1,RSBJNO		;GET USER'S JOB NUMBER
	MOVE T2,[-1,,Q1]	;GET USER'S CONNECTED DIRECTORY
	MOVEI T3,.JIDNO		; INTO Q1
	GETJI
	 RET			;INVALID JOB, ABORT REQUEST
	HRROI T1,TMCMSG		;POINT TO PLACE TO PUT NAME OF CONN DIR
	MOVE T2,Q1		;GET CONNECTED DIRECTORY
	DIRST
	 JRST USD1		;FORGET CONNECTED STR
	HRROI T1,TMCMSG		;GET DESIGNATOR OF CONNECTED STR
	STDEV
USD1:	 SETZ T2,		;FORGET CONNECTED STR
	MOVE Q1,T2		;STORE DESIGNATOR IN T3
	MOVEI T1,RSBSTA(RSB)	;GET SIXBIT ALIAS
	MOVE T2,[POINT 7,MSTAL]	;THIS IS PLACE TO STORE 7-BIT
	CALL SIXSEV		;CONVERT IT
	HRROI T1,MSTAL		;POINT TO ALIAS
	STDEV			;GET ITS DESIGNATOR
	 JRST [	JUMPN STR,[MOVEI T1,RST.WD ;STR SPINNING,BUT NOT MOUNTED?
			   STOR T1,RSBSTE ;SET STATE TO WAITING
			   JRST WOVDS]
		ABTRET (MREQ25)] ;STR IS NOT TO BE FOUND
	CAMN Q1,T2		;IS USER CONNECTED TO STR BEING REMOVED?
	JRST [	ABTRET (MREQ24)] ;YES, ILLEGAL

;USER ISN'T CONNECTED TO STRUCTURE.  PREPARE TO DISMOUNT IT.

	MOVEI T1,RST.WD
	STOR T1,RSBSTE		;SET STATE TO WAITING FOR DISMOUNT
	MOVEI T1,RSBSTN(RSB)	;CONVERT SIXBIT NAME TO 7-BIT
	MOVE T2,[POINT 7,MSTNM]
	CALL SIXSEV
	CALL TCKP		;UPDATE QUASAR'S QUEUES FOR "INFO MOUNT"
	CALLRET STRDMT		;DISMOUNT STRUCTURE
;USM - PROCESS USER STRUCTURE MOUNT REQUEST RECEIVED THROUGH QUASAR

;ACCEPTS: T1/	ADDR OF STRUCTURE MOUNT ENTRY IN IPCF MSSG FROM QUASAR
;	  RSB/	ADDR OR REQUEST STATUS BLOCK

;RETURNS: +1,	ALWAYS

USM:	MOVEI T2,BSRRTA		;SET UP ANALYSIS TABLE FOR BTMRSB
	CALL BTMRSB		;BUILD RSB FROM QUASAR MESSAGE
	 RET			;REQUEST ABORTED, EXIT
	MOVEI T1,RSBSTA(RSB)	;POINT TO SIXBIT ALIAS
	MOVE T2,[POINT 7,MSTAL]	;ASCII GOES HERE
	CALL SIXSEV		;CONVERT ALIAS TO ASCII
	HRROI T1,MSTAL		;POINT TO ASCII ALIAS
	STDEV			;IS THIS A TTY: OR OTHER ILLEGAL DEVICE
	 SKIPA			;ERROR, MUST BE OKAY
	JRST [	HLRZS T2	;GET LEFT HALF OF DESIGNATOR
		CAIN T2,.DVDES+.DVDSK ;IS IT A DISK?
		JRST [	CALL TELUSR ;YES, AND ALREADY MOUNTED
			ABTRET (ABRTNR)]
		MOVEI Q1,MSTRX7 ;GET ERROR MESSAGE
		ABTRET (Q1,ABT%IN)] ;ILLEGAL DEVICE FOR MOUNT
	MOVEI T1,RST.WM
	STOR T1,RSBSTE		;SET STATE TO WAITING FOR MOUNT
	CALL DDSCIH		;MAKE SURE TABLES UP-TO-DATE

	CALL CHKAB		;REQUEST ABORTED?
	 RET			;YES, MADE UNCORRECTABLE MOUNT ERROR
	MOVE T1,RSBSTA(RSB)	;GET STRUCTURE ALIAS
	MOVE T2,RSBSTN(RSB)	;GET STRUCTURE NAME
	SETZ T4,		;No unique code
	CALL MATCHS		;MATCH REQUEST TO STRUCTURE
	 JRST [JUMPE T1,USM1	;Not found, go ask to be mounted
	       JRST DUPSTA]	;Duplicate state
	SKIPG STR		;IS STRUCTURE MOUNTED?		
	JRST [	LOAD T1,STRUNI,(STR) ;NO, GET # OF DISKS IN STR
		LOAD T2,STRMCT,(STR) ;GET # OF DISK ON-LINE IN STR
		CAME T1,T2	;ARE ALL DISKS ON-LINE?
		JRST USM1	;NO, ASK OPERATOR
		CALL STRMNT	;PACK IS SPINNING. MOUNT IT
		 JRST USM1	;PROBLEM IN MOUNTING,CHECK WITH OPERATOR
		JRST USM0]

USM0:	CALL TELUSR		;LET USER KNOW HE HAS STRUCTURE
	ABTRET (ABRTNR)		;DUMP THE RSB AND RETURN TO CALLER

;STRUCTURE IS NOT PHYSICALLY OR LOGICALLY MOUNTED, GO TELL OPERATOR TO MOUNT IT

USM1:	CALL CHKAB		;REQUEST ABORTED?
	 RET			;YES, DON'T TALK TO OPERATOR
	SKIPN T1,RSBSTN(RSB)	;GET SIXBIT STRUCTURE NAME
	MOVE T1,RSBSTA(RSB)	;NONE SPECIFIED,GET ALIAS AS NAME
	CALL TCKP		;UPDATE QUASAR'S QUEUES FOR "INFO MOUNT"
	CALL PWATCH		;WATCH FOR USER DELETING HIS PID
	CALL GETACC		;GET AN ACCOUNT BLOCK
	 JRST [	CALL DELACC	;ABORT SINCE ACC BLOCKS IN SHORT SUPPLY
		ABTRET (MREQ31)] ;AND KILL REQUEST.
	SETOM ACCDD(ACC)	;FLAG ACCOUNT BLOCK NOT DELETABLE
	GTAD			;GET NOW
	MOVEM T1,ACCSCD(ACC)	;AS SCHEDULED TIME
	LOAD T1,RSBJNO		;GET USER'S JOB NUMBER
	STOR T1,ACCJN		;SAVE IN RSB
	STOR ACC,RSBACC		;ASSOCIATE ACC WITH REQUEST
	CALLRET WOVMS		;TELL OPERATOR TO MOUNT STRUCTURE
SUBTTL CFDIS - SET UP STRING CONTAINING INFORMATION FOR SHOW CONFIG DISK

;ACCEPTS DSK/	CURRENT DISK STATUS BLOCK ADDRESS
;RETURNS +1,	ALWAYS

CFDIS:: SAVEQ
	MOVE Q1,DSKFLG(DSK)	;GET STATUS WORD

; The DSN field 

CFDIS1:	MOVE	T1,DSKSNH(DSK) ;Get serial number
	TMCT	<%17C%1D >	;Disk drive serial number (HIGH ORDER)
	MOVE	T1,DSKSNL(DSK)	;Get serial number
	TMCT	<%27C%1D>	;Disk drive serial number (LOW ORDER)

;  The mount status field

CFDIS2:	TXNE Q1,MS%MNT		;Is it mounted
	JRST [TMCT <%40CMounted> ;Yes, say it is mounted
	      JRST CFDIS3]	; and add mount count field
	TXNE Q1,MS%OFL		; OFF LINE
	JRST [TMCT <%40COffline > ;Display offline
	      JRST CFDIS3]	;
	TMCT <%40CFree>		;Display free
	MOVX T1,MSG%FR		;Get free message bit
	IORM T1,DSPFLG		;Set free message flag	

;  The structure name field 

CFDIS3:	MOVE T1,DSKSTN(DSK)	;GET STRUCTURE NAME
	JUMPE T1,CFNEX		;No name all done
	TMCT <%49C%1S%56C(>	;Add name

;  Add number of disks in structure

	LOAD T2,DSKNOU,(DSK)	;GET NUMBER OF UNITS IN STR
	LOAD T1,DSKLUN,(DSK)
	MOVE T3,T1		;SAVE UNIT NUMBER
	AOS T1			;CHANGE UNIT NUMBER TO ORDINAL
	TMCT <%1D/%2D)>		;UNIT# / # OF UNITS

CFNEX:	RET
SUBTTL WOFRE - SET UP STRING CONTAINING INFORMATION ON FREE DRIVE

;WOFRE - SET UP STRING CONTAINING INFORMATION ON FREE DRIVE

;ACCEPTS DSK/	CURRENT DISK STATUS BLOCK ADDRESS
;RETURNS +1,	ALWAYS

WOFRE::	SAVEQ
	MOVX T1,MSG%AN		;Get the any bit
	IORM T1,DSPFLG		;Say we have one

	MOVE Q1,DSKFLG(DSK)	;GET STATUS WORD

	CALL WOINI		;Go fill out the first five fields

	SKIPE	CFGFLG		;For the CONFIG command?
	 JRST	WOFRE1		;Already have structure name

;  The structure name field 

	MOVE T1,DSKSTN(DSK)	;GET STRUCTURE NAME
	JUMPE T1,WOFREX		;No name all done
	TMCT <%42C%1S%49C(>
	LOAD T1,DSKLUN,(DSK)
	AOS T1			;CHANGE UNIT NUMBER TO ORDINAL
	TMCT <%1D/>
	LOAD T1,DSKNOU,(DSK)	;GET # OF UNITS IN STRUCTURE
	TMCT <%1D)>

;  Do we have any bad disk errors?

WOFRE1:	TXNE Q1,MS%BBB		; BAD BAT BLOCKS?
	CALL [	TMCTR <%_Bad BAT blocks >] ; DISPLAY MESSAGE
	TXNE Q1,MS%WLK		; IS UNIT WRITE LOCKED?
	CALL [  TMCTR <%_Unit is write locked >] ; DISPLAY MESSAGE
	TXNE Q1,MS%HBB		; BAD HOME BLOCKS?
	CALL [  TMCTR <%_Bad HOME blocks >] ; DISPLAY MESSAGE
	TXNE Q1,MS%DIA		; IN MAINTENANCE MODE?
	CALL [  TMCTR <%_Maintenance mode >] ; DISPLAY MESSAGE
	TXNE Q1,MS%ERR		;Error while reading?
	CALL [	TMCTR <%_Error reading this unit>] ;Display message
	TXNE Q2,MS%16B		;16 Bit format?
	CALL [TMCTR <%_Unit written in 16 bit mode>] ;Display message

WOFREX: TMCT <%_>

;  Is the disk on offline CI port

	MOVE T1,DSFE+DSFFLG	;Get the disk status
	TXNE T1,DSF%PO		;Is it unavailable due to port operation?
	CALL [TMCT <%5CCan't use disk drive - Port unavailable%_>
	      RET]
	RET
SUBTTL - WOINI -- Fills in the first five fields of the display

;Accepts - DSK/disk status block 
;Returns - DSFE disk entry

WOINI:	SAVEQ
	MOVE Q1,DSKFLG(DSK)	;GET STATUS WORD

;  The # of port field

	TXNN Q1,MS%2PT		;Dual ported?
	JRST WOINI0		;No, skip indication
	TMCT <*>		;Add a asterisk
	MOVX T1,MSG%DU		;Get the display flag word
	IORM T1,DSPFLG		;Dual ported drive message is to be printed

;  The disk type field

WOINI0:	LOAD T1,MS%TYP,Q1
	MOVSI T2,-MXUTYP	;GET READY FOR SEARCH
	HLRZ T3,UNTYTB(T2)	;GRAB NEXT TYPE FROM TABLE
	CAME T1,T3		;IS THIS IT?
	AOBJN T2,.-2		;NO, KEEP GOING
	HRRZ T1,UNTYTB(T2)	;GET POINTER TO DISK TYPE STRING
	TMCT <%2C%1A>		;Type it

;  The CKU field

	LOAD T1,DSKCHN,(DSK)	;GET CHANNEL NUMBER
	TMCT <%7C%1D,>		;Type it and palce the pointer in the 10 col
	CAIE T1,CIPORT		;Is it channel 7?
	JRST WOINI1		;No, skip setting special message bit
	MOVX T1,MSG%CI		;Get the channel 7 bit 
	IORM T1,DSPFLG		;Set it in display falg to say channel 7 
WOINI1:	LOAD T1,DSKCTR,(DSK)	;GET CONTROLLER NUMBER
	CAIN T1,<.RTJST(-1,DOP%K2)> ;IS THERE ONE?
	JRST [TMCT <  ,>
	      JRST WOINI2]	;NO, put two spaces
	CAIGE T1,12		;Is it double digit?
	CALL [TMCT <0>		;No, add a zero
	      RET]
	TMCT <%1D,>		;YES, TYPE IT
WOINI2:	LOAD T1,DSKDRV,(DSK)	;GET UNIT NUMBER
	TMCT <%1D>		;Type it

;  Get the disk entry from DDB

WOINI3:	MOVE T1,DSKPNT(DSK)	;Get the pointer to DDB
	CALL DSFGET		;Go get the entry
	 $STOP <Disk entry not in DDB...WOINI2:+3>

	SKIPE	CFGFLG		;For the CONFIG command?
	 CALLRET CFDIS		;Yes, finish the display.

;  The disk status field

	MOVE T1,DSFE+DSFFLG	;Get the flag word
	TXNE T1,DSF%AV		;Is it available?
	JRST [TMCT <%17CUnavail> ;No, Say it is unavailable
	      JRST WOINI4]
	TMCT <%17CAvail>	;Say it is available for now

;  The mount status field

WOINI4:	TXNE Q1,MS%MNT		;Is it mounted
	JRST [TMCT <%26CMounted> ;Yes, say it is mounted
	      JRST WOINEX]	; and add mount count field
	TXNE Q1,MS%OFL		; OFF LINE
	JRST [TMCT <%26COffline > ;Display offline
	      JRST WOINEX]	;
	TMCT <%26CFree>		;Display free
	MOVX T1,MSG%FR		;Get free message bit
	IORM T1,DSPFLG		;Set free message flag	
WOINEX:	RET
;WOMNT - SET UP STRING CONTAINING INFORMATION ON MOUNTED DRIVE

;ACCEPTS DSK/	CURRENT DISK STATUS BLOCK ADDRESS
;RETURNS +1,	ALWAYS

WOMNT::	SAVEQ
	
	MOVX T2,MSG%AN		;Get any bit
	IORM T2,DSPFLG		;Say we have one
	
	MOVE Q1,DSKFLG(DSK)	;GET STATUS WORD

	CALL WOINI		;Go fill out the first six fields

	MOVE Q2,DSFE+DSFFLG	;Save the disk status 

	SKIPE	CFGFLG		;For the CONFIG command?
	 JRST WOMNEX		;Finish off line

;  The mount count field, only for mounted disks

	MOVE T2,[POINT 7,MSTAL];SET UP POINTER FOR ALIAS
	MOVEI T1,DSKSTA(DSK)	;Get the alias
	CALL SIXSEV		;CONVERT SIXBIT ALIAS TO NEEDED 7-BIT
	MOVEI T1,MSTAL		;Get address of alias
	CALL STRSTT		;Go get the status
	 JRST WOMNT6		;NO STRUCTURE?
	MOVEM T1,Q3		;Save the status 
	TMCT <%34C%3D>		;Output mount count

;  The structure name field 

WOMNT6:	MOVE T1,DSKSTN(DSK)	;GET STRUCTURE NAME
	JUMPE T1,WOMNEX		;No name all done
	TMCT <%42C%1S%49C(>	;Add name

;  Add number of disks in structure

	LOAD T2,DSKNOU,(DSK)	;GET NUMBER OF UNITS IN STR
	LOAD T1,DSKLUN,(DSK)
	MOVE T3,T1		;SAVE UNIT NUMBER
	AOS T1			;CHANGE UNIT NUMBER TO ORDINAL
	TMCT <%1D/%2D)>		;UNIT# / # OF UNITS
	SOJE T2,WOMNT3		;JUMP IF ONLY ONE UNIT
	SKIPE T3		;IS THIS FIRST UNIT OF STRUCTURE?
	JRST WOMNEX		;NO, HAVE ALREADY OUTPUT INFORMATION

;  The usage option field

WOMNT3:	TMCT <%55C>		;Go to the usage option colume

;  Q3 should still contain the status


	TXNE Q3,MS%EXC		;Is it?
	CALL [TMCT <Excl >	;Assume exclusive
	      RET]


	TXNE Q3,MS%DIS		;IS IT
	CALL [TMCT <Unavail >	;Assume available
	      RET]

;  Set up for ignore

	MOVEI T1,.DVSTR		;Get the type
	MOVEM T1,DSFE+DSFTYP	;Save it
	MOVE T1,DSKSTA(DSK)	;Get the alias
	MOVEM T1,DSFE+DSFSPC	;Save it
	CALL DSFLOC		;Go find the entry
	 $STOP <Can't find structure entry in DDB.>

;  This is for ignored case

	MOVE T1,DSFE+DSFFLG	;Get the structure status flag word
	TXNE T1,DSF%IG		;Is it ignored
	CALL [TMCT <Ignored >	;Yes
	      RET]

;  The alias field

	MOVE T2,DSKSTA(DSK)	;Get structure name 
	CAMN T2,DSKSTN(DSK)	;ARE NAME AND ALIAS THE SAME?
	JRST WOMNEX		;YES
	TMCT <(Alias %2S)>	;Output name

WOMNEX:	TMCT <%_>		;Finish the line off
	
;  Is the disk on offline CI port

	TXNE Q2,DSF%PO		;Is it unavailable due to port operation?
	CALL [TMCT <%5CCan't use disk drive- Port unavailable%_>
	      RET]
	RET
SUBTTL WOMDAV - TELL OPERATOR OF AVAILABILITY OF DISK DRIVE FOR SYSTEM USE

;ACCEPTS: Q1/  1 IF UNAVAILABLE, 0 IF AVAILABLE
;	  Q2/  CKU NUMBER
;RETURNS: +1,  ALWAYS

WOMDAV::MOVE T1,Q2		;COPY FOR CALL
	TMCT <%I%1K set >	;TYPE UNIT ADDRESS
	JUMPN Q1,[TMCT <un>
		  JRST .+1]
	TMCT <available for mounting by MOUNTR>
	MOVE T3,[[ASCIZ/Disk Drive Set Available/]
		 [ASCIZ/Disk Drive Set Unavailable/]](Q1) ;GET HEADER
	CALLRET BTWTO		;GET MESSAGE OUT TO OPERATOR
SUBTTL WOSM - TELL OPERATOR OF A STRUCTURE


WOSM:	MOVEI T1,MSTNM		;GET STRUCTURE NAME
	TMCT <%IStructure %1A>
	MOVE T1,MSTNM		;ARE ALIAS AND NAME THE SAME
	CAME T1,MSTAL
	JRST WOS1		;NO, PRINT THE ALIAS
	MOVE T1,MSTNM+1
	CAMN T1,MSTAL+1
	RET			;YES, FORGET THE ALIAS
WOS1:	MOVEI T1,MSTAL		;POINT TO ALIAS
	TMCTR <: (Alias: %1A)>

;WOSDM - TELL OPERATOR OF A STRUCTURE DISMOUNT

WOSDM:	CALL WOSM		;SET UP STRUCTURE NAMES
	TMCT < dismounted>
	MOVEI T3,[ASCIZ/STRUCTURE DISMOUNTED/]
	CALLRET BTWTO		;TELL OPERATOR

;WOSMT - TELL OPERATOR OF A STRUCTURE MOUNT

WOSMT:	CALL WOSM		;SET UP STRUCTURE NAMES
	TMCT < mounted>
	MOVEI T3,[ASCIZ/STRUCTURE MOUNTED/]
	CALLRET BTWTO		;TELL OPERATOR

;WOSSC - TELL OPERATOR STATUS OF STRUCTURE AFTER STATUS CHANGE

WOSSC:	STAKT
	MOVEI T2,MSTAL		;GET STRUCTURE NAME
	TMCT <%I%2A: set %1A for use by system>
	MOVEI T3,[ASCIZ/STRUCTURE STATUS SET/]
	CALL BTWTO		;GET MESSAGE TO OPERATOR
	CAIE Q3,S.EXCL		;Is it exclusive
	CAIN Q3,S.SHAR		;or share
	JRST [	ABTRET (ABRTNR)] ;Yes, abort the request
	RET			;Else return
;WRDSC - ASK OPERATOR IF STRUCTURE SHOULD BE REMOVED, EVEN THOUGH THERE
;	 ARE USERS ON IT

;ACCEPTS: T1/	ADDRESS OF RESPONSE HANDLER CALLED BY INWTOR
;	  STR/	ADDRESS OF STRUCTURE STATUS BLOCK
;	  RSB/	ADDRESS OF REQUEST STATUS BLOCK

;RETURNS: +1,	ALWAYS

WRDSC::	MOVE T3,STRNAM(STR)	;GET STRUCTURE NAME
	MOVE T2,STRALI(STR)	;GET ALIAS
	CALL WTOCHK		;IS WTO DIASABLED
	RET			;YES
	TMCTI <DSMHDR>		;Build dismount message
	MOVEI T2,RSBWTB(RSB)	;GET WTB ADDRESS
	MOVEI T3,[ASCIZ/DISMOUNT QUERY/]
	CALLRET BTWTOR		;SEND WTOR OFF TO THE OPERATOR
;WOVDS - TELL OPERATOR A STRUCTURE MUST BE DISMOUNTED AND ACCEPT A
;	 POSSIBLE REFUSAL

;ACCEPTS: STR/	ADDRESS OF STRUCTURE STATUS BLOCK
;	  RSB/	ADDRESS OF REQUEST STATUS BLOCK

;RETURNS: +1,	ALWAYS

WOVDS:	MOVE T1,STRNAM(STR)	;GET SIXBIT STRUCTURE NAME
	MOVE T2,RSBSTA(RSB)	;GET SIXBIT STRUCTURE ALIAS
	CALL WTOCHK		;IS WTO DISABLED?
	RET			;YES
	MOVE T3,RSBIFL(RSB)	;Get the remove noremove bit
	TXNE T3,R%RNR		;To remove?
	JRST [ TMCT <%IRemove %1S: (alias %2S:)%_%U%_>
	       JRST .+2]
	TMCT <%IDo not remove %1S: (alias %2S:)%_%U%_>
	SKIPE RSBRMK(RSB)	;DID THE USER SUPPLY A REMARK?
	JRST [	MOVEI T1,RSBRMK(RSB) ;YES, GET ADDRESS OF ASCIZ REMARK
		TMCT <User's remark: %1A%_>
		JRST .+1]
	SKIPE T1,RSBOBN(RSB)	;[6011]Get "on behalf node name"
	TMCT <Structure is dismounted on behalf of %1S::%_>
	MOVEI T1,DSKHDR		;GET STATUS HEADER TEXT
	TMCT <%1A>
	LOAD Q1,STRUNI,(STR)	;GET NUMBER OF UNITS IN STRUCTURE
	MOVNS Q1		;SET UP INDEX
	HRLZ Q1,Q1
	MOVE T1,STR
	ADDI T1,STRADD		;GET INDEX TO START OF DISK ADDRESSES
	HRR Q1,T1		;GET ADDRESS FOR DISK
WOVD1:	MOVE DSK,(Q1)		;GET DISK BLOCK ADDRESS
	JUMPE DSK,WOVD2		;JUMP IF PACK GONE
	MOVX T1,MS%MNT		;MAKE SURE DISK IS NOT MOUNTED
	ANDCAM T1,DSKFLG(DSK)
	CALL WOFRE		;DISPLAY UNIT
WOVD2:	AOBJN Q1,WOVD1		;IF MORE PACKS, DISPLAY THEM
	MOVE T3,RSBIFL(RSB)	;Get the remove noremove bit
	TXNE T3,R%RNR		;To remove?
        JRST [TMCT <Structure cannot be mounted again unless MOUNTed via OPR or until removed%_>
	       JRST .+2]
	TMCT <Structure cannot be mounted unless MOUNTed via OPR%_>
	MOVEI T2,RSBWTB(RSB)	;GET WTB ADDRESS
	MOVEI T3,[ASCIZ/DISMOUNT STRUCTURE/]
	CALL BTNFO		;No formatting
	CALLRET BTWTO		;SEND WTO OFF TO THE OPERATOR
;WOVMS - TELL OPERATOR A STRUCTURE MUST BE MOUNTED

;ACCEPTS: RSB/ ADDRESS OF REQUEST STATUS BLOCK

;RETURNS: +1,	ALWAYS

WOVMS:	CALL MESCHK		;HAVE WE ALREADY NOTIFIED OPR OF STR?
	RET			;YES, FORGET THIS
	CALL WTOCHK		;IS WTO DISABLED
	RET			;YES
	SKIPGE T1,RSBITN(RSB)	;GET REQUEST # if not from operator
	JRST [TMCT <%IStructure Mount Request made by operator>
	      JRST WOVM0]
	TMCT <%IStructure Mount Request # %1D>
	SETONE R%ONR,RSBIFL(RSB) ;SET OPERATOR-NOTIFIED
WOVM0:	CALL CPYHDR		;COPY HEADER TO OPRHDR
	SKIPN T1,RSBSTN(RSB)	;GET SIXBIT STRUCTURE NAME
	MOVE T1,RSBSTA(RSB)	;NONE SPECIFIED, GET ALIAS AS NAME
	MOVE T2,RSBSTA(RSB)	;GET SIXBIT STRUCTURE ALIAS
	TMCT <%IMount %1S: (alias %2S:)%_%U%_>
	SKIPE RSBRMK(RSB)	;DID THE USER SUPPLY A REMARK?
	JRST [	MOVEI T1,RSBRMK(RSB) ;YES, GET ADDRESS OF REMARK
		TMCT <User's remark: %1A%_>
		JRST .+1]
	CALL KSHDF		;Displace the headers
	MOVEI T1,DSKHDR
	TMCT <%1A>

;  Loop through all disks

	MOVEI T1,.DVDSK		;Get the disk type
	MOVEM T1,DSFE+DSFTYP	;Save it in DSFE
	SETZ T1,		;Go for the first

	SETZ Q1,		;SET FLAG TO SAY NO AVAILABLE DRIVES
WOVM1:	CALL DSFGNX		;Go get an entry
	 JRST WOVM3		;No more
	PUSH P,T1		;Save pointer
	SKIPN DSK,DSFE+DSFPNT	;Get disk status block address
	JRST WOVM2		;No disk status block, get the next disk
	MOVE T1,DSKFLG(DSK)	;Get te status flag
	TXNN T1,MS%MNT		;IS THIS DISK MOUNTED?
	TXNE T1,MS%DIA		;NO, IS IT IN MAINT MODE?
	JRST WOVM2		;YES, SKIP THIS DISK
	CALL WOFRE		;DISPLAY STATUS OF THIS DRIVE
	SETO Q1,		;SET FLAG TO SAY WE HAVE A DRIVE

WOVM2:	MOVEI T1,.DVDSK		;Get the disk type
	MOVEM T1,DSFE+DSFTYP	;Save it in DSFE
	POP P,T1		;Get the pointer back
	JRST WOVM1		;Get the next

WOVM3:	JUMPE Q1,[TMCT <%INo drives available> 
		JRST .+1]
	MOVEI T3,OPRHDR		;GET ADDRESS OF HEADER TEXT
	CALL BTNFO		;No formatting	
	CALLRET BTWTO		;SEND WTO OFF TO THE OPERATOR
SUBTTL USER TAPE MOUNT REQUEST

; BTMRSB - EXTRACT INFORMATION FROM USER MOUNT REQUEST AND
;	   TRANSFER IT TO THE REQUEST STATUS BUFFER
;  T1/ ADDRESS OF MOUNT ENTRY IN IPCF MESSAGE FROM QUASAR
;  T2/ ADDRESS OF TABLE MOUNT REQUEST ANALYSIS ROUTINE ADRESSES
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: FAILURE, MOUNT REQUEST ABORTED
;	  +2: SUCCESS, INFORMATION TRANSFERRED TO RSB

BTMRSB:	SAVEQ
	DMOVE Q1,T1		;COPY ADDRESSES TO A SAFE PLACE

; PERFORM STRUCTURAL VALIDATION OF MOUNT ENTRY

	MOVE T1,.MECNT(Q1)	;GET SUBENTRY COUNT
	MOVEI T2,.MEHSZ(Q1)	;GET ADDRESS OF FIRST SUBENTRY
	LOAD T3,AR.LEN,.MEHDR(Q1) ;GET LENGTH OF SUBENTRY
	SUBI T3,.MEHSZ		;COMPUTE SIZE OF SUBENTRY AREA
	SKIPL T3		;ERROR IF HEADER IS INCOMPLETE
	CALL CKBSTR		;CHECK STRUCTURE OF MOUNT REQUEST
	 JRST [	ABTRET (MREQ20)] ;STRUCTURE ERROR IN MOUNT ENTRY

; PERFORM SEMANTIC ANALYSIS OF MOUNT ENTRY

BTMR1:	MOVEI T1,.MECNT(Q1)	;ADDRESS OF SUBENTRY COUNT WORD
	MOVEI T2,.MEHSZ(Q1)	;ADDRESS OF FIRST SUBENTRY
	SKIPN (Q2)		;FINISHED WITH ANALYSIS ROUTINES?
	RETSKP			;YES, GO HOME
	CALL @(Q2)		;CALL ANALYSIS ROUTINE
	 RET			;ERROR DETECTED, PASS IT TO CALLER
	AOJA Q2,BTMR1		;LOOP THRU ALL ANALYSIS ROUTINES

; TABLE OF TAPE MOUNT REQUEST ANALYSIS ROUTINE ADDRESSES
;   WARNING:
;   DO NOT CHANGE THE ORDER OF THE ROUTINES IN THIS TABLE - SOME
;   DEPEND UPON RSB FIELDS SET UP BY THEIR PREDECESSORS

BTRRTA:	IFIW!BTRFLG		;BIT FLAGS
	IFIW!BTRDEN		;DENSITY
	IFIW!BTRDRV		;DRIVE-TYPE
	IFIW!BTRLT		;LABEL TYPE
	IFIW!BTRSET		;SET NAME
	IFIW!BTRRMK		;REMARK
	IFIW!BTRVLS		;VOLID LIST
	IFIW!BTRSTV		;STARTING VOLID NUMBER
	IFIW!BTRVPR		;VOLUME PROTECTION
	0			;END OF ROUTINES

;TABLE OF STRUCTURE MOUNT REQUEST ANALYSIS ROUTINE ADDRESSES
;    WARNING:
;    BSRALI MUST BE AFTER BSRNAM IN THE TABLE

BSRRTA:	IFIW!BSRALI		;ALIAS OF STRUCTURE
	IFIW!BSRNAM		;NAME OF STRUCTURE
	IFIW!BTRRMK		;REMARK
	0			;END OF ROUTINES
; ROUTINES FOR PROCESSING SUBENTRIES OF TAPE MOUNT REQUEST
;  T1/ ADDRESS OF SUBENTRY COUNT WORD
;  T2/ ADDRESS OF FIRST SUBENTRY
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: REQUEST ABORTED
;	  +2: SUBENTRY PROCESSED SUCCESSFULLY

; DENSITY

BTRDEN:	MOVEI T3,.TMDEN
	MOVEI T4,DENMAX		;GET MAXIMUM
	CALL BTRG1		;LOOKUP DENSITY PARAMETER
	 JRST [	ABTRET (MREQX3)] ;DENSITY ILLEGAL
	STOR T1,RSBDEN		;STORE DENSITY IN RSB
	RETSKP

; DRIVE TYPE

BTRDRV:	MOVEI T3,.TMDRV
	MOVEI T4,.TMDMX		;GET MAXIMUM
	CALL BTRG1		;LOOKUP DRIVE PARAMETER
	 JRST [	ABTRET (MREQX4)] ;DRIVE TYPE ILLEGAL
	STOR T1,RSBDRV		;STORE DRIVE TYPE IN RSB
	RETSKP

; BIT FLAGS

BTRFLG:	MOVE T1,.MEFLG(Q1)	;GET USER-SUPPLIED FLAGS
	TXNE T1,TM%BYP		;DOES HE WANT BYPASS?
	JRST [	MOVX T2,R%PRIV	;YES
		TDNE T2,RSBIFL(RSB) ;IS HE PRIVILEGED?
		JRST .+1	;YES, LET HIM DO IT
		ABTRET (CAPX1)]	;NOT PRIVILEGED, ABORT REQUEST
	TXNE T1,TM%SCR
	JRST [	TXO T1,TM%NEW+TM%WEN ;FLAGS IMPLIED BY TM%SCR
		TXZ T1,TM%OSV+TM%VFY
		JRST .+1]
	TXNE T1,TM%NEW
	JRST [	TXO T1,TM%WEN	;FLAGS IMPLIED BY TM%NEW
		TXZ T1,TM%VFY
		MOVX T2,R%WVL
		IORM T2,RSBIFL(RSB)
		JRST .+1]
	MOVEM T1,RSBUFL(RSB)	;MOVE USER REQUEST FLAGS TO RSB
	RETSKP
; LABEL TYPE (MUST BE CALLED AFTER BTRDRV)

BTRLT:	MOVEI T3,.TMLT
	MOVEI T4,.LTMAX		;GET MAXIMUM
	CALL BTRG1		;LOOKUP DRIVE-TYPE PARAMETER
	 JRST [	ABTRET (MREQX5)] ;LABEL TYPE ILLEGAL
	MOVX T2,TM%BYP
	TDNE T2,RSBUFL(RSB)	;BYPASS?
	MOVEI T1,.LTUNL		;YES, FORCE LABEL TYPE = UNLABELED
	CAIE T1,.LTUNL		;LABELED TAPE?
	JUMPN T1,[LOAD T2,RSBDRV ;YES, GET DRIVE TYPE
		CAIE T2,.TMDR7	;7-TRACK?
		JRST .+1	;NO
		ABTRET (MREQX2)] ;YES, 7-TRACK LABELS NOT SUPPORTED
	STOR T1,RSBLT		;STORE LABEL TYPE IN RSB
	RETSKP

; REMARK

BTRRMK:	MOVEI T3,.TMRMK
	CALL BLKFND		;LOOKUP REMARK
	 RETSKP			;NO REMARK
	JUMPE T2,RSKP		;TREAT ZERO-LENGTH REMARK LIKE NO REMARK
	CAILE T2,RMKLEN		;IS REMARK TOO LONG?
	MOVEI T2,RMKLEN		;YES, TRUNCATE
	MOVSS T1		;BLT SOURCE
	HRRI T1,RSBRMK(RSB)	;BLT DESTINATION
	ADDI T2,RSBRMK-1(RSB)	;LAST WORD OF DESTINATION
	BLT T1,(T2)		;BLT REMARK INTO RSB
	MOVEI T1,377
	ANDCAM T1,(T2)		;MAKE SURE REMARK ENDS WITH A NULL
	RETSKP

; SETNAME

BTRSET:	MOVEI T3,.TMSET
	CALL BLKFND		;LOOKUP SETNAME
	 JRST BTRSE1		;SETNAME MISSING
	JUMPE T2,BTRSE1		;ERROR IF HEADER-ONLY SUBENTRY
	MOVE T1,(T1)		;GET SETNAME IN T1 FOR CHKID
	CALL CHKID		;IS IT A LEGAL SETNAME?
BTRSE1:	 JRST [	ABTRET (MREQX6)] ;SETNAME ILLEGAL OR MISSING
	MOVEM T1,RSBSSN(RSB)	;STORE USER-SUPPLIED SETNAME IN RSB
	MOVX T2,TM%NEW
	TDNE T2,RSBUFL(RSB)	;USER CREATING NEW VOLUME SET?
	MOVEM T1,RSBASN(RSB)	;YES, HIS SETNAME GOES IN THE LABELS
	RETSKP
; STARTING VOLID NUMBER (MUST BE CALLED AFTER BTRVLS)

BTRSTV:	SAVEQ
	MOVEI T3,1
	STOR T3,RSBCV		;DEFAULT CURRENT VOLID # IS 1
	MOVEI T3,.TMSTV
	CALL BLKFND		;STARTING VOLID ENTRY PRESENT?
	 RETSKP			;NO, DEFAULT WILL BE USED
	JUMPE T2,BTRSTI		;ERROR IF HEADER-ONLY SUBENTRY
	MOVX T3,TM%OSV+TM%NEW
	TDNE T3,RSBUFL(RSB)	;ANY BITS SET?
	JRST BTRSTI		;YES, USER CAN'T SPECIFY THIS PARAMETER
	SKIPE Q1,(T1)		;SPECIFYING NUMBER OR VOLID?
	JRST [	CALL VQCNT	;NUMBER, GET # OF VOLIDS IN REQUEST
		CAMG Q1,T1	;ERROR IF SPECIFIED VALUE .GT. MAX
		SKIPG Q1	;ERROR IF STARTING VOLID NOT POSITIVE
		JRST BTRSTI
		STOR Q1,RSBCV	;OFFSET IS LEGAL, STORE IT
		RETSKP]
	CAIGE T2,2		;SPECIFYING VOLID, IS ENTRY LONG ENOUGH?
	JRST BTRSTI		;NO
	MOVE Q1,1(T1)		;GET VOLID
	MOVEI Q2,1		;GET COUNTER
	QSCANI <RSBVLS(RSB)>	;SET UP TO SCAN VOLID LIST
BTRST1:	CALL QMSCAN		;LOOK AT NEXT VOLID FOR THIS REQUEST
BTRSTI:	 JRST [	ABTRET (MREQX7)] ;ABORT REQUEST - ILLEGAL STARTING VOLID
	CAME Q1,1(T2)		;IS THIS THE ONE?
	AOJA Q2,BTRST1		;NO, BUMP COUNTER & CONTINUE SEARCH
	STOR Q2,RSBCV		;FOUND IT, STORE ORDINAL VOLID #
	RETSKP
; VOLID LIST

BTRVLS:	SAVEQ
	MOVX T3,TM%OSV+TM%SCR
	TDNE T3,RSBUFL(RSB)	;IS USER PERMITTED TO SPECIFY VOLIDS?
	RETSKP			;NO, IGNORE VOLID LIST IF PRESENT
	MOVEI T3,.TMVOL
	CALL BLKFND		;LOOKUP VOLID LIST
	 SETZ T2,		;NO VOLID LIST
	JUMPE T2,[MOVX T2,TM%OSV+TM%NEW ;ZERO-LENGTH IS LIKE NO LIST
		TDNE T2,RSBUFL(RSB) ;IS VOLID LIST REQUIRED?
		RETSKP		;NO, LET HIM BY
		ABTRET (MREQ17)] ;YOU FORGOT TO LIST YOUR VOLIDS FELLA
	MOVN Q1,T2		;GET -#VOLIDS IN Q1
	MOVSS Q1		;CONSTRUCT LEFT HALF OF AOBJN POINTER
	HRR Q1,T1		;VOLID SOURCE ADDRESS IN RIGHT HALF
BTRVL1:	MOVE T1,(Q1)		;GET A VOLID FROM SUBENTRY
	CALL CHKID		;IS IT A LEGAL VOLID?
	 JRST [	ABTRET (MREQX9)] ;NO, ABORT REQUEST
	CALL VQADD		;ADD VOLID TO END OF LIST
	 RET			;POOL EXHAUSTED, REQUEST ABORTED
	AOBJN Q1,BTRVL1		;LOOP TO TRANSFER ALL VOLIDS
	RETSKP

; VOLUME PROTECTION

BTRVPR:	MOVEI T3,.TMVPR
	CALL BLKFND		;SEARCH FOR VOLUME-PROTECTION ENTRY
	 SETZ T2,		;NONE FOUND
	MOVE T1,(T1)		;GET ARG IF THERE
	SKIPN T2		;SKIP IF ARGUMENT PRESENT
	MOVEI T1,777777		;USE DEFAULT
	STOR T1,RSBVPR		;STORE VOLUME-PROTECTION CODE
	RETSKP
; BTRG1 - GET A NUMERIC ARGUMENT FROM A BUILDING-BLOCK LIST
;	  IF NO VALUE SPECIFIED, RETURN 0
;	  IF VALUE SUPPLIED, VERIFY THAT 0 .LE. VALUE .LE. MAXIMUM
; T1-T3/ ARGUMENTS FOR BLKFND
; T4/ MAXIMUM VALUE
; RETURNS +1: ENTRY CONTAINS HEADER ONLY OR ARG LIES OUTSIDE LIMITS
;	  +2: ARGUMENT VALID, T1/ VALUE

BTRG1:	STAKT
	CALL BLKFND		;SEARCH FOR ENTRY
	 JRST [	SETZ T1,	;ENTRY NOT THERE, RETURN ZERO
		RETSKP]
	JUMPE T2,R		;ERROR IF HEADER-ONLY
	SKIPGE T1,(T1)		;GET ARGUMENT
	RET			;CAN'T BE LESS THAN ZERO
	CAMLE T1,CT4
	RET			;.GT. UPPER LIMIT
	RETSKP


; TCITN - CANCEL A TAPE MOUNT REQUEST WITH A SPECIFIED ITN
;  T1/ INTERNAL TASK NAME (ITN) OF REQUEST TO BE CANCELED
; RETURNS +1: ITN NOT FOUND OR REQUEST COULD NOT BE CANCELED
;	  +2: REQUEST CANCELED

TCITN:	QSCANI ARBQDB		;SET UP TO SCAN TAPE REQUEST QUEUE
	SAVEAC <RSB>
	SAVEQ
	MOVE Q1,T1		;SAVE ITN
TCITN1:	CALL QMSCAN		;GET ADDR OF NEXT RSB IN T2
	 RET			;NONE LEFT, EXIT
	MOVEI RSB,-RSBLNK(T2)	;GET ADDRESS OF RSB INTO RSB AC
	CAME Q1,RSBITN(RSB)	;IS THIS THE RIGHT REQUEST?
	JRST TCITN1		;NO, CONTINUE SEARCH
	LOAD T1,RSBTYP
	CAIN T1,.MNTTP		;TAPE REQUEST?
	JRST [	JE RSBMT,,.+1	;YES, CANCEL ONLY IF MT NOT ASSIGNED YET
		RET]		;MT ASSIGNED, CAN'T CANCEL IT
	CALL CHKAB		;REQUEST ABORTED?
	 RET			;YES, CAN'T CANCEL
	CALL CHKDSM		;[335]Check to see if we a doing a str dismount
	ABTREQ (MREQX1)		;OK, KILL TI
	CALL WORCAN		;TELL OPERATOR REQUEST WAS CANCELED
	RETSKP

;**;[335]At TELMON:-1L add 8 lines  JYCW 12/5/86
;CHKDSM - Call only by TCITN to set the structure back to its previous
;	  state if we are canceling a dismount request. 
;Accepts RSB/Request Status Block
;Returns +1 always
CHKDSM:	LOAD T1,RSBTYP		;[335]Get the request type
	CAIE T1,.DSMST		;[335]Dismount str request?
	JRST CHKDS1		;[335]No, all done
	MOVE T1,RSBSTA(RSB)	;[335]Get structure alias
	MOVE T2,RSBSTN(RSB)	;[335]Get structure name
	SETZ T4,		;[335]No unique code
	CALL MATCHS		;[335]Get SSB in STR
	 SKIPA			;[335]Not there
	CALL STSTBK		;[335]Set str back to its previous state
CHKDS1:	RET
; TELMON - TELL THE MONITOR A TAPE VOLUME SWITCH WAS NOT PERFORMED
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

MTUABS==3			;SIZE OF ARGUMENT BLOCK
TELMON:	STKVAR <<MTUAB,MTUABS>>
	MOVEI T1,MTUABS
	MOVEM T1,.MTCNT+MTUAB	;SET COUNT IN ARGUMENT BLOCK
	LOAD T1,RSBSTE		;GET ERROR CODE
	MOVEM T1,.MTCOD+MTUAB	;SET ERROR CODE IN ARG BLOCK
	SETZ T1,		;ASSUME NO ERROR MESSAGE
	MOVX T2,R%ORES
	TDNE T2,RSBIFL(RSB)	;IS THERE AN OPERATOR RESPONSE?
	HRROI T1,ATMBFR		;YES, GET POINTER TO RESPONSE STRING
	MOVEM T1,.MTPTR+MTUAB	;SET STRING POINTER OR 0 IN ARG BLOCK

; ARGUMENT BLOCK IS SET UP, NOW LOAD THE AC'S AND ISSUE THE CALL

	MOVEI T1,.MTNVV		;GET MTU FUNCTION CODE
	LOAD T2,RSBMT		;GET MT STATUS BLOCK ADDRESS
	SUBI T2,MT0		;COMPUTE DISPLACEMENT FROM 0TH BLOCK
	IDIVI T2,MTSZ		;COMPUTE MT#
	MOVEI T3,MTUAB		;GET ARGUMENT BLOCK ADDRESS
	MTU%			;TELL MONITOR
	RET
; TELUSR - BUILD AND SEND IPCF MESSAGE TO USER TO NOTIFY HIM OF THE
;	   DISPOSITION OF A MOUNT REQUEST
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

TELUSR:	SAVEQ
	SETZM TBUF+.OFLAG	;CLEAR FLAGS WORD
	CALL PBINIT		;SET UP FOR CREATING BUILDING BLOCKS
	MOVE Q1,[2,,.MNRNM]	;BUILD BLOCK CONTAINING REQUEST NAME
	MOVE Q2,RSBRNM(RSB)
	MOVEI T1,Q1
	CALL PBBLK
	LOAD T1,RSBSTE		;GET REQUEST STATE
	CAIN T1,ABRTNR		;SHOULD USER GET A RESPONSE?
	RET			;NO, EXIT
	CAIL T1,.ERBAS		;IS THE REQUEST ABORTED?
	JRST [	CALL TLUAB	;YES, BUILD MESSAGE FOR ABORT
		JRST TELUS1]
	LOAD T1,RSBTYP		;GET REQUEST TYPE
	MOVEI T2,STOP		;IN CASE NO MATCH IS FOUND
	CAIN T1,.MNTTP		;TAPE-MOUNT?
	MOVEI T2,TLUTS		;YES
	CAIN T1,.MNTST		;STRUCTURE MOUNT?
	MOVEI T2,TLUSS		;YES
	CAIN T1,.DSMST		;DISMOUNT STRUCTURE?
	MOVEI T2,TLUSR		;YES
NOSHIP,<
	CAIN T1,.MNTDT		;DECTAPE-MOUNT?
	MOVEI T2,TLUDT		;YES
>;NOSHIP
	CALL (T2)		;CALL APPROPRIATE TELL-ROUTINE

; TELUS1 - T1/ GALAXY HEADER FLAGS

TELUS1:	MOVE T2,T1		;COPY FLAGS TO T2 FOR GALHDR
	MOVE T1,PBBPT		;GET POINTER AFTER LAST BLOCK
	SUBI T1,TBUF		;COMPUTE LENGTH OF MESSAGE
	MOVSS T1		;MOVE TO LH OF T1
	HRRI T1,.QOMNA		;PUT MESSAGE TYPE IN RIGHT HALF
	MOVE T3,RSBCOD(RSB)	;GET USER'S ACK CODE
	CALL GALHDR		;BUILD GALAXY HEADER FOR USER
	MOVE T1,RSBPID(RSB)	;GET USER'S PID
	CALLRET TRANU		;SEND THE MESSAGE AND RETURN TO CALLER
; TLUTS - BUILD BLOCKS FOR SUCCESSFUL TAPE MOUNT RESPONSE

TLUTS:	STKVAR <<DVBLK,3>,SAVMT>
	CALL VQGCV		;GET CURRENT VOLID IN T1
	MOVE T2,RSBSSN(RSB)	;GET SETNAME
	JUMPE T1,[TMCT <%I[Tape set %2S, scratch tape mounted]%_>
		JRST TLUTS1]
	TMCT <%I[Tape set %2S, volume %1S mounted]%_>
TLUTS1:	JN TM%OSV,RSBUFL(RSB),[TMCT <[Volume identifiers: >
		CALL TMCVLS	;DISPLAY VOLID LIST
		TMCT <]
>
		JRST .+1]
	MOVEI T1,TMCMSG		;GET ADDR OF ASCIZ TEXT
	MOVEI T2,.MNRTX		;GET ARGUMENT TYPE
	CALL PBTXT		;CREATE TEXT BUILDING BLOCK
	MOVE T1,[FLD(3,AR.LEN)+FLD(.MNRDV,AR.TYP)] ;GET HEADER
	MOVE T2,RSBSSN(RSB)	;GET SETNAME
	DMOVEM T1,DVBLK		;STORE HEADER AND SETNAME
	MOVEM MT,SAVMT		;PRESERVE MT AC
	LOAD MT,RSBMT		;GET ADDR OF MT STATUS BLOCK
	CALL GMTDD		;GET MT DEVICE DESIGNATOR IN T1
	MOVE MT,SAVMT		;RESTORE MT AC
	MOVEM T1,2+DVBLK	;STORE MT DESIGNATOR IN .MNRDV BLOCK
	MOVEI T1,DVBLK		;GET ADDRESS OF .MNRDV BLOCK
	CALL PBBLK		;ADD IT TO BUILDING BLOCK LIST
	SETZ T1,		;SET NO FLAGS IN GALAXY HEADER
	RET
; TLUAB - BUILD BLOCKS FOR UNSUCCESSFUL MOUNT-REQUEST RESPONSE

TLUAB:	SAVEQ
	MOVE Q1,[FLD(2,AR.LEN)+FLD(.MNREC,AR.TYP)] ;GET HEADER
	LOAD Q2,RSBSTE		;GET ERROR CODE
	MOVEI T1,Q1		;POINT AT ERROR CODE BLOCK
	CALL PBBLK		;PUT BLOCK IN MESSAGE
	JN R%ORES,RSBIFL(RSB),[MOVEI T1,ATMBFR ;POINT TO REASON
		TMCT <%IReason given by operator: %1A>
		MOVEI T1,TMCMSG	;GET ADDRESS OF ASCIZ TEXT
		MOVEI T2,.MNRTX	;GET ENTRY TYPE
		CALL PBTXT	;INSTALL TEXT BUILDING BLOCK
		JRST .+1]
	MOVX T1,MF.FAT		;GET FATAL-ERROR FLAG
	RET
; TRESCK - CHECK IF THE SYSTEM HAS AT LEAST ONE OF THE TYPE OF
;	   TAPE DRIVE REQUESTED BY THE USER JOB
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: REQUEST CANNOT BE HANDLED BY THE SYSTEM
;	  +2: REQUEST CAN BE HANDLED BY THE SYSTEM

TRESCK:	SAVEAC <MTA>
	SAVEQ
	SKIPE TSTF		;TEST MODE?
	RETSKP			;YES, ALWAYS SUCCEED
	MOVE Q1,MTAN		;GET # OF MTA DEVICES ON SYSTEM
	MOVEI MTA,MTA0-MTASZ	;INIT MTA AC FOR STATUS BLOCK SCAN
	LOAD Q2,RSBDRV		;GET REQUESTED DRIVE TYPE

; SCAN AVAILABLE TAPE DRIVES FOR ONE THAT CAN POTENTIALLY
; SATISFY THE USER TAPE MOUNT REQUEST

TRES1:	SOJL Q1,R		;TAKE +1 RETURN IF NONE LEFT TO CHECK
	ADDI MTA,MTASZ		;POINT AT NEXT MTA STATUS BLOCK
	JE MTASTE,,TRES1	;SKIP DRIVE IF NOT ASSIGNED TO ME
	JUMPN Q2,[LOAD T1,MTADRV ;GET TYPE OF DRIVE
		CAME T1,Q2	;DOES IT MATCH WHAT THE USER WANTS?
		JRST TRES1	;NO, SKIP IT
		JRST .+1]
	LOAD T1,RSBDEN		;GET REQUESTED DENSITY
	JUMPE T1,RSKP		;OK IF NOT PARTICULAR ABOUT DENSITY
	CALL DRVDEN		;CAN THE DRIVE OPERATE AT THIS DENSITY?
	 JRST TRES1		;NO, SKIP IT
	RETSKP			;OK, AT LEAST 1 DRIVE CAN DO IT
; UTM - PROCESS USER TAPE MOUNT REQUEST RECEIVED THROUGH QUASAR
;	1 - ANALYZE BUILDING-BLOCK REQUEST AND BUILD RSB
;	2 - GET VOLID LIST FROM OPERATOR (IF TM%OSV SET)
;	3 - GET THE FIRST REQUESTED VOLUME MOUNTED
;  T1/ ADDRESS OF TAPE MOUNT ENTRY IN IPCF MESSAGE FROM QUASAR
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

UTM:	MOVEI T2,BTRRTA		;TABLE OF TAPE MOUNT SUBENTRY PROCESSORS
	CALL BTMRSB		;BUILD RSB FROM QUASAR MESSAGE
	 RET			;REQUEST ABORTED, EXIT
	JXE F,TALCF,[ABTRET (MREQ26)] ;MUST HAVE ALLOCATION ENABLED
	CALL ACCMTR		;CREATE ACCOUNT BLOCK
	 JRST [	ABTRET (MREQ31)] ;ABORT REQUEST, NO BLOCKS AVAILABLE
	CALL PWATCH		;TELL INFO TO WATCH USER'S PID
	MOVX T1,TM%OSV
	TDNN T1,RSBUFL(RSB)	;WHO IS SUPPLYING THE VOLIDS?
	JRST [	CALLRET VOLMNT]	;USER, GO GET THE FIRST VOLUME MOUNTED

; GET THE VOLID LIST FROM THE OPERATOR

	MOVEI T1,RST.WV		;OPERATOR IS SUPPLYING VOLIDS
	STOR T1,RSBSTE		;SET STATE TO WAITING FOR VOLID KEYIN
	CALL TCKP		;SEND STATUS UPDATE TO QUASAR
UTM1:	JSP T1,WRUTR		;ASK OPERATOR TO KEY IN VOLID LIST
	MOVEI RSB,-RSBWTB(T2)	;LOAD UP ADDR OF REQUEST STATUS BLOCK
	CALL PMR		;PARSE RESPONSE TO VOLID REQUEST
	 JRST UTM1		;BAD RESPONSE, TRY IT AGAIN
	JUMPN T1,R		;RETURN IF REQUEST ABORTED
	CALLRET VOLMNT		;GET 1ST VOLUME MOUNTED AND RETURN
SUBTTL VOLUME/REQUEST ASSOCIATION LOGIC

; MATCHR - TRY TO MATCH USER REQUEST TO TAPE VOLUME
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

MATCHR:	SAVEAC <MTA,Q1>
	MOVE Q1,MTAN		;GET # OF MTA DEVICES ON SYSTEM
	MOVEI MTA,MTA0-MTASZ	;INIT MTA AC FOR SCAN

; SCAN MTA STATUS BLOCKS FOR VOLUMES THAT CAN SATISFY THE REQUEST

MCHR1:	ADDI MTA,MTASZ		;POINT AT NEXT MTA STATUS BLOCK
	SOJL Q1,R		;NONE LEFT, SO SPLIT
	CALL VRA		;TRY TO MATCH REQUEST TO VOLUME
	 JRST MCHR1		;CAN'T, SO CONTINUE SEARCH
	RET


; MATCHV - TRY TO MATCH TAPE VOLUME TO USER REQUEST
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

MATCHV:	SAVEQ
	SAVEAC <RSB>
; PROBLEM: IF THE VOLUME IS A SCRATCH TAPE WITH A VOLID, I WANT TO
; ENSURE THAT ANY USER REQUESTING THE TAPE BY ITS VOLID GETS PRIORITY
; OVER ANY USER REQUESTING A RANDOM SCRATCH TAPE.

; SOLUTION: IMPLEMENT THE HAIRY CODE BELOW THAT PERFORMS A 2-PASS
; SEARCH OF THE RSB QUEUE WHEN THE VOLUME IS A SCRATCH TAPE. THE FIRST
; PASS (Q1/1) CHECKS ONLY RSB'S THAT ARE REQUESTING SPECIFIC (I.E.,
; NON-SCRATCH) VOLUMES. THE SECOND PASS (Q1/0) WILL CHECK ALL RSB'S. IF
; THE TAPE IS NOT A SCRATCH TAPE, ONLY THE SECOND PASS IS EXECUTED.

	LOAD Q1,MA%SCR,MTAFLG(MTA) ;GET 1 IFF VOLUME IS A SCRATCH
MATV1:	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
MATV2:	CALL NMTRSB		;GET NEXT RSB
	 JRST [	SOJGE Q1,MATV1	;MAKE 2ND PASS IF NEEDED
		RET]		;ELSE RETURN
	CALL VQGCV		;THIS USER WANT A SCRATCH TAPE?
	SKIPN T1		;NO
	JUMPG Q1,MATV2		;YES, BYPASS IF IN NON-SCRATCH PASS
	CALL VRA		;TRY TO MATCH REQUEST TO VOLUME
	 JRST MATV2		;CAN'T DO IT, CONTINUE SEARCH
	RET			;REQUEST MATCHED TO VOLUME, EXIT
; MCHWMT - THIS ROUTINE IS CALLED WHEN MT DEVICES ARE FREED BY USER
;	   JOBS. ITS PURPOSE IS TO SCAN THE REQUEST QUEUE FOR REQUESTS
;	   THAT COULD NOT BE SATISFIED BECAUSE NO MT'S WERE AVAILABLE.
; RETURNS +1: ALWAYS

MCHWMT:	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	SAVEAC <RSB>
	TXZN F,NOMTF		;DOES AN MT SHORTAGE EXIST?
	RET			;NO, NOTHING TO DO

; SCAN REQUEST QUEUE FOR REQUESTS THAT NEED MT DEVICES

MCHWM1:	TXNN F,NOMTF		;EXIT IF MT SHORTAGE EXISTS
	CALL NMTRSB		;GET NEXT RSB
	 RET			;NOTHING MORE TO DO
	JN RSBMT,,MCHWM1	;BYPASS IF HE'S GOT AN MT ALREADY
	LOAD T1,RSBSTE		;GET STATE OF REQUEST
	CAIE T1,RST.WM		;WAITING FOR TAPE MOUNT?
	JRST MCHWM1		;NO, DOESN'T NEED MT
	CALL MATCHR		;TRY TO FIND A MATE FOR THIS REQUEST
	JRST MCHWM1		;GO ON TO NEXT REQUEST
; MOLOC - PERFORM .MOLOC MTOPR FUNCTION
;  MT/ ADDR OF MT STATUS BLOCK
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

MOLASZ==10			;SIZE OF .MOLOC ARG BLOCK
MOLOC:	STKVAR <<MOLARG,MOLASZ>>
; SET UP ARGUMENT BLOCK FOR MTOPR

	MOVEI T1,MOLASZ		;SET SIZE OF ARG BLOCK
	MOVEM T1,.MOCNT+MOLARG
	MOVE T1,MT		;GET MT STATUS BLOCK ADDR
	SUBI T1,MT0		;SUBTRACT BASE ADDRESS
	IDIVI T1,MTSZ		;COMPUTE MT UNIT#
	MOVEM T1,.MOMTN+MOLARG	;SET MT UNIT #
	LOAD T1,RSBDEN
	MOVEM T1,.MODNS+MOLARG	;SET DENSITY
	MOVEI T1,MTAV1(MTA)
	MOVEM T1,.MOAVL+MOLARG	;SET LABEL ADDRESS
	LOAD T1,RSBCV
	MOVEM T1,.MOCVN+MOLARG	;SET CURRENT VOLUME #
	MOVE T1,RSBASN(RSB)
	MOVEM T1,.MOVSN+MOLARG	;SET SIXBIT FILE SET IDENTIFIER
	LOAD T1,RSBLT
	MOVEM T1,.MOLBT+MOLARG	;SET LABEL TYPE
	MOVEI T2,1		;ASSUME EBCDIC OR ANSI
	CAIN T1,.LTUNL
	MOVEI T2,0		;UNLABELED
	CAIN T1,.LTT20
	MOVEI T2,2		;TOPS-20
	MOVEM T2,.MONVL+MOLARG	;SET LABEL COUNT

; NOW PASS ALL THIS STUFF ON DOWN TO THE MONITOR

	CALL MTAGJF		;GET JFN FOR MTOPR
	MOVEI T2,.MOLOC		;GET MTOPR FUNCTION CODE
	MOVEI T3,MOLARG		;ADDRESS OF ARGUMENT BLOCK
	MTOPR			;PERFORM REQUESTED FUNCTION
	 ERCAL WOLOCF		;ERROR, DISPLAY TO OPERATOR
	LOAD T1,MTAJFN		;GET JFN
	MOVEI T2,.MOSID		;FUNCTION = SET VOLUME-ID
	MOVE T3,MTAVOL(MTA)	;GET VOLID
	MTOPR			;MAKE VOLID AVAILABLE TO USER VIA .MOINF
	CALLRET MTARJF		;RELEASE JFN AND RETURN
; MTALC - ALLOC MT DEVICE TO A USER JOB
;  MT/ ADDR OF MT STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: FAILED, USER JOB DISAPPEARED
;	  +2: SUCCESS, MT AND RSB LINKED TO EACH OTHER

MTALC:	CALL GMTDD		;GET MT DEVICE DESIGNATOR IN T1
	MOVE T2,T1		;MOVE IT TO T2 FOR ALLOC JSYS
	MOVEI T1,.ALCAL		;ALLOC FUNCTION CODE
	LOAD T3,RSBJNO		;GET USER'S JOB #
	ALLOC			;ALLOCATE MT DEVICE TO USER JOB
	 JRST [	CAIE T1,ALCX4	;INVALID JOB #?
		CALL STOP	;NO, I CAN'T HANDLE THIS ERROR
		ABTRET (ABRTNR)] ;ABORT - USER WENT AWAY
	STOR MT,RSBMT		;STORE MT STATUS BLOCK ADDR IN RSB
	STOR RSB,MTRSB		;STORE RSB ADDR IN MT STATUS BLOCK
	RETSKP			;SUCCESSFUL COMPLETION


; MTGET - LOCATE A FREE MT DEVICE
; RETURNS +1: NO FREE MT'S AVAILABLE
;	  +2: FREE MT FOUND, MT/ ADDR OF MT STATUS BLOCK

MTGET:	MOVEI MT,MT0-MTSZ	;INIT MT AC FOR STATUS BLOCK SEARCH
	MOVE T1,MTN		;GET # OF MT DEVICES ON SYSTEM
MTGET1:	ADDI MT,MTSZ		;POINT AT NEXT MT STATUS BLOCK
	SOJL T1,[TXO F,NOMTF	;NONE LEFT, SET NONE-LEFT FLAG
		RET]		;ERROR RETURN
	JN MTRSB,,MTGET1	;SKIP THIS ONE IF IT'S IN USE
	RETSKP			;FREE MT FOUND


; MTRLS - PROCESS RELEASE OF MT DEVICE BY USER
;  MT/ ADDR OF MT STATUS BLOCK
; RETURNS +1: ALWAYS

MTRLS:	SAVEAC <RSB>
	LOAD RSB,MTRSB		;GET RSB ADDRESS
	JUMPE RSB,R		;EXIT IF NO RSB ASSOCIATED
	CALL PLDISA		;DISASSOCIATE MT FROM MTA
	SETZRO MTRSB		;CLEAR OWNER-OF-MT FIELD
	CAIN RSB,MTNAV		;WAS THERE AN RSB?
	RET			;NO, BYPASS RSB PROCESSING
	SETZRO RSBMT		;CLEAR POINTER TO MT IN RSB
	LOAD T1,RSBSTE		;[332]Get the status
	CAIN T1,RST.WM		;[332]Waiting for next volume?
	CALL WORCAN		;[332]Yes, Tell OPR of cancelation 
	SKIPE T1,RSBWTB+WTBCOD(RSB) ;WTOR OUTSTANDING?
	CALL CANWTR		;YES, CANCEL IT
	TXO F,ABORTF		;FORCE A SCAN TO DUMP THE RSB
	ABTRET (ABRTNR)		;GET THE REQUEST OUT OF MY QUEUES
; PLDISA - DISASSOCIATE PHYSICAL AND LOGICAL TAPE DEVICES
;  MT/ ADDR OF MT STATUS BLOCK
; RETURNS +1: ALWAYS

; NOTE - IF MOUNTR CRASHES AND GETS RESTARTED, THE CURRENT MT-MTA
;	 ASSOCIATIONS ARE RESTORED FROM MONITOR TABLES (ASMT ROUTINE)
;	 BUT MTRSB WILL CONTAIN MTNAV (HENCE PLDISA CHECKS FOR THIS)

PLDISA:	SAVEAC <MTA,RSB>
	LOAD MTA,MTMTA		;GET MTA STATUS BLOCK ADDRESS
	JUMPE MTA,R		;EXIT IF NO MTA ASSOCIATED WITH MT
	LOAD RSB,MTRSB		;GET REQUEST STATUS BLOCK ADDRESS
	SETZRO MTAMT		;CLEAR MTA-TO-MT LINK
	SETZRO MTMTA		;CLEAR MT-TO-MTA LINK
	CALL SCIENA		;GET STATUS INTERRUPTS FOR THIS DRIVE

	CAIN RSB,MTNAV		;RSB ASSOCIATED?
	JRST PLDISU		;NO, UNLOAD DRIVE TO PLAY IT SAFE
	CALL ACCMTD		;SEND ACCOUNT INFO TO MONITOR
	CALL CKMPAV		;DID OPERATOR SET MTA UNAVAILABLE?
	 JRST PLDISU		;YES, UNLOAD IT
	JE TM%NUL,RSBUFL(RSB),PLDISU ;JUMP IF USER WANTS VOLUME UNLOADED
	CALL REW		;IS MTA OFFLINE?
	 JRST PLDISU		;YES, NO HOPE FOR RE-USE
	MOVEI T1,[ASCIZ/Remaining mounted on drive/]
	CALL WODISA		;TELL OPERATOR THAT USER RELEASED TAPE
	LOAD T1,MTALT		;GET LABEL TYPE
	CAIE T1,.LTUNL		;UNLABELLED?
	JRST PLDSA1		;NO, DON'T TOUCH VOLID
	SETZM MTAVOL(MTA)	;CLEAR VOLID
	SETZM MTAIDV(MTA)	;AND OPERATOR KEYIN
PLDSA1:	JE MA%AVS,MTAFLG(MTA),[CALLRET MATCHV] ;TRY MATCHUP IF NON-AVR
	MOVX T1,MA%UXV+MA%OPF+MA%SCR
	ANDCAM T1,MTAFLG(MTA)	;CLEAR SOME FLAGS
	SETZRO MTALT		;CLEAR MTALT SO AVR WILL WORK
	CALLRET AVR		;INITIATE AVR SEQUENCE FOR DRIVE

; AVR SEQUENCE MAY NOT BE PERFORMED UPON TAPE

PLDISU:	LOAD T1,MTALT		;GET LABEL TYPE
	CAIN T1,.LTUNL		;UNLABELLED?
	JRST [SETZM MTAVOL(MTA)	;YES, CLEAR VOLID
	      SETZM MTAIDV(MTA)	;AND OPERATOR KEYIN
	      JRST .+1]		;CONTINUE
	CALL UNLOAD		;UNLOAD THE DRIVE
	MOVEI T1,[ASCIZ/Being unloaded/]
	CAIE RSB,MTNAV		;IF NO RSB, DON'T GIVE MESSAGE
	CALL WODISA		;TELL OPERATOR THAT USER RELEASED TAPE
	CALL CKMPAV		;DID OPERATOR SET MTA NOT-AVAILABLE?
	 CALL DACMTA		;YES, DEACTIVATE MTA
	RET			;NO
; PRQABT - PURGE ABORTED REQUESTS FROM MOUNT REQUEST QUEUE
; RETURNS +1: ALWAYS

PRQABT::SAVEAC <T1>		;Save T1
	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	SAVEAC <RSB>

; SEARCH MOUNT REQUEST QUEUE AND EXTRACT ABORTED REQUESTS

PRQAB1:	CALL QMSCAN		;GET ADDRESS OF NEXT RSB ON QUEUE
	 RET			;NONE LEFT, EXIT
	MOVEI RSB,-RSBLNK(T2)	;LOAD RSB AC WITH RSB ADDRESS
	CALL CHKAB		;REQUEST ABORTED?
	 SKIPA			;YES
	JRST PRQAB1		;NO, SKIP IT
	LOAD T1,RSBTYP		;GET TYPE OF REQUEST
	CAIN T1,.MNTTP		;TAPE MOUNT?
	JRST [	JN RSBMT,,PRQAB1 ;YES, SKIP IF USER STILL HAS MT DEVICE
		CALL VQDEL	;RELEASE VOLID LIST
		JRST .+1]	;CONTINUE DELETION LOGIC

; DEQUEUE AND DISCARD ABORTED RSB

	SKIPE RSBWTB+WTBCOD(RSB) ;IS WTB ACTIVE?
	CALL STOP		;YES, CRASH!!!
	MOVX T1,R%OPR
	TDNN T1,RSBIFL(RSB)	;WAS THIS REQUEST FROM OPR?
	CALL RLSMSG		;NO, TELL QUASAR TO RELEASE THIS ITN
	CALL QMDQS		;DEQUEUE RSB, GET LINKAGE ADDR IN T2
	MOVEI T1,IRBQDB		;GET QDB ADDRESS
	CALL QMQH		;QUEUE RSB TO HEAD OF INACTIVE QUEUE
	JRST PRQAB1		;CONTINUE SCAN OF RSB QUEUE
; PRQPID - PURGE REQUESTS FROM MOUNT REQUEST QUEUE WHOSE OWNERS
;	   HAVE DELETED THEIR PIDS BEFORE THE FIRST VOLUME WAS MOUNTED
; RETURNS +1: ALWAYS

PRQPID:	QSCANI ARBQDB		;SET UP TO SCAN ACTIVE RSB QUEUE
	SAVEAC <RSB>
PURGR1:	CALL QMSCAN		;GET ADDR OF NEXT RSB IN T2
	 RET			;END OF RSB QUEUE, EXIT
	MOVEI RSB,-RSBLNK(T2)	;COPY RSB ADDRESS TO RSB AC
	CALL CHKAB		;REQUEST ABORTED?
	 JRST PURGR1		;YES, SKIP IT
	CALL VALPID		;CHECK PID
	 JFCL			;REQUEST ABORTED
	JRST PURGR1		;CONTINUE SEARCH


; VALPID - ABORT REQUEST IF PID IS DELETED
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: REQUEST ABORTED BECAUSE USER PID WAS DELETED
;	  +2: REQUEST NOT ABORTED

VALPID:	LOAD T1,RSBTYP
	CAIN T1,.MNTTP		;TAPE REQUEST?
	JRST [	JE RSBMT,,.+1	;YES, DOES THE USER HAVE AN MT?
		RETSKP]		;YES, DON'T DO PID CHECK
	CAIN T1,.MNTDT		;DECTAPE-MOUNT REQUEST?
	SKIPN RSBDTA(RSB)	;DOES USER HAVE THE DTA?
	SKIPA			;NO TO EITHER
	RETSKP			;USER HAS DECTAPE, PRESERVE REQUEST
	MOVEI T1,.MUFOJ
	MOVE T2,RSBPID(RSB)	;GET USER'S PID
	CALL XMUTIL		;IS IT STILL VALID?
	 JRST [	CALL WORCAN	;NO, TELL OPERATOR REQ WAS CANCELED
		ABTRET (ABRTNR)] ;ABORT REQUEST
	RETSKP			;PID STILL GOOD
; VOLMNT - ATTEMPT TO MATCH REQUEST WITH MOUNTED VOLUME; IF THIS IS
;	   NOT POSSIBLE, THE OPERATOR IS TOLD TO MOUNT THE VOLUME
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

VOLMNT:	CALL VQCNT		;GET # OF VOLUMES IN SET IN T1
	LOAD T2,RSBCV		;GET CURRENT VOLUME #
	MOVX T3,R%WVL
	TDNN T3,RSBIFL(RSB)	;NEED TO ASK OPERATOR FOR NEXT VOLID?
	CAMG T2,T1
	SKIPA T1,[RST.WM]	;NO
	JRST [	MOVEI T1,RST.WV	;YES
		STOR T1,RSBSTE	;SET STATE TO WAITING FOR VOLID KEYIN
		CALL TCKP	;TELL QUASAR
		MOVEI T1,VOLMT2	;GET END-ACTION ADDRESS
		CALLRET WRNXTV]	;GO ASK FOR NEXT VOLID
	STOR T1,RSBSTE		;SET STATE TO WAITING FOR TAPE MOUNT
	SETZRO R%ONR,RSBIFL(RSB) ;CLEAR OPERATOR-NOTIFIED FLAG
	CALL TCKP		;SEND CHECKPOINT MESSAGE TO QUASAR
	CALL MATCHR		;MATCH REQUEST TO VOLUME
	CALL CHKAB		;REQUEST ABORTED?
	 RET			;YES, BACK TO CALLER
	LOAD T1,RSBSTE		;GET STATE TO SEE WHAT MATCHR DID
	CAIE T1,RST.WM		;STILL WAITING FOR A MOUNT?
	RET			;NO, EXIT
	CALLRET WOVMT		;TELL OPERATOR TO MOUNT VOLUME

; PROCESS RESPONSE TO WTOR ASKING OPERATOR TO SUPPLY NEXT VOLID

VOLMT2:	MOVEI RSB,-RSBWTB(T2)	;LOAD RSB AC
	CALL PNVR		;PARSE RESPONSE
	 JRST [	MOVEI T1,VOLMT2	;BAD RESPONSE, GET END-ACTION ADDRESS
		CALLRET WRNXTV]	;LET HIM TRY IT AGAIN
	JUMPN T1,R		;RETURN NOW IF REQUEST ABORTED
	JRST VOLMNT		;GOT THE VOLID, NOW GO GET IT MOUNTED
; VOLSW - PERFORM TAPE VOLUME-SWITCH
;  T1/ ABSOLUTE VOLUME NUMBER TO SWITCH TO
;  MT/ ADDR OF MT STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

VOLSW:	SAVEAC <MTA,ACC>
	STAKT
	LOAD T2,RSBCV		;GET CURRENT VOLUME #
	CAMN T1,T2		;SWITCHING TO SAME VOLUME?
	JRST [	LOAD MTA,MTMTA	;YES, GET MTA STATUS BLK ADDR
		CALLRET MOLOC]	;HOOK UP MT&MTA AGAIN
	CALL PLDISA		;DISASSOCIATE MTA FROM MT
	LOAD ACC,RSBACC		;GET ACC
	GTAD			;GET TIME
	MOVEM T1,ACCSCD(ACC)	;SAVE IN ACCOUNT BLOCK AS SCHEDULED TIME
	CALL VQCNT		;GET # OF VOLUMES IN SET
	ADDI T1,1		;ADD 1 IN CASE EXPANDING VOLUME SET
	SKIPLE T2,CT1		;ERROR IF GOING TO VOLUME BEFORE FIRST
	CAMLE T2,T1		;ERROR IF GOING BEYOND END OF SET
	JRST [	ABTRET (MREQX8)] ;ATTEMPT TO SWITCH TO VOL OUTSIDE SET
	STOR T2,RSBCV		;SET CURRENT VOLUME # IN RSB
	CALLRET VOLMNT		;GET THE REQUESTED VOLUME MOUNTED
; VRA - ASSOCIATE USER REQUEST AND TAPE VOLUME (IF POSSIBLE)
;  MTA/ ADDR OF MTA STATUS BLOCK OF DRIVE TO BE CHECKED
;  RSB/ ADDR OF USER REQUEST STATUS BLOCK
; RETURNS +1: FAILED, REQUEST MAY BE ABORTED
;	  +2: SUCCESS, MT/ ADDR OF MT STATUS BLOCK

VRA:	SAVEQ
	MOVE T1,MTAFLG(MTA)
	LOAD T2,MTASTE
	CAIN T2,S.AV		;INELIGIBLE IF DRIVE NOT AVAIL TO USERS
	TXNN T1,MA%LOD		;INELIGIBLE IF DRIVE NOT LOADED
	RET
	SKIPN MTAVOL(MTA)	;IS VOLUME IDENTIFIED?
	TXNE T1,MA%SCR		; OR SCRATCH?
	SKIPA			;YES TO EITHER, PROCEED
	RET			;BOTH NO
	JN MTAJCT,,R		;INELIGIBLE IF AVR IN PROGRESS
	JN MTAMT,,R		;INELIGIBLE IF DRIVE IN USE
	LOAD T1,RSBSTE		;GET STATE OF REQUEST
	CAIE T1,RST.WM		;WAITING FOR VOLUME TO BE MOUNTED?
	RET			;NO

; REQUEST AND DRIVE ARE IN THE PROPER STATES... A GOOD SIGN

	MOVEI Q1,VRACCN		;ASSUME NOT REQUESTING SCRATCH
	CALL VQGCV		;GET CURRENT VOLID IN T1
	SKIPN T1		;WANT SCRATCH VOLUME?
	MOVEI Q1,VRACCS		;YES, CALL SCRATCH ROUTINE
	CALL (Q1)		;CALL APPROPRIATE ROUTINE
	 RET			;WRONG VOLUME OR REQUEST ABORTED

; MISCELLANEOUS CHECKS BEFORE I ASSIGN AN MT TO THE USER

	CALL VALPID		;CHECK FOR DELETED PID
	 RET			;REQUEST ABORTED
	CALL REW		;CHECK IF DRIVE IS REALLY LOADED
	 RET			;NO, DON'T ASSIGN
	LOAD T1,MA%WEN,MTAFLG(MTA) ;GET DRIVE WRITE STATUS
	LOAD T2,TM%WEN,RSBUFL(RSB) ;GET REQUESTED WRITE STATUS
	CAME T1,T2		;DO DRIVE AND USER AGREE?
	JRST [	CALL UNLOAD	;NO, UNLOAD THE DRIVE
		CALLRET WOWPE]	;TELL THE OPERATOR TO FIX IT

; GET MT DEVICE FOR THIS REQUEST IF IT DOESN'T ALREADY HAVE ONE

	LOAD MT,RSBMT		;GET MT STATUS BLOCK ADDRESS
	JUMPE MT,[CALL MTGET	;NO MT YET, ANY MT'S AVAILABLE?
		 RET		;NO, FAILED
		JRST .+1]	;MT AC LOADED (NOT ALLOC'ED YET)
	CALL VQCNT		;GET # OF VOLIDS IN REQUEST
	LOAD T2,RSBCV		;GET CURRENT VOLUME #
	CAMGE T1,T2		;ASSIGNING SCRATCH TAPE TO USER?
	JRST [	MOVE T1,MTAVOL(MTA) ;YES, GET VOLID OF TAPE
		CALL VQADD	;TACK VOLID ON THE END OF LIST
		 RET		;REQUEST ABORTED (RESOURCES EXHAUSTED)
		JRST .+1]

; PUT VALUES IN DEFAULTED RSB FIELDS (DENSITY, DRIVE-TYPE, LABEL-TYPE)

	LOAD T1,MTADRV		;DRIVE-TYPE
	LOAD T2,RSBDRV
	SKIPN T2
	STOR T1,RSBDRV
	LOAD T1,MTALT		;LABEL-TYPE
	LOAD T2,RSBLT
	SKIPN T2
	STOR T1,RSBLT
	LOAD T1,RSBLT		;DENSITY
	CAIE T1,.LTUNL		;LABELED?
	JRST [	LOAD T1,MTADEN	;YES
		LOAD T2,RSBDEN
		SKIPN T2
		STOR T1,RSBDEN
		MOVX T1,MA%SCR
		MOVX T2,R%WVL
		TDNE T1,MTAFLG(MTA) ;SCRATCH TAPE?
		IORM T2,RSBIFL(RSB) ;YES, INSURE LABELS GET REWRITTEN
		CALL LTINIT	;WRITE LABELS IF NECESSARY
		 RET		;ERROR
		JRST .+1]

; ALLOC THE MT TO THE USER (HAPPENS WHEN MOUNTING THE FIRST TAPE OF SET)

	LOAD Q1,RSBMT		;HAVE I ALLOC'ED THE MT TO THE USER YET?
	JUMPE Q1,[CALL MTALC	;NO, ALLOC MT TO USER
		 RET		;ALLOC FAILED (USER DISAPPEARED)
		JRST .+1]	;MT DEVICE ALLOC'ED TO USER JOB

; MT DEVICE ASSIGNED TO USER JOB - ASSOCIATE MTA WITH MT

	MOVE T1,MTASET(MTA)	;GET SETNAME FROM TAPE
	SKIPN RSBASN(RSB)	;DOES THIS REQUEST HAVE A SETNAME YET?
	MOVEM T1,RSBASN(RSB)	;NO, USE SETNAME FROM HDR1 ON TAPE
	CALL MTAGJF		;GET MAGTAPE JFN
	MOVEI T2,.MOINF		;GET TAPE INFO
	MOVEI T3,.MOIWF		;LENGTH OF INFO BLOCK
	MOVEM T3,TAPEBK
	MOVEI T3,TAPEBK		;INFO INTO TAPEBK
	MTOPR			;GET IT
	CALL MTARJF		;RELEASE JFN
	MOVE T1,TAPEBK+.MOIRD	;Number of physical records read
	MOVEM T1,ACCPR(ACC)
	MOVE T1,TAPEBK+.MOIWT	;Number of physical records written
	MOVEM T1,ACCPW(ACC)
	MOVE T1,TAPEBK+.MOIRF	;GET FRAMES READ
	IDIVI T1,^D1000		;IN THOUSANDS
	MOVEM T1,ACCFR(ACC)
	MOVE T1,TAPEBK+.MOIWF	;GET FRAMES WRITTEN
	IDIVI T1,^D1000		;IN THOUSANDS
	MOVEM T1,ACCFW(ACC)
	MOVE T1,TAPEBK+.MOISR	;GET NUMBER OF SOFT READ ERRORS
	MOVEM T1,ACCSR(ACC)
	MOVE T1,TAPEBK+.MOISW	;GET NUMBER OF SOFT WRITE ERRORS
	MOVEM T1,ACCSW(ACC)
	MOVE T1,TAPEBK+.MOIHR	;GET NUMBER OF HARD READ ERRORS
	MOVEM T1,ACCHR(ACC)
	MOVE T1,TAPEBK+.MOIHW	;GET NUMBER OF HARD WRITE ERRORS
	MOVEM T1,ACCHW(ACC)
	CALL MOLOC		;ISSUE JSYS TO ASSOCIATE MT WITH MTA
	CALL SCIDIS		;DON'T TAKE INTERRUPTS FROM THIS MTA
	SKIPN Q1		;WAS MT DEVICE JUST GIVEN TO USER?
	CALL TELUSR		;YES, SEND IPCF CONFIRMATION MSG TO USER

; PERFORM MISCELLANEOUS POST-ASSOCIATION TASKS

	GTAD
	LOAD ACC,RSBACC		;GET ADDRESS OF ACCOUNT BLOCK
	MOVEM T1,ACCSVT(ACC)	;STORE SERVICED-TIME
	SKIPE T1,RSBWTB+WTBCOD(RSB) ;WTOR MESSAGE OUTSTANDING?
	CALL CANWTR		;YES, CANCEL IT
	MOVEI T1,RST.AC
	STOR T1,RSBSTE		;SET STATE TO ACTIVE
	STOR MT,MTAMT		;PUT MT STATUS BLK ADDR IN MTA STAT BLK
	STOR MTA,MTMTA		;PUT MTA STATUS BLK ADDR IN MT STAT BLK
	CALL TCKP		;TELL QUASAR ABOUT STATE CHANGE
	MOVX T1,MA%SCR
	ANDCAM T1,MTAFLG(MTA)	;NOT SCRATCH AFTER I GIVE IT TO USER
	CALL WOASO		;TELL OPERATOR ABOUT ASSOCIATION
	RETSKP
; VRACCN - CHECK COMPATIBILITY OF NON-SCRATCH REQUEST AND TAPE VOLUME
;  T1/ SIXBIT VOLID BEING REQUESTED
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: NOT COMPATIBLE OR REQUEST ABORTED
;	  +2: COMPATIBLE

VRACCN:	SAVEQ
	CAME T1,MTAVOL(MTA)	;DO I HAVE THE RIGHT VOLUME?
	RET			;NO
	LOAD T1,RSBDRV		;DID USER SPECIFY A DRIVE TYPE?
	JUMPN T1,[LOAD T2,MTADRV ;YES, GET ACTUAL DRIVE TYPE
		CAMN T1,T2	;DO THEY MATCH?
		JRST .+1	;YES
		ABTRET (MREQ11)] ;NO, ABORT REQUEST
	JN TM%BYP,RSBUFL(RSB),VRACN3 ;IF BYPASS, JUST CHECK DENSITY
	JE MTALT,,[LOAD Q1,MA%AVE,MTAFLG(MTA) ;TAPE NOT AVR'ED YET
		SETONE MA%AVE,MTAFLG(MTA) ;FORCE AVR
		CALL AVR	;INITIATE AVR SEQUENCE
		STOR Q1,MA%AVE,MTAFLG(MTA) ;RESTORE AVR-ENABLED FLAG
		RET]		;YOU HAVE TO WAIT UNTIL AVR IS DONE
	JN R%WVL,RSBIFL(RSB),VRACN2 ;SPECIAL CASE IF WRITING VOL LABELS
	LOAD T1,RSBLT		;CHECK LABEL TYPES
	LOAD T2,MTALT
	JUMPN T1,[CAMN T1,T2	;USER SPECIFIED LT, DOES IT MATCH TAPE?
		JRST .+1	;YES, PROCEED
		ABTRET (MREQ12)] ;NO, LABEL TYPE MISMATCH
	CAIN T2,.LTUNL		;WHAT KIND OF REQUEST?
	JRST VRACN3		;UNLABELED, CHECK DRIVE CAPABILITIES
	LOAD T1,RSBDEN		;DID USER SPECIFY DENSITY?
	JUMPN T1,[LOAD T2,MTADEN ;YES, GET DENSITY OF TAPE
		CAMN T1,T2	;DO REQUEST AND TAPE DENSITIES MATCH?
		JRST .+1	;YES, PROCEED
		ABTRET (MREQ10)] ;MISMATCHED DENSITY
	MOVX T1,TM%VFY
	TDNE T1,RSBUFL(RSB)	;CHECKING SETNAME OF LABELED TAPE?
	JRST [	MOVE T1,RSBSSN(RSB) ;YES, GET SETNAME FROM RSB
		CAMN T1,MTASET(MTA) ;DOES IT MATCH SETNAME OF VOLUME?
		JRST .+1	;YES
		ABTRET (MREQ14)] ;MISMATCHED SET NAME
	RETSKP

; REWRITING VOLUME LABELS

VRACN2:	CALL VRWLT		;LABEL TYPES COMPATIBLE?
	 JRST [	ABTRET (MREQ12)] ;NO, LABEL TYPE MISMATCH

; MAKE SURE THE DRIVE WILL HANDLE THE REQUESTED DENSITY

VRACN3:	LOAD T1,RSBDEN		;ANY DENSITY SPECIFIED?
	JUMPE T1,RSKP		;NO, IT'S OK
	CALL DRVDEN		;WILL THE DRIVE HANDLE IT?
	 JRST [	CALL UNLOAD	;NO, UNLOAD IT
		CALLRET WOWDDR]	;TELL OPERATOR AND POSTPONE REQUEST
	RETSKP			;DRIVE CAN HANDLE THE DENSITY, OK


; VRACCS - CHECK COMPATIBILITY OF SCRATCH REQUEST AND TAPE VOLUME
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: NOT COMPATIBLE
;	  +2: COMPATIBLE

VRACCS:	JE MA%SCR,MTAFLG(MTA),R	;REJECT VOLUME IF NOT A SCRATCH
	LOAD T1,RSBDRV		;GET REQUESTED DRIVE TYPE
	JUMPN T1,[LOAD T2,MTADRV ;GET DRIVE-TYPE OF DRIVE
		CAME T1,T2	;SAME DRIVE TYPE?
		RET		;NO
		JRST .+1]
	LOAD T1,RSBDEN		;GET REQUESTED DENSITY
	JUMPN T1,[CALL DRVDEN	;CAN THE DRIVE OPERATE AT THIS DENSITY?
		 RET		;NO, THIS SCRATCH WON'T WORK
		JRST .+1]
	CALLRET VRWLT		;CHECK IF LABEL TYPES ARE COMPATIBLE


; VRWLT - TAPE VOLUME LABELS WILL BE REWRITTEN - CHECK IF LABEL TYPES
;	  OF REQUEST AND VOLUME ARE COMPATIBLE
;  MTA/ ADDR OF MTA STATUS BLOCK
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: LABELED-UNLABELED OR UNLABELED-LABELED
;	  +2: UNLABELED-UNLABELED OR LABELED-LABELED

VRWLT:	LOAD T1,RSBLT		;GET REQUESTED LABEL TYPE
	JUMPE T1,RSKP		;NOT PARTICULAR, THIS ONE WILL DO
	LOAD T2,MTALT		;GET LABEL TYPE OF TAPE
	MOVE T3,[CAIE T2,.LTUNL] ;ASSUME HE WANTS UNLABELED SCRATCH
	CAIE T1,.LTUNL		;RIGHT?
	HRLI T3,(CAIN T2,)	;NO, WANTS LABELED
	XCT T3			;COMPARE REQUEST AND VOLUME
	 RET			;UNLABELED-LABELED OR LABELED-UNLABELED
	RETSKP			;LABELED-LABELED OR UNLABELED-UNLABELED
SUBTTL SUBROUTINES

; ACTMTA - ACTIVATE AN MTA DEVICE (INITIALIZE STATUS BLOCK, ETC.)
;  MTA/ ADDR OF MTA STATUS BLOCK
;  T1/ MTA STATE CODE
; RETURNS +1: MTA ASSIGNED TO ANOTHER JOB  T1/ OWNING JOB #
;	  +2: SUCCESS, MTA ACTIVATED

ACTMTA:	STKVAR <ACTCOD,<MTOBLK,MOSTAL>>
	MOVEM T1,ACTCOD		;SAVE STATE CODE
	JN MTASTE,,RSKP		;RETURN GOOD IF ALREADY ACTIVATED
; ASSIGN MTA TO MY JOB

	CALL GMTADD		;GET DEVICE DESIGNATOR
	ASND			;TRY TO ASSIGN DEVICE TO MY JOB
	 JRST [	CALL GMTADD	;GET DESIGNATOR
		DVCHR
		HLRZ T1,T3	;GET T1/ OWNER'S JOB#
		RET]

; TRY TO OPEN DRIVE. IF THIS FAILS ANOTHER PROCESS IN THIS JOB IS USING
; THE DRIVE.

	CALL MTAGJF		;GET JFN ON MTA
	MOVX T2,FLD(17,OF%MOD)+FLD(10,OF%BSZ)+OF%OFL+OF%RD
	OPENF			;TRY TO OPEN
	 JRST [	CAIE T1,OPNX9	;SOMEONE ELSE HAS THE DRIVE?
		JRST .+1	;NO IT IS OK
		CALL MTARJF	;YES, DUMP JFN
		SETZM T1	;SET SPECIAL JOB FLAG
		RET ]		;EXIT SADLY
	SETONE MA%OPN,MTAFLG(MTA)	;SET OPEN JFN FLAG
	CALL MTACLS		;CLOSE MTA

; INITIALIZE MTA STATUS BLOCK AND ENABLE FOR STATUS-CHANGE INTERRUPT

	SETZM (MTA)		;ZERO 1ST WORD OF STATUS BLOCK
	MOVS T1,MTA		;BLT SOURCE
	HRRI T1,1(MTA)		;BLT DESTINATION
	BLT T1,MTASZ-1(MTA)	;CLEAR ENTIRE STATUS BLOCK
	MOVE T1,ACTCOD
	STOR T1,MTASTE		;SET STATE
	CALL SCIENA		;RECEIVE STATUS CHANGE INTERRUPTS
	MOVEI T1,MTOBLK		;GET MOSTA ARG BLOCK ADDRESS
	CALL MOSTA		;GET MTA STATUS & CHARACTERISTICS
	MOVE T1,.MODVT+MTOBLK	;Get drive type
	STOR T1,MTADVT		;Save as device type
	MOVE T1,.MODDN+MTOBLK	;GET SUPPORTED DENSITIES
	HLLM T1,MTASDN(MTA)	;STORE SUPPORTED DENSITIES
	LOAD T1,SJ%7TR,.MOTRK+MTOBLK ;GET 7-TRACK FLAG
	MOVE T2,[EXP .TMDR9,.TMDR7](T1) ;GET DRIVE TYPE CODE
	STOR T2,MTADRV		;STORE DRIVE TYPE IN STATUS BLOCK
	TRC T1,1		;GET 0 FOR 7-TRACK, 1 FOR 9-TRACK
	STOR T1,MA%AVS,MTAFLG(MTA) ;STORE AVR-SUPPORTED FLAG
	CALL AVRENA		;ENABLE AVR (IF LEGAL)
	RETSKP
; AREQ - DRIVER FOR ABTREQ MACRO, ABORTS USER REQUEST
; ARET - DRIVER FOR ABTRET MACRO, ABORTS REQUEST AND DOES RET
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; CALL:	ABTREQ (abortcode,flags)
;	 OR
;	ABTRET (abortcode,flags)

AREQ::	SKIPA T2,[AOS (P)]	;GET AREQ INSTRUCTION
ARET::	MOVE T2,[ADJSP P,-1]	;GET ARET INSTRUCTION
	MOVE T1,@(P)		;GET FLAGS AND CODE
	XCT T2			;EXECUTE INSTRUCTION BASED ON ENTRY
	SAVEAC <MT,ACC>
	HRRZ T2,T1		;GET CODE
	TXNE T1,ABT%IN		;INDIRECT?
	MOVE T2,(T2)		;YES, GET CODE FROM LOCATION
	LOAD T3,RSBSTE		;GET CURRENT STATE OF REQUEST
	CAIE T2,ABRTNR		;FORCE STORE IF NO-REPLY ABORT
	CAIGE T3,.ERBAS		;STORE IF REQUEST NOT ABORTED YET
	JRST [	STOR T2,RSBSTE	;STORE CODE INTO RSB STATE FIELD
		LOAD T2,ABT%OP,T1 ;GET OPERATOR-RESPONSE-PRESENT FLAG
		STOR T2,R%ORES,RSBIFL(RSB) ;COPY FLAG TO RSB
		LOAD T1,RSBTYP	;GET REQUEST TYPE
		CAIE T1,.MNTTP	;TAPE-MOUNT?
		JRST .+1	;NO
		JE RSBMT,,.+1	;DON'T UPDATE STATUS IF RSB GOING AWAY
		CALL TCKP	;UPDATE QUASAR QUEUE DISPLAY
		JRST .+1]
	SKIPE T1,RSBWTB+WTBCOD(RSB) ;WTOR MESSAGE OUTSTANDING?
	CALL CANWTR		;YES, CANCEL IT
	LOAD ACC,RSBACC		;CHECK FOR ACCOUNT BLOCK PRESENT.
	SKIPE ACC		;IS THERE AN ACCOUNT BLOCK?
	CALL DELACC		;YES, DELETE IT.
	TXO F,ABORTF		;FORCE PURGE UPON RETURN TO SCHEDULER
	LOAD T1,RSBSTE		;GET REQUEST STATE
	MOVE T2,RSBIFL(RSB)	;GET INTERNAL REQUEST FLAGS
	TXNN T2,R%OPR		;DON'T REPLY TO OPR-ORIGINATED REQUEST
	CAIN T1,ABRTNR		;DON'T REPLY IF NO-REPLY REQUESTED
	RET
	LOAD T1,RSBTYP
	CAIE T1,.MNTTP		;TAPE RSB?
	JRST [	CALLRET TELUSR]	;NO, TELL USER VIA IPCF
	JE RSBMT,,[CALLRET TELUSR] ;TELL USER ON 1ST VOLUME
	CALLRET TELMON		;OTHERWISE TELL MONITOR TO TELL USER
; ASMT - PLACE MT DEVICES IN THE DEVICE ALLOCATOR'S POOL
;	 CALLED DURING INITIALIZATION
; RETURNS +1: ALWAYS

ASMT:	SAVEQ
	SAVEAC <MT,MTA>
	MOVSI Q1,-MAXMT		;RH(Q1)/ MT UNIT NUMBER
	MOVEI MT,MT0		;ADDRESS OF FIRST MT STATUS BLOCK

; LOOP TO PLACE ALL MT DEVICES IN THE DEVICE ALLOCATOR'S POOL

ASMT1:	SETZM (MT)		;CLEAR FIRST WORD OF MT STATUS BLOCK
IFG MTSZ-1,<
	MOVS T1,MT		;BLT SOURCE
	HRRI T1,1(MT)		;BLT DESTINATION
	BLT T1,MTSZ-1(MT)	;CLEAR REMAINDER OF MT STATUS BLOCK
>
	CALL GMTDD		;GET MT DEVICE DESIGNATOR IN T1
	DVCHR			;IS THIS A VALID DESIGNATOR?
	 ERJMP ASMT2		;NO, SKIP NON-DEVICE
	HRRZM Q1,MTN		;SET HIGHEST MT UNIT NUMBER
	MOVE T2,T1		;MOVE DESIGNATOR TO T2 FOR ALLOC
	MOVEI T1,.ALCAL		;GET ALLOC FUNCTION CODE
	MOVNI T3,1		;RELEASE DEVICE TO FREE POOL
	ALLOC			;TRY TO FREE UP THE DEVICE
	 MOVEI T1,.ALCAL	;IGNORE ERROR, RESTORE T1
	MOVNI T3,2		;ASSIGN MT TO ALLOCATOR'S POOL
	ALLOC			;TRY TO ASSIGN TO ALLOCATOR
	 SKIPA			;FAILED
	JRST ASMT2		;ASSIGNED TO ALLOCATOR, GO DO NEXT MT

; CANNOT PUT MT IN ALLOCATOR'S POOL, SO THIS IS PROBABLY A RESTART
; AND THE MT IS STILL IN A USER'S POSSESSION.  THE LOGIC HERE FINDS
; OUT WHAT MTA DEVICE IS ASSOCIATED WITH THE MT, LINKS THEM UP, AND
; BUSYS THEM OUT UNTIL THE USER RELEASES THE MT.

 	MOVEI T1,MTNAV		;CAN'T GET CONTROL OF MT
	STOR T1,MTRSB		;RSB ADDR NON-0 TO PREVENT ALLOCATION
	MOVEI T1,.MTASI		;GET MTU FUNCTION CODE
	HRRZ T2,Q1		;GET MT UNIT #
	MOVEI T3,Q2		;GET ARGUMENT BLOCK ADDRESS (Q2,Q3)
	MOVEI Q2,2		;SET LENGTH IN ARG BLOCK
	MTU%			;ASK MONITOR FOR ASSIGNMENT INFO
	CAIN Q3,.MTNUL		;ANY MTA ASSIGNED TO THIS MT?
	JRST ASMT2		;NO
	MOVE T1,Q3		;GET MTA UNIT #
	HRLI T1,.DVDES+.DVMTA	;MAKE DESIGNATOR
	CALL DDMTA		;GET MTA STATUS BLOCK ADDRESS IN MTA
	 CALL STOP		;BAD MTA UNIT # FROM MONITOR
	MOVEI T1,S.AV		;GET AVAILABLE-TO-USER STATE
	CALL ACTMTA		;ACTIVATE MTA IF POSSIBLE
	 JRST ASMT2		;CAN'T, SO DON'T CROSS-LINK
	STOR MT,MTAMT		;ASSOCIATE MT WITH MTA
	STOR MTA,MTMTA		;...
	SETONE MA%LOD,MTAFLG(MTA) ;SET DRIVE-LOADED FOR KSHS
ASMT2:	ADDI MT,MTSZ		;POINT AT NEXT MT STATUS BLOCK
	AOBJN Q1,ASMT1		;LOOP THRU ALL POSSIBLE MT'S
	AOS MTN			;CONVERT HIGHEST UNIT# TO # OF DEVICES
	RET
; ASMTA - ASSIGN MTA DEVICES TO THIS JOB
;	  CALLED DURING INITIALIZATION
; RETURNS +1: ALWAYS

ASMTA:	SAVEAC <MTA,Q1>
	MOVSI Q1,-MAXMTA	;# OF MTA DEVICES I CAN HANDLE
	MOVEI MTA,MTA0		;ADDRESS OF MTA0: STATUS BLOCK

; LOOP TO CHECK AND POSSIBLY ACTIVATE EVERY MTA DEVICE ON THE SYSTEM

ASMTA1:	SETZRO MTASTE		;SET DRIVE NOT ASSIGNED
	CALL GMTADD		;GET MTA DEVICE DESIGNATOR IN T1
	DVCHR			;IS THIS A VALID DESIGNATOR?
	 ERJMP ASMTA2		;NO, SKIP NON-DEVICE
	HRRZM Q1,MTAN		;STORE HIGHEST MTA UNIT #
	CALL CKMPAV		;IS THIS DRIVE SET AVAILABLE?
	 JRST ASMTA2		;NO, DON'T ASSIGN IT
	MOVEI T1,S.AV		;GET AVAILABLE-TO-USER STATE
	CALL ACTMTA		;ACTIVATE THE MTA
	 JFCL			;DON'T CARE IF I CAN'T ASND
ASMTA2:	ADDI MTA,MTASZ		;POINT AT NEXT MTA STATUS BLOCK
	AOBJN Q1,ASMTA1		;LOOP THROUGH ENTIRE DEVICE TABLE
	AOS MTAN		;CONVERT HIGHEST UNIT# TO # OF DEVICES
	RET
; ASCIZL - COMPUTE THE LENGTH OF AN ASCIZ STRING (NOT COUNTING NULL)
;  T1/ ADDRESS OF STRING
; RETURNS +1: ALWAYS, WITH LENGTH IN BYTES IN T2

ASCIZL:	HRLI T1,(POINT 7)	;CONSTRUCT BYTE POINTER
	SETZ T2,		;CLEAR COUNTER
ASCIL1:	ILDB T3,T1		;LOAD A BYTE
	JUMPE T3,R		;EXIT IF END OF STRING
	AOJA T2,ASCIL1		;OTHERWISE, COUNT IT AND LOOP


; AVRENA - ENABLE AVR FOR DRIVE (IF AVR SUPPORTED FOR THIS DRIVE TYPE)
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

AVRENA:	MOVX T1,MA%AVS
	TDNN T1,MTAFLG(MTA)	;AVR SUPPORTED FOR THIS DRIVE?
	RET			;NO
	MOVX T1,MA%AVE
	IORM T1,MTAFLG(MTA)	;SET AVR-ENABLED
	RET


; BLKFND - SEARCH A GALAXY-STYLE BUILDING BLOCK ARGUMENT LIST FOR
;	   THE LAST OCCURRENCE OF A SPECIFIED ARGUMENT TYPE
;  T1/ ADDRESS OF ARGUMENT COUNT WORD
;  T2/ ADDRESS OF FIRST ARGUMENT BLOCK
;  T3/ TYPE CODE OF DESIRED ARGUMENT
; RETURNS +1: NO ARGUMENTS OF REQUESTED TYPE FOUND
;	  +2: SUCCESS, T1/ ADDRESS OF FIRST WORD OF ARGUMENT
;		       T2/ LENGTH OF ARGUMENT (NOT COUNTING HEADER)

BLKFND:	STKVAR <GETLA>
	SETZM GETLA		;CLEAR ADDRESS OF LAST MATCHING HDR
	SKIPG T1,(T1)		;GET # OF ARGUMENTS
	RET			;NONE ???
BLKFN1:	LOAD T4,AR.TYP,(T2)	;GET ARGUMENT TYPE CODE
	CAMN T3,T4		;DOES IT MATCH THE ONE I WANT?
	MOVEM T2,GETLA		;YES, SAVE ITS ADDRESS
	LOAD T4,AR.LEN,(T2)	;GET LENGTH OF THIS ENTRY
	ADD T2,T4		;COMPUTE ADDRESS OF NEXT ENTRY
	SOJG T1,BLKFN1		;LOOP UNTIL ARG COUNT EXHAUSTED
	SKIPN T1,GETLA		;SCAN COMPLETE, ANY MATCHES?
	RET			;NO
	LOAD T2,AR.LEN,(T1)	;YES, GET SIZE OF ENTRY & HDR
	SOS T2			;SUBTRACT SIZE OF HEADER
	AOJA T1,RSKP		;POINT T1 AT 1ST DATA WORD & RETURN
; CHKAB - CHECK IF MOUNT REQUEST IS ABORTED
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: REQUEST IS ABORTED
;	  +2: REQUEST IS NOT ABORTED

CHKAB:	LOAD T1,RSBSTE		;GET STATE
	CAIL T1,.ERBAS		;ABORTED?
	RET			;YES
	RETSKP			;NO


; CHKID - DETERMINE IF A WORD QUALIFIES AS A LEGAL SIXBIT VOLID/SETNAME
;  T1/ WORD TO BE TESTED
; RETURNS +1: NOT A LEGAL VOLID/SETNAME
;	  +2: LEGAL VOLID SETNAME  T1/ PRESERVED

CHKID:	SKIPN T2,T1		;COPY WORD TO PRESERVE T1
	RET			;ALL BLANKS - ILLEGAL
CHKID1:	SETZ T3,		;CLEAR T3 FOR ROTATING
	ROTC T2,6		;MOVE A CHARACTER FROM T2 INTO T3
	ADJBP T3,[POINT 1,CHKCHR,0] ;GET BYTE POINTER TO BIT
	LDB T3,T3		;IS THIS A LEGAL CHARACTER?
	JUMPE T3,R		;NO, ERROR RETURN
	JUMPN T2,CHKID1		;LOOP IF MORE CHARACTERS LEFT IN T2
	RETSKP			;LOOKS OK TO ME

; TABLE OF LEGAL CHARACTERS FOR VOLIDS AND SETNAMES

CHKCHR:	^B111001111111111111111111111111110111 ;40-103
	^B111111111111111111111110000000000000 ;104-147
; CKBSTR - CHECK GALAXY BUILDING BLOCK STRUCTURE TO VERIFY THAT ALL
;	   BUILDING BLOCKS LIE WITHIN THE STRUCTURE
;  T1/ ENTRY COUNT
;  T2/ ADDRESS OF FIRST ENTRY
;  T3/ SIZE OF STRUCTURE
; RETURNS +1: ERROR WAS DETECTED
;	  +2: NO ERROR DETECTED

CKBSTR:	JUMPL T1,R		;NEGATIVE ENTRY COUNT IS AN ERROR
	JUMPL T3,R		;NEGATIVE STRUCTURE SIZE ALSO AN ERROR
	JUMPE T1,RSKP		;ZERO ENTRY COUNT IS OK
CKBST1:	LOAD T4,AR.LEN,(T2)	;GET SIZE OF THIS ENTRY
	JUMPE T4,R		;ENTRY MUST HAVE A NON-ZERO SIZE
	SUB T3,T4		;SUBTRACT FROM REMAINING STRUCTURE SIZE
	JUMPL T3,R		;ERROR IF BLOCK EXTENDS BEYOND END
	ADD T2,T4		;POINT T2 AT NEXT BLOCK
	SOJG T1,CKBST1		;LOOP THROUGH ALL BLOCKS
	RETSKP			;LOOKS OK TO ME


; CKGHDR - PERFORM BASIC CONSISTENCY CHECK ON INCOMING GALAXY MESSAGE
; CKGHDR also checks whether the message is local or remote.  If remote,
; the remote node name will be stored in RENODE.
;  RBUF, MRPDB/ MESSAGE AND PDB
; RETURNS +1: ERROR IN HEADER
;	  +2: HEADER OK,  T1/ SIZE OF MESSAGE IN WORDS
;			  T2/ MESSAGE TYPE
;		      RENODE/ Remote node name or zero
;			 RSB/ 1, no RSB at this point

CKGHDR:	SETZM RENODE		;[6017]Assume local message
	HLRZ T2,MRPDB+.IPCFP	;GET ACTUAL SIZE OF MESSAGE FROM PDB
	LOAD T1,MS.CNT,RBUF+.MSTYP ;GET SIZE OF MESSAGE FROM GLX HEADER
	CAIL T1,MSHSIZ		;CRASH IF MSG DOESN'T CONTAIN FULL HDR
	CAMGE T2,T1		;IS MSG AS BIG AS ITS HEADER CLAIMS?
	RET			;NO, ERROR IN HEADER
	LOAD T2,MS.TYP,RBUF+.MSTYP ;GET MESSAGE TYPE FOR CALLER
	MOVE T3,RBUF+.MSFLG	;[6010]Get the message flag word
	TXNN T3,MF.NEB		;[6017]From NEBULA
	IFSKP.
	 PUSH P,T1		;[6017]Save T1
	 PUSH P,T2		;[6017]And T2
 	 MOVEI T1,.NDENM	;[6017]Want node name
	 CALL ORNBLF		;[6017]Look for it
	  RET			;[6017]No there
	 MOVE T1,0(T1)		;[6017]Get remote node name from message
	 MOVEM T1,RENODE	;[6017]Save it
	 POP P,T2		;[6017]Restore T2
	 POP P,T1		;[6017]Restore T1
 	ENDIF.
	MOVEI RSB,1		;[6010]NO RSB
	RETSKP
; CKMPAV - TEST IF TAPE DRIVE IS AVAILABLE FOR USE BY SYSTEM
;	   BY CHECKING STATUS BIT IN DEVICE-STATUS FILE ENTRY
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: DRIVE NOT AVAILABLE
;	  +2: DRIVE AVAILABLE

CKMPAV:	CALL GMTADD		;GET T1/ MTA DEVICE DESIGNATOR
	MOVEM T1,DSFE+DSFSPC	;Save it as specification
	MOVEI T2,.DVMTA		;Get the device type
	MOVEM T2,DSFE+DSFTYP	;Save it
	CALL DSFLOC		;Go look for it
	  RETSKP		;Not represented, default to available
	MOVE T1,DSFE+DSFFLG	;Get the flags
	TXNE T1,DSF%AV		;Is it available?
	RET			;No
	RETSKP			;Yes


; CLRTAP - ISSUE MTOPR TO CLEAR ERRORS IN MTA DEVICE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: GDSTS TIMED OUT
;	  +2: SUCCESS, AC'S SET UP:
;		T1/ LAST ERROR CODE ENCOUNTERED BY PROCESS
;		T2/ GDSTS T2
;		T3/ # OF BYTES TRANSFERRED (LH OF GDSTS T3)

CLRTAP:	SAVET			;SET UP RETURN VALUES IN STACK
	CALL GETERR		;GET LAST ERROR CODE
	MOVEM T1,CT1		;GIVE TO CALLER
	LOAD T1,MTAJFN		;GET JFN
	IOXCT GDSTS,R,R		;GET STATUS IN T2,T3
	MOVEM T2,CT2		;GIVE T2 TO CALLER VERBATIM
	HLRZM T3,CT3		;PUT # OF BYTES XFERRED IN CALLER'S T3
	MOVEI T2,.MOCLE		;GET CLEAR-ERRORS FUNCTION
	MTOPR			;CLEAR ANY ERROR FLAGS
	 ERCAL STOP
	RETSKP			;RETURN PULLING T1-T4 FROM STACK


; CTIMER - CANCEL ALL TIMER JSYS REQUESTS FOR THIS FORK
; RETURNS +1: ALWAYS

CTIMER:	MOVE T1,[.FHSLF,,.TIMAL] ;FORK,,FUNCTION
	SETZB T2,T3		;PROPITIATE TIMER JSYS
	TIMER			;CANCEL ALL REQUESTS FOR THIS FORK
	 CALL STOP
	RET
; CVTA6 - CONVERT CONTIGUOUS ASCII CHARACTERS TO SIXBIT
; CVTA6R - SAME AS CVTA6, BUT INTERPRET LOWER CASE LETTERS AS UPPER CASE
;  T1/ BYTE POINTER TO FIRST ASCII CHARACTER
;  T2/ NUMBER OF CHARACTERS TO PROCESS
; RETURNS +1: FIELD WAS NOT A LEGAL VOLID OR SETNAME
;	  +2: FIELD WAS A LEGAL VOLID OR SETNAME,  T1/ SIXBIT RESULT

CVTA6:	TDZA T3,T3		;REMEMBER NO-RAISE ENTRY
CVTA6R:	MOVEI T3,1		;REMEMBER RAISE ENTRY
	STAKT
	SETZ T1,		;CLEAR RESULT REGISTER
	MOVE T4,[POINT 6,T1]	;GET BYTE POINTER FOR BUILDING RESULT
CVTA61:	ILDB T3,CT1		;GET NEXT CHARACTER FROM FIELD
	CAIL T3,"a"
	CAILE T3,"z"		;LOWER CASE?
	JRST CVTA62		;NO
	SKIPE CT3		;RAISING LOWER CASE?
	SUBI T3,40		;YES, DO IT
CVTA62:	SUBI T3,40		;CONVERT TO SIXBIT REPRESENTATION
	TRNE T3,777700		;OUT OF RANGE?
	RET			;YES, RETURN ERROR
	IDPB T3,T4		;PACK IT INTO T1
	SOJG T2,CVTA61		;LOOP THRU ALL CHARS IN FIELD
	CALLRET CHKID		;PASS JUDGMENT UPON CONVERTED VALUE


; DACMTA - UNDO THE EFFECTS OF ACTMTA (I.E. DEACTIVATE MTA DEVICE)
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

DACMTA:	JE MTASTE,,R		;RETURN IF ALREADY DONE
	JN MTAJCT,,R		;CAN'T DO IT IF I'M USING THE DRIVE
	JN MTAMT,,R		;CAN'T DO IT IF A USER HAS THE DRIVE
	CALL SCIDIS		;DON'T TAKE INTERRUPTS FROM THIS MTA
	CALL GMTADD		;GET DEVICE DESIGNATOR
	RELD			;RELEASE CONTROL OF DEVICE
	 CALL STOP
	SETZRO MTASTE		;SET MTA NOT ASSIGNED
	RET
; DDMT - CONVERT MT DEVICE DESIGNATOR TO STATUS BLOCK ADDRESS
;  T1/ DEVICE DESIGNATOR
; RETURNS +1: FAILED, NOT A VALID MT DEVICE DESIGNATOR
;	  +2: SUCCESS, MT/ ADDRESS OF MT STATUS BLOCK

DDMT:	HLRZ T2,T1		;GET LEFT HALF OF DESIGNATOR
	CAIN T2,.DVDES+.DVMTA	;CHECK LEFT HALF
	TRZN T1,400000		;CHECK RIGHT HALF
	RET			;SOMETHING'S ROTTEN
	HRRZ MT,T1		;GET UNIT# PART OF DESIGNATOR
	CAML MT,MTN		;DO I KNOW ABOUT IT?
	RET			;NO, ERROR
	IMULI MT,MTSZ		;COMPUTE ADDRESS
	ADDI MT,MT0		; OF STATUS BLOCK
	RETSKP			;SUCCESS


; DDMTA - CONVERT MTA DEVICE DESIGNATOR TO STATUS BLOCK ADDRESS
;  T1/ DEVICE DESIGNATOR
; RETURNS +1: FAILED, NOT A VALID MTA DEVICE DESIGNATOR
;	  +2: SUCCESS, MTA/ ADDRESS OF MTA STATUS BLOCK

DDMTA:	HLRZ T2,T1		;GET LEFT HALF OF DESIGNATOR
	CAIE T2,.DVDES+.DVMTA	;IS IT AN MTA DEVICE?
	RET			;NO, ERROR
	HRRZ MTA,T1		;GET RIGHT HALF OF DESIGNATOR
	CAML MTA,MTAN		;DO I KNOW ABOUT IT?
	RET			;NO, ERROR
	IMULI MTA,MTASZ		;COMPUTE ADDRESS
	ADDI MTA,MTA0		; OF STATUS BLOCK
	RETSKP			;SUCCESS


; DRVDEN - DETERMINE IF DRIVE CAN OPERATE AT A GIVEN DENSITY
;  T1/ DENSITY CODE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: DRIVE CANNOT OPERATE AT THIS DENSITY
;	  +2: DRIVE CAN OPERATE AT THIS DENSITY

DRVDEN:	MOVNS T1		;NEGATE FOR RIGHT SHIFT
	MOVSI T2,(1B0)
	LSH T2,(T1)		;POSITION BIT FOR INTERROGATION
	TDNN T2,MTASDN(MTA)	;CAN THE DRIVE WORK AT THIS DENSITY?
	RET			;NO
	RETSKP			;YES
; DDCTLD - CHECK FOR REQUEST TO ENABLE OR DISABLE ^D INTERCEPT
; RETURNS +1: ALWAYS

DDCTLD:	SKIPGE T1,CDFLG		;HAS A REQUEST BEEN MADE?
	RET			;NO
	SETOM CDFLG		;YES, CLEAR IT
	JUMPE T1,[MOVEI T1,.TICCD ;REQUEST TO DISABLE ^D
		DTI
		TXZ F,CDENF	;RESET ^D-ENABLED
		RET]
	MOVX T1,<.TICCD,,DDTCN>	;REQUEST TO ENABLE ^D
	ATI
	TXO F,CDENF		;SET ^D-ENABLED
	RET

; DDT INTERRUPT PROCESSOR

DDTIH:	CALL DDTLOD		;TRY TO LOAD DDT
	 SKIPA			;NO CAN DO
	CALL 770000		;CALL DDT - RETURN IS R$G
	MOVEI T1,.FHSUP
	MOVX T2,1B0
	TXNN F,CDENF		;DON'T INTERRUPT IF CALLED BY ^D
	IIC			;TRIGGER CHANNEL-0 INTERRUPT UPSTAIRS
	RET			;EXIT TO SCHED

; DDTLOD - LOADS DDT INTO MY ADDRESS SPACE IF NOT ALREADY THERE
; RETURNS +1: ERROR LOADING DDT
;	  +2: DDT LOADED SUCCESSFULLY

DDTLOD:	MOVE T1,[.FHSLF,,770]
	RPACS			;IS DDT LOADED ALREADY?
	JXN T2,PA%PEX,RSKP	;YES, RETURN +2
	MOVX T1,GJ%OLD+GJ%SHT
	HRROI T2,[ASCIZ/SYS:UDDT.EXE/]
	GTJFN
DDTLDX:	 JRST [	TMSG <% MOUNTR Can't find or get DDT>
		JRST JSERR0]	;TYPE MESSAGE AND RETURN +1
	HRLI T1,.FHSLF
	GET
	 ERJMP DDTLDX
	MOVE T1,.JBSYM		;GET ADDRESS OF SYMBOL TABLE
	HRRZ T2,770001		;GET ADDRESS OF WHERE TO STUFF IT
	MOVEM T1,(T2)		;POINT DDT AT MY SYMBOL TABLE
	RETSKP

; REENTER ADDRESS

DEBUG:	MOVE P,[IOWD PDLEN,PDL]	;NEED STACK POINTER FOR CALL
	CALL DDTLOD		;LOAD DDT
	 HALTF			;CAN'T
	JRST 770000		;GO RIGHT TO DDT


; ELOGOF - INHIBIT ERROR LOGGING FOR MAGTAPE
; ELOGON - RESTORE ERROR LOGGING FOR MAGTAPE
;  MTA/ ADDR OF MTA STATUS BLOCK (MTA MUST BE OPEN)
; RETURNS +1: ALWAYS, REQUESTED FUNCTION PERFORMED

ELOGON:	TDZA T3,T3		;ENABLE ERROR LOGGING
ELOGOF:	MOVEI T3,1		;INHIBIT ERROR LOGGING
	LOAD T1,MTAJFN		;GET JFN
	MOVEI T2,.MOIEL		;FUNCTION = CONTROL ERROR LOGGING
	IOXCT MTOPR,R,R		;SET DESIRED STATE
	RET
; FNOUT - TRANSLATE A NUMBER INTO RIGHT-JUSTIFIED, ZERO-FILLED ASCII
;  T1/ BYTE POINTER TO FIELD
;  T2/ NUMBER
;  T3/ FIELD SIZE ,, RADIX
; RETURNS +1: ALWAYS

FNOUT:	HLRZ T4,T3		;GET FIELD SIZE
	ADJBP T4,T1		;GET POINTER TO BYTE AFTER FIELD
	ILDB T4,T4		;GET BYTE FOLLOWING FIELD
	TXO T3,NO%LFL+NO%ZRO	;TURN ON FLAGS
	NOUT			;OUTPUT NUMBER
	 JFCL
	IDPB T4,T1		;FIX UP STUPID NULL LEFT BY NOUT
	RET


; GALHDR - CONSTRUCT STANDARD GALAXY HEADER IN TBUF
;  T1/ LENGTH OF MESSAGE (WORDS) ,, MESSAGE TYPE CODE
;  T2/ MESSAGE FLAGS ,, SIXBIT SUFFIX
;  T3/ ACKNOWLEDGMENT CODE
; RETURNS +1: ALWAYS, WITH GALAXY HEADER BUILT IN BEGINNING OF TBUF
; NOTE: THIS IS THE ONLY PLACE WHERE THE GALAXY HEADER IS BUILT
;	IN THE ENTIRE MODULE

GALHDR:	MOVEM T1,TBUF+.MSTYP
	MOVEM T2,TBUF+.MSFLG
	MOVEM T3,TBUF+.MSCOD
	RET


; GETDEN - Get system default magtape density
; Returns +1: Always, with density in DEFDEN

GETDEN:	SETO T1,		;Use value for current job
	HRROI T2,DEFDEN		;Get just one word
	MOVEI T3,.JIDEN		;System/job default density
	GETJI
	 ERJMP [ MOVEI T1,.SJD16 ;Failed use 1600 BPI
	 	 MOVEM T1,DEFDEN ;as default density
		 JRST .+1]
	RET

; GETERR - RETURN THE MOST RECENT ERROR CODE FOR THIS FORK
; RETURNS +1: ALWAYS, WITH ERROR CODE IN T1

GETERR:	MOVEI T1,.FHSLF
	GETER			;GET MOST RECENT ERROR IN RH OF T2
	 ERJMP .+1
	HRRZ T1,T2		;MOVE TO T1 STRIPPING LEFT HALF
	RET
; GETVU - TRANSFER USER NAME FROM VOL2 LABEL TO CALLER'S STRING AND
;	  RETURN USER NUMBER CORRESPONDING TO THE USER NAME
;  T1/ ADDRESS OF 8-WORD AREA TO RECEIVE ASCIZ USER NAME
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: T1/ BYTE POINTER TO CALLER'S ASCIZ USER NAME STRING
;	      T2/ USER # CORRESPONDING TO NAME OR 0 IF THE USER DOESN'T
;		  EXIST ON THE SYSTEM

GETVU:	HRLI T1,(POINT 7)	;CREATE BYTE POINTER TO CALLER'S AREA
	SAVET			;RETURN IT TO CALLER IN T1
	MOVEI T2,V2OWN-1
	ADJBP T2,[POINT 8,MTAV2(MTA)] ;GET BYTE PTR TO VOL2 USER NAME
	MOVEI T3,V2OWNL		;GET MAX LENGTH OF USER NAME
GETVU1:	ILDB T4,T2		;GET CHARACTER FROM VOL2
	TRZ T4,200		;MASK OFF TRASH
	CAIN T4," "		;END OF NAME?
GETVU2:	SETZ T4,		;YES, TIE IT OFF WITH A NULL
	IDPB T4,T1		;COPY CHARACTER TO CALLER'S AREA
	JUMPN T4,[SOJG T3,GETVU1 ;LOOP IF MORE LEFT IN VOL2 LABEL
		JRST GETVU2]	;OTHERWISE WRAP UP

; NOW TRY TO IDENTIFY THE USER WITH RCUSR

	SETZM CT2		;RETURN 0 IN T2 IF RCUSR FAILS
	MOVX T1,RC%EMO		;REQUEST EXACT MATCH
	MOVE T2,CT1		;GET POINTER TO CALLER'S STRING
	RCUSR			;TRY TO RECOGNIZE USER NAME
	 ERJMP R		;FAILED
	TXNN T1,RC%NOM		;GOT A MATCH?
	MOVEM T3,CT2		;YES, RETURN USER # IN T2
	RET
; GMTADD - GET MTA DEVICE DESIGNATOR
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS, WITH DEVICE DESIGNATOR IN T1

GMTADD:	MOVE T1,MTA		;COPY STATUS BLK ADDR
	SUBI T1,MTA0		;COMPUTE OFFSET FROM START OF BLOCKS
	IDIVI T1,MTASZ		;COMPUTE MTA UNIT #
	HRLI T1,.DVDES+.DVMTA	;ADD LEFT HALF OF DEVICE DESIGNATOR
	RET


; GMTADS - ISSUE MTOPR AND RETURN MTA DEVICE STATUS
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS, T1/ .MOSTA STATUS WORD .MOCST

GMTADS:	STKVAR <<MTOBLK,MOSTAL>>
	MOVEI T1,MTOBLK		;GET ARG BLOCK ADDRESS
	CALL MOSTA		;GET STATUS & CHARACTERISTICS
	MOVE T1,.MOCST+MTOBLK	;GET STATUS INFO FOR CALLER
	TXNE T1,SJ%OFS		;OFFLINE?
	TXZ T1,SJ%REW		;YES, CAN'T BE REWINDING THEN
	RET


; GMTDD - GET MT DEVICE DESIGNATOR
;  MT/ ADDR OF MT STATUS BLOCK
; RETURNS +1: ALWAYS, WITH DEVICE DESIGNATOR IN T1

GMTDD:	MOVE T1,MT		;COPY STATUS BLK ADDR
	SUBI T1,MT0		;COMPUTE OFFSET FROM START OF BLOCKS
	IDIVI T1,MTSZ		;COMPUTE MT UNIT #
	TDO T1,[.DVDES+.DVMTA,,400000] ;ADD THE FRILLS
	RET
; GTINAM - GET INSTALLATION NAME FROM FILE
; RETURNS +1: ALWAYS, ASCIZ INSTALLATION NAME IN TAPNAM

GTINAM:	MOVX T1,GJ%SHT+GJ%ACC+GJ%OLD
	HRROI T2,[ASCIZ/SYSTEM:TAPNAM.TXT/]
	GTJFN			;GET JFN ON FILE
	 RET			;NO JFN, NO ARBEIT
	MOVE T4,T1		;SAVE JFN
	MOVX T2,FLD(7,OF%BSZ)+OF%RD
	OPENF			;OPEN FILE FOR READ ACCESS
	 JRST [	MOVE T1,T4	;OPEN FAILED, GET JFN
		RLJFN		;DUMP IT
		 JFCL
		RET]
	HRROI T2,TAPNAM		;GET ADDRESS OF TEXT IN CORE
	MOVNI T3,TPNMSZ		;GET MAX # OF BYTES TO READ
	SIN			;READ 'EM IN
	 ERJMP .+1		;IGNORE ERRORS
	CLOSF			;CLOSE FILE, DUMP JFN
	 JFCL
	MOVE T1,[POINT 7,TAPNAM] ;GET POINTER TO TEXT
GTINM1:	ILDB T2,T1		;GET A BYTE
	JUMPE T2,R		;EXIT IF END OF STRING
	CAIE T2,.CHCRT		;CARRIAGE-RETURN?
	JRST GTINM1		;NO, CONTINUE SCAN
	SETZ T2,		;YES
	DPB T2,T1		;DELETE C/R AND EVERYTHING AFTER IT
	RET


; INAP - PERFORM INITIALIZATION RELATED TO ASSOCIATED PROCESSES
; RETURNS +1: ALWAYS

INAP:	SAVEQ
	MOVEI Q1,APNUM		;GET # OF A/P'S
INAP1:	SOJL Q1,R		;EXIT IF NONE LEFT
	CALL @APINI(Q1)		;CALL A/P INIT ROUTINE
	JRST INAP1		;LOOP THRU ALL A/P TABLE ENTRIES

; INT26 - CONVERT INTEGER TO SIXBIT, RIGHT-JUSTIFIED ZERO-FILLED
;  T1/ INTEGER
; RETURNS +1: ALWAYS, T1/ SIXBIT RESULT

INT26:	MOVM T2,T1		;GET ABSOLUTE VALUE
	IDIV T2,[^D1000000]	;GET NUMBER MOD 1000000 IN T3
	MOVE T1,[EXP 0]		;INIT RESULT
	MOVE T2,[POINT 6,T1,35]	;GET POINTER TO RESULT
INT261:	IDIVI T3,12		;PEEL OFF A DIGIT
	ADDI T4,20		;CONVERT INTEGER TO SIXBIT
	DPB T4,T2		;STORE INTO T1
	ADD T2,[6B5]		;BACK UP BYTE POINTER
	JUMPN T3,INT261		;LOOP IF MORE TO DO
	RET
;INT26L - CONVERT INTEGER TO SIXBIT, LEFT-JUSTIFIED ZERO-FILLED
;T1/ INTEGER
;RETURNS +1: ALWAYS, T1/SIXBIT RESULT

INT26L:	MOVM T2,T1		;Get absolute value
	IDIV T2,[^D1000000]	;Get number MOD 1000000 in T3
	MOVE T2,[POINT 6,T1]	;Set up a pointer
	SETZ T1,		;Initialize the sixbit value
I26LOP: IDIVI T3,^D10		;Convert the number
	PUSH P,T4		;Save the digit
	SKIPE T3		;Check if completed
	CALL I26LOP		;Standard recursive algorithm
	POP P,T4		;Restore the digit
	ADDI T4,20		;Convert to sixbit
	IDPB T4,T2		;Store the digit
	RET 			;And return
; IOXCTR - DRIVER FOR IOXCT MACRO; EXECUTES AND TIMES OUT A JSYS
;  T1-T4/ ARGUMENTS FOR JSYS
; CALL:	IOXCT <JSYS,ERJMP ADDRESS,TIMEOUT ADDRESS>
; RETURNS TO ERJMP ADDRESS IF JSYS ERJMP'ED
;	  TO TIMEOUT ADDRESS IF JSYS TIMED OUT
;	  TO INSTRUCTION AFTER IOXCT MACRO IF JSYS SUCCEEDED
;	ALL RETURNS: T1-T4 CONTAINING VALUES RETURNED BY JSYS

; CAUTION - IN ORDER TO PICK UP THE ARGUMENTS THAT FOLLOW THE CALL,
;	    THIS ROUTINE DOES SOME SHADY THINGS WITH THE STACK

IOXCTR:: CALL [	SAVET		;PRESERVE AC'S FOR JSYS
		MOVE T1,[14,,.SYSTA]
		GETAB		;GET CURRENT LOAD AVERAGE
		 CALL STOP	;SHOULD NEVER FAIL
		FIXR T2,T1	;CONVERT TO AN INTEGER
		IMULI T2,3	;TIMES 3
		CAIGE T2,^D180	;[334]Wait at least 3 minutes
		MOVEI T2,^D180	;[334]
		MOVE T1,[.FHSLF,,.TIMEL] ;FORK,,FUNCTION
		IMULI T2,^D1000	;CONVERT SECONDS TO MILLISECONDS
		MOVEI T3,JTOCN	;GET INTERRUPT CHANNEL #
		TIMER		;SET UP FOR INTERRUPT
		 JFCL
		RET]
	TXO F,JTOAF		;SET JSYS-TIMEOUT-ARMED
	XCT @(P)		;EXECUTE JSYS
	 ERJMP [TXZ F,JTOAF	;DISARM TIMER
		CALL [	SAVET
			CALLRET CTIMER] ;CANCEL TIMER
		POP P,CX	;GET ADDRESS OF CALL+1
		HLRZ CX,1(CX)	;GET ERJMP ADDRESS
		JRST (CX)]	;RETURN TO ERJMP ADDRESS
	TXZ F,JTOAF		;DISARM TIMER
	CALL [	SAVET
		CALLRET CTIMER]	;CANCEL TIMER
	AOS (P)			;RETURN TO
	RETSKP			; CALL+3

; INTERRUPT HANDLER FOR TIMER JSYS INTERRUPT

JTOIH:	TXZN F,JTOAF		;TIMER STILL ARMED?
	DEBRK			;NO, DON'T DO ANYTHING
	MOVEM T1,@LEVTAB+PRIEXT-1 ;SAVE T1
	MOVE T1,[PC%USR+IOXCT1]	;GET NEW PC
	EXCH T1,@LEVTAB+PRIEXT-1 ;RESTORE T1, SET NEW PC
	DEBRK			;DEBREAK TO IOXCT1

IOXCT1:	POP P,CX		;TIMEOUT OCCURRED, GET ADDR OF CALL+1
	HRRZ CX,1(CX)		;GET TIMEOUT-HANDLER ADDRESS
	JRST (CX)		;EXIT TO CALLER'S TIMEOUT HANDLER
; LDATIN - PARSE AND RETURN DATE FROM TAPE LABEL (IN FORM " YYDDD")
;  T1/ ILDB POINTER TO FIRST CHARACTER OF DATE FIELD
; RETURNS +1: DATE CONTAINED NON-NUMERIC CHARACTERS OR WAS ILLEGAL
;	  +2: DATE PARSED SUCCESSFULLY,
;		T1/ YEAR,,JULIANDAY   OR   0 (IF DATE WAS " 00000")

LDATIN:	SAVEQ
	IBP T1			;SKIP OVER THE SPACE
	MOVE Q1,T1		;MOVE POINTER TO ANOTHER PLACE
	SETO Q2,		;SET FOR 1ST PASS
LDAT1:	MOVEI T4,3(Q2)		;COMPUTE # OF DIGITS TO SCAN
	SETZ T2,		;CLEAR ACCUMULATOR
LDAT2:	ILDB T3,Q1		;GET NEXT CHARACTER
	CAIL T3,"0"		;ERROR IF .LT. 0
	CAILE T3,"9"		; OR .GT. 9
	RET
	IMULI T2,^D10		;SHIFT CONTENTS OF ACCUMULATOR
	ADDI T2,-"0"(T3)	;ADD IN NEW DIGIT
	SOJG T4,LDAT2		;LOOP
	AOJE Q2,[MOVS T1,T2	;DOING YEAR, GET T1/ YEAR-1900,,0
		JRST LDAT1]	;NOW GO BACK AND DO THE DAY
	JUMPE T2,[JUMPE T1,RSKP	;IF YEAR=DAY=0, RETURN GOOD WITH T1/ 0
		RET]		;IF DAY=0 BUT YEAR.NE.0, ERROR
	CAILE T2,^D366		;IS DAY TOO LARGE?
	RET			;YES, ERROR
	HRR T1,T2		;GET YEAR-1900,,JULIANDAY
	ADD T1,[^D1900,,0]	;ADD IN THE 1900
	RETSKP
; MOSTA - ISSUE .MOSTA MTOPR TO GET TAPE DRIVE CHARACTERISTICS AND STATUS
;	  NOTE - THIS MTOPR FUNCTION MUST BE GUARANTEED NOT TO BLOCK
;  T1/ ADDRESS OF BLOCK TO RECEIVE INFORMATION (MOSTAL WORDS LONG)
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS, WITH INFORMATION IN ARGUMENT BLOCK

MOSTA:	STAKT
	CALL MTAGJF		;GET JFN FOR MTOPR IN T1
	MOVEI T2,.MOSTA		;MTOPR FUNCTION CODE
	MOVE T3,CT1		;GET ADDR OF ARGUMENT BLOCK
	MOVEI T4,MOSTAL
	MOVEM T4,(T3)		;PUT LENGTH IN FIRST WORD OF BLOCK
	MTOPR			;GET STATUS INFO INTO ARG BLOCK
	CALLRET MTARJF		;RELEASE JFN AND RETURN


; MOVSTR - MOVE ASCIZ STRING (TRAILING NULL IS NOT MOVED)
;  T1/ SOURCE STRING POINTER
;  T2/ DESTINATION STRING POINTER
;  STRING POINTERS MAY BE OF THE FORM:  -1,,ADDRESS
; RETURNS +1: ALWAYS

MOVSTR:	TLC T1,-1
	TLCN T1,-1
	HRLI T1,(POINT 7)
	TLC T2,-1
	TLCN T2,-1
	HRLI T2,(POINT 7)
MOVST1:	ILDB T3,T1
	JUMPE T3,R
	IDPB T3,T2
	JRST MOVST1
; MTAGJF - GET A JFN ON MTA DEVICE
;  MTA/ MTA STATUS BLOCK
; RETURNS +1: ALWAYS, WITH JFN IN MTAJFN AND T1

MTAGJF:	JN MTAJCT,,MTAGJ1	;JFN EXISTS ALREADY, USE IT
	STKVAR <<GJFTXT,2>>
	CALL GMTADD		;GET DEVICE DESIGNATOR IN T1
	MOVE T2,T1		;MOVE TO T2 FOR DEVST
	HRROI T1,GJFTXT		;GET ADDRESS OF TEXT BUFFER
	DEVST			;BEGIN JFN STRING WITH "MTAn"
	 CALL STOP
	MOVEI T2,":"
	IDPB T2,T1		;TACK ON A COLON
	SETZ T2,
	IDPB T2,T1		;TERMINATE WITH A NULL
	MOVX T1,GJ%SHT+GJ%ACC	;GTJFN FLAGS
	HRROI T2,GJFTXT		;POINTER TO STRING
	GTJFN			;GET JFN ON MTA DEVICE
	 CALL STOP
	STOR T1,MTAJFN		;STORE JFN IN TABLE
MTAGJ1:	INCR MTAJCT		;INCREMENT JFN-IN-USE COUNT
	LOAD T1,MTAJFN		;GET JFN FOR CALLER
	RET


; MTARJF - RELEASE MTA JFN OBTAINED WITH MTAGJF
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

MTARJF:	LOAD T1,MTAJCT		;GET JFN-IN-USE COUNT
	SOSGE T1		;GOING NEGATIVE?
	CALL STOP		;YES, PROGRAM LOGIC ERROR
	STOR T1,MTAJCT		;STORE NEW COUNT
	JUMPG T1,R		;EXIT IF JFN STILL IN USE
	LOAD T1,MTAJFN		;GET JFN
	RLJFN			;DISCARD IT
	 CALL STOP
	SETZRO MTAJFN		;CLEAR JFN JUST TO PLAY IT SAFE
	RET
; MTAOPI - GET A JFN OPEN FOR READ ON AN MTA DEVICE
; MTAOPO - GET A JFN OPEN FOR WRITE ON AN MTA DEVICE
;  MTA/ ADDR OF MTA STATUS BLOCK (DENSITY SET FROM MTADEN)
; RETURNS +1: FAILED, DRIVE OFFLINE OR WRITE-LOCKED
;	  +2: SUCCESS, JFN IN MTAJFN AND T1

MTAOPI:	SKIPA T1,[OF%RD]	;OPEN FOR READ ACCESS
MTAOPO:	MOVX T1,OF%WR		;OPEN FOR WRITE ACCESS
	SAVEQ
	MOVE Q1,T1		;SAVE MODE
	MOVE T1,MTAFLG(MTA)	;GET MTA FLAGS
	TXNE T1,MA%OPN		;JFN OPEN ALREADY?
	CALL STOP		;YES, PROGRAM FAILURE
	CALL MTAGJF		;GET JFN ON MTA
	MOVX T2,FLD(17,OF%MOD)+FLD(10,OF%BSZ)
	TDO T2,Q1		;SET MODE BIT
	OPENF			;OPEN THE JFN
	 JRST [	CAIN T1,OPNX8	;DEVICE OFFLINE?
		JRST [	SETZRO MA%LOD,MTAFLG(MTA) ;YES, UPDATE STATUS
			CALLRET MTARJF] ;DUMP JFN AND TAKE +1
		CAIE T1,OPNX25	;DEVICE WRITE PROTECTED?
		CALL STOP	;NO, CAN'T HACK THIS ONE
		CALLRET MTARJF]	;YES, DUMP JFN AND TAKE +1
	SETONE MA%OPN,MTAFLG(MTA) ;SET JFN-OPEN FLAG
	MOVEI T2,.MOSDM
	MOVEI T3,.SJDM8		;SPECIFY INDUSTRY-COMPATIBLE MODE
	MTOPR			;SET DATA MODE OF DRIVE
	SKIPE UNLD		;Skip if the tape is not being unloaded
	JRST [ SETZM UNLD		;Reset tape unloading flag
	       RETSKP ]			;Return +2, T1/ JFN
	MOVEI T2,.MOSDN
	LOAD T3,MTADEN		;GET DESIRED DENSITY CODE
	MTOPR			;SET DENSITY
	RETSKP			;RETURN +2, T1/ JFN


; MTACLS - CLOSE MTA JFN
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

MTACLS:	MOVX T1,MA%OPN
	TDNN T1,MTAFLG(MTA)	;IS THE JFN OPEN?
	CALL STOP		;NO, PROGRAM FAILURE
	ANDCAM T1,MTAFLG(MTA)	;IT'LL BE CLOSED WHEN I GET DONE
	LOAD T1,MTAJFN		;GET MTA JFN
	LOAD T2,MTAJCT		;GET JFN-IN-USE COUNT
	SOSGE T2		;GOING NEGATIVE?
	CALL STOP		;YES, PROGRAM LOGIC ERROR
	STOR T2,MTAJCT		;STORE NEW COUNT
	SKIPE T2		;DOES SOMEONE ELSE NEED THE JFN?
	TXO T1,CO%NRJ		;YES, DON'T DUMP JFN, JUST CLOSE IT
	TXO T1,CZ%ABT		;CLOSE WITHOUT BLOCKING
	CLOSF			;CLOSE (AND POSSIBLY DISCARD) JFN
	 CALL STOP
	JUMPN T2,R		;EXIT IF JFN STILL IN USE
	SETZRO MTAJFN		;CLEAR JFN JUST TO PLAY IT SAFE
	RET
; NMTRSB - GET ADDRESS OF NEXT MAGTAPE MOUNT RSB
; NSTRSB - GET ADDRESS OF NEXT STRUCTURE MOUNT OR DISMOUNT RSB
; NXXRSB - GET ADDRESS OF NEXT ACTIVE RSB
;  QSB/ ADDR OF QUEUE SCAN BLOCK FOR ARBQDB
; RETURNS +1: NO RSB'S LEFT
;	  +2: SUCCESS, RSB/ ADDR OF REQUEST STATUS BLOCK

NMTRSB:	SAVEQ
	JSP Q1,NRSB1		;SETUP COROUTINE ADDRESS IN Q1
	CAIE T1,.MNTTP		;COROUTINE FOR TAPE MOUNT
	JRST NRSB1
	RETSKP

NSTRSB:	SAVEQ
	JSP Q1,NRSB1		;SETUP COROUTINE ADDRESS IN Q1
	CAIE T1,.MNTST		;COROUTINE FOR STRUCTURE MNT/DSMNT
	CAIN T1,.DSMST
	RETSKP
	JRST NRSB1

NXXRSB:	SAVEQ
	JSP Q1,NRSB1		;SETUP COROUTINE ADDRESS IN Q1
	RETSKP			;COROUTINE TO SUCCEED FOR ANY RSB

; CHECK NEXT RSB TO SEE IF IT QUALIFIES

NRSB1:	CALL QMSCAN		;GET ADDRESS OF RSB LINKAGE IN T2
	 RET			;END OF RSB LIST
	MOVEI RSB,-RSBLNK(T2)	;LOAD RSB AC
	CALL CHKAB		;REQUEST ABORTED?
	 JRST NRSB1		;YES, SKIP IT
	LOAD T1,RSBTYP		;LIVE RSB, GET TYPE FOR COROUTINE
	JRST (Q1)		;DISPATCH TO COROUTINE
; PB ROUTINES - CONSTRUCT GALAXY-STYLE BUILDING-BLOCK LIST IN TBUF

; PBINIT - SET UP DATABASE FOR CALLS TO OTHER PB ROUTINES
; RETURNS +1: ALWAYS

PBINIT:	SAVET			;[6010]Save T ACs
	XMOVEI T1,TBUF+.OARGC	;GET ADDRESS OF ARGUMENT COUNT WORD
	MOVEI T2,TBUF+.OHDRS	;GET ADDRESS OF FIRST BUILDING BLOCK
	MOVEM T1,PBACW		;SAVE ADDR OF ARGUMENT COUNT WORD
	SETZM (T1)		;ZERO THE ARGUMENT COUNT
	MOVEM T2,PBBPT		;SAVE ADDR OF 1ST BUILDING BLOCK
	RET


; PBBLK - ADD PREFORMATTED BUILDING BLOCK TO LIST
;  T1/ ADDRESS OF BUILDING BLOCK WITH HEADER
; RETURNS +1: ALWAYS

PBBLK:	SAVET			;[6010]Save T ACs
	LOAD T2,AR.LEN,(T1)	;GET LENGTH OF BLOCK
	MOVE T3,T2		;Get length in words
	IMULI T3,5		;Turn it to bytes
	EXCH T3,PBLFT		;flop them for sub
	SUBB T3,PBLFT		;number of bytes left in tbuf

	MOVSS T1		;BLT SOURCE
	HRR T1,PBBPT		;BLT DESTINATION
	ADDB T2,PBBPT		;COMPUTE ADDR OF NEXT BLOCK
	BLT T1,-1(T2)		;MOVE BLOCK INTO LIST
	AOS @PBACW		;BUMP ARG COUNT
	RET


; PBTXT - CONSTRUCT ASCIZ TEXT BUILDING BLOCK
;  T1/ ADDRESS OF ASCIZ TEXT
;  T2/ ARGUMENT TYPE CODE
; RETURNS +1: ALWAYS

PBTXT: 	MOVE T4,PBBPT		;GET ADDR OF BLOCK HEADER
	STOR T2,AR.TYP,(T4)	;STORE TYPE CODE IN HEADER
	HRLI T1,(POINT 7)	;Get default byte pointer to source
	CAIN T2,.WTTYP		;[6010]Is it the header?
	JRST PBTXT0		;[6010]Yes, use what is in T1
	SKIPLE MORTXT		;Is this a continuation
	MOVE T1,MORTXT		;Yes, restore byte pointer
	SETZM MORTXT		;Clear text continuation byte pointer
PBTXT0:	MOVEI T2,1(T4)		;[6010]COMPUTE ADDRESS OF TEXT IN BLOCK
	HRLI T2,(POINT 7)	;GET BYTE POINTER TO DESTINATION
PBTXT1:	ILDB T3,T1		;GET BYTE
	IDPB T3,T2		;TRANSFER IT
	JUMPE T3,PBTXT7		;End of this message
	SOSLE PBLFT		;Can orion handle more text
	JRST PBTXT1		;Yes, pick up next character
	MOVEI T3,BYTEND		;Pick up number of bytes left in the buffer
	MOVEM T3,PBLFT		;Store in byte count left
PBTXT2:	ILDB T3,T1		;Pick up the next character
	IDPB T3,T2		;Place into the buffer
	JUMPE T3,PBTXT7		;End of the ASCIZ string
	SOSG PBLFT		;Update the number of bytes left in the buffer
	JRST PBTXT6		;This should never happen, no more space
	CAIN T3,.CHCRT		;Is this a carriage return?
	JRST PBTXT3		;Yes, go do end of message processing
	CAIE T3,.CHLFD		;No, is this a line feed?
	JRST PBTXT2		;No, pick up the next character

;A carriage return or line feed has been found. Pick up any more if room

PBTXT3:	MOVE T4,T1		;Save the pointer 
PBTXT4:	ILDB T3,T1		;Pick up the next character
	SKIPN T3		;End of the ASCIZ string?
	JRST [  IDPB T3,T2	;Yes, place the null in the buffer
		MOVE T4,PBBPT	;Restore block pointer address
		JRST PBTXT7]	;Finish processing this packet
	CAIN T3,.CHCRT		;Carriage return?
	JRST PBTXT5		;Yes, include it in this packet
	CAIN T3,.CHLFD		;No, is it a line feed?
	JRST PBTXT5		;Yes, include it in this packet
	MOVE T1,T4		;No,restore the pointer to TMCMSG
	JRST PBTXT6		;Finish processing this packet
PBTXT5: IDPB T3,T2		;Include the CR or LF in this packet
	SOSLE PBLFT		;Update the amount of space left
	JRST PBTXT4		;Go pick up the next character
PBTXT6:	MOVX T4,WT.MOR		;More message for next time 
	IORM T4,BTFLGS	        ;Save it
	MOVE T4,PBBPT		;Addr of block header
	SKIPE T3		;Was last byte a nul
	MOVEM T1,MORTXT		;No, save byte pointer of next text
PBTXT7: MOVEI T2,1(T2)		;GET ADDR OF WORD AFTER LAST TEXT WORD
	MOVEM T2,PBBPT		;UPDATE BLOCK POINTER
	SUB T2,T4		;COMPUTE LENGTH OF BLOCK
	STOR T2,AR.LEN,(T4)	;PUT LENGTH IN HEADER
	AOS @PBACW		;BUMP ARG COUNT
	RET
; PROTIN - CONVERT 6-DIGIT ASCII PROTECTION CODE TO FIXED-POINT INTEGER
;  T1/ BYTE POINTER TO PROTECTION CODE
; RETURNS +1: CODE CONTAINED AT LEAST 1 NON-OCTAL DIGIT
;	  +2: SUCCESS, T1/ CODE

PROTIN:	MOVE T4,T1		;COPY POINTER TO T4
	SETZ T1,		;INIT VALUE AC
	MOVEI T2,6
PROT1:	ILDB T3,T4		;GET ASCII CHAR
	SUBI T3,"0"
	TRNE T3,777770		;LEGAL OCTAL DIGIT?
	RET			;NO
	LSH T1,3		;YES, SHIFT TO MAKE ROOM
	ADD T1,T3		;ADD IN THIS DIGIT
	SOJG T2,PROT1		;LOOP
	RETSKP
; QUEUE-MANAGING ROUTINES
;	ADD AND REMOVE PACKETS FROM QUEUES; QUEUES ARE DEFINED BY A
;	1-WORD QUEUE DESCRIPTOR WITH ADDRESS OF HEAD PACKET IN LEFT
;	HALF AND ADDRESS OF TAIL IN RIGHT. IF ZERO, QUEUE IS EMPTY.


; QMDQH - DEQUEUE THE HEAD PACKET OF A QUEUE
;  T1/ ADDRESS OF QUEUE DESCRIPTOR BLOCK
; RETURNS +1: QUEUE WAS EMPTY
;	  +2: SUCCESS, T2/ ADDRESS OF DEQUEUED HEAD PACKET

QMDQH:	HLRZ T2,(T1)		;GET ADDRESS OF HEAD PACKET
	JUMPE T2,R		;IF EMPTY, QUIT NOW
	SKIPN T3,(T2)		;QUEUE GOING TO BE EMPTY?
	SETZM (T1)		;YES, CLEAR DESCRIPTOR BLOCK
	HRLM T3,(T1)		;SET NEW HEAD POINTER IN QDB
	RETSKP


; QMQH - ADD A PACKET TO THE HEAD OF A QUEUE
;  T1/ ADDRESS OF QUEUE DESCRIPTOR BLOCK
;  T2/ ADDRESS OF PACKET TO BE ADDED TO HEAD OF QUEUE
; RETURNS +1: ALWAYS

QMQH:	HLRZ T3,(T1)		;GET ADDRESS OF CURRENT HEAD
	HRLM T2,(T1)		;SET ADDRESS OF NEW HEAD IN QDB
	JUMPE T3,[HRRM T2,(T1)	;QUEUE WAS EMPTY, SET NEW TAIL
		SETZM (T2)	;CLEAR LINKAGE IN ONLY ENTRY
		RET]
	MOVEM T3,(T2)		;POINT NEW HEAD AT OLD HEAD
	RET


; QMQT - ADD A PACKET TO THE TAIL OF A QUEUE
;  T1/ ADDRESS OF QUEUE DESCRIPTOR BLOCK
;  T2/ ADDRESS OF PACKET TO BE ADDED TO TAIL OF QUEUE
; RETURNS +1: ALWAYS

QMQT:	SETZM (T2)		;CLEAR LINKAGE IN NEW TAIL
	HRRZ T3,(T1)		;GET CURRENT TAIL ADDRESS
	HRRM T2,(T1)		;SET NEW TAIL
	JUMPE T3,[HRLM T2,(T1)	;QUEUE WAS EMPTY, SET NEW HEAD
		RET]
	MOVEM T2,(T3)		;POINT OLD TAIL AT NEW TAIL
	RET
; ROUTINES ON THIS PAGE ARE USED FOR SCANNING A QUEUE, POSSIBLY
; WITH THE INTENT OF DEQUEUEING ONE OF ITS ENTRIES.

; QUEUE-SCAN-BLOCK (QSB) OFFSETS:

QSB.QB==0		;OFFSET TO QUEUE DESCRIPTOR BLOCK
QSB.LE==1		;OFFSET TO LAST ENTRY SCANNED
QSB.LP==2		;OFFSET TO ENTRY BEFORE LAST ENTRY


; QSCNIR - DRIVER FOR QSCANI MACRO
; CALL:	QSCANI qdb-address

QSCNIR::PUSH P,QSB		;SAVE QSB AC
	MOVEI QSB,1(P)		;GET ADDRESS OF QSB IN STACK
	PUSH P,(CX)		;QSB.QB - QDB ADDRESS
	PUSH P,[0]		;QSB.LE - ADDRESS OF LAST ENTRY SCANNED
	PUSH P,[0]		;QSB.LP - ADDRESS OF ENTRY BEFORE THAT
	CALL 1(CX)		;BACK TO CALLER FOR A WHILE
	 TRNA			;NON-SKIP RETURN
	AOS -4(P)		;SKIP RETURN
	ADJSP P,-3		;DELETE QSB FROM STACK
	POP P,QSB		;RESTORE QSB AC
	RET			;TAKE +1 OR +2


; QMSCAN - RETURN ADDRESS OF NEXT ENTRY IN QUEUE
;  QSB/ ADDRESS OF QUEUE SCAN BLOCK
; RETURNS +1: NO ENTRIES REMAINING IN QUEUE
;	  +2: SUCCESS, T2/ ADDRESS OF NEXT ENTRY IN QUEUE

QMSCAN:	SKIPN T2,QSB.LE(QSB)	;FIRST CALL FOR THIS QUEUE SCAN?
	JRST [	SETZM QSB.LP(QSB) ;YES, CLEAR OLD-LAST ADDRESS
		HLRZ T2,@QSB.QB(QSB) ;GET ADDRESS OF HEAD PACKET
		JRST QMS1]
	MOVEM T2,QSB.LP(QSB)	;NOT FIRST TIME, SET OLD-LAST
	MOVE T2,(T2)		;GET ADDRESS OF NEXT PACKET
QMS1:	MOVEM T2,QSB.LE(QSB)	;SET NEW-LAST
	JUMPN T2,RSKP		;TAKE +2 IF I FOUND SOMETHING
	RET			;OTHERWISE +1

; QMDQS - DEQUEUE LAST PACKET RETURNED BY QMSCAN
;  QSB/ ADDRESS OF QUEUE SCAN BLOCK
; RETURNS +1: ALWAYS, T2/ ADDRESS OF DEQUEUED PACKET

QMDQS:	MOVE T2,QSB.LE(QSB)	;GET ADDRESS OF ENTRY TO BE DEQUEUED
	MOVE T3,QSB.LP(QSB)	;GET ADDRESS OF PREVIOUS ENTRY
	MOVEM T3,QSB.LE(QSB)	;FIX LE IN CASE QMSCAN IS CALLED AGAIN
	SKIPN T4,(T2)		;GET ADDR OF FOLLOWING ENTRY
	HRRM T3,@QSB.QB(QSB)	;IF DEQING TAIL, SET NEW TAIL IN QDB
	JUMPE T3,[HRLM T4,@QSB.QB(QSB) ;DEQING HEAD, SET NEW HEAD IN QDB
		RET]
	MOVEM T4,(T3)		;NOT HEAD, FIX LINKAGE IN PREDECESSOR
	RET
; REW - INITIATES A REWIND OPERATION ON AN MTA
; REWEA - LIKE REW, BUT ALSO SCHEDULES A CALLER-SPECIFIED ROUTINE
;	  WHEN THE REWIND IS COMPLETE
;  T1/ ADDRESS OF END-ACTION ROUTINE THAT WILL BE ENTERED WHEN
;      REWIND OPERATION IS COMPLETE (REWEA ONLY)
;  MTA/ ADDR OF STATUS BLOCK
; RETURNS +1: DEVICE OFFLINE OR TIMED OUT
;	  +2: REWIND OPERATION INITIATED
;		CONTROL IS GIVEN TO END-ACTION ROUTINE WHEN REWIND
;		COMPLETES. MTA AC WILL HAVE ADDR OF MTA STATUS BLK.
; NOTE: SINCE NOT ALL THE MAGTAPE HARDWARE IS CONSCIENTIOUS ABOUT
;	REPORTING STATUS CHANGES, THIS PROGRAM RELIES HEAVILY UPON
;	DEVICE OPERATIONS (IN PARTICULAR, REWIND) TO DETERMINE THE
;	LOADED/UNLOADED STATUS OF A TAPE DRIVE. THE BASIC LINE OF
;	REASONING IS: IF SJ%OFS IS SET THEN BELIEVE IT; IF IT IS
;	RESET, CHECK FOR ONLINE/OFFLINE BY ISSUING A REWIND MTOPR.

REW:	SETZ T1,
REWEA:	SAVEQ
	MOVEI Q3,1		;SET UP FOR SUCCESSFUL RETURN
	MOVE Q2,T1		;SAVE END-ACTION ADDRESS
	LOAD T1,MTAREA
	SKIPE T1		;END-ACTION ALREADY REQUESTED?
	CALL STOP		;YES, PROGRAM LOGIC FAILURE
	CALL MTAGJF		;GET JFN NOW TO LIMIT GTJFN CALLS
	CALL GMTADS		;GET MTA DEVICE STATUS
	JXN T1,SJ%OFS,[SETZRO MA%LOD,MTAFLG(MTA) ;OFFLINE, SAY SO
		CALLRET MTARJF] ;DUMP JFN AND GIVE ERROR RETURN
	JXN T1,SJ%REW,[CALL MTARJF ;REWINDING ALREADY, DUMP JFN
		STOR Q2,MTAREA	;SET END-ACTION ADDRESS
		RETSKP]		;TAKE SUCCESSFUL RETURN
	LOAD Q1,MA%OPN,MTAFLG(MTA) ;IS MTA JFN OPEN ALREADY?
	JUMPE Q1,[CALL MTAOPI	;NO, OPEN IT
		 SKIPA		;OFFLINE
		JRST .+1	;OPENED
		CALLRET MTARJF] ;DUMP JFN AND GIVE ERROR RETURN
	CALL MTARJF		;UN-NEST PRIOR MTAGJF
	CALL ELOGOF		;DON'T LOG ERRORS
	MOVEI T1,.MOREW
	MOVEI T2,1		;REPEAT COUNT
	CALL XMTOPR		;INITIATE REWIND
	 SETZ Q3,		;OFFLINE OR TIMED OUT, SET +1 RETURN
	CALL ELOGON		;RESTORE ERROR LOGGING
	STOR Q3,MA%LOD,MTAFLG(MTA) ;SET STATE (LOADED/UNLOADED)
	SKIPN Q1		;SKIP IF I DIDN'T OPEN MTA
	CALL MTACLS		;I OPENED IT, SO I'LL CLOSE IT
	JUMPE Q3,R		;TAKE ERROR RETURN IF INDICATED
	STOR Q2,MTAREA		;GOOD RETURN, SET END-ACTION ADDR
	RETSKP
; SCIDIS - DISABLE STATUS-CHANGE INTERRUPTS FROM MTA DEVICE
; SCIENA - ENABLE STATUS-CHANGE INTERRUPTS FROM MTA DEVICE
;	WHEN A TAPE DRIVE IS ENABLED FOR STATUS-CHANGE INTERRUPTS, THE
;	FOLLOWING EVENTS CAUSE A PSI INTERRUPT ON CHANNEL "TDSCCN":
;	TRANSITION TO ONLINE, TRANSITION TO OFFLINE, REWIND COMPLETE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

SCIDIS:	SKIPA T2,[0,,-1]
SCIENA:	MOVEI T2,TDSCCN
	MOVEI T1,2		;BUILD ARG BLOCK IN CT1 AND CT2
	STAKT
	CALL MTAGJF		;GET JFN ON MTA
	MOVEI T2,.MOOFL		;MTOPR FUNCTION CODE
	MOVEI T3,CT1		;GET ADDRESS OF ARG BLOCK
	MTOPR			;ENABLE OR DISABLE
	CALLRET MTARJF		;DUMP JFN AND EXIT


; SIXASC - CONVERT SIXBIT WORD TO ASCII STRING
;  T1/ SIXBIT WORD
;  T2/ BYTE POINTER TO ASCII DESTINATION STRING
; RETURNS +1: ALWAYS, 6 CHARACTERS PLACED IN DESTINATION STRING

SIXASC:	MOVE T4,T2		;MOVE POINTER OUT OF T2
	MOVEI T3,6
SIXAS1:	SETZ T2,		;CLEAR FOR SHIFT
	ROTC T1,6		;GET A SIXBIT CHARACTER
	ADDI T2,40		;CONVERT TO ASCII
	IDPB T2,T4		;STORE CHARACTER
	SOJG T3,SIXAS1
	RET
; SAVEQR - DRIVER FOR SAVEQ MACRO

SAVEQR::ADJSP P,3		;CREATE ROOM ON STACK FOR Q1-Q3
	DMOVEM Q1,-2(P)		;STACK Q1 & Q2
	MOVEM Q3,0(P)		;STACK Q3
	CALL (CX)		;BACK TO CALLER
	 TRNA			;NON-SKIP RETURN
	AOS -3(P)		;SKIP RETURN
	DMOVE Q1,-2(P)		;RESTORE Q1 & Q2
	MOVE Q3,0(P)		;RESTORE Q3
	ADJSP P,-3		;DELETE TEMP SPACE FROM STACK
	RET			;BACK TO CALLER'S CALLER +1 OR +2

; SAVETR - DRIVER FOR SAVET MACRO

SAVETR::ADJSP P,4		;CREATE ROOM ON STACK FOR T1-T4
	DMOVEM T1,-3(P)		;STACK T1 & T2
	DMOVEM T3,-1(P)		;STACK T3 & T4
	CALL (CX)		;BACK TO CALLER
	 TRNA			;NON-SKIP RETURN
	AOS -4(P)		;SKIP RETURN
	DMOVE T1,-3(P)		;RESTORE T1 & T2
	DMOVE T3,-1(P)		;	 T3 & T4
	ADJSP P,-4		;DELETE TEMP SPACE FROM STACK
	RET			;BACK TO CALLER'S CALLER +1 OR +2

; STAKTR - DRIVER FOR STAKT MACRO

STAKTR::ADJSP P,4		;CREATE ROOM ON STACK FOR T1-T4
	DMOVEM T1,-3(P)		;STACK T1 & T2
	DMOVEM T3,-1(P)		;STACK T3 & T4
	CALL (CX)		;BACK TO CALLER
	 TRNA			;NON-SKIP RETURN
	AOS -4(P)		;SKIP RETURN
	ADJSP P,-4		;DELETE TEMP SPACE FROM STACK
	RET			;BACK TO CALLER'S CALLER +1 OR +2
; SMPAV - SET AVAILABLE STATUS OF TAPE DRIVE
;  T1/ 0 TO SET DRIVE UNAVAILABLE, 1 TO SET DRIVE AVAILABLE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

SMPAV:	STAKT
	SKIPE T1,MTAPNT(MTA)	;Do we have a DDB?
	JRST [CALL DSFGET	;Yes, go get DDB
	      $STOP <Invalid DDB pointer in magtape status block>
	      JRST SMPA.1]	;Continue with common code
	CALL GMTADD		;Get designator
	MOVEM T1,DSFE+DSFSPC	;Save it as specification
	MOVEI T1,.DVMTA		;Get type
	MOVEM T1,DSFE+DSFTYP	;Save it
	SETZM DSFE+DSFFLG	;Default flags
	CALL DSFCRE		;Try to create
	  JFCL			;Don't care if already exists

;  Now have DDB in DSFE

SMPA.1:	MOVE T2,CT1		;GET AVAILABLE OR UNAVAILABLE FLAG
	STOR T2,DSF%AV,DSFE+DSFFLG ;STORE FLAG
	CALL DSFUDE		;Update entry
	 $STOP <Update of previously known DDB with DSFUDE failed>
	RET			;And done


; STMTA - CONVERT AN ASCIZ STRING TO AN MTA STATUS BLOCK ADDRESS
;  T1/ ADDRESS OF ASCIZ STRING FOR MTA (IN FORM SUITABLE FOR STDEV JSYS)
; RETURNS +1: STRING DOES NOT SPECIFY MTA DEVICE
;	  +2: MTA/ ADDR OF MTA STATUS BLOCK

STMTA:	HRLI T1,-1		;GET STRING POINTER TO ASCIZ DEVNAME
	STDEV			;TRANSLATE STRING TO DEV DESIGNATOR
	 RET			;NOT A DEVICE
	MOVE T1,T2		;GET DESIGNATOR
	CALLRET DDMTA		;CONVERT TO MTA STATUS BLOCK ADDR IN MTA
; STOPNW - Same as STOP but a message is supplied.
; Invoked by:
;	$STOP <message>

STPHLP:	BLOCK 1			;Local storage location
STOPNW::			;New stop with message
	SETOM STPHLP		;Say we came in here
	SKIPA			;Don't execute first instruction in STOP

; STOP - A FATAL ERROR WAS DETECTED; PROGRAM MUST HALT
; INVOKED BY:
;	CALL STOP

STOP::	SETZM STPHLP		;Say we came in here
	MOVEM 17,CRSHAC+17	;SAVE AC'S FROM CRASH
	MOVEI 17,CRSHAC
	BLT 17,CRSHAC+16
	MOVEI T1,.FHSLF
	SETZ T2,
	GETER			;GET MOST RECENT ERROR
	 ERJMP .+1
	HRRZM T2,LSTERR		;STORE IT FOR ANALYSIS
	DIR			;DISABLE ALL INTERRUPTS
	TMSG <

?MOUNTR crashing, PC = >
	MOVEI T1,.PRIOU
	HRRZ T2,CRSHAC+P	;GET TOP-OF-STACK ADDRESS
	HRRZ T2,(T2)		;GET ADDRESS OF CALL + 1
	SOS T2			;GET ADDRESS OF CALL
	MOVE T3,[NO%ZRO+NO%LFL+FLD(6,NO%COL)+10]
	NOUT			;TYPE PC
	 JFCL
	TMSG <
>				;Add a CRLF after number of crash PC

	SKIPE STPHLP		;Do we want a message?
	JRST [AOS T2		;Yes, point to it
	      HRRO T1,(T2)	;Setup pointer to error message
	      PSOUT		;Print it
	       ERJMP STOP0	;Don't believe/care about errors
	      TMSG <
>				;Add a CRLF after message
	      JRST STOP0]	;Continue on

STOP0:	SKIPE TSTF		;TESTING?
	JRST [	TMSG <Test flag set, not saving MOUNTR core image>
				;YES, DON'T SAVE CORE IMAGE
		JRST STOP1]

; SAVE CORE IMAGE IN CRASH FILE

	MOVX T1,GJ%SHT+GJ%FOU+GJ%ACC
	HRROI T2,CFSPEC		;GET POINTER TO FILESPEC
	GTJFN			;GET JFN ON CRASH FILE
	 JRST STOP2
	MOVE Q2,T1		;COPY JFN TO A SAFE PLACE
	TMSG <Saving MOUNTR core image on file >
	MOVEI T1,.PRIOU
	MOVE T2,Q2		;JFN
	SETZ T3,
	JFNS			;DISPLAY FILESPEC
	 ERJMP STOP2
	MOVSI T1,.FHSLF
	HRR T1,Q2		;FORK HANDLE,,JFN
	MOVE T2,[-1000,,SS%CPY]	;ALL PAGES OF PROCESS, COPY-ON-WRITE
	SETZ T3,
	SSAVE			;SAVE CORE IMAGE
	 ERJMP STOP2
	JRST STOP1		;SKIP AROUND FAILURE-PROCESSOR

; ERROR SAVING CORE IMAGE, REPORT IT

STOP2:	TMSG <
?Cannot save MOUNTR core image: >
	MOVEI T1,.PRIOU
	HRLOI T2,.FHSLF		;FORK HANDLE ,, -1 (MOST RECENT ERROR)
	SETZ T3,		;NO LIMIT
	ERSTR			;SHOW WHY SAVE FAILED
	 JFCL
	 JFCL
STOP1:	MOVSI 17,CRSHAC		;GET BLT SOURCE,,DESTINATION
	BLT 17,17		;RESTORE AC'S TO CRASH STATE
	HALTF

; STOPP - STOP BECAUSE OF SOME KIND OF STACK PROBLEM
; INVOKED BY:
;	JSP CX,STOPP

STOPP:	MOVEM P,BADP		;SAVE BAD P
	MOVE P,[IOWD 4,PDL1]	;GET NEW P SO PDL IS PRESERVED
	CALL STOP		;NOW CRASH

; PANIC INTERRUPT HANDLERS - PROGRAM IS CRASHING
; DATA ERROR IS NON FATAL AND IS REPORTED

PANPOV:	JSP CX,STOPP		;PDL OVERFLOW
PANDAE:	EXCH T1,@LEVTAB+PRIPAN-1 ;GET RETURN PC
	MOVEM T1,DAEPC		;SAVE IT
	EXCH T1,@LEVTAB+PRIPAN-1 ;RESTORE T1 AND PC
	SOS DAEPC		;PC OF INTERRUPT
	CALL EIHR		;SCHEDULE
	EXP DAEIH		;ROUTINE TO SCHEDULE	
PANQTA:	CALL STOP		;QUOTA EXCEEDED
PANILI:	CALL STOP		;ILLEGAL INSTRUCTION
PANIRD:	CALL STOP		;ILLEGAL READ
PANIWR:	CALL STOP		;ILLEGAL WRITE
PANMSE:	CALL STOP		;MACHINE SIZE EXCEEDED

; DAEIH - INFORM OPERATOR OF A DATA ERROR.
; RETURNS +1 ALWAYS

DAEIH:	MOVE T1,DAEPC		;GET PC OF ERROR
	TMCT <%IData Error encountered. PC= %1O Last Error: %J>
	MOVEI T3,[ASCIZ/MOUNTR System Task Error/]
	CALLRET BTWTO		;TELL OPERATOR
; SYTSET - BUILD AND LOG SYSERR ENTRY FOR TAPE DRIVE STATUS CHANGE
;  T1/ FUNCTION CODE (CS%ADV = SET AVAILABLE, CS%DDV = SET UNAVAILABLE)
;  T2/ ADDRESS OF ASCIZ REASON, OR 0 IF NO REASON GIVEN
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

SYTSET:	SAVEQ
	STKVAR <<SYTA,.MOISN+1>>
	SETZM SYRMSG		;ZERO OUT SYSERR MESSAGE AREA
	MOVE T4,[SYRMSG,,SYRMSG+1]
	BLT T4,SYRMSG+SYRMSZ-1

; TRANSFER OPERATION CODE AND REASON TO MESSAGE

	STOR T1,CS%OPR,SYRMSG+CS%OPW ;STORE OPERATION CODE INTO MESSAGE
	MOVEI Q1,SYRHSZ+CS%SIZ	;ASSUME NO REASON GIVEN
	SKIPN T1,T2		;REASON GIVEN?
	JRST SYTSE1		;NO
	MOVS Q2,T1		;YES, COPY ADDRESS OF STRING FOR BLT
	CALL ASCIZL		;GET # OF CHARACTERS
	IDIVI T2,5		;GET # OF WORDS MINUS 1
	CAIL T2,SYRMSZ		;TOO LONG?
	MOVEI T2,SYRMSZ-1	;YES, TRUNCATE
	MOVEI Q1,SYRHSZ+CS%SIZ+1(T2) ;SAVE SIZE OF ENTIRE MESSAGE
	HRRI Q2,SYRMSG+CS%SIZ	;GET BLT DESTINATION
	BLT Q2,SYRMSG+CS%SIZ(T2) ;TRANSFER STRING TO MESSAGE
	MOVEI T1,CS%SIZ
	STOR T1,CS%RSN,SYRMSG+CS%RSW ;STORE POINTER TO REASON
SYTSE1:	MOVEI T1,SEC%CS		;GET CONFIGURATION STATUS CHANGE CODE
	DPB T1,[POINT 9,SYRHDR,8] ;STORE INTO SYSERR ENTRY HEADER

; BUILD AND STORE SIXBIT DEVICE NAME (E.G. MTA0)
; (CAN'T STORE CHANNEL TYPE BECAUSE I DON'T KNOW IT)

	CALL GMTADD		;GET MTA DEVICE DESIGNATOR
	MOVE T2,T1		;TO T2 FOR DEVST
	HRROI T1,SYTA		;GET ADDR OF STRING AREA
	DEVST			;GET ASCIZ DEVICE NAME (E.G. MTA0)
	 SETZM SYTA		;SHOULD NEVER FAIL
	MOVEI T1,SYTA		;GET ADDR OF STRING
	CALL ASCIZL		;GET LENGTH OF STRING FOR CVTA6
	MOVSI T1,(POINT 7)
	HRRI T1,SYTA		;GET POINTER TO STRING
	CALL CVTA6		;GET SIXBIT DEVICE NAME IN T1
	 SETZ T1,		;SHOULDN'T FAIL
	MOVEM T1,SYRMSG+CS%DNM	;STORE SIXBIT DEVICE NAME

; GET DEVICE ADDRESS AND SERIAL#

	JE MTASTE,,R		;DON'T BOTHER IF DEVICE NOT ASSIGNED
	MOVEI T1,.MOISN
	MOVEM T1,.MOICT+SYTA	;SET ARG BLOCK LENGTH IN ARG BLOCK
	CALL MTAGJF		;GET MTA JFN IN T1
	MOVEI T2,.MOINF		;GET MTOPR FUNCTION CODE
	MOVEI T3,SYTA		;GET ADDRESS OF ARG BLOCK
	MTOPR			;GET MTA INFO FROM MONITOR
	CALL MTARJF		;DUMP JFN
	MOVE T1,.MOISN+SYTA	;GET UNIT ADDRESS AND SERIAL#
	MOVEM T1,SYRMSG+CS%ADS	;STORE IN SYSERR MESSAGE
	MOVE T1,.MOITP+SYTA	;GET DRIVE TYPE CODE
	STOR T1,CS%UTP,SYRMSG+CS%HTP ;STUFF IT

; LOG THE MESSAGE

	MOVEI T1,SYRHDR		;GET ADDRESS OF SYSERR MESSAGE
	MOVE T2,Q1		;GET # OF WORDS IN MESSAGE
	SKIPN TSTF		;DON'T LOG SYSERRS IF TESTING
	SYERR			;LOG IT
	 ERJMP R		;IGNORE ERRORS
	RET
; UNLOAD - UNLOAD A VOLUME FROM AN MTA DEVICE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

UNLOAD:	SAVEQ
	CALL MTAGJF		;GET JFN NOW TO LIMIT GTJFN CALLS
	CALL GMTADS		;GET DEVICE STATUS IN T1
	JXN T1,SJ%OFS,[SETZRO MA%LOD,MTAFLG(MTA) ;OFFLINE, SAY SO
		CALLRET MTARJF] ;DUMP JFN AND RETURN
	JXN T1,SJ%REW,[SETONE MA%ULP,MTAFLG(MTA) ;SET UNLOAD-PENDING
		CALLRET MTARJF]	;DUMP JFN AND RETURN
	SETZRO MA%LOD,MTAFLG(MTA) ;SET STATUS TO UNLOADED
	LOAD Q1,MA%OPN,MTAFLG(MTA) ;IS MTA JFN OPEN ALREADY?
	JUMPE Q1,[CALL MTAOPI	;NO, OPEN IT
		 SKIPA		;OFFLINE
		JRST .+1	;OPENED
		CALLRET MTARJF] ;DUMP JFN AND GIVE ERROR RETURN
	CALL MTARJF		;UN-NEST PRIOR MTAGJF
	CALL ELOGOF		;DON'T LOG ERRORS
	MOVEI T1,.MOREW		;[333]Get the rewind function 
	MOVEI T2,1		;[333]Repeat count
	CALL XMTOPR		;[333]Rewind before we unload (TM03)
	 JRST .+1		;[333]Don't care if it fails
	MOVEI T1,.MORUL
	MOVEI T2,1		;REPEAT COUNT
	CALL XMTOPR		;INITIATE REWIND-AND-UNLOAD
	 CALL XMTREP		;REPORT UNLOAD ERROR
	CALL ELOGON		;RESUME LOGGING ERRORS
	JUMPN Q1,R		;EXIT IF I DIDN'T OPEN MTA
	CALLRET MTACLS		;I OPENED IT, SO I'LL CLOSE IT
; VQADD - APPEND A NEW VOLID TO THE END OF THE RSB VOLID LIST
;  T1/ SIXBIT VOLID
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: NO SLOTS LEFT IN VOLID POOL, REQUEST ABORTED
;	  +2: SUCCESS

VQADD:	STAKT
	MOVEI T1,FVSQDB		;POINT TO FREE POOL QDB
	CALL QMDQH		;DEQUEUE HEAD OF FREE CHAIN
	 JRST [	ABTRET (MREQ31)] ;NO FREE SLOTS, ABORT REQUEST
	MOVE T1,CT1		;T2/ SLOT ADDR, GET VOLID
	MOVEM T1,1(T2)		;STORE VOLID IN SLOT
	MOVEI T1,RSBVLS(RSB)	;GET ADDR OF RSB VOLID LIST QDB
	CALL QMQT		;ADD NEW VOLID TO END OF RSB VOLID QUEUE
	RETSKP


; VQCNT - RETURN THE LENGTH OF THE RSB VOLID LIST
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS, T1/ LENGTH OF VOLID LIST

VQCNT:	SETZ T1,		;CLEAR COUNTER
	HLRZ T2,RSBVLS(RSB)	;GET HEAD OF QUEUE
VQCNT1:	JUMPE T2,R		;END OF QUEUE, RETURN
	MOVE T2,(T2)		;NOT THE END, GET ADDR OF NEXT ENTRY
	AOJA T1,VQCNT1		;COUNT THIS ENTRY AND LOOP


; VQDEL - RETURN RSB VOLID QUEUE TO FREE VOLID SLOT POOL
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS

VQDEL:	SKIPN T1,RSBVLS(RSB)	;IS QUEUE EMPTY?
	RET			;YES, NOTHING TO DO
	SETZM RSBVLS(RSB)	;CLEAR QDB IN RSB
	HRRZ T2,FVSQDB		;GET CURRENT FREE POOL TAIL
	JUMPE T2,[MOVEM T1,FVSQDB ;NO FREE POOL, SO CREATE IT
		RET]
	HLRZM T1,(T2)		;POINT CURRENT TAIL AT RSB LIST HEAD
	HRRM T1,FVSQDB		;SET TAIL OF FREE POOL TO RSB TAIL
	RET
; VQGCV - GET CURRENT VOLID FOR TAPE MOUNT REQUEST
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: ALWAYS, T1/ 0 IF SCRATCH TAPE, ELSE SIXBIT VOLID

VQGCV:	LOAD T1,RSBCV		;GET CURRENT VOLUME #
	CALL VQGET		;GET VOLID IN T1
	 SETZ T1,		;BAD INDEX, MUST BE A SCRATCH
	RET


; VQGET - RETURN A VOLID FROM RSB VOLID LIST
; VQSET - STORE A VOLID INTO RSB VOLID LIST
;  T1/ ORDINAL NUMBER OF VOLID TO BE RETURNED
;  T2/ SIXBIT VOLID TO BE STORED (VQSET ONLY)
;  RSB/ ADDR OF REQUEST STATUS BLOCK
; RETURNS +1: VOLID NUMBER OUT OF RANGE
;	  +2: SUCCESS, T1/ SIXBIT VOLID

VQGET:	SKIPA T3,[MOVE T1,1(T2)]
VQSET:	MOVE T3,[MOVEM T1,1(T2)]
	JUMPLE T1,R		;CHECK FOR FUNNY INPUT
	QSCANI <RSBVLS(RSB)>	;SET UP TO SCAN RSB VOLID LIST
	STAKT
VQGET1:	CALL QMSCAN		;GET NEXT VOLID IN LIST
	 RET			;NONE LEFT, FAILED
	SOSLE CT1		;IS THIS THE ONE THE CALLER WANTED?
	JRST VQGET1		;NO, CONTINUE SCAN
	MOVE T1,CT2		;GET VOLID IN CASE OF VQSET
	XCT CT3			;LOAD OR STORE VOLID AS REQUESTED
	RETSKP


; VQSPIN - INITIALIZE FREE POOL OF VOLID SLOTS
; RETURNS +1: ALWAYS

VQSPIN:	SAVEQ
	SETZM FVSQDB		;SET QUEUE EMPTY INITIALLY
	MOVEI Q1,VOLP0		;GET ADDRESS OF 1ST SLOT IN POOL
	MOVEI Q2,VOLPN		;GET # OF SLOTS IN POOL
VQSPI1:	MOVEI T1,FVSQDB		;GET QDB ADDRESS
	MOVE T2,Q1		;GET ADDRESS OF NEXT SLOT
	CALL QMQT		;ADD SLOT TO TAIL OF FREE LIST
	ADDI Q1,2		;POINT TO NEXT SLOT
	SOJG Q2,VQSPI1		;LOOP
	RET
; WRTP - WRITE-PROTECT MOUNTR'S CODE TO CATCH STRAY STORES
; RETURNS +1: ALWAYS
Comment /
WRTP:	MOVEI T1,PURE		;COMPUTE PAGE # OF FIRST
	LSH T1,-11		; PAGE OF NON-MODIFYABLE MEMORY
	HRLI T1,.FHSLF		;GET FORK HANDLE ,, PAGE#
	MOVX T2,PA%RD+PA%EX	;REQUEST READ AND EXECUTE ACCESS
	MOVEI T3,.RLEND		;COMPUTE PAGE # OF LAST READ-ONLY
	LSH T3,-11		; PAGE PLUS 1
WRTP1:	CAIG T3,(T1)		;ALL DONE?
	RET			;YES
	SPACS			;SET PAGE TO READ & EXECUTE
	AOJA T1,WRTP1		;INCREMENT PAGE # AND LOOP
/

;WTOCHK CHECKS TO SEE IF WTOR FUNCTION IS DISABLED IN BATCH JOB
;RETURNS +1 IF DISABLED
;RETURNS +2 IF NOT DISABLED
;ABTRET WITH ERROR MESSAGE IF DISABLED

WTOCHK:	SAVET			;SAVE T1-T4
	LOAD T1,RSBJNO		;GET JOBNUMBER
	SETO T2,		;JUST ONE ITEM
	HRRI T2,T3		;INTO T3
	MOVEI T3,.JIBCH		;GET BATCH FLAGS
	GETJI			;
	 SETZ T3,		;UNLIKELY
	LOAD T3,OB%WTO,T3	;CHECK FOR WTO ENABLED
	CAIE T3,.OBALL		;ARE MESSAGES ALLOWED?
	JRST [ ABTRET (MREQ15)]	;NO, ABORT WITH MESSAGE
	RETSKP			;YES, RETURN +2

; XMTOPR - EXECUTE MAGTAPE MTOPR FUNCTION A GIVEN NUMBER OF TIMES
;  T1/ MTOPR FUNCTION CODE
;  T2/ NUMBER OF TIMES TO EXECUTE
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: DEVICE FAILURE, T1/ 0=ERROR 1=TIMEOUT
;	  +2: SUCCESS

XMTOPR:	SAVEQ
	DMOVE Q1,T1		;SAVE FUNCTION CODE AND REPEAT COUNT
XMTOP1:	LOAD T1,MTAJFN		;GET JFN
	MOVE T2,Q1		;GET MTOPR FUNCTION CODE
	IOXCT MTOPR,XMTOP2,XMTOP3 ;START POSITIONING OPERATION
	MOVEI T2,.MONOP
	IOXCT MTOPR,XMTOP2,XMTOP3 ;WAIT TILL OPERATION COMPLETES
	CALL CLRTAP		;CLEAR ERRORS
	 JRST XMTOP3		;TIMED OUT
	TXNE T2,MT%DVE+MT%DAE	;ANY SERIOUS PROBLEMS?
	JRST XMTOP2		;YES
	SOJG Q2,XMTOP1		;LOOP TILL DONE
	RETSKP			;SUCCESS

XMTOP2:	TDZA T1,T1		;ERROR, PUT 0 IN T1
XMTOP3:	MOVEI T1,1		;TIMEOUT, PUT 1 IN T1
	RET			;TAKE ERROR RETURN
; XMTREP - REPORT MTA DEVICE FAILURE TO OPERATOR
;  T1/ 0 TO REPORT DEVICE ERROR, 1 TO REPORT DEVICE TIMEOUT
;  MTA/ ADDR OF MTA STATUS BLOCK
; RETURNS +1: ALWAYS

XMTREP:	JUMPN T1,[CALLRET WOTIMO] ;TIMEOUT, RETURN THROUGH TIMEOUT CODE
	TMCT <%I%M positioning operation failed. Last Error: %J>
	MOVEI T3,[ASCIZ/Tape Positioning Error/]
	CALLRET BTWTO		;TELL OPERATOR AND RETURN


; XMUTIL - EXECUTE MUTIL FOR CALLER
;  T1-T4/ ARGUMENT BLOCK WORDS 0-3
; RETURNS +1: ERROR ON MUTIL CALL, CODE IN T1
;	  +2: SUCCESS, WITH COPY OF ARG BLOCK IN T1-T4

XMUTIL:	SAVET			;SAVE CALLER'S AC'S ON STACK
	MOVEI T1,4		;ARGUMENT BLOCK LENGTH
	MOVEI T2,CT1		;ADDRESS OF ARGUMENT BLOCK
	MUTIL			;DO MUTIL (ARG BLOCK IS IN STACK)
	 JRST [	MOVEM T1,CT1	;ERROR, SUPPLY ERROR TO CALLER
		RET]		;TAKE ERROR RETURN
	RETSKP			;GOOD RETURN, T1-T4 COME OFF STACK
SUBTTL STRSTT -- Returns the structure status

;  Accepts: T1 / Address of name (alias) of structure

;  Returns: +1 if failed to get status for structure
;	    +2 with status
;	    T1 / Status flags
;	    T2 / Number of units in structure
;	    T3 / Mount count for structure
;	    T4 / Open file count for structure

STRSTT:	HRRO T1,T1		;Set pointer for alias
	MOVEM T1,MSTRST+.MSGSN	;Save it
	MOVE T1,[.MSGFC+1,,.MSGSS] ;Get length,,function
	MOVEI T2,MSTRST		;Get the address of argument block
	MSTR			;Try for the status
	  ERJMP R		;Just return
	DMOVE T1,MSTRST+.MSGST	;Get the flags and the number of units
	DMOVE T3,MSTRST+.MSGMC	;Get the mount count and the open file count
	RETSKP			;And return

LIT:				;ADDRESS OF START OF LITERAL POOL
	END <ENTVSZ,,ENTVEC>