Google
 

Trailing-Edge - PDP-10 Archives - BB-F494Z-DD_1986 - 10,7/qsrcat.mac
There are 7 other files named qsrcat.mac in the archive. Click here to see a list.
TITLE	QSRCAT - Interface to [SYSTEM]CATALOG and catalog cache management

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

	SEARCH	GLXMAC			;GALAXY SYMBOLS
	SEARCH	QSRMAC			;QUASAR SYMBOLS
	SEARCH	ORNMAC			;ORION SYMBOLS
	SEARCH	CATPRM			;CATALOG SYMBOLS
	PROLOG	(QSRCAT)		;INITIALIZE ASSEMBLY

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

	SALL				;FOR CLEAN LISTINGS
	.DIREC	FLBLST			;FOR CLEANER LISTINGS
SUBTTL	Table of Contents


;               TABLE OF CONTENTS FOR QSRCAT
;
;
;                        SECTION                                   PAGE
;    1. Table of Contents.........................................   2
;    2. Local storage.............................................   3
;    3. V$INIT - Initialize.......................................   4
;    4. V$AQST - Send queue structure info to catalog daemon......   5
;    5. V$BCAT - BLISS interface to retrieve cache entries........   6
;    6. V$CERR - Report errors detected in [SYSTEM]CATALOG........   7
;    7. V$COMP - Compare catalog entries..........................   8
;    8. V$CREA - Create an entry for an existing volume-set.......  10
;    9. V$DELE - Delete a non-sharable volume-set from the cache..  11
;   10. V$DELS - Delete a sharable volume-set from the cache......  11
;   11. V$DUMP - Dump entire cache................................  12
;   12. V$DISA - Disable catalog updates by MDA...................  13
;   13. V$ENAB - Enable catalog updates by MDA....................  13
;   14. V$GCAT - Get catalog information..........................  14
;   15. V$FIND - Find a volume-set in the cache...................  15
;   16. V$RCAT - Response from [SYSTEM]CATALOG....................  16
;   17. V$SEND - Send a message to [SYSTEM]CATALOG................  19
;   18. V$STRG - Convert SIXBIT volume-set names to ASCIZ.........  20
;   19. V$TYPE - Type a catalog entry.............................  21
;   20. Message translation
;        20.1   VSL table.........................................  22
;        20.2   Device code table.................................  23
;        20.3   VSL processing....................................  25
;        20.4   VOL processing....................................  26
;        20.5   Load resource numbers into MDA volume blocks......  28
;   21. End.......................................................  31
SUBTTL	Local storage


	DATSIZ==<2*ARG.SZ>+.CTVSL+.CTVLM;SIZE OF VSL & VOL BLOCK STORAGE
CATMSG:	BLOCK	.OHDRS+DATSIZ		;STORAGE FOR CATALOG MESSAGES
CATQUE:	BLOCK	1			;CATALOG CACHE LINKED LIST ID
CATTMP:	BLOCK	VSNSIZ			;TEMPORARY VOLUME-SET NAME STORAGE
CATOLD:	BLOCK	1			;OLD CATALOG CACHE ENTRY ADDRESS
CATNEW:	BLOCK	1			;NEW CATALOG CACHE ENTRY ADDRESS
CATTXT:	BLOCK	<CATSIZ==100>		;TEXT BLOCK
CATCNT:	BLOCK	1			;CHARACTER COUNT
CATPTR:	BLOCK	1			;BYTE POINTER
DTAFLG:	BLOCK	1			;DECTAPE CATALOG UPDATE FLAG
MTAFLG:	BLOCK	1			;MAGTAPE CATALOG UPDATE FLAG
STRFLG:	BLOCK	1			;STRUCTURE CATALOG UPDATE FLAG
VOLCUR:	BLOCK	1			;CURRENT VOL BLOCK OFFSET
DMPFLG:	BLOCK	1			;DUMP FLAG
RSNNUM:	BLOCK	1			;RESOURCE NUMBER
RSNNAM:	BLOCK	1			;RESOURCE NAME
SUBTTL	V$INIT - Initialize


; Here to initialize the interface to the catalog daemon
; Call:	PUSHJ	P,V$INIT

V$INIT::SKIPN	G$MDA##			;QUASAR NEED A CATALOGER?
	$RETT				;NOPE, JUST RETURN
	MOVEI	S1,SP.CAT		;SPECIAL PID INDEX
	PUSHJ	P,C%RPRM		;SEE IF THE CATALOG DEAMON
	JUMPT	INIT.1			;IS ALIVE AND KICKING
	MOVEI	S1,1			;TIME TO WASTE
	PUSHJ	P,I%SLP			;ZZZZZZ
	JRST	V$INIT			;TRY AGAIN

INIT.1:	MOVEI	S1,1			;INITIAL FLAG
	MOVEM	S1,DTAFLG		;ALLOW DECTAPE UPDATES
	MOVEM	S1,MTAFLG		;ALLOW MAGTAPE UPDATES
	MOVEM	S1,STRFLG		;ALLOW STRUCTURE UPDATES
	PUSHJ	P,L%CLST		;CREATE A LINKED LIST
	MOVEM	S1,CATQUE		; FOR THE CATALOG CACHE
	PUSHJ	P,AQST.1		;SEND QUEUE STRUCTURE TO CATALOG DAEMON
	$RETT				;RETURN
SUBTTL	V$AQST - Send queue structure info to catalog daemon


V$AQST::MOVE	S1,G$MCOD##		;EXTERNAL ENTRY POINT
AQST.1:	MOVEI	S1,0			;INTERNAL ENTRY POINT
	$SAVE	<P1>			;SAVE P1
	PUSH	P,S1			;SAVE ACK CODE
	MOVEI	P1,CATMSG		;POINT TO MESSAGE BLOCK
	MOVEI	S1,.CFAQS		;MESSAGE TYPE
	STORE	S1,.MSTYP(P1),MS.TYP	;SAVE
	MOVEI	S1,.OHDRS+1		;MESSAGE LENGTH
	STORE	S1,.MSTYP(P1),MS.CNT	;SAVE
	SETZM	.MSFLG(P1)		;NO MESSAGE FLAGS
	POP	P,.MSCOD(P1)		;SET POSSIBLE ACK CODE
	SETZM	.OFLAG(P1)		;NO FLAGS
	SETZM	.OARGC(P1)		;NO BLOCK COUNT
	MOVE	S1,G$QSTR##		;GET QUEUE STRUCTURE
	MOVEM	S1,.OHDRS(P1)		;SAVE
	MOVEM	P1,G$SAB##+SAB.MS	;SAVE MESSAGE ADDRESS
	LOAD	S1,.MSTYP(P1),MS.CNT	;GET MESSAGE SIZE
	MOVEM	S1,G$SAB##+SAB.LN	;SAVE
	PUSHJ	P,V$SEND		;SEND TO CATALOG DAEMON
	$RETT				;RETURN
SUBTTL	V$BCAT - BLISS interface to retrieve cache entries


; Call:	MOVE	S1, resource number
;	PUSHJ	P,V$BCAT
;
; TRUE return:	S2 contains the cache entry address
; FALSE return:	Never (stopcodes on failures)

V$BCAT::MOVEM	S1,RSNNUM		;SAVE RESOURCE NUMBER
	IMULI	S1,AMALEN		;CALC THE 'A' MATRIX OFFSET
	ADD	S1,AMATRX##		;POINT TO THE RESOURCE ENTRY
	LOAD	S1,.AMNAM(S1),AM.NAM	;GET ADDRESS OF RESOURCE NAME
	MOVEM	S1,RSNNAM		;SAVE RESOURCE NAME
	PUSHJ	P,V$FIND		;FIND IT IN THE CATALOG
	SKIPT				;SKIP IF FOUND...
	$STOP	(CEM,<Catalog entry is missing for resource ^D/RSNNUM/ (^T/@RSNNAM/)>)
	MOVE	S2,S1			;GET THE ADDRESS IN S2
	$RETT				;AND RETURN
SUBTTL	V$CERR - Report errors detected in [SYSTEM]CATALOG


V$CERR::$WTO	(<^I/CATTX1/>,<^I/CATTX2/>,,<$WTFLG(WT.SJI)>)
	$RETF				;RETURN

CATTX1:	ITEXT	(<Invalid message from [SYSTEM]CATALOG>)
CATTX2:	ITEXT	(<Message header:
Len,,type	^O6R0/.MSTYP(M),MS.CNT/,,^O6R0/.MSTYP(M),MS.TYP/
Flg,,pfx	^O6R0/.MSFLG(M),LHMASK/,,^W3L /.MSFLG(M),MF.SUF/
Ack code	 ^O12R0/.MSCOD(M)/>)
SUBTTL	V$COMP - Compare catalog entries


; Call:	MOVE	S1, old entry address
;	MOVE	S2, new entry address
;	PUSHJ	P,V$COMP
;
; TRUE return:	match, duplicate (new) entry deleted, or old entry
;		updated to reflect changed parameters if possible.
;
; FALSE return:	mismatch, attempt to update the old entry failed.
;		to purge the old entry will be made
;
; Note:		On either return, the operator will be notified of a
;		catalog update or failure to do so.  S1 will always
;		contain the entry address to use.
;

V$COMP::$SAVE	<P1,P2,P3,P4>		;SAVE SOME ACS
	DMOVE	P1,S1			;COPY ARGUMENTS
	DMOVE	P3,P1			;THIS WAY WE'LL NEVER FORGET!
	MOVE	S1,.CQNVL(P1)		;GET NUMBER OF VOLUMES IN OLD VSN
	CAME	S1,.CQNVL(P2)		;SAME AS NEW VSN?
	JRST	COMP.2			;NO
	HRROI	S1,.CQVSN(P1)		;GET OLD VSN
	HRROI	S2,.CQVSN(P2)		;GET NEW VSN
	PUSHJ	P,S%SCMP		;COMPARE
	JUMPN	S1,COMP.2		;JUMP IF DIFFERENT
	MOVE	TF,.CQNVL(P1)		;GET NUMBER OF VOLUMES
	MOVEI	P1,.CQVSL(P1)		;POINT TO START OF VOLUME BLOCKS
	MOVEI	P2,.CQVSL(P2)		;HERE TOO

COMP.1:	MOVE	S1,.CQVID(P1)		;GET AN OLD UNIT ID
	MOVE	S2,.CQRSN(P1)		;GET AN OLD RESOURCE NUMBER
	CAMN	S1,.CQVID(P2)		;SAME AS NEW UNIT ID?
	CAME	S2,.CQRSN(P2)		;SAVE AS NEW RESOURCE NUMBER?
	JRST	COMP.2			;NO
	ADDI	P1,.CQVLL		;POINT TO NEXT ENTRY
	ADDI	P2,.CQVLL		;HERE TOO
	SOJG	TF,COMP.1		;LOOP
	MOVE	S1,P4			;GET DUPLICATE (NEW) ENTRY ADDRESS
	PUSHJ	P,DELETE		;DELETE IT
	MOVE	S1,P3			;GET ENTRY ADDRESS TO USE
	$RETT				;AND RETURN
COMP.2:	MOVEI	S1,.CQVSN(P3)		;POINT TO THE VOLUME-SET NAME
	$WTO	(<QUASAR catalog conflict>,<^I/COMP.T/>,,<$WTFLG(WT.SJI)>)
	MOVE	S1,P4			;GET DUPLICATE (NEW) ENTRY ADDRESS
	PUSHJ	P,DELETE		;DELETE IT
	MOVE	S1,P3			;GET ENTRY TO USE
	$RETF				;AND RETURN


COMP.T:	ITEXT	(<Volume-set ^T/(S1)/ is currently in use>)
SUBTTL	V$CREA - Create an entry for an existing volume-set


V$CREA::PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	P1,S1			;COPY VOLUME BLOCK ADDRESS
	MOVE	S1,.VLNAM(P1)		;GET SIXBIT NAME
	PUSHJ	P,V$STRG		;CONVERT TO A STRING
	PUSHJ	P,V$FIND		;LOOK FOR IT IN THE CATALOG
	SKIPT				;FOUND IT?
	SETZ	S1,			;NO
	MOVEM	S1,CATOLD		;REMEMBER IT FOR LATER
	MOVE	S1,CATQUE		;GET THE CATALOG QUEUE ID
	PUSHJ	P,L%LAST		;POSITION TO THE END OF THE Q
	MOVE	S1,P1			;GET THE VOL BLK ADDRESS BACK
	SETZM	S2			;ZERO THE VOLUME COUNTER

CREA.1:	LOAD	S1,.VLPTR(S1),VL.NXT	;GET THE NEXT VOL BLK ADDRESS
	AOS	S2			;BUMP THE VOLUME COUNT
	JUMPN	S1,CREA.1		;CONTINUE FOR ALL VOLUMES
	PUSH	P,S2			;SAVE THE VOLUME COUNT
	IMULI	S2,.CQVLL		;CALCULATE NUMBER OF WORDS TO GET
	ADDI	S2,.CQVSL		;INCLUDE THE CATALOG HEADER
	MOVE	S1,CATQUE		;GET THE CATALOG QUEUE ID BACK
	PUSHJ	P,L%CENT		;CREATE A NEW CATALOG ENTRY
	JUMPF	CREA.4			;FAILD FOR SOME REASON
	MOVEM	S2,CATNEW		;SAVE NEW ADDRESS FOR LATER
	MOVSI	S1,CATTMP		;POINT TO ASCIZ NAME
	HRRI	S1,.CQVSN(S2)		;WHERE TO COPY
	BLT	S1,.CQVSN+VSNSIZ-1(S2)	;MOVE VOLUME-SET NAME
	MOVEI	TF,%UNKN		;ASSUME DEVICE TYPE UNKNOWN
	SKIPE	S1,.VLVSL(P1)		;GET A VSL ADDRESS
	LOAD	TF,.VSFLG(S1),VS.TYP	;GET THE VOLUME TYPE
	CAIE	TF,%UNKN		;STILL UNKNOWN?
	JRST	CREA.2			;NO
	SKIPE	S1,.VLUCB(P1)		;SEE IF THERE'S A UCB
	LOAD	TF,.UCBST(S1),UC.DVT	;GET MDA DEVICE CODE

CREA.2:	STORE	TF,.CQFLG(S2),CQ.TYP	;SAVE
	LOAD	S1,.CQFLG(S2),CQ.USE	;GET USE COUNT
	ADDI	S1,1			;PLUS ONE
	STORE	S1,.CQFLG(S2),CQ.USE	;UPDATE
	MOVE	S1,.VLOID(P1)		;GET THE OWNER PPN
	MOVEM	S1,.CQVUS(S2)		;SAVE IT
	MOVEI	S1,.CQQSR		;SET THE BUILD CODE TO SAY
	STORE	S1,.CQFLG(S2),CQ.BLD	; THIS ENTRY WAS CREATED BY QUASAR
	POP	P,.CQNVL(S2)		;INSERT VOLUME COUNT
	MOVEI	S2,.CQVSL(S2)		;POINT TO VOLUME BLOCKS

CREA.3:	MOVE	S1,.VLVID(P1)		;GET THE VOLID
	MOVEM	S1,.CQVID(S2)		;SET IT
	MOVE	S1,.VLUCB(P1)		;GET THE UNIT THIS VOLUME IS ON
	LOAD	S1,.UCBST(S1),UC.RSN	;GET THE UNIT RESOURCE NUMBER
	MOVEM	S1,.CQRSN(S2)		;SET IT
	ADDI	S2,.CQVLL		;POINT TO THE NEXT VOLID BLOCK
	LOAD	P1,.VLPTR(P1),VL.NXT	;GET THE NEXT VOL BLK ADDRESS
	JUMPN	P1,CREA.3		;CONTINUE IF THERE IS ONE
	SKIPN	S1,CATOLD		;WAS THERE AN OLD ENTRY?
	$RETT				;NO
	MOVE	S2,CATNEW		;GET THE NEW ENTRY
	PUSHJ	P,V$COMP		;COMPARE THE TWO
	POPJ	P,			;RETURN TRUE OR FALSE

CREA.4:	$WTO	(<Internal catalog cache error>,<^I/CREA.T/>,,<$WTFLG(WT.SJI)>)
	$RETF				;RETURN

CREA.T:	ITEXT	(<Cannot create entry for ^T/CATTMP/>)
SUBTTL	V$DELE - Delete a non-sharable volume-set from the cache
SUBTTL	V$DELS - Delete a sharable volume-set from the cache


; Call:	MOVE	S1, address of ASCIZ volume-set name
;	PUSHJ	P,V$DELE/V$DELS
;
; TRUE return:	VSN found and deleted
; FALSE return:	VSN not in the the cache

V$DELE::TDZA	S2,S2			;DELETE ANY  ENTRY
V$DELS::MOVEI	S2,1			;DELETE SHARABLE RESOURCE ENTRY
	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	DMOVE	P1,S1			;COPY ARGUMENTS
	PUSHJ	P,V$FIND		;SEARCH THE CACHE
	$RETIF				;RETURN IF NO MATCH
	SKIPN	S2,P2			;SKIP IF DELETING A STRUCTURE
	LOAD	S2,.CQFLG(S1),CQ.USE	;GET USE COUNT
	SUBI	S2,1			;MINUS ONE
	STORE	S2,.CQFLG(S1),CQ.USE	;UPDATE
	JUMPG	S2,.RETT		;RETURN IF STILL IN USE
DELETE:	MOVE	S2,S1			;COPY ENTRY ADDRESS
	SETZM	.CQVSN(S2)		;BE DEFENSIVE
	MOVE	S1,CATQUE		;GET LINKED LIST HANDLE
	PUSHJ	P,L%APOS		;POSITION
	SKIPF				;SHOULDN'T HAPPEN
	PUSHJ	P,L%DENT		;DELETE THE ENTRY
	$RETT				;AND RETURN
SUBTTL	V$DUMP - Dump entire cache


; Call:	PUSHJ	P,V$DUMP

V$DUMP::PUSHJ	P,.SAVE4
	PUSHJ	P,.SAVET
	PUSH	P,S1			;SAVE S1
	PUSH	P,S2			;SAVE S2
	SETOM	DMPFLG			;INDICATE DUMP
	SKIPN	CATQUE			;SANITY CHECK
	JRST	DUMP.2			;DONE
	HRROI	S1,DUMP.H		;POINT TO HEADER
	PUSHJ	P,K%SOUT		;PRINT IT
	MOVE	S1,CATQUE		;GET LINKED LIST HANDLE
	PUSHJ	P,L%FIRST		;FIND FIRST ENTRY

DUMP.1:	JUMPF	DUMP.2			;RETURN IF NO MORE
	MOVEI	S1,<CATSIZ*5>-1		;GET CHARACTER COUNT
	MOVEM	S1,CATCNT		;SAVE IT
	MOVE	S1,[POINT 7,CATTXT]	;GET BYTE POINTER
	MOVEM	S1,CATPTR		;SAVE IT
	MOVE	S1,S2			;COPY ENTRY ADDRESS
	PUSHJ	P,V$TYPE		;TYPE IT
	HRROI	S1,CATTXT		;POINT TO TEXT
	PUSHJ	P,K%SOUT		;TYPE IT
	MOVE	S1,CATQUE		;GET LINKED LIST HANDLE
	PUSHJ	P,L%NEXT		;FIND NEXT ENTRY
	JRST	DUMP.1			;LOOP

DUMP.2:	SETZM	DMPFLG			;DUMP COMPLETED
	POP	P,S2			;RESTORE S2
	POP	P,S1			;RESTORE S1
	POPJ	P,			;RETURN


DUMP.H:	ASCIZ	/
 Addr    Use               Volume Set Name              Volume  Resource
------  -----  ---------------------------------------  ------  --------
/
SUBTTL	V$DISA - Disable catalog updates by MDA
SUBTTL	V$ENAB - Enable catalog updates by MDA


V$DISA::TDZA	S1,S1			;DISABLE
V$ENAB::MOVEI	S1,1			;ENABLE
	SKIPN	S2,.OFLAGS(M)		;GET CATALOG DEVICE TYPE
	PJRST	V$CERR			;NO DEVCE?
	CAIN	S2,.CTDTA		;DECTAPE?
	MOVEM	S1,DTAFLG		;YES
	CAIN	S2,.CTMTA		;MAGTAPE?
	MOVEM	S1,MTAFLG		;YES
	CAIN	S2,.CTSTR		;STRUCTURE?
	MOVEM	S1,STRFLG		;YES
	$RETT				;RETURN
SUBTTL	V$EXTV - Extend a volume-set


; Notify [SYSTEM]CATALOG of a possible volume-set extension
; Call:	MOVE	S1, VSL address
;	PUSHJ	P,V$EXTV

V$EXTV::PUSHJ	P,.SAVE3		;SAVE SOME ACS
	MOVE	P1,S1			;COPY VSL
	MOVEI	S1,.VSVSN(P1)		;POINT TO VOLUME-SET NAME
	PUSHJ	P,V$FIND		;SEARCH THE CACHE
	$RETIF				;DON'T BOTHER IF NOT CACHED
	MOVE	P2,S1			;COPY CACHE ENTRY ADDRESS
	LOAD	S1,.VSCVL(P1),VS.CNT	;GET TOTAL VOLS IN THIS VOLUME-SET
	CAMG	S1,.CQNVL(P2)		;REALLY A VOL SWITCH?
	$RETT				;NO
	LOAD	S1,.CQFLG(P2),CQ.TYP	;GET MDA DEVICE CODE
	PUSHJ	P,QCDEV			;TRANSLATE TO CATALOG CODE
	MOVEM	S1,EXTDEV		;SAVE IN MESSAGE
	MOVSI	S1,.CQVSN(P2)		;POINT TO VOLUME-SET NAME
	HRRI	S1,EXTVSN		;AND STORAGE IN MESSAGE
	BLT	S1,EXTVSN+VSNSIZ-1	;COPY
	LOAD	P3,.VSCVL(P1),VS.OFF	;GET OFFSET TO CURRENT VOL
	ADDI	P3,.VSVOL(P1)		;POINT TO ADDRESS OF VOL
	MOVE	P3,(P3)			;GET VOL ADDRESS
	$TEXT	(<-1,,EXTUNI>,<^W/.VLNAM(P3)/^0>) ;COPY TO MESSAGE
	PUSHJ	P,EXTSND		;SEND MESSAGE TO [SYSTEM]CATALOG
	PUSHJ	P,EXTCAT		;ADD NEW VOL TO CATALOG CACHE
	$RETT				;RETURN
; Here to actually send the message to [SYSTEM]CATALOG
EXTSND:	PUSHJ	P,M%GPAG		;GET A PAGE
	MOVEI	S2,.CFMOD		;FUNCTION CODE
	STORE	S2,.MSTYP(S1),MS.TYP
	MOVEI	S2,.OHDRS+EXTLEN	;LENGTH OF MESSAGE
	STORE	S2,.MSTYP(S1),MS.CNT
	MOVEI	S2,^D8			;ARGUMENT BLOCK COUNT
	MOVEM	S2,.OARGC(S1)
	MOVSI	S2,EXTMSG		;POINT TO STATIC BLOCK
	HRRI	S2,.OHDRS(S1)		;AND TO THE DESTINATION
	BLT	S2,.OHDRS+EXTLEN-1(S1)	;COPY
	MOVEM	S1,G$SAB##+SAB.MS	;SAVE MESSAGE ADDRESS
	LOAD	S2,.MSTYP(S1),MS.CNT	;GET MESSAGE SIZE
	MOVEM	S2,G$SAB##+SAB.LN	;SAVE
	PJRST	V$SEND			;SEND TO [SYSTEM]CATALOG


EXTMSG:	XWD	2,.CMKEY		;DEVICE TYPE
EXTDEV:	EXP	.CTMTA
	XWD	VSNSIZ+1,.CMFLD		;VOLUME-SET NAME
EXTVSN:	BLOCK	VSNSIZ
	XWD	1,.CMCFM		;CRLF
	XWD	2,.CMKEY		;ADD
	EXP	.CTADD
	XWD	3,.CMFLD		;REELID
EXTUNI:	BLOCK	2
	XWD	1,.CMCFM		;CRLF
	XWD	2,.CMKEY		;DONE
	EXP	.CTDON
	XWD	1,.CMCFM		;CRLF
EXTLEN==.-EXTMSG			;LENGTH OF MESSAGE
; Here to expand the catalog cache entry
EXTCAT:	MOVE	S1,CATQUE		;POINT TO QUEUE HEADER
	PUSHJ	P,L%SIZE		;GET SIZE OF THIS ENTRY
	$RETIF				;CAN'T EXTEND CACHE
	PUSH	P,S2			;SAVE IT
	ADDI	S2,.CQVLL		;PLUS WHAT'S NEEDED FOR ANOTHER BLOCK
	PUSHJ	P,L%CENT		;CREATE A NEW ENTRY
	POP	P,S1			;RESTORE OLD LENGTH
	$RETIF				;CAN'T EXTEND CACHE
	PUSH	P,S2			;SAVE NEW ADDRESS
	ADDI	S1,(S2)			;COMPUTE END OF BLT
	HRLI	S2,(P2)			;MAKE A BLT POINTER
	BLT	S2,-1(S1)		;COPY
	MOVE	S2,.VLNAM(P3)		;GET VOL NAME
	MOVEM	S2,.CQVID(S1)		;SAVE IN CACHE
	MOVE	S2,.VLUCB(P3)		;GET THE UCB ADDRESS
	LOAD	S2,.UCBST(S2),UC.RSN	;AND IT'S PHYSICAL RESOURCE NUMBER
	MOVEM	S2,.CQRSN(S1)		;SAVE IN CACHE
	POP	P,S1			;GET NEW ADDRESS BACK
	AOS	.CQNVL(S1)		;COUNT THE NEW VOLUME
	MOVE	S1,P2			;COPY OLD CACHE ENTRY ADDRESS
	PJRST	DELETE			;DELETE IT AND RETURN
SUBTTL	V$GCAT - Get catalog information


; Routine to get catalog informat.  First, QUASAR's catalog
; cache is checked.  If the entry isn't found, a request will
; be sent to [SYSTEM]CATALOG for the necessary information.
; Call:	MOVE	S1, [-1,,VSN address]	;IF AN INTERNAL REQUEST
;	MOVE	S1, [0,,VSN address]	;IF A USER REQUEST
;	PUSHJ	P,V$GCAT
;
; TRUE return:	VSN found in cache, VSL and VOLs updates, S1=VSL address
; FALSE return:	VSN not in cache

V$GCAT::PUSHJ	P,.SAVE4		;SAVE SOME ACS
	SKIPL	P1,S1			;SAVE CALLING PARMS, SKIP IF INTERNAL
	MOVEI	S1,.VSVSN(P1)		;POINT TO THE ASCIZ VOLUME SET NAME
	PUSHJ	P,V$FIND		;FIND IT IN OUR CATALOG CACHE
	JUMPF	GCAT.2			;NOT THERE,,GO REQUEST IT
	LOAD	S2,.CQFLG(S1),CQ.USE	;GET USE COUNT
	ADDI	S2,1			;PLUS ONE
	STORE	S2,.CQFLG(S1),CQ.USE	;UPDATE
	LOAD	S2,.CQFLG(S1),CQ.TYP	;GET MDA DEVICE CODE
	SKIPL	P1			;SKIP IF AN INTERNAL REQUEST
	STORE	S2,.VSFLG(P1),VS.TYP	;MARK THIS VOLUME SET
	MOVE	P4,P1			;COPY VSL INTO P4
	MOVE	P1,S1			;COPY ENTRY INTO P1
	PUSHJ	P,CQVSL			;DO VSL SPECIFIC PROCESSING
	MOVN	P3,.CQNVL(P1)		;GET NUMBER OF VOLUMES IN VOLUME-SET
	HRLZS	P3			;PUT IN LH
	HRRI	P3,.CQVSL(P1)		;POINT TO START OF VOLUME ENTRY BLOCKS

GCAT.1:	PUSHJ	P,CQVOLX		;DO VOLUME BLOCK PROCESSING
	$RETIF				;SHOULD NEVER FAIL
	ADDI	P3,.CQVLL-1		;ADVANCE CATALOG CACHE POINTER
	AOBJN	P3,GCAT.1		;LOOP FOR ALL VOLUME BLOCKS
	MOVE	S1,P4			;COPY POSSIBLY NEW VSL ADDRESS
	$RETT				;AND RETURN

GCAT.2:	MOVEI	P2,CATMSG		;GET A TEMP MSG BUFFER
	MOVEM	P2,G$SAB##+SAB.MS	;SAVE IT IN THE SAB
	MOVE	S1,[.OHDRS+1,,.CFRCT]	;GET REQUEST FOR CATALOG INFO HEADER
	MOVEM	S1,.MSTYP(P2)		;SAVE IT
	SETOM	S2			;INDICATE 'NOT A USER' REQUEST
	SKIPL	P1			;UNLESS WE POINT TO A VSL
	LOAD	S2,.VSRID(P1),VS.RID	;THEN GET THE REQUEST ID
	MOVEM	S2,.MSCOD(P2)		;SAVE THE ACK CODE (RID OR -1)
	SETZM	.MSFLG(P2)		;NO FLAG WORD
	SETZM	.OFLAG(P2)		;NO MESSAGE FLAG WORD
	MOVEI	S1,1			;GET A BLOCK COUNT OF 1
	MOVEM	S1,.OARGC(P2)		;SAVE IT
	MOVEI	P2,.OHDRS(P2)		;POINT TO THE FIRST (ONLY) MSG BLOCK
	MOVE	S1,[.CTVSL+ARG.DA,,.CTVSB] ;GET VOLUME SET NAME BLOCK HEADER
	MOVEM	S1,ARG.HD(P2)		;SAVE IT
	MOVEI	P3,ARG.DA(P2)		;POINT TO FIRST DATA WORD
	LOAD	S1,.VSFLG(P1),VS.TYP	;GET MDA DEVICE CODE
	PUSHJ	P,QCDEV			;TRANSLATE TO CATALOG DEVICE CODE
	STORE	S1,.CTVFL(P3),CT.TYP	;SAVE IN MESSAGE
	SETZM	S1			;CLEAR S1 (USE AS BYTE COUNTER)
	SKIPL	P1			;IF INTERNAL,,SKIP
	MOVEI	P1,.VSVSN(P1)		;POINT TO THE VOL SET NAME
	HRLI	P1,(POINT 7,0)		;MAKE THE VOL SET NAME ADDR A BYTE PTR
	MOVE	S2,[POINT 7,.CTVSN(P3)]	;GET THE DESTINATION BYTE POINTER
GCAT.3:	ILDB	TF,P1			;GET A VOLUME SET NAME BYTE
	IDPB	TF,S2			;INSERT IT INTO THE MESSAGE
	AOS	S1			;BUMP BYTE COUNT BY 1
	JUMPN	TF,GCAT.3		;CONTINUE TILL ASCIZ
	MOVEI	S1,.CTVSL+ARG.DA	;SIZE OF BLOCK
	LOAD	S2,CATMSG+.MSTYP,MS.CNT	;GET CURRENT LENGTH
	ADDI	S1,(S2)			;ACCUMULATE
	STORE	S1,CATMSG+.MSTYP,MS.CNT	;UPDATE
	MOVEM	S1,G$SAB##+SAB.LN	;SAVE IT IN THE SAB
	PUSHJ	P,V$SEND		;SEND IT OFF TO THE TAPE LABELER
	$RETF				;AND RETURN
SUBTTL	V$FIND - Find a volume-set in the cache


; Call:	MOVE	S1, address of ASCIZ volume-set name
;	PUSHJ	P,V$FIND
;
; TRUE return:	S1 contains the entry address
; FALSE return:	Volume-set not cached

V$FIND::PUSHJ	P,.SAVE3		;SAVE SOME ACS
	MOVE	P1,S1			;SAVE THE VOL SET NAME
	HRLI	P1,(POINT 7,)		;MAKE A BYTE POINTER
	MOVE	S1,CATQUE		;GET THE CATALOG QUEUE ID
	PUSHJ	P,L%FIRST		;GET THE FIRST ENTRY
	JRST	FIND.2			;JUMP THE FIRST TIME THROUGH

FIND.1:	MOVE	S1,CATQUE		;GET THE CATALOG QUEUE ID
	PUSHJ	P,L%NEXT		;GET THE NEXT ENTRY

FIND.2:	JUMPF	.RETF			;NOT THERE,,RETURN NO GOOD
	MOVE	P2,P1			;COPY POINTER TO TARGET
	MOVEI	P3,.CQVSN(S2)		;POINT TO THIS NAME
	HRLI	P3,(POINT 7,)		;MAKE A BYTE POINTER

FIND.3:	ILDB	TF,P2			;GET A CHARACTER
	ILDB	S1,P3			;HERE TOO
	CAIE	TF,(S1)			;MATCH?
	JRST	FIND.1			;NO
	ADDI	TF,(S1)			;ADD THEM
	JUMPN	TF,FIND.3		;LOOP 'TIL END OF STRING
	MOVE	S1,S2			;VOLUME-SET NAMES MATCH
	$RETT				;AND RETURN
SUBTTL	V$RCAT - Response from [SYSTEM]CATALOG

V$RCAT::MOVX	S1,MF.FAT		;GET FATAL BIT
	TDNE	S1,.MSFLG(M)		;KNOWN VOLUME-SET?
	JRST	RCAT.E			;NO
	PUSHJ	P,.SAVE4		;SAVE SOME ACS
	MOVX	S1,.CTVSB		;VOLUME-SET BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT
	JUMPF	RCAT.6			;NOT THERE,,THATS AN ERROR
	MOVEI	P2,(S1)			;PUT BLOCK ADDRESS IN P2
	HRROI	S1,.CTVSN(P2)		;POINT TO VSN TEXT
	PUSHJ	P,S%SIXB		;CONVERT TO SIXBIT
	MOVEM	S2,MDAOBJ##+OBJ.UN	;SAVE
	SETZ	P4,			;ASSUME NOT A USER REQUEST
	SKIPN	S1,.MSCOD(M)		;GET THE ACK CODE (MDR ID)
	JRST	RCAT.6			;NONE THERE,,THATS AN ERROR
	CAMN	S1,[-1]			;IS IT -1 ???
	JRST	RCAT.0			;YES,,NOT A USER REQUEST
	PUSHJ	P,D$FVSL##		;FIND THE VSL FOR THIS USER
	JUMPF	RCAT.0			;NOT THERE,,SKIP THIS
	MOVE	P4,S1			;SAVE THE VSL ADDRESS

RCAT.0:	SETZM	CATOLD			;CLEAR OLD CATALOG ENTRY ADDRESS
	MOVEI	S1,.CTVSN(P2)		;POINT TO VOLUME-SET NAME TEXT
	PUSHJ	P,V$FIND		;TRY TO FIND THE VOL SET IN THE CATALOG
	SKIPF				;FOUND IT?
	MOVEM	S1,CATOLD		;YES - REMEMBER THE ADDRESS

	;Here to create an entry in the Vol Set Catalog

	MOVE	S1,CATQUE		;GET THE CATALOG QUEUE ID
	PUSHJ	P,L%LAST		;POSITION TO LAST ENTRY
	MOVE	S1,CATQUE		;GET THE CATALOG QUEUE ID
	MOVE	S2,.OARGC(M)		;GET NUMBER OF ARGUMENT BLOCK
	CAIE	S2,1			;JUST ONE (NO VOLUME BLOCKS)?
	SUBI	S2,1			;ACCOUNT FOR VOLUME-SET BLOCK
	IMULI	S2,.CQVLL		;ADD LENGTH OF EACH ENTRY
	ADDI	S2,.CQVSL		;ADD THE HEADER LENGTH
	PUSHJ	P,L%CENT		;CREATE AN ENTRY
	MOVEM	S2,CATNEW		;REMEMBER IT FOR LATER

	PUSH	P,M
	MOVE	P1,S2
	MOVE	M,P2
	PUSHJ	P,C2Q			;COPY FROM CATALOG DATA INTO CACHE
	POP	P,M
	PUSHJ	P,CQVSL			;DO VSL SPECIFIC PROCESSING
	MOVN	P3,.CQNVL(P1)		;GET NUMBER OF VOLUMES IN VOLUME-SET
	HRLZS	P3			;PUT IN LH
	HRRI	P3,.CQVSL(P1)		;POINT TO START OF VOLUME ENTRY BLOCKS
	MOVEI	S1,.CTVLB		;VOLUME BLOCK TYPE
	PUSHJ	P,A$FNDB##		;FIND IT
	JUMPF	RCAT.6			;NOT THERE,,THATS AN ERROR
	MOVEI	P2,(S1)			;PUT BLOCK ADDRESS IN P2
RCAT.1:	PUSHJ	P,CQVOL			;DO VOLUME BLOCK PROCESSING
	JUMPF	RCAT.5			;NO GOOD,,THATS AN ERROR
	LOAD	S1,-ARG.DA(P2),AR.LEN	;GET LENGTH OF BLOCK
	ADDI	P2,(S1)			;ADVANCE MESSAGE POINTER
	ADDI	P3,.CQVLL-1		;ADVANCE CATALOG CACHE POINTER
	AOBJN	P3,RCAT.1		;LOOP FOR ALL VOLUME BLOCKS

RCAT.2:	SKIPN	S1,CATOLD		;HAVE AN OLD ENTRY?
	JRST	RCAT.3			;NO
	MOVE	S2,CATNEW		;GET NEW ENTRY ADDRESS
	MOVEI	TF,.CQCAT		;SET THE BUILD CODE TO SAY
	STORE	TF,.CQFLG(S2),CQ.BLD	; THIS ENTRY CAME FROM [SYSTEM]CATALOG
	PUSHJ	P,V$COMP		;COMPARE THE TWO
	MOVE	P1,S1			;GET THE ENTRY ADDRESS TO USE
	MOVE	S2,S1			;...
	MOVE	S1,CATQUE		;GET QUEUE HEADER
	PUSHJ	P,L%APOS		;POSITION THERE

RCAT.3:	LOAD	S2,.CQFLG(P1),CQ.USE	;GET USE COUNT
	ADDI	S2,1			;PLUS ONE
	STORE	S2,.CQFLG(P1),CQ.USE	;UPDATE
	JUMPE	P4,.RETT		;RETURN IF AN INTERNAL REQUEST
	MOVE	S1,P4			;GET THE VSL ADDRESS
	PUSHJ	P,D$ALOC##		;TRY TO COMPLETE ALLOCATION
	JUMPF	[JUMPL	S1,.RETT	;ALLOCATION POSTPONED,,JUST RETURN
		 MOVE	S1,P4		;NO GOOD,,GET THE VSL ADDRESS BACK
		 PJRST	D$DLVS##]	;  AND DELETE THE VOL SETS JUST ADDED

RCAT.4:	LOAD	S2,.MRJOB(AP),MR.JOB	;GET THE PROCESS JOB NUMBER
	MOVE	S1,P4			;GET THE VSL ADDRESS BACK
	TXNE	S2,BA%JOB		;IS THIS A PSEUDO PROCESS ??
	MOVE	S1,.MRVSL(AP)		;YES,,MOUNT TO THE FIRST VSL
	PUSHJ	P,D$MNTV##		;TRY TO MOUNT THE USERS REQUEST
	$RETT				;RETURN IN ANY CASE

RCAT.5:	MOVE	S1,CATQUE		;GET THE QUEUE ID
	PUSHJ	P,L%DENT		;DELETE THE CURRENT ENTRY
	JUMPE	P4,.RETT		;AN INTERNAL REQUEST,,RETURN
	$TEXT	(<-1,,G$MSG##>,<Can't mount volume set ^T/.VSVSN(P4)/ - No drives available^M^J^0>)
	SETOM	ERRACK##		;INDICATE AN ERROR ACK
	MOVE	S1,P4			;[1173] GET VSL ADDRESS
	SETOM	S2			;[1173] USE MDR ACK DATA IF VALID
	PUSHJ	P,D$USRN##		;TELL THE USER
	MOVE	S1,P4			;GET THE VSL ADDRESS
	PUSHJ	P,D$REMO##		;DELETE THIS VSL AND RETRY THE MOUNT
	$RETT				;RETURN

RCAT.6:	PUSHJ	P,V$CERR		;REPORT ERROR
	$RETT				;AND RETURN
; Here on catalog NAKs
RCAT.E:	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	SKIPG	S1,.MSCOD(M)		;GET THE ACK CODE
	$RETT				;INTERNAL REQUEST,,RETURN NOW
	PUSHJ	P,D$FVSL##		;FIND THE VSL
	JUMPF	.RETT			;NOT THERE,,JUST RETURN
	MOVE	P1,S1			;SAVE THE VSL ADDRESS
	MOVE	AP,.VSMDR(P1)		;SETUP THE MDR ADDRESS
	$TEXT	(<-1,,G$MSG##>,<^I/RCAT.T/^M^J^0>)
	SETOM	ERRACK##		;THIS IS AN ERROR ACK
	MOVE	S1,P1			;GET VSL ADDRESS
	SETZM	S2			;USE VSL ACK DATA
	PUSHJ	P,D$USRN##		;ACK THE USER
	MOVE	S1,P1			;GET THE VSL ADDRESS BACK
	PUSHJ	P,D$REMO##		;GO AND DELETE THIS VSL & RETRY MOUNT
	HRROI	S1,.VSVSN(P1)		;POINT TO THE ASCIZ VOL SET NAME
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVE	S1,S2			;MOVE IT TO S1
	PUSHJ	P,D$SRSN##		;GET THE RESOURCE NUMBER
	PUSHJ	P,D$GVRS##		;TRY TO RETURN IT
	$RETT				;RETURN

RCAT.T:	ITEXT	(<Volume-set "^T/.VSVSN(P1)/" is not cataloged>)
SUBTTL	V$SEND - Send a message to [SYSTEM]CATALOG


V$SEND::MOVX	S1,SI.FLG+SP.CAT	;SPECIAL INDEX FOR THE CATALOG MANAGER
	MOVEM	S1,G$SAB##+SAB.SI	;SAVE IT IN THE SAB
	SETZM	G$SAB##+SAB.PD		;ZAP THE SAB PID WORD
	PUSHJ	P,C$SEND##		;SEND THE MESSAGE OFF
	$RETT				;AND RETURN
SUBTTL	V$STRG - Convert SIXBIT volume-set names to ASCIZ


; Call:	MOVE	S1, SIXBIT name
;	PUSHJ	P,V$STRG
;
; TRUE return:	S1 contains the address of ASCIZ name
; FALSE return:	Never

V$STRG::MOVE	S2,[CATTMP,,CATTMP+1]	;SET UP BLT
	SETZM	CATTMP			;CLEAR FIRST WORD
	BLT	S2,CATTMP+VSNSIZ-1	;CLEAR ENTIRE BLOCK
	PUSH	P,[POINT 7,CATTMP]	;BYTE POINTER TO RESULT
	MOVE	S2,S1			;COPY NAME

STRG.1:	LSHC	S1,6			;SHIFT IN A CHARACTER
	ANDI	S1,77			;STRIP OFF JUNK
	ADDI	S1,40			;CONVERT TO ASCII
	IDPB	S1,(P)			;STORE CHARACTER
	JUMPN	S2,STRG.1		;LOOP
	POP	P,(P)			;PHASE STACK
	MOVEI	S1,CATTMP		;POINT TO ASCIZ TEXT
	POPJ	P,			;AND RETURN
SUBTTL	V$TYPE - Type a catalog entry


; Call:	MOVE	S1, entry address
;	PUSHJ	P,V$TYPE

V$TYPE::PUSHJ	P,.SAVE3		;SAVE SOME ACS
	MOVE	P1,S1			;SAVE ENTRY ADDRESS
	SKIPE	DMPFLG			;DUMPING?
	$TEXT	(TYPE.T,<^O6R0/P1/  ^A>);YES--PUT OUT ENTRY ADDRESS
	LOAD	S1,.CQFLG(P1),CQ.USE	;GET USE COUNT
	$TEXT	(TYPE.T,<^D5R /S1/  ^T39L /.CQVSN(P1)/  ^A>)
	MOVEI	P2,.CQVSL(P1)		;POINT TO START OF VOLUME BLOCKS
	MOVEI	P3,1			;START WITH THE FIRST VOLUME

TYPE.1:	CAIN	P3,1			;FIRST TIME?
	JRST	TYPE.2			;YES
	MOVEI	S1," "			;GET A SPACE
	MOVEI	S2,^D48			;NORMAL DISPLAY COLUMNS TO PAD
	SKIPE	DMPFLG			;DUMPING?
	MOVEI	S2,^D56			;YES (ENTRY ADDRESS INCLUDED)
	PUSHJ	P,TYPE.T		;PUT OUT A SPACE
	SOJG	S2,.-1			;LOOP

TYPE.2:	MOVE	S1,.CQRSN(P2)		;GET RESOURCE NUMBER
	IMULI	S1,AMALEN		;GET 'A' MATRIX OFFSET
	ADD	S1,AMATRX##		;COMPUTE RESOURCE ENTRY IN MATRIX
	LOAD	S1,.AMNAM(S1),AM.NAM	;GET ADDRESS OF ASCIZ RESOURCE NAME
	$TEXT	(TYPE.T,<^W6L /.CQVID(P2)/  ^T/(S1)/>)
	ADDI	P2,.CQVLL		;POINT TO NEXT VOL BLOCK
	CAMGE	P3,.CQNVL(P1)		;DONE?
	AOJA	P3,TYPE.1		;LOOP FOR ANOTHER VOLUME
	MOVEI	S1,.CHNUL		;GET A NUL

TYPE.T:	SOSLE	CATCNT			;COUNT CHARACTERS
	IDPB	S1,CATPTR		;STUFF ONE IN THE BUFFER
	$RETT				;RETURN
SUBTTL	Message translation -- VSL table


; Macro to generate translation table
DEFINE	CQ	(R,C,Q),<
	ZZ==0
	REPEAT R,<
		<<C>+ZZ>
		<<Q>+ZZ>
		ZZ==ZZ+1
	> ;;END REPEAT
> ;END CQ MACRO


; Translation table for converting catalog data to QUASAR cache data.
; This table consists of word pairs, each containing a byte pointer
; to some storage.  The format is:
;
; Word 1: byte pointer to catalog data
; Word 2: byte pointer to QUASAR's cache

CQTAB:
CQ VSNSIZ,<POINT   36,.CTVSN(M),35>,<POINT   36,.CQVSN(P1),35>
CQ      1,<POINTR .CTVFL(M),CT.NVL>,<POINT   36,.CQNVL(P1),35>
CQ      1,<POINT   36,.CTVUS(M),35>,<POINT   36,.CQVUS(P1),35>
CQ NAMSIZ,<POINT   36,.CTVNM(M),35>,<POINT   36,.CQVNM(P1),35>
CQ LOCSIZ,<POINT   36,.CTVLO(M),35>,<POINT   36,.CQVLO(P1),35>
CQ      1,<POINT   36,.CTVSC(M),35>,<POINT   36,.CQVSC(P1),35>
CQLEN==.-CQTAB
SUBTTL	Message translation -- Device code table


; Device code translation
; Format: catalog code,,MDA code
CQDEVT:	XWD	.CTDTA,%DTAP		;DECTAPE
	XWD	.CTMTA,%TAPE		;MAGTAPE
	XWD	.CTSTR,%DISK		;STRUCTURE
	XWD	.CTUNK,%UNKN		;UNKNOWN (MUST BE LAST)
CQDEVL==.-CQDEVT			;LENGTH OF TABLE


MDADVN:	[ASCIZ	/Unknown  /]
	[ASCIZ	/Magtape  /]
	[ASCIZ	/Structure/]
	[ASCIZ	/DECtape  /]
; Copy catalog data to QUASAR's cache
C2Q:	PUSH	P,T1			;SAVE T1
	MOVE	T1,[<-CQLEN/2>,,CQTAB]	;AOBJN POINTER
C2Q.1:	LDB	TF,0(T1)		;GET A BYTE
	DPB	TF,1(T1)		;PUT A BYTE
	ADDI	T1,1			;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	T1,C2Q.1		;LOOP
	LOAD	S1,.CTVFL(M),CT.TYP	;GET CATALOG DEVICE CODE
	PUSHJ	P,CQDEV			;TRANSLATE TO MDA DEVICE CODE
	STORE	S1,.CQFLG(P1),CQ.TYP	;SAVE
	POP	P,T1			;RESTORE T1
	POPJ	P,			;AND RETURN


; Copy QUASAR's cache to catalog data
Q2C:	PUSH	P,T1			;SAVE T1
	MOVE	T1,[<-CQLEN/2>,,CQTAB]	;AOBJN POINTER
Q2C.1:	LDB	TF,1(T1)		;GET A BYTE
	DPB	TF,0(T1)		;PUT A BYTE
	ADDI	T1,1			;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	T1,Q2C.1		;LOOP
	LOAD	S1,.CQFLG(P1),CQ.TYP	;GET MDA DEVICE CODE
	PUSHJ	P,QCDEV			;TRANSLATE TO CATALOG DEVICE CODE
	STORE	S1,.CTVFL(M),CT.TYP	;SAVE
	POP	P,T1			;RESTORE T1
	POPJ	P,			;AND RETURN
SUBTTL	Message translation -- VSL processing


CQVSL:	JUMPE	P4,.POPJ		;RETURN IF NO VSL
	SETZM	VOLCUR			;INIT CURRENT VOL NUMBER
	LOAD	S1,.CQFLG(P1),CQ.TYP	;GET MDA DEVICE CODE
	STORE	S1,.VSFLG(P4),VS.TYP	;SET DEVICE TYPE IN VSL
	POPJ	P,			;RETURN
SUBTTL	Message translation -- VOL processing


CQVOL:	PUSHJ	P,CQRSN			;LOAD DEVICE RESOURCE NUMBERS
	$RETIF				;GIVE UP IF ERRORS
CQVOLX:	JUMPE	P4,.RETT		;NO VOL BLOCKS IF NO VSL
	LOAD	S1,.CQFLG(P1),CQ.TYP	;GET MDA DEVICE CODE
	CAIN	S1,%DISK		;STRUCTURE?
	$RETT				;YES--ALL DONE
	MOVE	S1,.CQRSN(P3)		;GET RESOURCE NUMBER
	STORE	S1,.VSATR(P4),VS.RSN	;SAVE AS VSL RESOURCE
	AOS	S1,VOLCUR		;GET CURRENT VOL BLOCK OFFSET
	LOAD	S2,.VSCVL(P4),VS.CNT	;GET VOL COUNT FOR THIS VSL
	CAIG	S1,(S2)			;RUN OUT OF VOL BLOCKS?
	JRST	CQVOL1			;NO
	MOVE	S2,.CQNVL(P1)		;GET NUMBER OF VOLUMES IN VOLUME-SET
	SUBI	S2,-1(S1)		;COMPUTE ADDITIONAL NUMBER NEEDED
	MOVE	S1,P4			;COPY VSL ADDRESS
	PUSHJ	P,D$XVSL##		;EXTEND THE VSL
	$RETIF				;FAILED
	MOVE	P4,S1			;UPDATE NEW VSL ADDRESS IN P4
	MOVE	S1,VOLCUR		;GET CURRENT VOLUME NUMBER

CQVOL1:	ADDI	S1,.VSCVL(P4)		;OFFSET TO THIS VOL POINTER
	MOVE	S1,(S1)			;POINT TO THE VOL BLOCK
	MOVE	S2,.CQVID(P3)		;COPY REAL VOLUME NAME
	MOVEM	S2,.VLNAM(S1)		; INTO VOL BLOCK
	MOVE	S2,.CQVUS(P1)		;GET USER ID (PPN)
	MOVEM	S2,.VLOID(S1)		;SET IN VOL
	LOAD	S2,.CQFLG(P1),CQ.TYP	;GET MDA DEVICE CODE
	JRST	@.+1(S2)		;DISPATCH
	EXP	.RETF			;INVALID CODE
	EXP	CQVMTA			;(%TAPE) MAGTAPES
	EXP	CQVSTR			;(%DISK) STRUCTURES
	EXP	CQVDTA			;(%DTAP) DECTAPES
; Magtapes
CQVMTA:	MOVX	S2,VS.SCR!VS.NEW!VS.DDN!VS.DTK ;LOTS OF BITS
	ANDCAM	S2,.VSFLG(P4)		;CLEAR IN VSL
	MOVX	S2,VL.SCR		;GET SCRATCH BIT
	ANDCAM	S2,.VLFLG(S1)		;CLEAR IN VOL
	LOAD	S2,.CQVSC(P1),CT.LAB	;GET LABEL CODE
	STORE	S2,.VSFLG(P4),VS.LBT	;SET IN VSL
	STORE	S2,.VLFLG(S1),VL.LBT	;SET IN VOL
	LOAD	S2,.CQVSC(P1),CT.DEN	;GET DENSITY CODE
	STORE	S2,.VSATR(P4),VS.DEN	;SET IN VSL
	STORE	S2,.VLFLG(S1),VL.DEN	;SET IN VOL
	MOVX	S2,VL.SRD		;BIT TO SET
	IORM	S2,.VLFLG(S1)		;SET DENSITY FOR USER
	LOAD	S2,.CQVSC(P1),CT.TRK	;GET TRACK CODE
	STORE	S2,.VSATR(P4),VS.TRK	;SET IN VSL
	$RETT				;AND RETURN


; Structures
CQVSTR:	$RETT				;RETURN


; DECtapes
CQVDTA:	MOVX	S2,VS.SCR!VS.NEW	;GET SCRATCH AND NEW BITS
	ANDCAM	S2,.VSFLG(P4)		;CLEAR
	$RETT				;AND RETURN
SUBTTL	Message translation -- Load resource numbers into MDA volume blocks


CQRSN:	LOAD	S1,.CQFLG(P1),CQ.TYP	;GET MDA DEVICE CODE
	JRST	@.+1(S1)		;DISPATCH
	EXP	CQRERR			;INVALID CODE
	EXP	CQRMTA			;(%TAPE) MAGATAPES
	EXP	CQRSTR			;(%DISK) STRUCTURES
	EXP	CQRDTA			;(%DTAP) DECTAPES

; Here when invalid codes detected in catalog message
CQRERR:	PUSHJ	P,V$CERR		;COMPLAIN TO OPR
	$RETF				;AND RETURN


; Magtapes
CQRMTA:	MOVEI	S1,.MTRID(P2)		;POINT TO REELID
	HRLI	S1,(POINT 8,)		;MAKE A BYTE POINTER
	MOVEI	S2,.CQVID(P3)		;POINT TO STORAGE
	HRLI	S2,(POINT 6,)		;MAKE A BYTE POINTER
	
CQRMT1:	ILDB	TF,S1			;GET A CHARACTER
	JUMPE	TF,CQRMT2		;DONE?
	SUBI	TF,40			;CONVERT TO SIXBIT
	ANDI	TF,77			;STRIP OFF JUNK
	IDPB	TF,S2			;STORE
	JRST	CQRMT1			;LOOP FOR ALL CHARACTERS

CQRMT2:	SETZB	S1,S2			;INIT DENSITY AND TRACK CODES
	LOAD	TF,.CQVSC(P1),CT.DEN	;GET DENSITY
	CAIN	TF,.CT200		;200 BPI?
	MOVX	S1,UC.200		;YES
	CAIN	TF,.CT556		;556 BPI?
	MOVX	S1,UC.556		;YES
	CAIN	TF,.CT800		;800 BPI?
	MOVX	S1,UC.800		;YES
	CAIN	TF,.CT160		;1600 BPI?
	MOVX	S1,UC.160		;YES
	CAIN	TF,.CT625		;6250 BPI?
	MOVX	S1,UC.625		;YES
	JUMPE	S1,.RETF		;RETURN IF UNKNOWN DENSITY CODE
	LOAD	TF,.CQVSC(P1),CT.TRK	;GET TRACKS
	CAIN	TF,.CT7TK		;7-TRACKS?
	MOVX	S2,%TRK7		;YES
	CAIN	TF,.CT9TK		;9-TRACKS?
	MOVEI	S2,%TRK9		;YES
	JUMPE	S2,.RETF		;RETURN IF UNKNOWN TRACK CODE
	PUSHJ	P,D$TRSN##		;GET ITS RESOURCE NUMBER
	$RETIF				;GIVE UP IF NO RESOURCE NUMBER
	MOVEM	S1,.CQRSN(P3)		;SAVE IT
	$RETT				;RETURN
; Structures
CQRSTR:	MOVE	S1,.STUID(P2)		;GET UNIT-ID
	MOVEM	S1,.CQVID(P3)		;SAVE IT
	SETZ	S1,			;INIT UNIT STATUS WORD
	LOAD	S2,.STUCH(P2),ST.UKT	;GET KONTROLLER TYPE
	STORE	S2,S1,UC.KTP		;SAVE IT
	LOAD	S2,.STUCH(P2),ST.UTY	;GET UNIT TYPE
	STORE	S2,S1,UC.UTP		;SAVE IT
	PUSHJ	P,D$DRSN##		;GET ITS RESOURCE NUMBER
	$RETIF				;GIVE UP IF NO RESOURCE NUMBER
	MOVEM	S1,.CQRSN(P3)		;SAVE IT
	$RETT				;RETURN


; DECtapes
CQRDTA:	MOVEI	S1,1			;DECTAPES CAN ONLY HAVE
	MOVEM	S1,.CQNVL(P1)		; ONE REEL PER VOLUME-SET
	HRROI	S1,.CQVSN(P1)		;POINT TO THE VSN
	SKIPN	S2,.DTRID(P2)		;TRY FOR THE DECTAPE REELID IF THERE
	PUSHJ	P,S%SIXB		;ELSE CONVERT VSN TO SIXBIT
	MOVEM	S2,.CQVID(P3)		;SAVE REELID
	PUSHJ	P,D$ORSN##		;GET ITS RESOURCE NUMBER
	$RETIF				;GIVE UP IF NO RESOURCE NUMBER
	MOVEM	S1,.CQRSN(P3)		;SAVE IT
	$RETT				;RETURN
; Translate catalog device code to MDA device code
CQDEV:	PUSH	P,T1			;SAVE T1
	MOVE	T1,[-CQDEVL,,CQDEVT]	;AOBJN POINTER
	HLRZ	S2,(T1)			;GET CATALOG DEVICE CODE
	CAIE	S1,(S2)			;MATCH?
	AOBJN	T1,.-2			;LOOP
	HRRZ	S1,(T1)			;GET MDA DEVICE CODE
	POP	P,T1			;RESTORE T1
	POPJ	P,			;RETURN


; Translate MDA device code to catalog device code
QCDEV:	PUSH	P,T1			;SAVE T1
	MOVE	T1,[-CQDEVL,,CQDEVT]	;AOBJN POINTER
	HRRZ	S2,(T1)			;GET MDA DEVICE CODE
	CAIE	S1,(S2)			;MATCH?
	AOBJN	T1,.-2			;LOOP
	HLRZ	S1,(T1)			;GET CATALOG DEVICE CODE
	POP	P,T1			;RESTORE T1
	POPJ	P,			;RETURN
SUBTTL	End


	END