Google
 

Trailing-Edge - PDP-10 Archives - tops20_version7_0_monitor_sources_clock - monitor-sources/cfsusr.mac
There are 13 other files named cfsusr.mac in the archive. Click here to see a list.
; UPD ID= 8605, RIP:<7.MONITOR>CFSUSR.MAC.5,  11-Feb-88 17:11:11 by RASPUZZI
;TCO 7.1220 - Modify CFS global job assignments. Make JBGET1 get more global
;	      jobs if we are out of them and make CFGTJB have another (local)
;	      entry point (CFSGJB) that obtains that extra job chunk.
; UPD ID= 8489, RIP:<7.MONITOR>CFSUSR.MAC.4,   9-Feb-88 12:17:47 by GSCOTT
;TCO 7.1218 - Insert copyright notice.
; UPD ID= 8466, RIP:<7.MONITOR>CFSUSR.MAC.3,   7-Feb-88 18:25:26 by RASPUZZI
;TCO 7.1210 - Correct module name for BUG.s.
; UPD ID= 8358, RIP:<7.MONITOR>CFSUSR.MAC.2,  20-Jan-88 11:41:32 by RASPUZZI
;TCO 7.1190 - Split CFSSRV up. Make CFSPAR and CFSUSR to allow CFSSRV
;             to be assembled and have the ability to obtain a CREF.

;	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 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.
	SEARCH CFSPAR,SCAPAR,PHYPAR,PROLOG

	TTITLE (CFSUSR,,< - CFS User related routines>)
;	M. Raspuzzi January 88

	SALL
	EXTN <HSHDRI,LNGHSH,NSPCQ0,NSPCQ1,WRDHSH>
	DEBUG==1		;Do debugging

	RESCD			;Unless otherwise noted
	Subttl	Table of Contents

;		     Table of Contents for CFSUSR
;
;				  Section		      Page
;
;
;    1. Initialization
;        1.1    CFSJYN/CFSJYX (Join the CFS network) . . . . .   4
;        1.2    CFSCSC (Create private pages)  . . . . . . . .   7
;    2. Support Routines
;        2.1    CFSSPC (Obtain request block space)  . . . . .  10
;        2.2    CFCARV (Carve a block from page pool)  . . . .  12
;        2.3    SNDTIM (Send date and time to new node)  . . .  13
;        2.4    BRDTIM (Send date and time at startup) . . . .  14
;        2.5    CFTADB (Broadcast date and time via STAD)  . .  15
;        2.6    CFSPRT (Return local port number)  . . . . . .  16
;        2.7    CFSNOD (Routine to get node name)  . . . . . .  17
;    3. Global Job Number Routines
;        3.1    JBAVAL (Manage job bit table)  . . . . . . . .  19
;        3.2    JBGET1 (Get global job number for local job) .  20
;        3.3    GL2LCL (Return local job number) . . . . . . .  21
;        3.4    LCL2GL (Return global job number)  . . . . . .  22
;        3.5    CFGTJB (Get jobs at system startup)  . . . . .  23
;    4. DIAG% JSYS Support
;        4.1    CFDIAG (Code for Set CI Unavailable) . . . . .  24
;    5. CNFIG% JSYS Support
;        5.1    CFCIN (Return CFS information) . . . . . . . .  26
;        5.2    CFCSE (Return serial numbers of CFS nodes) . .  27
;        5.3    CFCND (Return list of node names)  . . . . . .  28
;    6. End of CFSUSR  . . . . . . . . . . . . . . . . . . . .  31
	SUBTTL	Initialization -- CFSJYN/CFSJYX (Join the CFS network)

;Routine to join the CFS network. This is called after SETSPD has run
;so that all of the system configuration options have been selected.
;Accepts no arguments, and gives no backtalk (a fair arrangement)

;[7.1011] This routine will print out descriptive messages whenever the
;[7.1011] joining process encounters any problems.

;CFSIFL starts at -2. CFSINI calls CFSJYX, which increments it and
;returns.

CFSJYN::			;Do the join
   IFN CFSSCA,<			;If want an SCA interface
	MOVEI T1,.NDGLN		;Set up to get our name
	MOVEI T2,T3		;The argument block
	MOVE T3,[POINT 8,MYPOR2] ;Where to stash the name
	NODE%			;Get it
	 ERJMP .+1		;If no name, move on
CFSJYX::AOSE CFSIFL		;Time to join up?
	RET			;No
	SAVEAC <P1>		;Save a reg
	STKVAR <DTIMER,REASON>	;[7.1011] Save some work registers
	CALL CFDLSN		;[7.1021] () Open a dump listener
	 NOP			;[7.1021] Don't care about failure
	CALL CFSLSN		;OPEN A LISTENER FIRST
	 NOP			;BETTER WORK
	BLCAL. (SC.SOA,<<.,CFSINT>>) ;[7.1190] Want to know about configuration changes
				;NOTE: This will callback at CFSINT for nodes
				; that are already online
	 NOP
; Now we must wait until we have a CFS connection open to every TOPS-20  
; system already up.  This will allow for a deterministic way to insure that
; we are fully joined to the CI once we return from this routine.

	CALL CFSPRT		;(/T1) Get our own port number
	MOVEM T1,MYPOR4		;Store it
	MOVSI P1,-C%SBLL	;Loop for all the nodes
	MOVEI T1,5		;[7.1011] Store the initial delay time value
	MOVEM T1,DTIMER		;[7.1011] 
	DO.
	  HRRZ T1,P1		;Get the current node
	  CAMN T1,MYPOR4	;Is this our node?
	  JRST CFSJY1		;Yes, skip it
	  CALL PTHSTS		;(T1/T1,T2) What is path status to node
	   EXIT.		;The port is not running - quit
	  TXNN T2,UDB%WA+UDB%WB ;No-response on both wires?
	  JRST CFSJY1		;Yes, skip it
	  TXNE T2,UDB%MA	;No, is node in maintenance mode?
	  JRST CFSJY1		;Yes, skip it
	  SKIPE SBLIST(P1)	;[7.1011] No, is System Block created yet?
	  IFSKP.		;[7.1011] No, so we must wait
	    HRROI T1,[ASCIZ/No System Block created/]  ;[7.1011] Save message
	    MOVEM T1,REASON	;[7.1011] 
	    JRST CFSJY2		;[7.1011] Go and wait a second
	  ENDIF.		;[7.1011] 
	  HRRZ T2,P1		;Get the node number again
	  CALL ISIT20		;(T2/) Is this a TOPS-20 system?
	   JRST CFSJY1		;No, skip it
	  HRRZ T1,P1		;Get node number
	  CALL CFCNCK		;(T1/) Is there a CFS connection?
	  IFNSK.		;No, there should be so we will wait
	    HRROI T1,[ASCIZ/No CFS connection/]  ;[7.1011] Save message
	    MOVEM T1,REASON	;[7.1011] 
CFSJY2:	    SOSL DTIMER		;[7.1011] Should a message be given?
	    IFSKP.		;[7.1011] Yes
	      HRROI T1,[ASCIZ/
%CANNOT JOIN CLUSTER WITH NODE /]  ;[7.1011] Print first part of message
	      CALL PMES		;[7.1011] (T1/)
	      HRRZ T1,P1	;[7.1011] Now print the node number in decimal
	      CALL PNUM		;[7.1011] (T1/)
	      HRROI T1,[ASCIZ/ BECAUSE: /]  ;[7.1011]
	      CALL PMES		;[7.1011] (T1/)
	      MOVE T1,REASON	;[7.1011] Finally, print the reason
	      CALL PMES		;[7.1011] (T1/)
	      HRROI T1,CRLF	;[7.1011] End with a CRLF
	      CALL PMES		;[7.1011] (T1/)
	      MOVEI T1,^D60	;[7.1011] Now, set the delay timer to 60 to...
	      MOVEM T1,DTIMER	;[7.1011] ...delay message for about 1 minute.
	    ENDIF.		;[7.1011] 
	    MOVEI T1,^D1000	;Wait for a second
	    DISMS
	    LOOP.		;Try again
	  ENDIF.
CFSJY1:   MOVEI T1,5		;[7.1011] Reset delay time value
          MOVEM T1,DTIMER	;[7.1011] 
	  AOBJN P1,TOP.		;Continue with next node
	ENDDO.			;All done - we have joined the cluster
	SETONE SCVER		;str verify in job 0
	AOS JB0FLG		; so awake it
	ENDSV.			;[7.1011]
   >	;IFN CFSSCA
	RET			;AND DONE
	SUBTTL	Initialization -- CFSCSC (Create private pages)

;Routine called from JOB 0 start up to create private stock of pages.

CFSCSC::EA.ENT
	SAVEQ
	CALL CFSDIN		;Do basic set up
   REPEAT 0,<			;DONE IN PGRINI, NOT NEEDED HERE
	CALL ASSPTL		;Get an SPT slot for the map
	TDO T1,SHRPTR		;Make a share pointer out of it
	MOVEM T1,MSECTB+CFSSEC	;Stash in the EPT

;Section map all set up. Now put a page in it.

	HRRZS T1		;Get SPT index only
	CALL SWPIN1		;Create a page table for our use
   >
	MOVEI Q1,LNGHSH		;Get words in long entries
	ADDI Q1,WRDHSH		;Add words in short entries
	ADDI Q1,HSHLEN+CFSSLN+DMPSLN+PGSIZ+PGSIZ-1 ;[7.1021] Add extra words
   IFN CFSSCA,<			;If an SCA interface...
	ADDI Q1,NOFN+HSTSIZ	;Add in extra data bases
	ADDI Q1,VOTLEN+STRN	;And the extras if SCA is supported
   >	;IFN CFSSCA
	LSH Q1,-PGSFT
	MOVNI Q1,1(Q1)		;Get -(n+1)
	HRLZS Q1
	DO.
	  MOVSI T1,CFSSEC	;The section
	  HRRI T1,0(Q1)		;The page
	  CALL MLKMA		;Lock it down
	  ADDI Q1,PGSIZ-1	;Increase by appropriate amount
	  AOBJN Q1,TOP.		;Do them all
	ENDDO.			;All pages now created
;Now create queue entries
;First, the vote queues

	MOVSI Q2,CFSSEC		;Start at the beginning
	HRRI Q2,HSHLEN		;Start after the hash table
   IFN CFSSCA,<			;Only need this if doing SCA stuff
	MOVEM Q2,OLDTAB		;Base of OLDTAB
	ADDI Q2,HSTSIZ
	MOVEI Q1,NVOTQ0		;Number of vote packets
	DO.
	  LOAD T1,PGWD,Q2	;Get page offset in the address
	  ADDI T1,VOTSIZ-1	;See if this fits on the page
	  CAIL T1,PGSIZ		;Does it?
	  IFNSK.		;If not
	    MOVE T1,Q2		;No. See if they are usable anyway
	    CALL CPPCON		;Check if they are contiguous
	    ANNSK.		;If not
	      TXZ Q2,PGWD	;put on page boundary
	      ADDI Q2,PGSIZ	; next page, that is
	  ENDIF.
IFN DEBUG,<
	  MOVE T3,[252525]
	  STOR T3,CFGWD,(Q2)  	;Store unique guard word
  >				;IFN DEBUG
	  MOVE T3,Q2		;The address
	  PIOFF
	  CALL CFSWDN		;Enqueue this one
	  PION
	  ADDI Q2,VOTSIZ	;Next address
	  SOJG Q1,TOP.		;Do them all
	ENDDO.			;Vote packets on the queue
   >	;IFN CFSSCA
;Now do the hash packest

	MOVEI Q1,NSPCQ0		;The number to do
	DO.
	  MOVE T1,Q2		;Next one
	  EXCH T1,CFSPCQ	;Put it on
	  MOVEM T1,@CFSPCQ	;And link rest to it
	  ADDI Q2,HSHSIZ	;Next entry
	  SOJG Q1,TOP.		;Do them all
	ENDDO.			;All done

;Now allocate long packets. Always need these, even for non-SCA systems

	MOVEI Q1,NSPCQ1		;Number to get
	DO.
	  MOVE T1,Q2		;Next one
	  EXCH T1,CFSPQL	;Enqueue it
	  MOVEM T1,@CFSPQL	;Link it in
	  ADDI Q2,HSHSIZ+HSHDRI	;Length of an entry
	  SOJG Q1,TOP.
	ENDDO.
   IFN CFSSCA,<			;If SCA present
	MOVEM Q2,CFSSTR		;STR transaction table
	ADDI Q2,STRN		;# of structures
	MOVEM Q2,CFSOFN		;Beginning of OFN pointer table
	ADDI Q2,NOFN
   >	;IFN CFSSCA
	MOVEM Q2,CFSSTK		;Put the stack here
	ADDI Q2,CFSSLN		;[7.1021] Goto beginning of dump stack
	MOVEM Q2,DMPSTK		;[7.1021] Save the address
	ADDI Q2,PGSIZ+DMPSLN	;[7.1021] Get to the guard page
	MOVE T1,Q2		;Copy it
	ADDI Q2,PGSIZ		;Get to the next page
	TXZ Q2,PGSIZ-1		;And to the first word
	MOVEM Q2,CFNXPG		;Next free cell
	CALL FPTA		;Get ID
	MOVX T2,PTCACH		;Read-only
	CALLRET MSPACS		;Set it
 	SUBTTL	Support Routines -- CFSSPC (Obtain request block space)

;Routine to acquire a request block.
;Returns:
;	+1/ no space
;	+2 /success. T1/ block address

CFSSPC::PIOFF
	SKIPN T1,CFSPCQ		;A PACKET HERE?
	IFSKP.			;If so
	  MOVE T2,0(T1)		;Get the link
	  MOVEM T2,CFSPCQ	;Pop the stack
	  PION
	  AOS CFGTSH		;Count this event
	  XMOVEI T2,SHTADD
	  SETZM HSHPST(T1)
	  SETZM HSHOKV(T1)	;No clla-back for voting
	  MOVEM T2,HSHRET(T1)
	  SETZM HSFLAG(T1)	;And the flags
	  RETSKP		;AND SUCCESS
	ENDIF.
	PION			;Nothing here.
	CALL SPCCOL		;Collect some
	SKIPE CFSPCQ		;Any appear?
	JRST CFSSPC		;Yep. Go get it
	MOVEI T1,HSHSIZ		;Size we need
	CALL CFCARV		;Get one please
	CALL SHTADD		;Add it
	JRST CFSSPC		;And try again
;Entry for a long block

CFSSPL::PIOFF
	SKIPN T1,CFSPQL		;Any packets here?
	IFSKP.			;If so
	  AOS CFGTLG		;Count this event
	  MOVE T2,0(T1)		;Pop it
	  MOVEM T2,CFSPQL	;And update the list
	  PION
	  XMOVEI T2,LNGADD
	  SETZM HSHPST(T1)
	  SETZM HSHOKV(T1)	;No call-back for voting
	  MOVEM T2,HSHRET(T1)
	  MOVX T2,HSHLOS	;Say it is long
	  MOVEM T2,HSFLAG(T1)	; and clear other flags
	  RETSKP		;AND SUCCESS
	ENDIF.
	PION
	CALL SPCCOL		;Collect some
	SKIPE CFSPQL		;Any appear?
	JRST CFSSPL		;Yep. Go get it
	MOVEI T1,HSHDRI+HSHSIZ	;Size needed
	CALL CFCARV		;Get one
	CALL LNGADD		;Put it in
	JRST CFSSPL		;And continue

;Coroutine to add a short block to the CFSPCQ queue

SHTADD:	PIOFF
	EXCH T1,CFSPCQ		;Make it the head.
	MOVEM T1,@CFSPCQ	;And link old queu back in
	PION
	RET			;Done

;Coroutine to add a long block to the CFSPQL queue

LNGADD:	PIOFF
	EXCH T1,CFSPQL		;Make it the head
	MOVEM T1,@CFSPQL	;Link old queue back in
	PION
	RET
 	SUBTTL	Support Routines -- CFCARV (Carve a block from page pool)

;Routine to "carve" another block from the page pool
;	T1/ Size Needed
;Returns:	+1 always.
;	T1/ address of block

CFCARV:	NOSKED
	DO.
	  MOVE T2,CFNXSZ	;Get size remaining in pool
	  SUB T2,T1		;Compute remainder
	  IFL. T2		;If not enough
	    PUSH P,T1		;Save size needed
	    MOVE T1,CFNXPG	;Get current address
	    ADD T1,CFNXSZ	;Increment to the next page
	    CALL MLKMA		;Create and lock it
	    POP P,T1		;Recover size
	    MOVEI T2,PGSIZ	;Increment of size
	    ADDM T2,CFNXSZ	;Add it
	    LOOP.
	  ENDIF.
	ENDDO.
	MOVEM T2,CFNXSZ		;Store new size
	EXCH T1,CFNXPG		;Get address
	ADDM T1,CFNXPG		;And increment by new count
	OKSKED
	RET			;And done

;Routine to collect some space when a queue is empty. Used by above routines

SPCCOL:	MOVEI T1,CFSCTM		;Time
	MOVEI T2,SKDCNT		;# to collect
	CALLRET CFSRSX		;Do it
 	SUBTTL	Support Routines -- SNDTIM (Send date and time to new node)

;Send date and time to newly on-line host
;Called from various places in CFSSRV
;	T1/ Local host index
;Sends date and time if it can
;Clobbers T1-T4

   IFN CFSSCA,<			;If SCA support
SNDTIM::ACVAR <W1,W2>
	MOVE W1,T1
	CALL LGTAD		;Do we have TAD?
	CAMN T1,[-1]		;Have it?
	RET			;No. DOn't bother doing the rest
	MOVE W2,T1		;Save it
	CALL GVOTE1		;Get a buffer
	 RET			;None
	MOVEI T2,.CFTAD		;Get function
	STOR T2,CFCOD,(T1)
	MOVEM W2,CFROT(T1)	;Stash the TAD
	MOVEI T2,0(W1)		;Host number
	CALL SCASND		;Send it off
	IFNSK.			;If failed
	  PIOFF
	  CALL CFSWDN		;Return the buffer
	  PION
	ENDIF.
	RET			;And done
	ENDAV.
>	;IFN CFSSCA
  	SUBTTL	Support Routines -- BRDTIM (Send date and time at startup)

;Routine called from MEXEC after date and time is typed in to send
;date and time to any processors that are "inferior" to us.

BRDTIM::
   IFE CFSSCA,<RET>		;If no SCA support, nothing to do
   IFN CFSSCA,<			;If SCA support...
	SAVEQ			;Get some work regs
	CFSLOK			;keep things stable for a bit
	MOVSI Q1,-HSTSIZ	;Set to loop over the host table
	MOVE Q2,MYPORT		;Get our serial number
	DO.
	  SKIPLE CFSHST(Q1)	;Is this one possible around?
	  SKIPL CFHSTS(Q1)	;yes. Still?
	  IFSKP.			;If it is here
	    CAMG Q2,CFSHNM(Q1)	;Are we a bigger wheel?
	    ANSKP.		;If so
	      MOVEI T1,0(Q1)	;Get host index
	      CALL SNDTIM		;Send it the time
	  ENDIF.
	  AOBJN Q1,TOP.		;Do all hosts
	ENDDO.
	CALLRET CFSFAL		;And done
   >	;IFN CFSSCA
 	SUBTTL	Support Routines -- CFTADB (Broadcast date and time via STAD)

;Routine to broadcast date and time. Called from STAD JSYS

CFTADB::
   IFN CFSSCA,<
	CALL LGTAD		;Get local date and time
	BLCAL. (CFSBRD,<T1,[0],[.CFTAD],[0]>) ;Do the sends
   >	;IFN CFSSCA
	RET			;And done
  	SUBTTL	Support Routines -- CFSPRT (Return local port number)

;Routine to return the local port ID to whoever needs it.
;		CALL CFSPRT
;Returns:	+1
;		  T1/ ID

CFSPRT::
   IFE CFSSCA,<CALLRET RETZ>	;If no SCA, return a zero
   IFN CFSSCA,<			;If SCA is present
	CALL SC.PRT		;Ask SCA for the amswer
	 SETZM T1		;If no port, trouble!!!
	RET
   >	;IFN CFSSCA
	SUBTTL	Support Routines -- CFSNOD (Routine to get node name)
;[7.1074]
;CFSNOD - This routine will return the name of a node within a CFS
;cluster given its node number.
;
;Called with:
;	T1/ CI node number
;	CALL CFSNOD
;
;Returns:
;	+1 - Failure, error code in T1
;	+2 - Success with:
;		T1/ CI node number
;		T2 & T3/ 8-bit CI node name

	SWAPCD			;Called from TTMSG% JSYS

CFSNOD::SAVEQ			;Preserve these (Q1 is our counter)
	STKVAR <NODNUM>		;Place holder for node number
	CAIL T1,0		;Too small?
	CAIL T1,C%SBLL		;Or too large?
	RETBAD (TTMSX3)		;Yep, CI node is out of range
	MOVEM T1,NODNUM		;Stash it
	CALL SC.PRT		;(/T1) Get our CI node number
	 RETBAD ()		;Let the caller know an error occurred
	CAME T1,NODNUM		;Is the node supplied ours?
	IFSKP.			;Yes,
	  HRLI Q1,(POINT 7,)	;Get 7 bit byte pointer
	  HRRI Q1,OURNAM	;For our node name
	  HRLI Q2,(POINT 8,)	;Get 8 bit byte pointer for destination
	  HRRI Q2,T2		;It goes here
	  SETZ T3,		;Be sure no garbage is left over
	  DO.			;Do all characters until a null is hit
	    ILDB Q3,Q1		;Get character
	    SKIPN Q3		;Is it a null?
	    EXIT.		;Yes, all done
	    IDPB Q3,Q2		;Not null, stick it in return place
	    LOOP.		;End of loop
	  ENDDO.
	  RETSKP		;Return node name to caller
	ENDIF.
	CIOFF			;No interruptions while we check this
	MOVSI Q1,-HSTSIZ	;Init AOBJN counter
	DO.			;Loop over all entries
	  MOVE T1,CFSHST(Q1)	;Get host entry's CID
	  SKIPL T1		;Just a listener?
	  SKIPN T1		;Or nothing?
	  JRST CFSNO2		;Yes to one, so do next entry
	  CALL SC.NOD		;(T1/T1,T2) Get CI node number for this
	  CAME T2,NODNUM	;Is this the node we want?
	  IFSKP.		;If so
	    LOAD T2,SID,T1	;Get index into CFNNAM table from SID field
	    LSH T2,1		;CFNNAM has 2 words per entry
	    DMOVE T2,CFNNAM(T2)	;Retrieve node name and stash in T2 & T3
	    CION		;And done
	    RETSKP		;Return to user
	  ENDIF.
CFSNO2:	  AOBJN Q1,TOP.		;Do next CFS entry
	ENDDO.
	CION			;Turn CI back on before going back
	RETBAD (TTMSX3)		;All nodes checked, found no match
	SUBTTL	Global Job Number Routines -- JBAVAL (Manage job bit table)

;Routines to manage job bit table.
;First, routine to make a job available
;	T1/ Job to make available
;Returns:	+1
; clobbers all temps

	RESCD

JBAVAL::SKIPN T1		;Job 0 is not reserved, so
	RET			;Just return
	MOVE T4,T1		;Copy ti
	IDIVI T1,^D36		;Compute word and bit offset
	MOVE T2,BITS(T2)	;Get the bit
	IORM T2,JOBMBT(T1)	;Make it available
	ADJBP T4,GLBPTR		;Point to entry in translation table
	MOVEI T3,0		;Get a zero
	DPB T3,T4		;Clear the entry
	RET			;Done
 	SUBTTL	Global Job Number Routines -- JBGET1 (Get global job number for local job)
;[7.1220]
;JBGET1 - Get a free job global for a local job. If there are no free global
;job slots from this system, then try to get another set of 32 jobs. Do this
;only if we have less global jobs than we have NJOBS.
;
; Called with:
;	T1/ Local job number
;	CALL JBGET1
;
; Returns:
;	+1 - Failure, no more global jobs or all jobs in use
;	+2 - Success,
;	     T1/ Global job number

JBGET1::STKVAR <PASS1,JOB>	;[7.1220] Temp storage
	SKIPN T1		;Local Job 0 is always Global Job 0
	RETSKP			;So just return
	SETZM PASS1		;[7.1220] Say we are on pass 1
	MOVEM T1,JOB		;[7.1220] Save argument
JBGET2:	MOVSI T1,-JBWDS		;[7.1220] Scan the table
	DO.
	  SKIPN T2,JOBMBT(T1)	;Anything here?
	  IFSKP.		;If so
	    JFFO T2,.+1		;Find the first
	    MOVE T2,BITS(T3)	;Get the bit
	    ANDCAM T2,JOBMBT(T1) ;Clear it
	    MOVEI T1,0(T1)
	    IMULI T1,^D36	;Compute jobs ahead of this one
	    ADDI T1,(T3)	;Add in the bit
	    MOVEI T2,(T1)	;Copy it
	    ADJBP T2,GLBPTR	;Point to entry in translation table
	    MOVE T4,JOB		;[7.1220] Get local job number back
	    DPB T4,T2		;Store local job number
	    RETSKP		;And done
	  ENDIF.
	  AOBJN T1,TOP.		;Look over them all
	ENDDO.
	SKIPE PASS1		;[7.1220] On pass 1?
	RET			;[7.1220] No, we already tried this
	MOVE T1,GBLCNT		;[7.1220] Get current count of jobs allocated
	CAIL T1,NJOBS		;[7.1220] Do we have enough jobs already?
	RET			;[7.1220] No, all done and no more jobs
	SETOM PASS1		;[7.1220] Flag pass 1 finishing up
	NOINT			;[7.1220] Not interruptable while grabbing resources
	CALL CFSGJB		;[7.1220] (/) Try to get some more jobs
	OKINT			;[7.1220] Can be interrupted now.
	JRST JBGET2		;[7.1220] Now see if we can assign a global job

	ENDSV.			;[7.1220]
	SUBTTL	Global Job Number Routines -- GL2LCL (Return local job number)

;Routine to return the local job number for a global job number.
;	T1/ Global job number
;Returns:	+1 not a local job. T1/ Error code
;		+2 T1/ local job number
;
;Note:	This routine is also called by Non-CFS monitors, since they
;	depend upon it to check the range of the job number supplied.

GL2LCL::SKIPN T1		;Job 0 always returns 0
	RETSKP
	SKIPL T1		;Must be positive
	CAILE T1,MXGLBS		;And must be within range
	RETBAD(GTJIX3)		;Invalid
	IFG. T1
	  ADJBP T1,GLBPTR	;Point to entry
	  LDB T1,T1		;Get the value
	  SKIPE T1		;SKIP if it's zero
	  CAILE T1,NJOBS	;SKIP if it's below the max.
	  RETBAD(GTJIX4)	;Illegal job number
	ENDIF.
	RETSKP			;Else, return the local job number
 	SUBTTL	Global Job Number Routines -- LCL2GL (Return global job number)

;Routine to return the Global Job number, given the local job number.
;Search the Global job number table serially, comparing each entry to
;the desired local job number.  This routine can be very slow, and not
;recommended unless absolutely necessary.
;
;	T1/	Local Job number
;Returns:	+1 No Global job assigned to this local index
;			T1/ Error code
;		+2 T1/ Global Job number
;

LCL2GL::SKIPN T1		;Local Job 0 is always Global Job 0
	RETSKP			;So return good
	CAIL T1,1		;Check for legal local index
	CAILE T1,NJOBS		;Like so
	IFNSK.			;If that didn't skip, job index is bad
	  BUG.(CHK,CFSILJ,CFSUSR,SOFT,<CFSSRV - Illegal Local Job Number>,,<

Cause:	LCL2GL as been called to convert a local job number to a global
	index, but the local job number is invalid.

Action:	If this problem persists, change the CHK to a HLT and determine why
	the caller is passing a bad job number.

>)
	  RETBAD(GTJIX3)	;Return error code for invalid job index
	ENDIF.
	SAVEP			;Save P registers.
	MOVE P1,T1		;Save requested local job number
	MOVSI P4,-MXGLBS	;Build counter
	MOVE P3,GLBPTR		;Get pointer to start of table
	DO.			;Loop through the table
	  MOVEI T1,1(P4)	;Get Current Global Job number in T1
	  ILDB P2,P3		;Get a table entry
	  CAIN P2,(P1)		;Does it match requested number?
	  RETSKP		;Yes.  Simply return
	  AOBJN P4,TOP.		;No, bump counter, and continue loop
	ENDDO.			;end of loop, job not found
	RETBAD(GTJIX4)		;Return 'No such job'.
	SUBTTL	Global Job Number Routines -- CFGTJB (Get jobs at system startup)

;[7.1220]
;CFGTJB/CFSGJB - Routine called to get a block of jobs for this system.
;CFGTJB is called at system startup to get the initial set of jobs and
;CFSGJB is called when all of those jobs are used up.
;
; Called with:
;	no arguments
;	CALL CFGTJB/CFSGJB
;
; Returns:
;	+1 - Always

CFSGJB:	SAVEQ			;[7.1220] Save work registers
	MOVEI Q2,1		;[7.1220] Only want one set of jobs
	JRST CFGTJ1		;[7.1220] Join common code
CFGTJB::SAVEQ			;Get some work regs
	MOVEI Q2,LCLPKT		;[7.1220] Number we need
CFGTJ1:	MOVSI Q1,-MXPKTS	;[7.1220] Max,,packet we are on
	DO.			;Loop
	  CALL CFSSPC		;Get some space
	   CALL CFSERR
	  MOVX T2,CFJBAS	;Assign job numbers
	  MOVEM T2,HSHROT(T1)	;Store root code
	  MOVX T2,.HTOEX	;Need exclusive
	  STOR T2,HSHTYP,(T1)	;Stash it	
	  HRRZM Q1,HSHQAL(T1)	;Store slot needed
	  SETZM T2		;No retry
	  CALL CFSGET		;Get it
	  IFSKP.		;If we got this one
	    MOVEI T1,JBPCKT	;[7.1220] This is how many jobs we got
	    ADDM T1,GBLCNT	;[7.1220] Account for this chunk
	    MOVEI Q3,0(Q1)	;Get slot
	    IMULI Q3,JBPCKT	;Jobs in a slot
	    HRLI Q3,-JBPCKT
	    DO.
	      HRRI T1,1(Q3)	;Get job number
	      CALL JBAVAL	;Make it available
	      AOBJN Q3,TOP.	;Do them all
	    ENDDO.
	    SOJLE Q2,R		;If all done, return
	  ENDIF.
	  AOBJN Q1,TOP.		;Try next slot
	ENDDO.
	RET			;Done
	SUBTTL	DIAG% JSYS Support -- CFDIAG (Code for Set CI Unavailable)

;Routine called from DIAG code when the CI is placed off-line. This
;routine closes all of the CFS connections.

	SWAPCD			;More JSYS support

CFDIAG::
   IFE CFSSCA,<RET>		;If nothing to do, don't do anything
   IFN CFSSCA,<			;If we might have something to do
	SAVEQ
	CFSLOK			;Lock everything up
	MOVSI Q1,-HSTSIZ	;Scan the table
	DO.
	  SKIPE CFSHST(Q1)	;Anybody here?
	  SKIPL CFHSTS(Q1)	;Yes, and opened?
	  IFSKP.		;If this is opened
	    BLCAL. (SC.DIS,<CFSHST(Q1),[0]>) ;Close it
	    IFNSK.
	      MOVE T3,T1	;Save error code
	      MOVE T1,CFSHST(Q1) ;Get connect ID
	      CALL SC.NOD	;(T1/T1,T2) Get node number
	      BUG.(CHK,CFCCLZ,CFSUSR,SOFT,<CFSSRV - Can't close CFS connection>,<<T2,NODE>,<T1,CID>,<T3,ERROR>>,<

Cause:	A "set CI offline" has been requested and SCA refuses to close
	a CFS connection.  The call to SC.DIS to disconnect from the remote
	node failed.  This may result in a CFRECN BUGHLT when the CI is put
	on-line.

Data:	NODE  - node number of remote
	CID   - connect ID
	ERROR - error code returned by SCA
>)
	    ELSE.
	      MOVE T3,CFSHST(Q1) ;Get the connect ID
	      CALL PHYNOL	;Declare the disk's offline
	      SETZM CFSHST(Q1)	;It is closed
	      MOVE T1,CFHSTS(Q1)
	      SETZM CFHSTS(Q1)
	      SOS CFSHCT	;One less of this
	      TRNE T1,-1	;Full?
	      SOS CFSHCM	;Yes
	    ENDIF.
	    HRRZ Q2,Q1		;GET POSITION
	    ADD Q2,OLDTAB	; IN OLD CONNECTIONS TABLE
	    MOVE T1,CFSHNM(Q1)	;GET REMOTE SYSTEM'S SERIAL NUMBER
	    MOVEM T1,(Q2)	;SAVE IT
	  ENDIF.
	  AOBJN Q1,TOP.		;Do all of the table
	ENDDO.
	CALLRET CFSFAL		;And done
   >	;IFN CFSSCA
	SUBTTL	CNFIG% JSYS Support -- CFCIN (Return CFS information)

IFN CFSSCA,<

; CNFIG% JSYS SUPPORT ROUTINES FOR CFS
; THEY ALSO USE CNFIG% SUPPORT ROUTINES IN JSYSA.MAC
; THE FOLLOWING CONVENTIONS ARE USED FOR PRESERVED REGISTERS
;
;	Q1/ MONITOR BLOCK ADDRESS (ESTABLISHED IN THESE ROUTINES)
;	Q2/ USER BLOCK ADDRESS
;	Q3/ WORDS PROCESSED,,WORDS SUPPLIED

CFCIN::	TRVAR <<CFCINB,.CFCLN>>
	XMOVEI Q1,CFCINB	;Q1 POINTS TO MONITOR BLOCK
	MOVEI T1,.CFCLN
	CALL CFLNDO		;PROCESS .CFLEN
	MOVE T1,CFSHCT		;NUMBER OF OTHER CFS HOSTS UP
	ADDI T1,1
	MOVEM T1,.CFNCN(Q1)	;NUMBER OF CFS NODES
	SETZM T2
	LOAD T1,SCCNC		;GOT CONNECTED FLAG
	SKIPE T1
	TXO T2,CF%CFR		;NONZERO MEANS WE DID
	MOVEM T2,.CFCDO(Q1)	;DYNAMIC SOFTWARE OPTIONS
	CALL CFRET		;RETURN STUFF TO USER
	RETSKP
	ENDTV.
	SUBTTL	CNFIG% JSYS Support -- CFCSE (Return serial numbers of CFS nodes)

;RETURN SERIAL NUMBERS OF OTHER HOSTS UP

CFCSE::	TRVAR <<CFCSEB,MAXNDS+2>> ;MAX NUMBER OF OTHER HOSTS + OURS + .CFLEN
	XMOVEI Q1,CFCSEB	;ADDRESS OF MONITOR BLOCK
	MOVE T1,CFSHCT		;NUMBER OF OTHER HOSTS CURRENTLY UP
	ADDI T1,2		;PLUS US PLUS .CFLEN
	CALL CFLND2
	XMOVEI P1,.CFCS1(Q1)	; P1/ PLACE TO STORE SERIAL NUMBERS
	SETZM 0(P1)		;INITIALIZE TO ZEROS
	MOVE T1,APRSER		;APR SERIAL NUMBER IN RIGHT HALF
	STOR T1,CF%HSN,0(P1)	;STORE AWAY OUR SERIAL NUMBER
	CALL SC.PRT		;GET OUR CI NODE NUMBER
	 ERJMP .+1		;IGNORE ERRORS
	STOR T1,CF%CIN,0(P1)	;STASH IT
	ADDI P1,1

; HERE IS OUR MAIN LOOP TO GET THE SERIAL NUMBERS AND STASH THEM

	MOVEI P2,CFSHST		; P2/ PRESENCE TABLE
	MOVEI P3,CFHSTS		; P3/ ACTIVENESS TABLE
	MOVEI P4,CFSHNM		; P4/ SERIAL NUMBER TABLE
	MOVEI P5,HSTSIZ		; P5/ LOOP
	DO.
	  SKIPLE 0(P2)		;ANYTHING HERE?
	  SKIPL 0(P3)		;ANYTHING ACTIVE?
	  IFSKP.	
	    SETZM 0(P1)		;INITIALIZE TO ZEROS
	    MOVE T1,0(P4)	;GET SERIAL NUMBER
	    LSH T1,-4		;NORMALIZE
	    STOR T1,CF%HSN,0(P1) ;STASH IT
	    MOVE T1,0(P2)	;Get connect ID
	    CALL SC.NOD		;(T1/T1,T2) Get CI node number
	    STOR T2,CF%CIN,0(P1) ;Save CI node number
	    ADDI P1,1		;BUMP STASH POINTER
	  ENDIF.
	  ADDI P2,1		;BUMP ALL LOOP VARIABLES
	  ADDI P3,1
	  ADDI P4,1
	  SOJG P5,TOP.		;END WHEN WHOLE TABLE SEARCHED
	ENDDO.
	CALL CFRET		;RETURN STUFF TO USER SPACE
	RETSKP
	ENDTV.
	SUBTTL	CNFIG% JSYS Support -- CFCND (Return list of node names)

CFCND::	TRVAR <<CFCNDB,MAXNDS*3+4>>
	XMOVEI Q1,CFCNDB
	MOVE T1,CFSHCT		;NUMBER OF OTHER HOSTS CURRENTLY UP
	IMULI T1,3
	ADDI T1,4		;MAX WORDS RETURNABLE
	CALL CFLND2
	MOVE T1,CFSHCT
	ADDI T1,1
	STOR T1,CF%NND,.CFNND(Q1) ; SET NUMBER OF NODES
	XMOVEI P1,.CFBP1(Q1)	; P1/ PLACE TO STORE BYTE POINTERS
	XMOVEI P2,.CFBP1+1(Q1)
	ADD P2,CFSHCT		; P2/ PLACE TO STORE HOST NAMES
	MOVEI T3,.CFBP1+1(Q2)
	ADD T3,CFSHCT		; T3/ RUNNING ADDRESS FOR BYTE POINTERS
	HRR T1,T3
	HRLI T1,(POINT 7,)
	MOVEM T1,0(P1)		; STORE B.P. FOR OUR NAME
	ADDI P1,1		; BUMP POINTER
	ADDI T3,2
	DMOVE T1,OURNAM
	DMOVEM T1,0(P2)
	ADDI P2,2		; BUMP POINTER
; HERE IS OUR MAIN LOOP TO GET THE NAMES AND STATES AND STASH THEM

	MOVEI P3,CFSHST		; P3/ PRESENCE TABLE
	MOVEI P4,CFHSTS		; P4/ ACTIVENESS TABLE
	MOVEI P5,CFNNAM		; P5/ HOST NAME TABLE
	MOVEI T4,HSTSIZ		; T4/ LOOP
	DO.
	  SKIPLE 0(P3)		;ANYTHING HERE?
	  SKIPL 0(P4)		;ANYTHING ACTIVE?
	  IFSKP.	
	    HRR T1,T3
	    HRLI T1,(POINT 7,)
	    MOVEM T1,0(P1)	; STORE B.P. FOR OUR NAME
	    ADDI P1,1		; BUMP POINTER
	    ADDI T3,2
	    CALL ASC8T7		; COPY 0,1(P5) TO 0,1(P2) AND CONVERT
	    ADDI P2,2		; BUMP POINTER
	  ENDIF.
	  ADDI P3,1
	  ADDI P4,1
	  ADDI P5,2
	  SOJG T4,TOP.
	ENDDO.

	CALL CFRET
	RETSKP
	ENDTV.
; THE FOLLOWING CONVERTS 0,1(P5) FROM 8 TO 7 BIT ASCII
; AND STORES THE RESULT IN 0,1(P2)

ASC8T7::SAVET
	HRLI T1,(<POINT 8,0>)
	HRRI T1,0(P5)		; BYTE POINTER TO SOURCE
	HRLI T2,(<POINT 7,0>)
	HRRI T2,0(P2)		; BYTE POINTER TO DESTINATION
	SETZM 1(P2)		; ZERO DESTINATION NOT TOUCHED
	MOVEI T3,8		; COUNT, 8 BYTES

LOP8T7:	ILDB T4,T1		; THIS IS OUR COPY LOOP
	IDPB T4,T2
	SOJG T3,LOP8T7
	RET
>	;IFN CFSSCA
	SUBTTL End of CFSUSR

	END