Trailing-Edge
-
PDP-10 Archives
-
bb-kl11l-bm_tops20_v7_0_tsu03_2_of_3
-
galsrc/nebula.mac
There are 23 other files named nebula.mac in the archive. Click here to see a list.
S
ADDI S1,777 ;ROUND IT OFF
ADR2PG S1 ;MAKE IT A PAGE NUMBER
MOVEM S1,NEBSIZ ;SAVE IT
;DETERMINE AND SAVE THE LOCAL ACK CODE SEED
$CALL I%NOW ;PICK UP THE ACK CODE SEED
MOVEM S1,LOCACK ;AND SAVE IT
$RET ;RETURN
SUBTTL WAIQSR - WAIT FOR QUASAR TO STARTUP
;[6036]WAIQSR is called during NEBULA startup. This routine will wait
;[6036]for QUASAR to start up. This prevents any IPCF messages from being
;[6036]lost.
;[6036]
;[6036]Call is: No arguments
;[6036]Returns true: QUASAR has started up
WAIQSR: MOVEI S1,SP.QSR ;[6036]GET QUASAR'S PID INDEX
$CALL C%RPRM ;[6036]PICK UP QUASAR'S PID
$RETIT ;[6036]RETURN NOW IF QUASAR IS THERE
MOVEI S1,1 ;[6036]OTHERWISE ...
$CALL I%SLP ;[6036]SLEEP FOR A SECOND
JRST WAIQSR ;[6036]AND TRY AGAIN
SUBTTL WAIORN - WAIT FOR ORION TO STARTUP
;[6034]WAIORN is called during NEBULA startup. This routine will wait
;[6034]for ORION to start up. This prevents any IPCF messages from being
;[6034]lost.
;[6034]
;[6034]Call is: No arguments
;[6034]Returns true: ORION has started up
WAIORN: MOVEI S1,SP.OPR ;[6034]GET ORION'S PID INDEX
$CALL C%RPRM ;[6034]PICK UP ORION'S PID
$RETIT ;[6034]RETURN NOW IF ORION IS THERE
MOVEI S1,1 ;[6034]OTHERWISE ...
$CALL I%SLP ;[6034]SLEEP FOR A SECOND
JRST WAIORN ;[6034]AND TRY AGAIN
SUBTTL INTINI - INTERRUPT INITIALIZATION AND HANDLERS
;INTINI is called during NEBULA startup. This routine activates
;the interrupt channels:
;
;0 - A listener has a message
;1 - A sender is ready to send a message
;2 - IPCF has one or more messages available
;3 - A sender or listener has just made a DECnet connection
;4 - SCS% detected a cluster topology change
;19 - (channel .IPIFT) A listener or sender has crashed
;
;Call is: No arguments
;Returns: The interrupt system has been successfully set up
;Crashes: Cannot activate the interrupt system or cannot enable
; SCS% event interruptions
INTINI: $SAVE <T1,T2> ;CHANGED BY SCS% JSYS
MOVE S1,[1,,ENDFRK] ;SET UP INFERIOR FORK TERM PARMS
MOVEM S1,CHNTAB+.ICIFT ;IN THE CHANNEL TABLE
MOVEI S1,.FHSLF ;GET MY HANDLE
MOVX S2,37B4+1B19 ;GET CHANNELS 0-4 AND 19
AIC% ;ACTIVATE THEM
ERJMP S..CSI ;THIS SHOULD NEVER HAPPEN
$CALL I%ION ;ENABLE THE INTERRUPTS
JUMPF S..CSI ;THIS SHOULD NEVER HAPPEN
;TELL SCS% TO INTERRUPT US FOR EVENTS
MOVEI S1,.SSAIC ;ADD INTERRUPT CHANNEL FOR SCA EVENTS
MOVEI S2,SCSBLK ;POINT TO THE BLOCK
SCS% ;INFORM SCS%
ERJMP S..CSI ;THIS SHOULD NOT HAPPEN
$RET ;RETURN
SUBTTL NEBULA INTERRUPT HANDLERS
;LISMSG - Listener has a message interrupt handler. This routine sets flag
; word LREADY which indicates that a listener has a message to
; deliver to NEBULA's top fork.
;
;SNDREA - Sender is free to deliver a message interrupt handler. This routine
; sets flag word SREADY which indicates that a sender is free to
; deliver a message.
;
;NBIPCF - IPCF interrupt handler. This routine sets flag word MSGFLG
; which indicates that there are one or more IPCF messages available.
;
;INFRDY - Inferior fork has a DECnet connection interrupt handler. This
; routine sets flag word IREADY which indicates that a sender's
; request to make a DECnet connection to a listener has been
; accepted by the listener, or a listener has accepted a DECnet
; connection request from a sender.
;
;ENDFRK - Inferior fork crashed interrupt handler. This routine sets flag
; word TRMFRK which indicates that a sender or listener has crashed.
;
;NBSCS - Topology change detected interrupt handler. This routine sets
; flag word SCSFLG which indicates that a cluster topology change
; has occurred. Also, if the node table (NODTBL) is not being
; updated, and a node has left the cluster, then its node table
; entry is marked indicating that the node has left the cluster.
LISMSG: $BGINT 1, ;INITIALIZE INTERRUPT LEVEL
SETOM LREADY ;A LISTENER HAS A MESSAGE
$DEBRK ;AND LEAVE INTERRUPT LEVEL
SNDREA: $BGINT 1, ;INITIALIZE INTERRUPT LEVEL
SETOM SREADY ;A SENDER IS READY FOR A MESSAGE
$DEBRK ;AND LEAVE INTERRUPT LEVEL
NBIPCF: $BGINT 1, ;INITIALIZE INTERRUPT LEVEL
$CALL C%INTR ;FLAG THE IPCF INTERRUPT
$DEBRK ;AND LEAVE INTERRUPT LEVEL
INFRDY: $BGINT 1, ;INITIALIZE INTERRUPT LEVEL
SETOM IREADY ;AN INFERIOR FORK A DECNET CONNECTION
$DEBRK ;AND LEAVE INTERRUPT LEVEL
ENDFRK: $BGINT 1, ;INTIALIZE INTERRUPT LEVEL
SETOM TRMFRK ;A LISTENER OR SENDER HAS CRASHED
$DEBRK ;AND LEAVE INTERRUPT LEVEL
SUBTTL NBSCS - TOPOLOGY CHANGE DECTECTED INTERRUPT HANDLER
;NBSCS processes interrupts that occur as a consequence of a cluster
;topology change. Flag word SCSFLG is set to -1 to indicate that a
;cluster topology change has occurred.
;If routine NODINT is finished building the node table and if a node has
;left the cluster, then the status word of the node's entry in the node
;table is set (i.e., bit NN%SCS is turned on) to indicate that the node has
;left the cluster
;
;DEBRKs with word SCSFLG set to -1
;Crashes: If the SCS% JSYS returns an error other than "event queue empty"
NBSCS: $BGINT 1, ;INITIALIZE INTERRUPT LEVEL
;PICK UP THE NEXT EVENT FROM THE EVENT QUEUE
NBSC2: MOVEI S1,SCSLEN ;LENGTH OF THE ARGUMENT BLOCK
MOVEM S1,SCSEBK+.SQLEN ;PLACE IN THE ARGUMENT BLOCK
SETOM SCSEBK+.SQCID ;GET THE NEXT EVENT
MOVEI S1,.SSEVT ;RETRIEVE NEXT ENTRY FROM EVENT QUEUE
MOVEI S2,SCSEBK ;ADDRESS OF THE ARGUMENT BLOCK
SCS% ;PICK UP THE NEXT EVENT QUEUE ENTRY
ERJMP NBSC4 ;CHECK IF THE EVENT QUEUE IS NOW EMPTY
;CHECK THE TYPE OF EVENT THAT HAS OCCURRED
MOVE S1,SCSEBK+.SQEVT ;PICK UP THE EVENT CODE
CAIN S1,.SENCO ;HAS A NODE COME ONLINE?
JRST NBSC3 ;YES, SET THE FLAG WORD
CAIE S1,.SEPBC ;HAS A NODE GONE OFFLINE?
JRST NBSC2 ;NO, DON'T CARE ABOUT THIS EVENT
;A NODE HAS GONE OFFLINE. IF ROUTINE NODINT IS NOT BUILDING THE NODE TABLE,
;OR IF ROUTINE TOPCHN IS NOT MODIFYING THE NODE TABLE, THEN
;FIND THE ENTRY FOR THIS NODE IN THE NODE TABLE AND MARK IT AS NN%SCS
;(SCS% DETECTED THAT THE NODE HAS LEFT THE CLUSTER).
SKIPE BLDTAB ;IS NODE TABLE BEING WORKED ON?
JRST NBSC3 ;YES, CAUSE TOPCHN TO SET TOPOLOGY
;CHANGE TIMER
MOVE S1,SCSEBK+.SQDTA ;PICK UP THE NODE NUMBER
$CALL SNUMNT ;FIND THE NODE TABLE ENTRY
;NOTE: IT MAY BE POSSIBLE THAT THE NODE CAME ONLINE AND NOW HAS GONE
;OFFLINE DURING THE CURRENT SCHEDULING PASS BUT AFTER ROUTINE TOPCHN
;WAS EXECUTED. SO IT IS POSSIBLE THAT ROUTINE TOPCHN NEVER ENTERED
;THE NODE INTO THE NODE TABLE.
JUMPF NBSC3 ;NOT THERE, CAUSE TOPCHN TO SET TIMER
MOVE S1,.NNSTA(S2) ;PICK UP THE STATUS WORD
TXO S1,NN%SCS ;INDICATE THAT SCS% DETECTED NODE GONE
TXZ S1,NN%OKS ;NO LONGER OK TO SEND MSG TO THIS NODE
MOVEM S1,.NNSTA(S2) ;UPDATE THE NODE STATUS WORD
SKIPA ;[6016]DON'T SET NODE ONLINE FLAG
NBSC3: SETOM RECHEK ;[6016]INDICATE NODE CAME ONLINE
SETOM SCSFLG ;A CLUSTER TOPOLOGY CHANGE OCCURRED
JRST NBSC2 ;CHECK FOR ANOTHER EVENT QUEUE ENTRY
;THE SCS% JSYS RETURNED AN ERROR. CHECK IF THE EVENT QUEUE IS EMPTY.
;IF SO, RETURN. ON OTHER ERRORS, CRASH. CANNOT JUST ASSUME THAT A TOPOLOGY
;CHANGE HAS OCCURRED, SINCE IF THE ROUTINE EXITS ON THIS ASSUMPTION AND
;THERE ARE MORE EVENTS IN THE EVENT QUEUE, THEN NEBULA WILL NOT BE
;INTERRUPTED AGAIN IF A CLUSTER TOPOLOGY CHANGE OCCURS.
NBSC4: MOVEI S1,.FHSLF ;GET LATEST ERROR OF NEBULA
GETER% ;PICK UP THE ERROR
ERJMP S..SIF ;FATAL ERROR IN SCS% INTERRUPT HANDLER
HRRZS S2 ;ISOLATE THE ERROR CODE
CAIN S2,SCSQIE ;EVENT QUEUE EMPTY?
$DEBRK
JRST S..SIF ;FATAL ERROR IN SCS% INTERRUPT HANDLER
SUBTTL NODINT - INITIALIZE THE NODE DATA BASE
;NODINT is called during NEBULA's startup.
;This routine sets up the Node Table (NODTBL).
;For each remote node in the cluster, this routine determines:
; The node name
; The node number
; If the node has DECnet enabled
; If the node's monitor is of release 7.0 or later
;While NODINT is building the node table, the cluster topology interrupt
;handler must not access the table. This is accomplished by flag word
;BLDTAB. If the contents of this word is -1, then this indicates that
;the node table is being built.
;If more than MAXNOD nodes are detected, then NODINT crashes NEBULA.
;
;Call is: No arguments
;Returns true: There is at least one remote node but not more than MAXNOD
;Returns false: There are no remote nodes
;Crashes: If an illegal number of remote nodes are in the cluster
; (i.e., there are more than MAXNOD remote nodes).
NODINT: $SAVE <P1,P2,P3,P4> ;SAVE THESE AC
NODIN1: $CALL GTNDAT ;PICK UP THE NODE NAMES AND NUMBERS
;CONVERT THE ASCIZ NODE NAMES INTO SIXBIT AND STORE IN THE NODE TABLE
SETZM RENNUM ;ASSUME NO REMOTE NODES
MOVEI P1,ASZNAM ;POINT TO THE ARGUMENT BLOCK
HLRZ P2,.CFNND(P1) ;PICK UP THE NUMBER OF NODES
SOJE P2,NODIN5 ;[6016]DON'T INCLUDE THE LOCAL NODE
CAILE P2,MAXNOD ;CANNOT BE MORE THAN MAXNOD NODES
$CALL S..CTL ;ILLEGAL NUMBER OF REMOTE NODES
MOVEM P2,RENNUM ;REMEMBER THE NUMBER OF NODES
MOVEI P4,NNMTBL+.CFCS1+1 ;POINT TO THE FIRST REMOTE NODE NUMBER
ADDI P1,.CFBP1+1 ;POINT TO THE FIRST REMOTE NODE NAME
MOVEI P3,NODTBL ;POINT TO THE NODE TABLE
NODIN2: MOVE S1,0(P1) ;PLACE THE BYTE POINTER IN S1
$CALL S%SIXB ;RETURN WITH THE SIXBIT NODE NAME IN S2
MOVEM S2,.NNNAM(P3) ;PLACE NODE NAME IN NODE TABLE ENTRY
HLRZ S2,0(P4) ;PICK UP THE CORRESPONDING NODE NUMBER
ANDI S2,NNMFLD ;THE NUMBER IS IN THE HIGH 4 BITS
HRRZM S2,.NNSTA(P3) ;PLACE IN THE NODE NUMBER/STATUS WORD
ADDI P3,.NNNSZ ;POINT TO THE NEXT NODE TABLE ENTRY
AOS P1 ;POINT TO THE NEXT BYTE POINTER
AOS P4 ;POINT TO THE NEXT NODE NUMBER
SOJG P2,NODIN2 ;GET THE NEXT NODE NAME
;CHECK IF THE REMOTE NODES HAVE DECNET AND A MONITOR OF RELEASE 7 OR LATER
;STORE THIS INFORMATION IN THE NODE'S NODE TABLE ENTRY
MOVEI P2,NODTBL ;POINT TO THE NODE TABLE
MOVE P1,RENNUM ;THE NUMBER OF NODES TO LOOK AT
NODIN3: MOVE S1,P2 ;PICK UP NODE TABLE ENTRY ADDRESS
$CALL NODPAR ;CHECK OUT THIS NODE
JUMPT NODIN4 ;[6016]O.K. TO SEND MSG TO THIS NODE
MOVE S1,P2 ;[6016]PICK UP NODE TABLE ENTRY ADDRESS
$CALL STINFO ;[6016]SET TIMER TO CHECK STATUS LATER
NODIN4: ADDI P2,.NNNSZ ;[6016]POINT TO THE NEXT NODE
SOJG P1,NODIN3 ;CHECK OUT THE NEXT NODE
SKIPE SCSFLG ;ONE FINAL CHECK FOR TOPOLOGY CHANGE
JRST NODIN1 ;A CHANGE HAS OCCURRED, REBUILD
NODIN5: AOS BLDTAB ;[6016]SCS INTERRUPT HANDLER MAY NOW
;[6016]TOUCH THE NODE TABLE
SKIPN RENNUM ;[6016]ANY REMOTE NODES?
$RETF ;[6016]NO, INDICATE SO
TIME% ;[6016]PICK UP THE MONITOR UPTIME
CAMG S1,[TIMUP] ;[6016]ENOUGH TIME FOR CONFG% STABILITY?
SETOM RECHEK ;[6016]NO, INDICATE TO ROUTINE TOPCHN
$RETT ;[6016]AT LEAST ONE REMOTE NODE
SUBTTL BLDLST - INITIALIZES PACKN TABLE
;BLDLST is called during NEBULA startup to initialize the previously
;and currently known nodes (PACKN) table. This table is used to support
;the OPR commands:
; SHOW CLUSTER-GALAXY-LINK-STATUS
; ENABLE/DISABLE REPORT-CONNECTION-FAILURES
; ENABLE/DISABLE DECNET-CONNECTION-ATTEMPTS
;Every remote node known to be or to have been in the cluster is kept in this
;table. Each node's entry indicates if the node's sender and listener ever had
;a DECnet connection or not. Each entry also indicates whether NEBULA
;should report to the operators if that node's sender cannot obtain
;a DECnet connection. Also, if a node's sender cannot obtain a DECnet
;connection, then the entry for that node indicates if the sender is to
;continue to obtain a DECnet connection or cease attempting to obtain a
;connection.
;BLDLST assumes that if there are any remote nodes in the cluster known to
;NEBULA, then the entries in use in the node table (NODTBL) are contiguous.
;The PACKN table, once it is built, is always assumed by routines that use
;it to have at least one free entry. The PACKN entries that are in use
;are always contiguous.
;
;Call is: No arguments
;Returns true: There are remote nodes known to be in the cluster and the
; PACKN table has been built
;Returns false: There are no known remote nodes in the PACKN table.
; Memory has been allocated for the PACKN table. All the entries
; are free.
BLDLST: $SAVE <P1,P2,P3> ;SAVE THESE AC
;SET UP THE PACKN TABLE FOR THE FIRST TIME BY OBTAINING THE INITIAL
;MEMORY REQUIRED.
SETZM NDLKST ;NO PACKN TABLE ADDRESS
SETZM NDLKNM ;NO PACKN TABLE ENTRIES
SETZM NDLKFR ;NO FREE PACKN TABLE ENTRIES
SETZM RCFFLG ;REPORT ALL CONNECTION ERRORS
SETZM DCAFLG ;ATTEMPT TO OBTAIN A CONNECTION
$CALL EXPTAB ;GET THE MEMORY FOR THE PACKN TABLE
SKIPG RENNUM ;ANY REMOTE NODES?
$RETF ;NO, SO DON'T BUILD ANY ENTRIES
;BUILD THE PACKN ENTRIES
MOVEI P1,NODTBL ;POINT TO THE NODE TABLE
MOVE P2,NDLKST ;POINT TO THE PACKN TABLE
MOVE P3,RENNUM ;PICK UP NUMBER OF REMOTE NODES
BLDLS2: MOVE S2,.NNNAM(P1) ;PICK UP THE REMOTE NODE NAME
MOVEM S2,.NDNAM(P2) ;PLACE IN THE PACKN TABLE
SETZM .LKSTS(P2) ;NO CONNECTIONS AND REPORT CONN. ERRORS
SOSG NDLKFR ;DECREMENT THE NUMBER OF FREE ENTRIES
$CALL EXPTAB ;NO MORE FREE ENTRIES, EXPAND THE TBL
ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE TABLE ENTRY
ADDI P2,.NDLSZ ;POINT TO THE NEXT PACKN TABLE ENTRY
SOJG P3,BLDLS2 ;PICK UP THE NEXT REMOTE NODE NAME
$RETT ;RETURN TO STARTUP
SUBTTL GTNDAT - PICK UP THE NODE NAMES AND NUMBERS
;GTNDAT is called to pick up the node names and numbers of the
;nodes in the cluster.
;If a topology change occurs while this routine is picking up the node
;names and numbers, then it starts over in order to pick up the latest
;information about the cluster.
;
;Call is: No arguments
;Returns: The node names and node numbers are obtained.
;Crashes: If cannot obtain the node name or node number
GTNDAT: $SAVE <T1,T2> ;SAVE THESE AC. CNFIG% CHANGES THEM
;PICK UP THE NODE NAMES
GTNDA2: MOVEI S1,CNFLEN ;ENSURE ENOUGH ROOM IN THE ARG BLOCK
MOVEI S2,ASZNAM ;ADDRESS OF THE ARGUMENT BLOCK
MOVEM S1,.CFNND(S2) ;STORE THE SIZE OF THE ARG BLOCK
MOVEI S1,.CFCND ;GET THE ASCIZ NODE NAMES
SETZM SCSFLG ;CHECK FOR CLUSTER TOPOLOGY CHANGE
CNFIG% ;PICK UP THE ASCIZ NODE NAMES
ERJMP S..CON ;CAN'T PICK UP CLUSTER TOPOLOGY
;GET THE NODE NUMBERS
MOVEI S2,NNMTBL ;PICK UP THE NODE NUMBER TABLE ADDRESS
MOVEI S1,1+<MAXNOD+1> ;ENSURE ENOUGH ROOM IN THE ARG BLOCK
MOVEM S1,.CFLEN(S2) ;STORE THE SIZE OF ARGUMENT BLOCK
MOVEI S1,.CFCSE ;NODE NUMBER/SERIAL NUMBER FUNCTION
CNFIG% ;PICK UP THE NODE NUMBERS
ERJMP S..CGN ;CAN'T OBTAIN THE NODE NUMBERS
SKIPE SCSFLG ;CLUSTER TOPOLOGY CHANGE OCCURRED?
JRST GTNDA2 ;YES, NEED TO GET THE LATEST
$RET ;RETURN TO THE CALLER
$STOP (CON,CAN'T OBTAIN THE CLUSTER NODE NAMES)
$STOP (CGN, CAN'T GET THE CLUSTER NODE NUMBER)
SUBTTL STLAS - START UP THE LISTENERS AND SENDERS
;STLAS is called during NEBULA startup.
;This routine checks each node in the node table to determine if that
;node has DECnet enabled and is also running a monitor of release 7.0
;or later. If both of these conditions are true, then this routine
;starts a listener and sender directed at the node.
;This routine assumes:
; 1. There is at least one remote node in the cluster (i.e., the contents
; of RENNUM is greater than zero.)
; 2. The node table entries in use are contiguous and begin with the
; first entry in the node table.
;
;Call is: No arguments
;Returns: The sender and listener have been started
;Crashes: If a sender or listener cannot be started
STLAS: $SAVE <P1,P2> ;SAVE THESE AC
MOVEI P1,NODTBL ;POINT TO THE FIRST NODE
MOVE P2,RENNUM ;PICK UP THE NUMBER OF NODES
;FIRST MAKE SURE THAT THE NODE HAS DECNET AND HAS A MONITOR OF RELEASE 7
;OR LATER
STLAS2: MOVE S1,P1 ;PICK UP THIS NODE'S NODE TABLE ENTRY
$CALL CHKSTS ;CHECK FOR DECNET AND RELEASE 7 MONITOR
JUMPF STLAS3 ;LOSES, CHECK THE NEXT NODE
;START UP THE LISTENER AND SENDER FOR THIS NODE. (If STAINF CANNOT STARTUP
;A LISTENER AND SENDER, THEN IT CRASHES.)
$CALL STAINF ;START UP THE LIS/SEN FOR THIS NODE
STLAS3: ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE ENTRY
SOJG P2,STLAS2 ;START THE NEXT NODE'S LIS/SEN
SKIPN [N$ACKO] ;[6016]NEBULA ACK MSG OPTION ENABLED?
$RET ;[6016]NO, RETURN TO THE CALLER NOW
SKIPE DEBUGW ;[6016]DEBUGGING?
$RET ;[6016]YES, RETURN NOW
$CALL NEBTMR ;[6016]NO, SET UP THE ACK MESSAGE TIMER
$RET ;[6016]AND RETURN TO THE CALLER
SUBTTL STAINF - STARTUP A LISTENER AND SENDER TO A NODE
;STAINF is called to start up a listener and sender to a node.
;This routine is called during NEBULA's startup and when a cluster
;topology change has occurred which results in a node joining the cluster.
;A listener and sender can only be started for a node that has DECnet
;enabled and has a monitor of release 7 or later.
;
;This routine also sets status bits in the node table entry for this node
;indicating that the sender has not yet received a response to its HELLO
;message and that the listener has not yet received a HELLO message.
;
;Call is: S1/Node table entry address of the node that a sender and
; listener are to be started for
;Returns: The listener and sender have been started to the node
;Crashes: If a listener or sender cannot be started
STAINF: $SAVE <P1> ;SAVE THIS AC
MOVE P1,S1 ;PICK UP THE NODE TABLE ENTRY ADDRESS
;SET THE STATUS BITS IN THE NODE TABLE ENTRY TO INDICATE THAT THE LISTENER
;IS WAITING FOR A HELLO MESSAGE AND THAT THE SENDER IS WAITING FOR A
;HELLO RESPONSE
MOVX S2,NN%SHO!NN%LHO ;SENDER/LISTENER HAVE NO HELLO
IORM S2,.NNSTA(P1) ;INDICATE IN THE NODE STATUS WORD
MOVX S2,NL%WHL ;LISTENER WAITING FOR A HELLO
IORM S2,.NLSTA(P1) ;INDICATE IN THE LISTENER STATUS WORD
MOVX S2,NS%WHR ;SENDER WAITING FOR A HELLO RESPONSE
IORM S2,.NSSTA(P1) ;INDICATE IN THE SENDER STATUS WORD
;START UP A LISTENER. FIRST OBTAIN AND INITIALIZE THE LISTENER DATA BASE
MOVEI S1,DBSIZ ;SIZE OF THE LISTENER BLOCK IN PAGES
$CALL M%AQNP ;GET THE LISTENER BLOCK PAGES
PG2ADR S1 ;CHANGE PAGE NUMBER TO ADDRESS
MOVEM S1,.NNLBA(P1) ;SAVE ADDRESS IN THE LISTENER BLOCK
MOVE LIS,S1 ;PLACE ADR IN LISTENER BLOCK DB POINTER
ADDI S1,PAGSIZ ;POINT TO THE MESSAGE BUFFER ADDRESS
MOVEM S1,.LSMSG(LIS) ;SAVE THE MESSAGE BUFFER ADDRESS
MOVEM P1,.LSNTA(LIS) ;SAVE THE NODE TABLE ENTRY ADDRESS
MOVE S1,.NNNAM(P1) ;PICK UP THE REMOTE NODE NAME
MOVEM S1,.LSNME(LIS) ;PLACE IN THE LISTENER BLOCK
$CALL BLDSRV ;BUILD THE DECNET SRV: DEVICE NAME
$CALL STLIS ;START UP THE LISTENER
;START UP A SENDER. FIRST OBTAIN AND INITIALIZE THE SENDER DATA BASE
MOVEI S1,DBSIZ ;SIZE OF THE SENDER BLOCK IN PAGES
$CALL M%AQNP ;GET THE SENDER BLOCK PAGES
PG2ADR S1 ;CHANGE PAGE NUMBER TO ADDRESS
MOVEM S1,.NNSBA(P1) ;SAVE ADR IN THE SENDER BLOCK
MOVE SEN,S1 ;PLACE ADR IN SENDER BLOCK DB POINTER
ADDI S1,PAGSIZ ;POINT TO THE MESSAGE BUFFER ADDRESS
MOVEM S1,.SNMSG(SEN) ;SAVE THE MESSAGE BUFFER ADDRESS
MOVEM P1,.SNNTA(SEN) ;SAVE THE NODE TABLE ENTRY ADDRESS
MOVE S1,.NNNAM(P1) ;PICK UP THE REMOTE NODE NAME
MOVEM S1,.SNNME(SEN) ;PLACE IN THE SENDER BLOCK
$CALL BLDDCN ;BUILD THE DECNET DCN: DEVICE NAME
$CALL STSEN ;START UP THE SENDER
;CREATE THE TIMER LIST INDEX
$CALL L%CLST ;CREATE THE TIMER LIST INDEX
MOVEM S1,.NTIML(P1) ;SAVE IN THE NODE TABLE ENTRY
$RET ;RETURN TO THE CALLER
SUBTTL BLDSRV - BUILD THE SRV: DEVICE NAME
;BLDSRV builds the listener's DECnet SRV: device name and places it in the
;listener block. It also builds the name of the sender that will attempt
;to establish a DECnet connection with the listener. The sender name is
;used by the listener as part of validating the link request.
;
;Call is: LIS/Address of the listener block
;Returns: The SRV: device name and the sender name have been built and
; placed in the listener block
BLDSRV: SKIPE DEBUGW ;[6003]DEBUGGING?
JRST BLDS.1 ;[6003]YES, SET UP DIFFERENTLY
$TEXT (<-1,,.LSSRV(LIS)>,<SRV:TASK.^N/.LSNME(LIS)/$NEBULA$LS^0>)
$TEXT (<-1,,.LSSNE(LIS)>,<^N/.LSNME(LIS)/$NEBULA$SN^0>) ;SENDER NAME
$RET ;RETURN TO THE CALLER
BLDS.1: $SAVE <T1,T2> ;[6003]SAVE THESE AC
GJINF% ;[6003]PICK UP THE USER'S NUMBER
MOVE S2,S1 ;[6003]SAVE NUMBER WHERE EXPECTED
MOVEI S1,.LSDBW(LIS) ;[6003]WHERE TO PLACE USER NAME
HRLI S1,(POINT 7) ;[6003]MAKE INTO A POINTER
DIRST% ;[6003]PICK UP THE USER NAME
JRST S..COD ;[6003]CRASH ON AN ERROR
MOVEI S1,.LSDBW(LIS) ;[6003]PICK UP USER NAME ADDRESS
HRLI S1,(POINT 7,) ;[6003]MAKE INTO A POINTER
SETZ T1, ;[6003]NUMBER OF CHAR IN NAME
BLDS.2: ILDB S2,S1 ;[6003]PICK UP THE NEXT CHARACTER
SKIPN S2 ;[6003]IS THIS THE LAST ONE?
JRST BLDS.3 ;[6003]YES, BUILD THE DEVICE NAME
AOS T1 ;[6003]INCREMENT THE CHAR COUNT
CAIG T1,^D6 ;[6003]MAXIMUM COUNT?
JRST BLDS.2 ;[6003]NO, GET THE NEXT CHAR
SETZ S2, ;[6003]PICK UP A NULL
DPB S2,S1 ;[6003]PLACE IN USER NAME
BLDS.3: MOVEI S1,.LSDBW(LIS) ;[6003]ADDRESS OF THE USER NAME
$TEXT (<-1,,.LSSRV(LIS)>,<SRV:TASK.^N/.LSNME(LIS)/$^T/0(S1)/$LS^0>)
$TEXT (<-1,,.LSSNE(LIS)>,<^N/.LSNME(LIS)/$^T/0(S1)/$SN^0>) ;SENDER NAME
$RET ;[6003]RETURN TO THE CALLER
SUBTTL STLIS - START UP THE LISTENER
;STLIS is called to start up a listener.
;This routine is called at NEBULA startup and also when a cluster topology
;change occurs that results in a node joining the cluster.
;
;Note: The listener block pages are obtained via the GLXMEM routine M%AQNP.
;M%AQNP zeros out the pages it returns. This implies the following:
;
; SETZM .LSLNK(LIS) ;ZERO OUT THE DECNET STATUS LINK
; SETZM .LSAVA(LIS) ;THE TOP FORK IS BUSY
; SETZM .LSQUE(LIS) ;THERE ARE NO MESSAGES IN THE MSG QUEUE
;
;Call is: LIS/ Listener block address
;Returns: A listener is successfully started.
;Crashes: If the listener cannot be started (i.e., a CFORK%, SFORK% or
; PMAP% error has occurred).
;SETUP THE CONTEXT OF THE LISTENER
STLIS: $SAVE <T1,T2> ;SAVE THESE AC
MOVEI S1,.LSPDL-1(LIS) ;SET UP THE LISTENER CONTEXT
HRLI S1,-PDSIZ ;STACK POINTER
PUSH S1,[EXP LISTEN] ;START THE LISTENER HERE
MOVEM S1,.LSREG+P(LIS) ;PLACE IN THE DATABASE
MOVEM LIS,.LSREG+LIS(LIS) ;SAVE THE ADDRESS OF THE DB
;START UP THE LISTENER. FIRST CREATE THE LISTENER AS AN INFERIOR FORK
;WITH THE SAME CAPABILIIES AS THE TOP FORK.
MOVX S1,<CR%CAP+CR%ACS> ;SUPERIOR CAPS AND AC'S
MOVEI S2,.LSREG(LIS) ;AC LOAD BUFFER
CFORK% ;CREATE A LISTENER
ERJMP STLIS2 ;CRASH ON AN ERROR
;MAP NEBULA'S PAGES INTO THE LISTENER
MOVEM S1,.LSHND(LIS) ;SAVE THE LISTENER'S HANDLE
MOVSI S1,.FHSLF ;GET THE TOP FORK'S HANDLE
HRLZ S2,.LSHND(LIS) ;GET THE LISTENER'S HANDLE
HRR T1,NEBSIZ ;GET THE LENGTH IN PAGES
HRLI T1,(PM%RWX!PM%CNT) ;COUNT+READ+EXECUTE
PMAP% ;MAP THE PAGES
ERJMP STLIS3 ;CRASH ON AN ERROR
;MAP THE LISTENER BLOCK PAGES INTO THE LISTENER
MOVE S1,LIS ;GET THE LISTENER'S BLOCK ADDRESS
ADR2PG S1 ;CONVERT IT TO A PAGE NUMBER
MOVE S2,S1 ;SAVE IT IN S2
HRLI S1,.FHSLF ;GET THE TOP FORK'S HANDLE
HRL S2,.LSHND(LIS) ;GET THE LISTENER'S HANDLE
MOVEI T1,DBSIZ ;GET THE PAGE COUNT
HRLI T1,(PM%RWX!PM%CNT) ;R,W,E + COUNT
PMAP% ;MAP THE DATA BASE
ERJMP STLIS3 ;CRASH ON AN ERROR
;START THE LISTENER
MOVE S1,.LSHND(LIS) ;GET THE LISTENER'S HANDLE
MOVEI S2,LISTEN ;GET THE START ADDRESS
SFORK% ;START THE LISTENER
ERJMP STLIS4 ;ON ERROR,,PROCESS IT
$RET ;AND RETURN
STLIS2: $STOP (CCL,CAN'T CREATE A LISTENER FORK)
STLIS3: $STOP (CML,CAN'T MAP A LISTENER)
STLIS4: $STOP (CSL, CAN'T START A LISTENER)
SUBTTL BLDDCN - BUILD THE DCN: DEVICE NAME
;BLDDCN builds the DECnet DCN: device name that the sender will use
;in opening its DECnet link. The format of the DCN: device name is:
;DCN:RNODE-TASK-LNODE$NEBULA$LS.LNODE$NEBULA$SN;BDATA:NNNNN
;
;where RNODE is the remote node name
; LNODE is the local node name
; NNNNN comes from the listener's node name and is used by the listener
; in accepting a connection
;
;Call is: SEN/Address of the sender block
;Returns: The DCN: device name has been built and placed in the sender block
BLDDCN: $SAVE <T1,T2,T3,T4> ;SAVE THESE AC
;BUILD THE OPTIONAL DATA FIELD, USING THE SIXBIT REMOTE NODE NAME AS
;THE STARTING VALUE. CREATE 12 OCTAL CHARACTERS AND CONVERT THEM TO ASCII.
MOVE S2,.SNNME(SEN) ;PICK UP THE REMOTE SIXBIT NODE NAME
ROT S2,3 ;ROTATE BY HALF A CHARACTER
MOVE T1,[POINT 7,S1,35] ;POINTER TO BYTE TO PICK UP
MOVE T2,[POINT 7,NODDAT] ;POINTER TO WHERE BYTE IS TO BE PUT
SETZ S1, ;CLEAR RECEIVING WORD OF OCTAL VALUE
MOVEI T3,^D36/3 ;NUMBER OF OCTAL CHARACTERS
BLDDC2: LSHC S1,3 ;MOVE NEXT OCTAL VALUE OVER
ADDI S1,60 ;MAKE IT ASCII
LDB T4,T1 ;PICK UP ASCII VALUE
IDPB T4,T2 ;PLACE IN ASCII STRING
SETZ S1, ;PREPARE FOR NEXT OCTAL VALUE
SOJN T3,BLDDC2 ;PICK UP NEXT OCTAL VALUE
IDPB S1,T2 ;MAKE INTO AN ASCIZ STRING
;BUILD THE DECNET DCN: DEVICE NAME
SKIPE DEBUGW ;[6003]DEBUGGING?
JRST BLDDC6 ;[6003]YES, DO DIFFERENTLY
;**;[6037]At BLDDC2:+9L change 1 line JYCw Oct-18-88
$TEXT(<-1,,.SNDCN(SEN)>,<DCN:^I/@BLDDC3/^I/@BLDDC4/^I/@BLDDC5/^I/@BLDD20/^0>) ;[6037]Include the password.
$RET ;RETURN TO THE CALLER
BLDDC3: [ITEXT(<^N/.SNNME(SEN)/-TASK-^N/NODNAM/$NEBULA$LS.>)] ;LISTENER NAME
BLDDC4: [ITEXT(<^N/NODNAM/$NEBULA$SN;BDATA:^T/NODDAT/>)] ;THE SENDER NAME
BLDDC5: [ITEXT(<;USERID:^N/NODNAM/$NEBULA$SN>)]
;**;[6037]At BLDDC5:+0L add 1 line JYCW Oct-18-88
BLDD20: [ITEXT(<;PASSWORD:AUTO20>)] ;[6037]Include the autopatch #
BLDDC6: GJINF% ;[6003]PICK UP THE USER'S NUMBER
MOVE S2,S1 ;[6003]SAVE NUMBER WHERE EXPECTED
MOVEI S1,.SNDBW(SEN) ;[6003]WHERE TO PLACE USER NAME
HRLI S1,(POINT 7) ;[6003]MAKE INTO A POINTER
DIRST% ;[6003]PICK UP THE USER NAME
JRST S..COD ;[6003]CRASH ON AN ERROR
MOVEI S1,.SNDBW(SEN) ;[6003]PICK UP USER NAME ADDRESS
HRLI S1,(POINT 7,) ;[6003]MAKE INTO A POINTER
SETZ T1, ;[6003]NUMBER OF CHAR IN NAME
BLDDC7: ILDB S2,S1 ;[6003]PICK UP THE NEXT CHARACTER
SKIPN S2 ;[6003]IS THIS THE LAST ONE?
JRST BLDDC8 ;[6003]YES, BUILD THE DEVICE NAME
AOS T1 ;[6003]INCREMENT THE CHAR COUNT
CAIG T1,^D6 ;[6003]MAXIMUM COUNT?
JRST BLDDC7 ;[6003]NO, GET THE NEXT CHAR
SETZ S2, ;[6003]PICK UP A NULL
DPB S2,S1 ;[6003]PLACE IN USER NAME
BLDDC8: MOVEI S1,.SNDBW(SEN) ;[6003]ADDRESS OF THE USER NAME
;**;[6037]At BLDDC8:+1L change 1 line JYCW Oct-18-88
$TEXT(<-1,,.SNDCN(SEN)>,<DCN:^I/@BLDDC9/^I/@BLDD10/^I/@BLDD11/^I/@BLDD20/^0>) ;[6037]
$RET ;RETURN TO THE CALLER
BLDDC9: [ITEXT(<^N/.SNNME(SEN)/-TASK-^N/NODNAM/$^T/0(S1)/$LS.>)] ;[6003]LISTENER NAME
BLDD10: [ITEXT(<^N/NODNAM/$^T/0(S1)/$SN;BDATA:^T/NODDAT/>)] ;[6003]SENDER NAME
BLDD11: [ITEXT(<;USERID:^N/NODNAM/$^T/0(S1)/$SN>)] ;[6003]
SUBTTL STSEN - START UP A SENDER
;STSEN is called to start up a sender.
;This routine is called at NEBULA startup and also when a cluster
;topology change occurs that results in a node joining the cluster.
;
;Note: The sender block pages are obtained via the GLXMEM routine M%AQNP.
;M%AQNP zeros out the pages it returns. This implies the following:
;
; SETZM .SNLNK(SEN) ;ZERO OUT THE DECNET STATUS LINK
; SETZM .SNFRE(SEN) ;SENDER NOT READY TO PICK UP A MESSAGE
;
;Call is: SEN/Address of the sender block
;Returns: The sender has been sucessfully started
;Crashes: The sender cannot be started (i.e., a CFORK%, SFORK% or
; PMAP% error has occurred)
;SET UP THE CONTEXT OF THE SENDER
STSEN: $SAVE <T1,T2> ;SAVE THESE AC
MOVEI S1,.SNPDL-1(SEN) ;SET UP THE SENDER CONTEXT
HRLI S1,-PDSIZ ;STACK POINTER
PUSH S1,[EXP SENDER] ;START THE SENDER HERE
MOVEM S1,.SNREG+P(SEN) ;PLACE IN THE DATA BASE
MOVEM SEN,.SNREG+SEN(SEN) ;SAVE THE ADDRESS OF THE DB
;START UP THE SENDER. FIRST CREATE THE SENDER AS AN INFERIOR FORK
;WITH THE SAME CAPABILITIES AS THE TOP FORK.
MOVX S1,<CR%CAP+CR%ACS> ;SUPERIOR CAPS AND AC'S
MOVEI S2,.SNREG(SEN) ;AC LOAD BUFFER
CFORK% ;CREATE A SENDER
ERJMP STSEN2 ;CRASH ON AN ERROR
;MAP NEBULA'S PAGES INTO THE SENDER
MOVEM S1,.SNHND(SEN) ;SAVE THE SENDER'S HANDLE
MOVSI S1,.FHSLF ;GET NEBULA'S HANDLE
HRLZ S2,.SNHND(SEN) ;GET THE SENDER'S HANDLE
HRR T1,NEBSIZ ;GET THE LENGTH IN PAGES
HRLI T1,(PM%RWX!PM%CNT) ;COUNT+READ+EXECUTE
PMAP% ;MAP THE PAGES
ERJMP STSEN3 ;CRASH ON AN ERROR
;MAP THE SENDER BLOCK INTO THE SENDER
MOVE S1,SEN ;GET THE SENDER BLOCK ADDRESS
ADR2PG S1 ;CONVERT IT TO A PAGE NUMBER
MOVE S2,S1 ;SAVE IT IN S2
HRLI S1,.FHSLF ;GET THE TOP FORK'S HANDLE
HRL S2,.SNHND(SEN) ;GET THE SENDER'S HANDLE
HRRI T1,DBSIZ ;GET THE PAGE COUNT
HRLI T1,(PM%RWX!PM%CNT) ;R,W,E + COUNT
PMAP% ;MAP THE DATA BASE
ERJMP STSEN3 ;CRASH ON AN ERROR
;START THE SENDER
MOVE S1,.SNHND(SEN) ;GET THE SENDER'S HANDLE
MOVEI S2,SENDER ;GET THE START ADDRESS
SFORK% ;START THE SENDER
ERJMP STSEN4 ;CRASH ON AN ERROR
$RET ;AND RETURN
STSEN2: $STOP (CCS,CAN'T CREATE A SENDER)
STSEN3: $STOP (CPS,CAN'T PMAP A SENDER)
STSEN4: $STOP (CSS, CAN'T START A SENDER)
SUBTTL CLUSTER TOPOLOGY CHANGE DETECTED
;TOPCHN is called as a result of the SCS interrupt handler
;detecting that the cluster topology has changed. This routine
;updates the node data base and cleans up the message queue, remote
;queue and in behalf of queue for any nodes that may have left the
;cluster.
;
;Call is: No arguments
;Returns: Updated node data base
;Crashes: If the node table is inconsistent
TOPCHN: $SAVE <P1,P2,P3,P4,T1> ;SAVE THE CONTENTS OF THESE AC
;FIRST READ IN THE LATEST TOPOLOGY OF THE CLUSTER
SOS BLDTAB ;DON'T LET TOPOLOGY CHANGE INTERRUPT
;HANDLER TOUCH THE NODE TABLE
TOPCH1: SETZM SCSFLG ;TURN OFF SCS% INTERRUPT FLAG
SETOM NBSCHD ;FORCE A SCHEDULING PASS
$CALL GTNDAT ;PICK UP THE NODE NAMES AND NUMBERS
;CONVERT THE ASCIZ NODE NAMES TO SIXBIT AND PLACE IN THE SIXBIT NODE NAME
;TABLE NDNTBL
MOVEI P1,ASZNAM ;POINT TO THE ARGUMENT BLOCK
HLRZ P2,.CFNND(P1) ;PICK UP THE NUMBER OF NODES
SOJE P2,TOPC12 ;NO MORE REMOTE NODES
CAILE P2,MAXNOD ;IS LESS THAN MAX SUPPORTED NODES?
$CALL S..CTL ;NO, CRASH NOW
MOVEM P2,CURNUM ;REMEMBER THE CURRENT # OF REMOTE NODES
ADDI P1,.CFBP1+1 ;POINT TO THE FIRST ASCIZ NODE NAME
MOVEI T1,NDNTBL ;POINT TO THE FIRST SIXBIT NODE NAME
TOPCH2: MOVE S1,0(P1) ;PICK UP THE NODE NAME BYTE POINTER
$CALL S%SIXB ;CONVERT THE NODE NAME TO SIXBIT
MOVEM S2,0(T1) ;PLACE IN THE SIXBIT NODE NAME TABLE
AOS P1 ;POINT TO THE NEXT ASCIZ NAME POINTER
AOS T1 ;POINT TO THE NEXT SIXBIT NAME
SOJG P2,TOPCH2 ;CONVERT THE NEXT NODE NAME
;DETERMINE WHICH NODES NOW IN THE CLUSTER WERE PREVIOUSLY IN THE CLUSTER
SKIPG RENNUM ;WERE THERE REMOTE NODES IN CLUSTER?
JRST TOPC15 ;NO, CHECK FOR NEW NODES
MOVEI P1,NODTBL ;POINT TO THE NODE TABLE
MOVE P3,RENNUM ;PICK UP PREVIOUS NUMBER OF NODES
MOVEI P4,MAXNOD ;PICK UP MAX NUMBER OF REMOTE NODES
MOVS P2,CURNUM ;PICK UP CURRENT # OF NODES
MOVNS P2 ;MAKE IT NEGATIVE FOR THE AOBJN
MOVE T1,P2 ;SAVE FOR LATER
TOPCH3: SKIPN S1,.NNNAM(P1) ;PICK UP NEXT NODE NAME FROM NODE TABLE
JRST TOPCH8 ;THIS NODE TABLE ENTRY IS NOT IN USE
TOPCH4: CAMN S1,NDNTBL(P2) ;COMPARE WITH THE CURRENT NODE NAMES
JRST TOPCH9 ;A MATCH, CHECK THE STATUS OF THE NODE
AOBJN P2,TOPCH4 ;CHECK THE NEXT CURRENT NODE
;THE NODE NAME IN THE NODE TABLE ENTRY WAS NOT FOUND IN THE CURRENT NODE
;NAME LIST. THIS MEANS THAT THIS NODE IS NO LONGER IN THE CLUSTER.
;DELETE THIS NODE FROM THE NODE DATA BASE.
MOVE S1,P1 ;PASS THE NODE TABLE ENTRY ADDRESS
$CALL KILNOD ;DELETE THIS NODE FROM NODE DATA BASE
TOPCH6: SOJE P3,TOPC15 ;FINISHED CHECKING FOR KNOWN NODES?
MOVE P2,T1 ;NO, POINT TO NODE NAME TABLE
TOPCH8: ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE TABLE ENTRY
SOJE P4,S..NTI ;CRASH, THE NODE TABLE IS INCONSISTENT
JRST TOPCH3 ;CHECK IF THIS NODE IS KNOWN
;THE NODE EXISTS, FIRST CHECK IF THE NODE MAY HAVE CRASHED AND COME BACK
TOPCH9: MOVE S1,.NNSTA(P1) ;PICK UP THE NODE'S STATUS
TXNN S1,NN%SCS ;DID THIS NODE CRASH AND COME BACK
JRST TOPC11 ;NO, CHECK IF INFO% ENCOUNTERED ERROR
;THE NODE HAS CRASHED AND COME BACK. FIRST KILL THE SENDER AND THE LISTENER
;AND ZERO OUT THE NODE ENTRY. ALSO, UPDATE THE MESSAGE, REMOTE, AND
;IN BEHALF OF QUEUES FOR THIS NODE.
MOVE S1,P1 ;PICK UP THE NODE ENTRY ADDRESS
$CALL KILNOD ;KILL THE SENDER AND LISTENER
;REBUILD THE NODE TABLE ENTRY AND CHECK THAT THE NODE HAS BOTH DECNET
;ENABLED AND HAS A RELEASE 7 OR LATER MONITOR
MOVE S1,P1 ;PICK UP THE NODE TABLE ENTRY ADDRESS
MOVE S2,P2 ;PICK UP THE NODE NAME TABLE OFFSET
$CALL BLDNEN ;BUILD THE NODE ENTRY
JUMPF TOPCH6 ;NO DECNET AND/OR RELEASE 7 MONITOR
;THE NODE HAS DECNET AND A RELEASE 7 OR LATER MONITOR. THEREFORE, START A
;LISTENER AND SENDER DIRECTED AT THIS NODE
TOPC10: MOVE S1,P1 ;PICK UP THE NODE ENTRY ADDRESS
$CALL STAINF ;START THE LISTENER AND SENDER
JRST TOPCH6 ;CHECK THE NEXT NODE
;CHECK IF THE INFO% JSYS HAD AN ERROR OBTAINING THIS NODE'S S.W. ENVIRONMENT
;IF SO, HAVE THE INFO% JSYS RETRY TO OBTAIN THIS NODE'S SOFTWARE ENVIRONMENT
TOPC11: TXNN S1,NN%COI ;INFO% PREVIOUSLY HAD AN ERROR?
JRST TOPCH6 ;NO, GO CHECK THE NEXT NODE
MOVE S1,P1 ;YES, PICK UP THE NODE TABLE ENTRY ADR
$CALL NODPAR ;LET INFO% TRY AGAIN
JUMPF TOPCH6 ;[6016]CHECK NEXT NODE ON AN ERROR
MOVX S1,NN%COI!NN%DCN!NN%REL ;[6016]PICK UP THE ERROR BITS
ANDCAM S1,.NNSTA(P1) ;[6016]TURN THEM OFF IN THE STATUS WORD
MOVE S1,.NIETM(P1) ;[6016]PICK UP INFO% TIME WORD VALUE
SETZM .NIERC(P1) ;[6016]ZERO OUT INFO% RETRY COUNT
SETZM .NIETM(P1) ;[6016]ZERO OUT INFO% TIME WORD
CAMN S1,[-1] ;[6016]RETRY COUNT EXHAUSTED?
JRST TOPCH6 ;[6016]YES, THEN NO TIMER IS SET
MOVEI S2,IEPROC ;[6016]CLEAR THE INFO% TIMER ENTRY
$CALL REMTIM ;[6016]CLEAR THE TIMER
JRST TOPCH6 ;[6016]CHECK THE NEXT NODE
;THERE ARE NO LONGER ANY REMOTE NODES IN THIS CLUSTER. CLEAN UP THE
;NODE DATA BASE FOR ANY PREVIOUSLY KNOWN NODES
TOPC12: SKIPG P1,RENNUM ;ANY PREVIOUSLY KNOWN REMOTE NODES?
JRST TOPC23 ;NO, SO ARE FINISHED WITH THE UPDATE
SETZM RENNUM ;NO MORE REMOTE NODES AFTER THIS
MOVEI P2,NODTBL ;PICK UP ADDRESS OF THE NODE TABLE
MOVEI P3,MAXNOD ;PICK UP MAXIMUM NUMBER OF NODES
TOPC13: SKIPN .NNNAM(P2) ;IS THIS ENTRY IN USE?
JRST TOPC14 ;NO, CHECK THE NEXT ENTRY
MOVE S1,P2 ;ADR OF THIS NODE'S NODE TABLE ENTRY
$CALL KILNOD ;DELETE THIS NODE FROM NODE DATA BASE
SOJE P1,TOPC23 ;FINISHED IF NO MORE NODES TO PROCESS
TOPC14: ADDI P2,.NNNSZ ;POINT TO THE NEXT ENTRY
SOJE P3,S..NTI ;CHECK FOR INCONSISTENCY IN NODE TABLE
JRST TOPC13 ;CHECK THE NEXT NODE
;ALL THE PREVIOUSLY KNOWN NODES HAVE BEEN PROCESSED. NOW CHECK FOR ANY
;NEW NODES IN THE CLUSTER. FIRST SET UP THE SEARCH
TOPC15: MOVS P2,CURNUM ;PICK UP THE NEW NUMBER OF NODES
MOVNS P2 ;SET UP FOR THE AOBJN LOOP
;SEARCH FOR THE NODE NAME IN THE NODE TABLE
TOPC16: MOVEI P1,NODTBL ;POINT TO THE NODE TABLE
MOVEI P3,MAXNOD ;PICK UP SIZE OF THE NODE TABLE
MOVE S1,NDNTBL(P2) ;PICK UP NEXT CURRENT NODE NAME
TOPC17: CAMN S1,.NNNAM(P1) ;DO THEY MATCH?
JRST TOPC22 ;YES, CHECK THE NEXT LATEST NODE NAME
ADDI P1,.NNNSZ ;NO, POINT TO NEXT NODE IN NODE TABLE
SOJG P3,TOPC17 ;GO CHECK THIS NODE
;NODE NAME NOT FOUND IN THE NODE TABLE. THIS IS A NEW NODE. ADD THIS NODE
;TO THE NODE TABLE. FIRST FIND A FREE ENTRY.
MOVEI P1,NODTBL ;POINT TO THE NODE TABLE
MOVEI P3,MAXNOD ;PICK UP SIZE OF THE NODE TABLE
TOPC18: SKIPN .NNNAM(P1) ;IS THIS NODE TABLE ENTRY FREE?
JRST TOPC19 ;YES, GO SET UP THE NODE ENTRY
ADDI P1,.NNNSZ ;NO, POINT TO THE NEXT ENTRY
SOJG P3,TOPC18 ;CHECK THE NEXT ENTRY
PJRST S..NTI ;CRASH IF NODE TABLE IS INCONSISTENT
;BUILD THE NODE TABLE ENTRY AND CHECK IF THE NODE IS IN THE PACKN TABLE.
;IF IT IS NOT, THEN ADD IT
TOPC19: MOVE S1,P1 ;PICK UP THE NODE TABLE ENTRY ADR
MOVE S2,P2 ;PICK UP OFFSET INTO NODE NAME TABLE
$CALL BLDNEN ;BUILD THE NODE ENTRY
MOVE T1,TF ;SAVE THE TRUE/FALSE AC CONTENTS
MOVE S2,TF ;INDICATE IF A SENDER CAN BE STARTED
MOVE S1,P1 ;PICK UP NODE TABLE ENTRY ADDRESS
$CALL FNDPNE ;FIND OR BUILD A PACKN ENTRY
JUMPE T1,TOPC22 ;NO DECNET AND/OR RELEASE 7 MONITOR?
;THE NODE HAS DECNET AND A RELEASE 7 OR LATER MONITOR. THEREFORE, START A
;LISTENER AND SENDER DIRECTED AT THIS NODE
TOPC21: MOVE S1,P1 ;PICK UP THE NODE ENTRY ADDRESS
$CALL STAINF ;START THE LISTENER AND SENDER
TOPC22: AOBJN P2,TOPC16 ;CHECK THE NEXT NODE
MOVE S1,CURNUM ;PICK UP THE LATEST NUMBER OF NODES
MOVEM S1,RENNUM ;SAVE FOR LATER
TOPC23: SKIPE SCSFLG ;DID A TOPOLOGY CHANGE OCCUR?
JRST TOPCH1 ;YES, UPDATE THE NODE DATA BASE
AOS BLDTAB ;ALLOW NBSCS TO TOUCH NODE TABLE
SKIPN RECHEK ;[6016]NEED A RECHECK?
$RETT ;[6016]NO, RETURN NOW
$CALL TOPTMR ;[6016]SET UP THE TOPOLOGY TIMER
SETZM RECHEK ;[6016]INDICATE NO RECHECK
$RETT ;[6016]AND RETURN TO THE CALLER
SUBTTL KILNOD - DELETE A NODE FROM THE NODE DATA BASE
;KILNOD removes a node from the node data base. The node's sender
;and listener are killed. Also, all the node's entries in the
;message, remote and in behalf of queues must be updated. In addition, the
;node's timer list must be deleted and all timers turned off.
;
;Call is: S1/Node Table entry address of the node
;Returns: Node is deleted from the node data base
KILNOD: $SAVE <P1,P2> ;SAVE THESE AC
MOVE P1,S1 ;SAVE THE NODE ENTRY ADDRESS
;DETERMINE IF THIS NODE HAS A SENDER AND LISTENER ASSOCIATED WITH IT
SKIPN .NNSBA(P1) ;SENDER ADDRESS BLOCK PRESENT?
JRST KILNO2 ;NO, SO NO LISTENER AND SENDER
;KILL THE LISTENER AND SENDER
MOVE S1,P1 ;PICK UP THE NODE TABLE ENTRY ADDRESS
$CALL KILINF ;KILL THE LISTENER AND SENDER
;DELETE THE TIMER LIST AND TURN OFF THE TIMERS FOR THIS NODE.
;UPDATE ANY REMOTE QUEUE ENTRIES FOR THIS NODE. MARK THE STATUS OF THE
;REMOTE QUEUE ENTRY FOR THIS NODE AS "SENDER/LISTENER ARE CRASHED".
;ALSO, DELETE ALL IN BEHALF OF QUEUE ENTRIES TO THIS NODE.
;ALSO, UPDATE THE MESSAGE QUEUE FOR THIS NODE.
MOVE S1,P1 ;PICK UP THE NODE TABLE ENTRY ADDRESS
$CALL UPDQUE ;UPDATE THIS NODE'S TIMER LIST & QUEUES
;RELEASE THE SENDER BLOCK AND LISTENER BLOCK PAGES
MOVEI S1,DBSIZ ;NUMBER OF PAGES IN SENDER BLOCK
MOVE S2,.NNSBA(P1) ;ADDRESS OF SENDER BLOCK
ADR2PG S2 ;CHANGE TO PAGE NUMBER
$CALL M%RLNP ;RELEASE THE PAGES
MOVEI S1,DBSIZ ;NUMBER OF PAGES IN LISTENER BLOCK
MOVE S2,.NNLBA(P1) ;ADDRESS OF LISTENER BLOCK
ADR2PG S2 ;CHANGE TO PAGE NUMBER
$CALL M%RLNP ;RELEASE THE PAGES
;[6016]IF AN INFO% JSYS TIMER IS SET, THEN CLEAR IT
KILNO2: SKIPN S1,.NIETM(P1) ;[6016]PICK UP THE INFO% TIMER WORD
JRST KILNO3 ;[6016]IF NOT SET, CLEAR NODE ENTRY
CAMN S1,[-1] ;[6016]RETRY COUNT EXHAUSTED?
JRST KILNO3 ;[6016]YES, CLEAR THE NODE ENTRY
MOVEI S2,IEPROC ;[6016]CLEAR THE INFO% TIMER ENTRY
$CALL REMTIM ;[6016]CLEAR THE TIMER
;ZERO OUT THE NODE ENTRY TO INDICATE THAT IT IS FREE
KILNO3: SETZM .NNNAM(P1) ;[6016]CLEAR 1ST WORD OF THE NODE ENTRY
MOVE S1,P1 ;PICK UP THE ADDRESS OF THE NODE ENTRY
ADDI S1,.NNNSZ ;POINT TO END OF NODE ENTRY + 1
HRLS P1 ;SOURCE ADDRESS OF BLT IN LEFT HALF
AOS P1 ;DESTINATION ADR OF BLT IN RIGHT HALF
BLT P1,-1(S1) ;ZERO THE NODE ENTRY
$RET ;AND RETURN TO THE CALLER
SUBTTL KILINF - KILL A NODE'S LISTENER AND SENDER
;KILINF kills the sender and listener associated with a node. This occurs when
;it is detected that the remote node associated with the sender and listener
;no longer exists, or has crashed and come back, or the sender and/or listener
;to that node has crashed.
;
;Call is: S1/Node table entry address
;Returns: The sender and listener have been killed
KILINF: $SAVE <P1> ;SAVE THIS AC
MOVE P1,S1 ;SAVE THE NODE TABLE ENTRY ADDRESS
;FIRST KILL THE SENDER
MOVE SEN,.NNSBA(P1) ;PICK UP ADDRESS OF THE SENDER BLOCK
MOVE S1,.SNHND(SEN) ;PICK UP THE SENDER'S HANDLE
KFORK% ;KILL THE SENDER
ERJMP .+1 ;HANDLE NO LONGER VALID, IGNORE
;NOW KILL THE LISTENER
MOVE LIS,.NNLBA(P1) ;PICK UP ADDRESS OF THE LISTENER BLOCK
MOVE S1,.LSHND(LIS) ;PICK UP THE LISTENER'S HANDLE
KFORK% ;KILL THE LISTENER
ERJMP .+1 ;HANDLE NO LONGER VALID, IGNORE
$RET ;RETURN TO THE CALLER
SUBTTL UPDQUE - UPDATE A NODE'S QUEUES
;UPDQUE is called to delete a node's timer list (and turn off its timers),
;remote queue, in behalf of queue and message queue. The queue updates
;are done as part of processing the data base of a node that has left the
;cluster (or left the cluster and has come back) or as part of the processing
;when a sender and/or listener associated with the node has crashed.
;
;Call is: S1/Node table entry address of the node
;Returns: The node's queues have been updated
UPDQUE: $SAVE <P1> ;SAVE THESE AC
MOVE P1,S1 ;PICK UP THE NODE TABLE ENTRY ADDRESS
$CALL DELTIM ;DELETE THE TIMER LIST AND TIMERS
SKIPE S1,.NRQLH(P1) ;IS THE REMOTE QUEUE EMPTY?
$CALL UPDREM ;NO, UPDATE THE REMOTE QUEUE
MOVE S1,.NNNAM(P1) ;PICK UP THE NODE NAME
SKIPE IBQHDR ;IS THE IBH QUEUE EMPTY?
$CALL UPDIBH ;NO, UPDATE THE IN BEHALF OF QUEUE
MOVE S2,.NNSBA(P1) ;PICK UP THE SENDER BLOCK ADDRESS
SKIPE S1,.SNHWD(S2) ;IS THE MESSAGE QUEUE EMPTY?
$CALL UPDMSG ;NO, UPDATE THE MESSAGE QUEUE
$RET ;RETURN TO THE CALLER
SUBTTL DELTIM - DELETE THE TIMER LIST AND TURN OFF TIMERS
;DELTIM is called when communication has been lost to a remote node
;(a sender or listener to that node has crashed, the node has left
;the cluster, or a timeout to that node has occurred).
;DELTIM deletes the timer list and turns off any outstanding timer
;events of the node.
;
;Call is: S1/Node table entry address
;Returns: Timer list has been deleted and timers turned off
DELTIM: $SAVE <P1> ;SAVE THIS AC
;DETERMINE IS THE TIMER LIST IS EMPTY. IF IT IS, JUST DELETE THE LIST HEADER
MOVE S1,.NTIML(S1) ;PICK UP TIMER LIST INDEX
MOVE P1,S1 ;SAVE LIST INDEX IN CASE LIST IS EMPTY
$CALL L%FIRST ;PICK UP FIRST LIST ENTRY
JUMPF DELTI3 ;IF EMPTY, DELETE THE LIST HEADER
;THE TIMER LIST IS NOT EMPTY. DELETE ALL ENTRIES AND TURN OFF ALL THE
;CORRESPONDING TIMERS.
DELTI2: MOVE S1,.TMUDT(S2) ;GET THE UDT THE TIMER IS TO GO OFF
SETZ S2, ;[6016]DELETE ALL ENTRIES AT THIS UDT
$CALL REMTIM ;TURN OFF THE TIMER FOR THIS ENTRY
MOVE S1,P1 ;PICK UP THE LIST INDEX
$CALL L%NEXT ;GET THE NEXT TIMER LIST ENTRY
JUMPT DELTI2 ;GO TURN OFF THE TIMER FOR THIS ENTRY
;NO MORE TIMER LIST ENTRIES. DELETE THE TIMER LIST
DELTI3: MOVE S1,P1 ;PICK UP THE LIST INDEX
$CALL L%DLST ;DELETE THE LIST
$RET ;RETURN TO THE CALLER
SUBTTL UPDREM - CLEAN UP REMOTE QUEUE FOR SENDER/LISTENER CRASH
;UPDREM is called when communication to a remote node has been lost (a sender
;or listener to that node has crashed, the node has left the cluster, or a
;timeout to that node has occurred), part of the cleanup is to update the
;remote queue for that node. This is accomplished by marking every entry for
;that node as "sender/listener" has crashed.
;If there are no other outstanding responses, then a FROM NEBULA DISMOUNT
;ACK message is built and sent to ORION to be forwarded to MOUNTR.
;
;Call is: S1/Remote queue link list header word for node with crashed
; listener or sender
;Returns: The remote queue has been updated for the crashed node
;Crashes: Unable to send an ACK message to ORION
UPDREM: $SAVE <P1,P2> ;SAVE THESE AC
;POINT TO THE INVARIANT BLOCK ADDRESS OF THIS ENTRY AND POINT TO THE
;NODE BLOCK OF THIS NODE IN THE REMOTE QUEUE ENTRY
MOVE P1,S1 ;SAVE THE REMOTE QUEUE L.L. HDR WORD
UPDRE2: LOAD P2,.RQBLK(P1),RQ.OFF ;PICK UP THE OFFSET TO INVARIANT BLOCK
ADD S1,P2 ;POINT TO THE INVARIANT BLOCK
LOAD S2,.RQNUM(S1),RQ.NTS ;PICK UP NUMBER OF NODE BLOCKS
SUB S2,P2 ;SUBTRACT THE OFFSET TO GET BLOCK NUMBER
IMULI S2,.RQNSZ ;CALCULATE THE SIZE OCCUPIED BY THE BLKS
ADDI S2,.RQNIZ(S1) ;ADD INVARINAT BLOCK SIZE TO GET THE
;ADDRESS OF THE NODE BLOCK
;INDICATE IN THE NODE BLOCK THAT THE "SENDER/LISTENER HAVE CRASHED"
;AND DECREMENT THE NUMBER OF OUTSTANDING RESPONSES TO BE RECEIVED
;FOR THIS QUEUE ENTRY
MOVX P2,RQ%SLD!RQ%TER ;[6030]SENDER/LISTENER CRASHED
IORM P2,.RQNST(S2) ;INDICATE IN NODE BLOCK
MOVEI P2,SCLX08 ;[6027]INDICATE COMMUNICATION IS LOST
STORE P2,.RQNST(S2),RQ.ERR ;[6027]INDICATE IN THE NODE BLOCK
SOS .RQNUM(S1) ;ONE LESS RESPONSE TO EXPECT
LOAD P1,.RQBLK(P1),RQ.NEA ;PICK UP ADDRESS OF NEXT REMOTE QE
LOAD P2,.RQNUM(S1),RQ.NOR ;PICK UP NUMBER OF REMAINING RESPONSES
SKIPN P2 ;IF MORE RESPONSES GO TO NEXT REMOTE QE
;THERE ARE NO MORE OUTSTANDING RESPONSES FOR THIS REMOTE QUEUE ENTRY.
;BUILD A TO NEBULA DISMOUNT ACK MESSAGE AND SEND IT TO ORION.
$CALL SNDACK ;BUILD AND SEND THE MESSAGE
JUMPG P1,UPDRE2 ;PROCESS THE NEXT REMOTE QE, IF ANY
$RET ;FINISHED, RETURN TO THE CALLER
SUBTTL UPDIBH - CLEAN UP IBH QUEUE FOR SENDER/LISTENER
;UPDIBH is called when communication to a remote node has been lost (a sender
;or listener to that node has crashed, the node has left the cluster, or a
;timeout to that node has occurred). Part of the cleanup is to delete the
;the entries in the in behalf of queue that correspond to that node.
;
;Call is: S1/SIXBIT NODE NAME that has a crashed listener or sender
;Returns: IBH queue has been cleaned up
UPDIBH: $SAVE <P1,P2,P3> ;SAVE THESE AC
SKIPN P2,IBQHDR ;IS THE IBH QUEUE EMPTY?
JRST UPDIB4 ;YES, SO ARE FINISHED
;CHECK IF THIS ENTRY CORRESPONDS TO THE NODE
MOVEI P1,IBQHDR ;PICK UP ADDRESS OF PREVIOUS ENTRY
MOVE P3,S1 ;REMEMBER THE NODE NAME
UPDIB2: CAME P3,.IQNEN(P2) ;DO THE NAMES MATCH?
JRST UPDIB3 ;NO, CHECK THE NEXT ENTRY
;THIS ENTRY BELONGS TO THE NODE. DELETE IT FROM THE IN BEHALF OF QUEUE
LOAD S1,.IQLNK(P2),IQ.NXT ;GET THE NEXT ENTRY'S ADDRESS
STORE S1,.IQLNK(P1),IQ.NXT ;REMEMBER IT IN THE PREVIOUS ENTRY
MOVEI S1,.IQSIZ ;PICK UP THE ENTRY'S SIZE
MOVE S2,P2 ;PICK UP THE ENTRY'S ADDRESS
$CALL M%RMEM ;RETURN ENTRY TO THE MEMORY MANAGER
SKIPA ;GO CHECK IF LAST ENTRY
;PICK UP THE NEXT ENTRY. IF THERE ARE NO MORE, THEN UPDATE THE LINK LIST
;TRAILER WORD.
UPDIB3: MOVE P1,P2 ;CURRENT ENTRY BECOMES PREVIOUS ENTRY
LOAD P2,.IQLNK(P1),IQ.NXT ;PICK UP THE NEXT ENTRY
SKIPE P2 ;IS THIS THE LAST ENTRY?
JRST UPDIB2 ;NO, CHECK THE NEXT ENTRY
MOVEM P1,IBQTRL ;YES, PLACE ADR IN L.L. TRAILER WORD
SKIPN IBQHDR ;UNLESS THE MESSAGE QUEUE IS EMPTY
SETZM IBQTRL ;THEN ZERO OUT THE TRAILER WORD
UPDIB4: $RET ;AND RETURN TO THE CALLER
SUBTTL UPDMSG - CLEAN UP MESSAGE QUEUE FOR SENDER/LISTENER
;UPDMSG is called when communication to a remote node has been lost (a sender
;or listener to that node has crashed, the node has left the cluster, or a
;timeout to that node has occurred). Part of the cleanup is to delete all
;message queue entries for that node. If a message is not in response to an
;in behalf of request or if the message does not have a corresponding
;remote queue entry, then an ACK message is sent to the OPR of the message
;indicating the message could not be delivered to the remote node.
;If the message is not to be sent to any other nodes, then the message entry
;is returned to the memory manager.
;
;Call is: S1/Message queue header word
; S2/Sender block address
;Returns: Message queue for the node has been deleted
UPDMSG: $SAVE <P1,P2,P3,P4> ;SAVE THESE AC
;SET UP THE POINTERS INTO THE MESSAGE QUEUE:
;(P1) PREVIOUS MESSAGE QUEUE ENTRY ADDRESS
;(P2) CURRENT MESSAGE QUEUE ENTRY ADDRESS
;(P3) POINTER TO INVARIANT BLOCK
SKIPN P2,S1 ;IS THE MESSAGE QUEUE EMPTY?
JRST UPDMS6 ;YES, SO FINISHED
MOVEI P1,.SNHWD(S2) ;PICK UP PREVIOUS MSG ENTRY ADDRESS
MOVE P4,S2 ;REMEMBER SENDER BLOCK ADDRESS
UPDMS1: LOAD P3,.MQBLK(P2),MQ.OFF ;[6012]PICK UP THE OFFSET
ADD P3,P2 ;POINT TO THE INVARIANT BLOCK
;DETERMINE IF THIS MESSAGE HAS A CORRESPONDING REMOTE QUEUE ENTRY OR IS
;A RESPONSE TO AN IN BEHALF OF QUEUE MESSAGE. IF SO, DON'T NOTIFY THE SENDER
;OF THE MESSAGE. (THIS IS BECAUSE THE SENDER OF THE MESSAGE IS NOTIFIED
;WHEN THE REMOTE QUEUE ENTRY IS PROCESSED AND THE SENDER OF THE IN BEHALF
;OF MESSAGE IS ON THE REMOTE NODE WHICH IS INACCESSABLE.)
MOVE S2,.MQNOM(P3) ;[6012]PICK UP THE FLAG BITS
TXNE S2,MQ%REM!MQ%IBH ;[6012]RQE OR IBH MESSAGE RESPONSE?
JRST UPDMS3 ;YES, SO DON'T SEND AN ACK TO SENDER
;BUILD AN ACK MESSAGE TO BE SENT TO THE OPR THAT MADE THE REQUEST OR BUILD
;A TEXT MESSAGE TO BE SENT TO THE EXEC THAT MADE THE REQUEST
$CALL E$NSM ;PLACE ERROR CODE IN G$ERR
LOAD M,.MQNOM(P3),MQ.ADR ;PICK UP ADDRESS OF THE MESSAGE
MOVE S1,.SNNTA(P4) ;PICK UP NODE TABLE ENTRY ADDRESS
MOVE S1,.NNNAM(S1) ;PICK UP THE SIXBIT REMOTE NODE NAME
MOVEM S1,G$ARG1 ;PLACE IN E$ ERROR BLOCK
TXNN S2,MQ%EXE ;[6012]WAS THE MSG FROM AN EXEC?
JRST UPDMS2 ;[6012]NO, SEND ACK TO THE OPERATOR
MOVE S1,.MQPID(P3) ;[6012]PICK UP THE EXEC'S PID
MOVEM S1,G$SND ;[6012]SAVE IT FOR EREXEC
$CALL EREXEC ;[6012]SEND THE ERROR MSG TO THE EXEC
JRST UPDMS3 ;[6013]CHECK FOR ANY MORE NODES
UPDMS2: MOVE S1,G$ERR ;[6013]PICK UP THE ERROR DISPLACEMENT
$ACK (<^I/@TXTTBL(S1)/>,,,.MSCOD(M)) ;[6013]SEND THE ACK TO ORION
;IF THE MESSAGE IS NOT TO BE SENT TO ANY MORE NODES, THEN RETURN ITS
;MEMORY TO THE MEMORY MANAGER.
UPDMS3: LOAD S1,.MQNOM(P3),MQ.NUM ;# OF REMAINING NODES TO SEND MSG TO
SOJE S1,UPDMS4 ;RETURN ENTRY IF NO NODES LEFT TO SEND
STORE S1,.MQNOM(P3),MQ.NUM ;STORE THE NUMBER OF NODES LEFT TO SEND
JRST UPDMS5 ;CHECK THE NEXT MESSAGE QUEUE ENTRY
;PLACE THE LINK LIST WORD OF THE ENTRY TO BE DELETED IN THE PRECEDING ENTRY'S
;LINK LIST WORD AND RETURN THE ENTRY TO THE MEMORY MANAGER
UPDMS4: LOAD S1,.MQBLK(P2),MQ.NEA ;PICK UP THE LINK LIST WORD
STORE S1,.MQBLK(P1),MQ.NEA ;PLACE IN THE PRECEDING ENTRY
MOVE S1,P3 ;PICK UP THE INVARIANT BLOCK ADDRESS
$CALL RELMQE ;RETURN THE ENTRY TO THE MEMORY MANAGER
SKIPA ;GO CHECK THE NEXT ENTRY
;DETERMINE IF ANOTHER ENTRY EXISTS. IF SO, THEN CHECK IT
UPDMS5: MOVE P1,P2 ;CURRENT ENTRY BECOMES PRECEDING ENTRY
LOAD P2,.MQBLK(P1),MQ.NEA ;PICK UP ADDRESS OF THE NEXT ENTRY
SKIPE P2 ;IS THERE ANOTHER ENTRY?
JRST UPDMS1 ;[6012]YES, CHECK IT OUT
UPDMS6: $RET ;FINISHED WITH MESSAGE QUEUE CLEAN UP
SUBTTL BLDNEN - BUILD AN ENTRY IN THE NODE TABLE
;BLDNEN is called when a cluster topology change has occurred which
;results in either a node joining the cluster or a node which has left the
;cluster and rejoined it since the last scheduler pass.
;
;Call is: S1/Node Table entry address for the node joining the cluster
; S2/Offset into SIXBIT Node Name Table pointing to the node name
;Returns true: Node has DECnet enabled and a monitor of release 7 or later
;Returns false: Node does not have DECnet and/or a monitor of release 7
; or later
BLDNEN: $SAVE <P1> ;SAVE THIS AC
MOVE P1,NDNTBL(S2) ;PICK UP THE NODE NAME
MOVEM P1,.NNNAM(S1) ;PLACE IN THE NODE TABLE ENTRY
HLRZ P1,<NNMTBL+.CFCS1+1>(S2) ;PICK UP THE CURRENT NODE NUMBER
ANDI P1,NNMFLD ;JUST WANT THE NODE NUMBER
HRRZM P1,.NNSTA(S1) ;PLACE IN NODE TABLE ENTRY
MOVE P1,S1 ;[6016]SAVE THE NODE TABLE ENTRY ADR
$CALL NODPAR ;[6016]PICK UP THE NODE CHARACTERISTICS
$RETIT ;[6016]RETURN IF CAN SEND TO THE NODE
MOVE S1,P1 ;[6016]PICK UP THE NODE ENTRY ADDRESS
$CALL STINFO ;[6016]SET UP THE INFO% RETRY TIMER
$RETF ;[6016]INDICATE FAILURE
SUBTTL CHKDEC - INFERIOR FORK HAS A DECNET CONNECTION
;CHKDEC is called as a result of a sender's DECnet connection request to a
;listener being accepted by the listener or as a result of a listener
;accepting a sender's DECnet connection request.
;For a sender whose connection has been accepted, its state is changed from
;"waiting for a HELLO response" to "HELLO message has been successfully
;sent".
;For a listener whose connection has been accepted, its state is changed from
;"waiting for a HELLO message" to "received a HELLO message."
;
;Messages are never sent to a remote node until the sender's DECnet connection
;has been accepted and the listener has accepted a DECnet connection from
;the remote node's sender. If both of these events have occurred, then
;CHKDEC turns on bit NN%OKS in the node's node table entry status word. This
;indicates that messages can be sent to that node. The word .SNFRE is
;set to -1 in the sender block of the sender indicating that the sender
;is available to send a message. The word .LSAVA is also set to indicate that
;the top fork is available to pick up a message.
;
;Call is: No arguments
;Returns: Node's sender and listener status is updated.
CHKDEC: SETZM IREADY ;RESET FOR THE INTERRUPT HANDLER
SETOM NBSCHD ;FORCE A SCHEDULING PASS
$SAVE <P1,P2,P3> ;SAVE THESE AC
;CHECK IF THE SENDER OF THE CURRENT NODE BEING LOOKED AT HAS JUST MADE A
;SUCCESSFUL DECNET CONNECTION.
MOVEI P1,NODTBL ;PICK UP THE NODE TABLE ADDRESS
MOVEI P2,MAXNOD ;PICK UP MAX # OF ENTRIES IN NODE TABLE
SKIPG P3,RENNUM ;[6035]ANY NODES LEFT IN THE CLUSTER?
$RET ;[6035]NO, RETURN NOW
CHKDE2: SKIPN .NNNAM(P1) ;IS THIS ENTRY IN USE?
JRST CHKDE8 ;NO, CHECK THE NEXT ENTRY
MOVE S1,.NSSTA(P1) ;PICK UP THE SENDER STATUS WORD
TXNN S1,NS%NRH ;JUST COMPLETED A DECNET CONNECTION?
JRST CHKDE4 ;NO, CHECK IF THE LISTENER HAS
;THE REMOTE LISTENER HAS ACCEPTED THIS SENDER'S DECNET CONNECTION REQUEST.
;UPDATE THIS SENDER'S STATUS. UPDATE, IF NECESSARY, THE PACKN SENDER STATUS FOR
;THIS NODE. CHECK IF LISTENER HAS ALREADY ACCEPTED A CONNECTION.
MOVX S1,NS%NRH!NS%WHR!NS%HEL ;NO LONGER WAITING FOR HELLO RESPONSE
XORM S1,.NSSTA(P1) ;UPDATE STATUS IN NODE TABLE
MOVX S1,NN%SHO ;SENDER HAS A CONNECTION
ANDCAM S1,.NNSTA(P1) ;INDICATE IN THE NODE STATUS WORD
MOVE S1,.NNNAM(P1) ;PICK UP THE NODE NAME
$CALL SRHPNE ;FIND THE PACKN TBL ENTRY FOR THIS NODE
JUMPF CHKDE3 ;CAN'T FIND ENTRY (SHOULD NEVER HAPPEN)
MOVX S1,LK%SEN ;INDICATE SENDER HAS A CONNECTION
IORM S1,.LKSTS(S2) ;UPDATE PACKN SENDER STATUS
CHKDE3: SKIPGE .NLSTA(P1) ;HAS LISTENER RECEIVED A HELLO MESSAGE?
JRST CHKDE6 ;YES, INDICATE NODE READY FOR MESSAGES
;CHECK IF THIS NODE'S LISTENER JUST ACCEPTED A DECNET CONNECTION.
CHKDE4: MOVE S1,.NLSTA(P1) ;PICK UP LISTENER'S STATUS WORD
TXNN S1,NL%NRH ;JUST ACCEPTED A DECNET CONNECTION?
JRST CHKDE7 ;NO, CHECK THE NEXT NODE
;THE LISTENER HAS JUST ACCEPTED THE REMOTE NODE'S SENDER'S DECNET CONNECTION
;REQUEST. UPDATE THE LISTENER'S STATUS IN THE NODE DATA BASE AND THE PACKN
;TABLE
MOVX S1,NL%NRH!NL%WHL!NL%HEL ;NO LONGER WAITING FOR A HELLO
XORM S1,.NLSTA(P1) ;SAVE THE UPDATED STATUS IN NODE TABLE
MOVX S1,NN%LHO ;LISTENER HAS A CONNECTION
ANDCAM S1,.NNSTA(P1) ;INDICATE IN THE NODE STATUS WORD
MOVE S1,.NNNAM(P1) ;PICK UP THE NODE NAME
$CALL SRHPNE ;FIND THE PACKN ENTRY FOR THIS NODE
JUMPF CHKDE5 ;ENTRY NOT FOUND (SHOULD NOT HAPPEN)
MOVX S1,LK%LIS ;INDICATE LISTENER HAS A CONNECTION
IORM S1,.LKSTS(S2) ;UPDATE THE LISTENER'S PACKN FIELD
CHKDE5: SKIPL .NSSTA(P1) ;DOES SENDER HAVE A DECNET CONNECTION
JRST CHKDE7 ;NO, CHECK THE NEXT NODE
;BOTH THE SENDER AND LISTENER HAVE DECNET CONNECTIONS TO THE REMOTE NODE.
;INDICATE THAT THE REMOTE NODE IS NOW AVAILABLE TO SEND MESSAGES TO AND
;TO PICK UP MESSAGES FROM.
CHKDE6: MOVX S1,NN%OKS ;O.K. TO SEND MESSAGES TO THIS NODE
IORM S1,.NNSTA(P1) ;PLACE IN NODE'S STATUS WORD
MOVE SEN,.NNSBA(P1) ;PICK UP SENDER BLOCK ADDRESS
SETOM .SNFRE(SEN) ;INDICATE SENDER IS AVAILABLE TO SEND
SETOM SREADY ;INDICATE THIS FACT TO SENDER PROCESSOR
MOVE LIS,.NNLBA(P1) ;PICK UP LISTENER BLOCK ADDRESS
MOVE S1,.LSHND(LIS) ;PICK UP LISTENER'S HANDLE
MOVX S2,<1B2> ;CHANNEL TO INTERRUPT ON
SETOM .LSAVA(LIS) ;INDICATE READY TO PROCESS A MESSAGE
IIC% ;TELL THE LISTENER READY TO PROCESS
ERJMP S..UII ;IF CAN'T INTERRUPT SENDER, THEN CRASH
$WTOJ (<NEBULA has communication>,<NEBULA has established communication with node ^N/.NNNAM(P1)/>,,<$WTFLG(WT.SJI)>)
;CHECK CHECK THE NEXT NODE
CHKDE7: SOJE P3,.POPJ ;GO CHECK THE NEXT NODE
CHKDE8: ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE TABLE ENTRY
SOJE P2,S..NTI ;NODE TABLE INCONSISTENCY
JRST CHKDE2 ;CHECK THE NEXT NODE TABLE ENTRY
SUBTTL CHKQUE - IPCF MESSAGE PROCESSING
;CHKQUE is called by the scheduler to check if any IPCF messages are
;available. If there are any IPCF messages available, then each message is
;processed. Only messages sent directly from ORION or QUASAR are accepted.
;Any messages with an unknown message code are ignored.
;
;IPCF message syntax error handling is performed differently depending
;on the message type and who the sender is. The message types and
;senders can be broken down as follows:
;
;Class 1. Remote messages. (Original) senders are MOUNTR, OPR and the EXEC.
; Remote messages are messages that request a service or status from a
; remote node in the cluster. E.g.,
; TO NEBULA DISMOUNT message
; SHOW QUEUES PRINTER message
; These messages are forwarded to the remote system to be acted upon by
; the remote system.
;
;Class 2. Action messages. (Original) sender is OPR.
; Action messages are messages that request NEBULA to perform an action
; for the sender of the message. E.g.,
; SHOW CLUSTER-GALAXY-LINK-STATUS
; ENABLE LINK-STATUS
; These messages are acted upon by NEBULA itself.
;
;Class 3. Response to in behalf of messages. These messages are the
; responses to remote messages (A remote message, once it is at the
; remote node, becomes an in behalf of message since the remote node is
; acting in behalf of a request that originated from a node other than
; itself.) and are forwarded to the original sender - MOUNTR, OPR or the EXEC.
;
;Class 1 error handling.
; If the sender of the message is MOUNTR, then NEBULA crashes when it detects
; an illegally formatted IPCF message.
; If the sender of the message is OPR or the EXEC, then NEBULA sends an
; ACK (.OMACK) message back to the OPR or the EXEC if it detects an illegally
; formatted IPCF message.
;
;Class 2 error handling.
; If NEBULA detects an illegally formatted message, then it sends an ACK
; message back to the OPR that sent the message.
;
;Class 3 error handling.
; If the sender of the message is MOUNTR, then NEBULA crashes when it detects
; an illegally formatted IPCF message.
; If the sender of the message is OPR or the EXEC, then NEBULA simplys forwards
; the response back to the sender of the original request. The only syntax
; checking it does is to ensure that the message length is valid. If it is not,
; then NEBULA sends an ACK message back to the sender indicating that the
; response message specified an illegal message length.
;
;Call is: No arguments
;Returns: All the messages are processed from the IPCF message queue
CHKQUE: $CALL C%RECV ;CHECK IF THERE IS A MESSAGE
JUMPF .POPJ ;RETURN,,NOTHING THERE.
$SAVE <P1,P2> ;SAVE THESE AC
;**;[6037]At CHKQUE:+3L add 1 line JYCW Oct-18-88
SETZM NMFFLG ;[6037]Assume old format
MOVE P1,S1 ;SAVE ADDRESS OF THE MDB
MOVEI S1,TIMOUT ;PICK UP THE TIMEOUT VALUE
SKIPE DEBUGW ;[6031]DEBUGGING?
MOVEI S1,777700 ;[6031]YES, SET FOR A LONG TIME
MOVEM S1,TIMCTR ;SAVE FOR SETTING UP ANY TIMERS
JRST CHKQU3 ;JOIN COMMON CODE
CHKQU2: $CALL C%RECV ;CHECK IF THERE IS A MESSAGE
JUMPF .POPJ ;RETURN,,NOTHING THERE.
MOVE P1,S1 ;SAVE THE ADDRESS OF THE MDB
CHKQU3: SKIPE SCSFLG ;A CLUSTER TOPOLOGY CHANGE OCCURRED?
$CALL TOPCHN ;YES, UPDATE THE NODE DATA BASE
;MAKE SURE THE MESSAGE IS FROM ORION OR QUASAR
LOAD S2,MDB.SI(P1) ;GET SPECIAL INDEX WORD
TXNN S2,SI.FLG ;IS THERE AN INDEX THERE?
JRST CHKQU6 ;NO, IGNORE THIS MESSAGE
ANDX S2,SI.IDX ;AND OUT THE INDEX BIT
CAIE S2,SP.OPR ;IS THE MESSAGE FROM ORION?
CAIN S2,SP.QSR ;IS THE MESSAGE FROM QUASAR?
SKIPA ;YES, CONTINUE ON
JRST CHKQU6 ;NO, DISCARD IT
LOAD M,MDB.MS(P1),MD.ADR ;GET THE MESSAGE ADDRESS
LOAD S2,.MSTYP(M),MS.TYP ;GET THE MESSAGE TYPE
MOVSI S1,-NMSGT ;MAKE AOBJN POINTER FOR MSG TYPES
;CHECK IF THE MESSAGE TYPE IS KNOWN TO NEBULA
CHKQU4: HRRZ P2,MSGTAB(S1) ;GET A MESSAGE TYPE
CAMN S2,P2 ;MATCH?
JRST CHKQU5 ;YES, WIN
AOBJN S1,CHKQU4 ;NO, LOOP
;**;[6037]At CHKQU4:+4L change 1 line JYCW Oct-18-88
JRST CHKQ10 ;[6037]Unknown, might be new format
;A KNOWN MESSAGE HAS BEEN RECEIVED
CHKQU5: MOVE S2,MDB.SP(P1) ;PICK UP THE SENDER'S PID
MOVEM S2,G$SND ;SAVE IT IN CASE OF AN ERROR
SETZM G$ERR ;CLEAR THE ERROR FLAG
SETZM REMORG ;ASSUME MESSAGE ORIGINATED LOCALLY
HLRZ P2,MSGTAB(S1) ;PICK UP THE PROCESSING ROUTINE ADR
SETZM EXESND ;[6012]ASSUME MESSAGE NOT FROM THE EXEC
$CALL @P2 ;DISPATCH THE MESSAGE PROCESSOR.
SKIPN S1,G$ERR ;[6012]DID AN ERROR OCCUR?
JRST CHKQU7 ;[6027]NO, GO RELEASE THE MESSAGE
SKIPN EXESND ;[6012]MESSAGE FROM THE EXEC?
$ACK (<^I/@TXTTBL(S1)/>,,,.MSCOD(M)) ;[6013]NO, INFORM ORION
SKIPE EXESND ;[6012]MESSAGE FROM THE EXEC?
$CALL EREXEC ;[6012]YES, SEND ERROR MSG TO THE EXEC
SKIPA ;[6027]RELEASE THE MESSAGE
;A MESSAGE NOT FROM ORION OR QUASAR HAS BEEN RECEIVED; OR ELSE AN UNKNOWN
;MESSAGE HAS BEEN RECEIVED; OR ELSE A KNOWN MESSAGE HAS JUST BEEN PROCESSED.
CHKQU6: $WTOJ(<NEBULA received an unknown IPCF message>,,,<$WTFLG(WT.SJI)>) ;[6027]
CHKQU7: $CALL C%REL ;[6027]RELEASE THE MESSAGE
JRST CHKQU2 ;CHECK FOR ANY MORE MESSAGES
SUBTTL CHKQ10 - Check format
;ACCEPT S2/MESSAGE CODE
;**;[6037]At CHKQU7:+2L add routine (33 Lines) CHKQ10: JYCW Oct-18-88
CHKQ10: TXNN S2,NEB%MS ;[6037]NEW MSG FORMAT
JRST CHKQU6 ;[6037]NO, invalid msg
SETOM NMFFLG ;[6037]NEW MSG FORMAT
MOVE S2,MDB.SP(P1) ;[6037]PICK UP THE SENDER'S PID
MOVEM S2,G$SND ;[6037]SAVE IT IN CASE OF AN ERROR
SETZM G$ERR ;[6037]CLEAR THE ERROR FLAG
SETZM REMORG ;[6037]ASSUME MSG ORIGINATED LOCALLY
SETZM EXESND ;[6037]ASSUME MESSAGE NOT FROM THE EXEC
$CALL CHKLEN ;[6037]CHECK FOR VALID IPCF MSG LENGTH
JUMPF E$IML ;[6037]INVALID LENGTH, TELL OPERATOR
$CALL FNDNBK ;[6037]PICK UP THE NODE TO SEND MSG TO
JUMPF E$NNF ;[6037]FAIL IF NO NODE BLOCK IN THE MSG
;PLACE LOCAL NODE NAME IN THE MESSAGE
PUSH P,S1 ;[6037]SAVE THE ORIGINAL NODE NAME
MOVE S1,NODNAM ;[6037]PICK UP THE LOCAL NODE NAME
MOVEM S1,ARG.DA(S2) ;[6037]PLACE IN THE MESSAGE
POP P,S1 ;[6037]RESTORE THE ORIGINAL NODE NAME
;DETERMINE WHICH NODE OR NODES TO SEND THE MESSAGE TO. SEND OR QUEUE THE
;MESSAGE TO THE INDICATED NODE OR NODES
CAMN S1,[-1] ;[6037]SEND MSG TO ALL REMOTE NODES?
JRST CHKQ11 ;[6037]YES,SEND MSG TO ALL REMOTE NODES
$CALL QSREMM ;[6037]NO, SEND MSG TO INDICATED NODE
JUMPF CHKQ12 ;[6037]ERROR, INDICATE TO THE SENDER
JRST CHKQU7 ;[6037]SENT, CHECK FOR MORE
CHKQ11: $CALL QMREMM ;[6037]SEND THE MSG TO ALL REMOTE NODES
SETZM G$ERR ;[6037]INDICATE ERROR ALREADY REPORTED
SKIPA ;[6037]
CHKQ12: $CALL @S1 ;[6037]PROCESS THE ERROR
SKIPN S1,G$ERR ;[6037]DID AN ERROR OCCUR?
JRST CHKQU7 ;[6037]NO, GO RELEASE THE MESSAGE
SKIPN EXESND ;[6037]MESSAGE FROM THE EXEC?
$ACK (<^I/@TXTTBL(S1)/>,,,.MSCOD(M)) ;[6037]NO, INFORM ORION
SKIPE EXESND ;[6037]MESSAGE FROM THE EXEC?
$CALL EREXEC ;[6037]YES, SEND ERROR MSG TO THE EXEC
JRST CHKQU7 ;[6037]CHECK FOR ANY MORE MESSAGES
MSGTAB: XWD NTDSM,.NTDSM ;TO NEBULA DISMOUNT
XWD NTMTS,.NTMTS ;TO NEBULA MOUNT
XWD NFDAK,.NFDAK ;FROM NEBULA DISMOUNT ACK
XWD NCDSM,.NCDSM ;NEBULA CANCEL DISMOUNT
;**;[6053]At MSGTAB:+4L change 1 line JCR 4/27/90
XWD NWTOX,.OMDSP ;[6053]ACK, WTOR OR WTO
XWD NDISPY,.OMACS ;QUASAR SHOW ACK
XWD NDISPY,MT.TXT ;ORION ACK
XWD NSHOW,.NMSHS ;SHOW STATUS (.OMSHS)
XWD NSHOW,.NDSHT ;[6001]SHOW STATUS TAPE (.ODSHT)
XWD NSHOW,.NDSHD ;[6001]SHOW STATUS DISK (.ODSHD)
XWD NSHOW,.NDSTR ;[6004]SHOW STATUS STRUCTURE (.ODSTR)
XWD NSHOW,.NDSCD ;SHOW CONFIGURATION (.ODSCD)
XWD NSHOW,.NMSHQ ;SHOW QUEUES (.OMSHQ)
XWD NSHOW,.NMSHP ;SHOW PARAMETERS (.OMSHP)
XWD NSHOW,.NMSHR ;SHOW ROUTE (.OMSHR)
XWD NSHOW,.NMESS ;SHOW MESSAGES
XWD NSHOW,.NSHOP ;SHOW OPERATORS
XWD NLIST,.QOLIS ;[6012]INFORMATION OUTPUT FROM THE EXEC
XWD QREXMG,.NMACS ;[6012]RESPONSE TO AN EXEC INFO REQUEST
XWD NKILL,.QOKIL ;[6012]CANCEL PRINT FROM THE EXEC
XWD QREXMG,.NMTXT ;[6012]RESPONSE TO AN EXEC CANCEL REQUEST
XWD NSCLU,.NSCLU ;SHOW CLUSTER-GALAXY-LINK-STATUS
XWD NDRCF,.NDRCF ;ENA/DIS REPORT-CONNECTION-FAILURES
XWD NDDCA,.NDDCA ;ENA/DIS DECNET-CONNECTION-ATTEMPTS
XWD NSHOW,.NMSSN ;[6033]SHOW STATUS NETWORK (.OMSSN)
XWD NSHOW,.NMSPN ;[6033]SHOW PARAMETERS NETWORK (.OMSPN)
;**;[6043]AT MSGTAB:+26L add 1 line JCR 11/29/89
XWD NDISPY,.OMNAK ;[6043]Null ACK
NMSGT==.-MSGTAB
SUBTTL NTDSM - PROCESS A "TO NEBULA DISMOUNT" MESSAGE
;NTDSM processes a "TO NEBULA DISMOUNT" message that is sent by MOUNTR
;by way of ORION. MOUNTR sends a TO NEBULA DISMOUNT message during its
;processing of a DISMOUNT with REMOVAL of a structure or setting a structure
;EXCLUSIVE. NTDSM builds a remote queue entry for the dismount request
;which contains the status of the structure for each node the structure is
;to be dismounted from. For each remote node that is in communication with
;this node, a "FROM NEBULA DISMOUNT" message is placed in that node's
;message queue. If the sender communicating with that node is free, then
;it is interrupted to inform it that a message is available for it to send.
;
;Call is: M/Address of the TO NEBULA DISMOUNT Message
;Returns: The TO NEBULA DISMOUNT Message was processed
;Crashes: TO NEBULA DISMOUNT Message was illegally formatted
NTDSM: $SAVE <T1,T2,T3,T4,P1,P2> ;SAVE THESE REGISTERS
;CHECK THAT THE MESSAGE IS CORRECTLY FORMATTED
$CALL CHKLEN ;CHECK FOR VALID IPCF MESSAGE LENGTH
JUMPF S..IMM ;CRASH ON ILLEGALLY FORMATTED MESSAGE
MOVE T1,.OARGC(M) ;PICK UP THE ARGUMENT COUNT
SOJE T1,S..IMM ;NO NODE BLOCKS, ILLEGAL MOUNTR MSG
CAILE T1,MAXNOD ;MORE NODES IN MSG THAN SUPPORTED?
PJRST S..IMM ;YES, ILLEGALLY FORMATTED MOUNTR MSG
MOVEI T3,.OHDRS(M) ;POINT TO THE STRUCTURE NAME BLOCK
LOAD S1,ARG.HD(T3),AR.TYP ;PICK UP THE TYPE OF BLOCK
CAIE S1,.STRDV ;IS THIS THE STRUCTURE NAME BLOCK?
PJRST S..IMM ;NO, ILLEGALLY FORMATTED MOUNTR MSG
MOVEM T1,NNIMSG ;SAVE THE NUMBER OF NODES IN MSG
;OBTAIN A REMOTE QUEUE ENTRY (RQE) FROM THE MEMORY MANAGER
MOVE S1,T1 ;NUMBER OF NODES IN REMOTE QUEUE ENTRY
IMULI S1,.RQBSZ+.RQNSZ ;AMOUNT OF MEMORY NEEDED FOR THE NODES
ADDI S1,.RQNIZ ;INVARIANT BLOCK SIZE FOR RQE
$CALL M%GMEM ;OBTAIN THE NECESSARY MEMORY
MOVE P1,S2 ;SAVE THE ADDRESS OF THE RQE
;CALCULATE THE ADDRESS OF THE INVARIANT BLOCK OF THE REMOTE QUEUE ENTRY.
;SAVE THE ADDRESS AND SIZE OF THE RQE FOR THE MEMORY MANAGER.
MOVE T2,T1 ;PICK UP THE NUMBER OF NODES IN MSG
IMULI T2,.RQBSZ ;MEMORY THE LINK LIST WORDS TAKE UP
ADD T2,P1 ;ADDRESS OF THE INVARIANT BLOCK IN RQE
STORE S1,.RQMEM(T2),RQ.LEN ;SAVE THE LENGTH OF THE RQE IN THE RQE
STORE S2,.RQMEM(T2),RQ.ADR ;SAVE THE ADDRESS OF THE RQE IN THE RQE
STORE T1,.RQNUM(T2),RQ.NTS ;SAVE NUMBER OF NODES IN RQE
MOVE P2,T2 ;SAVE THE INVARIANT BLOCK ADDRESS
MOVEM T2,IBLADR ;AND HERE TOO
;POINT TO THE CURRENT NODE IN THE REMOTE QUEUE ENTRY
ADDI T2,.RQNIZ ;POINT TO THE FIRST NODE BLOCK
MOVEM T2,FIRNOD ;REMEMBER THE ADR OF THE 1ST NODE BLOCK
;CHECK THE STATE OF EACH NODE SPECIFIED IN THE MESSAGE AND ADD THAT STATE
;TO THE RQE FOR THAT NODE
LOAD S1,ARG.HD(T3),AR.LEN ;PICK UP LENGTH OF STRUCTURE NAME BLOCK
ADD T3,S1 ;POINT TO THE FIRST IPCF MSG NODE BLOCK
NTDS1: MOVE S1,ARG.DA(T3) ;PICK UP THE SIXBIT NODE NAME
MOVEM S1,.RQNDN(T2) ;PLACE NODE NAME IN THE REMOTE QE
$CALL SNAMNT ;FIND THE NODE NAME IN THE NODE TABLE
;CHECK THE STATE OF THE NODE. IS IT O.K. TO SEND A MESSAGE TO THIS NODE?
JUMPF NTDS4 ;DOES THE NODE EXIST IN OUR DATA BASE?
SKIPL S2,.NNSTA(S2) ;YES, THIS NODE O.K. TO SEND MSG TO?
JRST NTDS2 ;NO, FIND OUT WHY
MOVX S1,RQ%SNR ;[6024]NO RESPONSE REC'D FROM THIS NODE
AOS .RQNUM(P2) ;INCREMENT THE # OF OUTSTANDING RSP
JRST NTDS5 ;STORE THE STATUS OF THIS NODE
;IT IS NOT O.K. TO SEND A MESSAGE TO THIS NODE. FIND OUT THE REASON WHY
;AND STORE THE REASON IN THE STATUS WORD FOR THIS NODE.
NTDS2: MOVEI S1,NSPX18 ;[6024]INDICATE NODE IS UNREACHABLE
TXO S1,RQ%TER ;[6025]MOUNTR NEEDS THIS BIT SET
TXNE S2,NN%COI ;INFO% UNABLE TO GET S.W. ENVIRONMENT?
TXO S1,RQ%COI ;YES, INDICATE SO
TXNE S2,NN%DCN ;REMOTE MONITOR HAS DECNET INSTALLED?
TXO S1,RQ%NDC ;NO, INDICATE SO
TXNE S2,NN%REL ;REMOTE MONITOR VERSION 7 OR LATER?
TXO S1,RQ%PSM ;NO, INDICATE SO
TXNE S2,NN%SCS ;SCS% DETECTED NODE LEFT THE CLUSTER?
TXO S1,RQ%SCS ;YES, INDICATE SO
TXNE S2,NN%SHO ;SENDER WAITING FOR HELLO RESPONSE?
TXO S1,RQ%SNH ;YES, INDICATE SO
TXNE S2,NN%LHO ;LISTENER WAITING FOR HELLO MESSAGE?
TXO S1,RQ%LNH ;YES, INDICATE SO
TXNE S2,NN%IFC ;SENDER/LISTENER NOT IN FATAL ERROR?
TXO S1,RQ%SLD ;NO, INDICATE SO
SKIPA ;GO STORE THE NODE STATUS IN THE RQE
NTDS4: TXO S1,RQ%NSN ;INDICATE NO SUCH NODE IN OUR DATA BASE
NTDS5: MOVEM S1,.RQNST(T2) ;STORE NODE STATUS IN RQE
;POINT TO THE NEXT NODE NAME IN THE IPCF MESSAGE AND THE NEXT NODE NAME IN
;THE REMOTE QUEUE ENTRY. CHECK THE STATUS OF THE NEXT NODE.
ADDI T3,.NDESZ ;POINT TO THE NEXT NODE IN THE IPCF MSG
ADDI T2,.RQNSZ ;POINT TO THE NEXT NODE IN THE RQE
SOJG T1,NTDS1 ;CHECK THE STATUS OF THE NEXT NODE
;ALL THE NODES IN THE "TO NEBULA DISMOUNT" MESSAGE HAVE BEEN CHECKED.
;FINISH BUILDING THE REMOTE QUEUE ENTRY EXCEPT FOR THE LINK LIST WORDS
MOVE S1,MSGTIM ;PICK UP TIME THIS MESSAGE
MOVEM S1,.RQTSP(P2) ;PLACE IN THE RQE
MOVEI S1,.NRDSM ;PICK UP THE MESSAGE TYPE
MOVEM S1,.RQMST(P2) ;PLACE IN THE RQE
MOVEI S1,<.OHDRS+ARG.DA>(M) ;PICK UP ADDRESS OF THE STRUCTURE NAME
HRLI S1,(POINT 7) ;MAKE IT INTO A POINTER
$CALL S%SIXB ;CONVERT THE STRUCTURE NAME TO SIXBIT
MOVEM S2,.RQSTN(P2) ;PLACE THE STRUCTURE NAME IN THE RQE
MOVE S1,.MSCOD(M) ;PICK UP MOUNTR'S ACK CODE
MOVEM S1,.RQACK(P2) ;PLACE IN THE RQE
MOVE S1,.OFLAG(M) ;PICK UP WHAT CAUSED MESSAGE TO BE SENT
TXNE S1,.DMSEX ;DUE TO SET STRUCTURE EXCLUSIVE?
MOVX S2,RQ%SEX ;YES, INDICATE SO
TXNE S1,.DMDIS ;DUE TO DISMOUNT/REMOVAL?
MOVX S2,RQ%DIS ;YES, INDICATE SO
MOVEM S2,.RQSTS(P2) ;PLACE IN THE STATUS WORD
;DETERMINE IF THE MESSAGE MUST BE SENT TO ANY OF THE NODES
LOAD S1,.RQNUM(P2),RQ.NOR ;NUMBER OF NODES TO SEND THE MESSAGE TO
JUMPE S1,NTD10 ;NO NODES TO SEND TO, TELL MOUNTR
MOVEM S1,NTSMSG ;REMEMBER THE NUMBER OF NODES
;CHANGE THE "TO NEBULA DISMOUNT" MESSAGE INTO A "FROM NEBULA DISMOUNT"
;MESSAGE. THIS WILL ENTAIL CHANGING THE MESSAGE TYPE AND REPLACING THE
;DESTINATION NODE BLOCKS WITH A NODE BLOCK CONTAINING THE LOCAL NODE NAME.
MOVEI S1,.OHDRS(M) ;PICK UP ADR OF THE STRUCTURE NAME BLK
LOAD S2,ARG.HD(S1),AR.LEN ;PICK UP LENGTH OF STRUCTURE NAME BLOCK
MOVEI T1,.OHDRS+.NDESZ(S2) ;PICK UP THE SIZE OF THE MESSAGE
STORE T1,.MSTYP(M),MS.CNT ;SAVE THE SIZE OF THE MSG IN THE MSG
ADD S1,S2 ;OBTAIN ADDRESS OF NODE NAME BLOCK
MOVEI S2,.NFDSM ;PICK UP FROM NEBULA DISMOUNT MSG CODE
STORE S2,.MSTYP(M),MS.TYP ;SAVE CODE IN THE MESSAGE
MOVEI S2,2 ;PICK UP THE ARGUMENT COUNT
MOVEM S2,.OARGC(M) ;PLACE IN THE MESSAGE
MOVE S2,[.NDESZ,,.NDENM] ;PICK UP NODE NAME HEADER WORD
MOVEM S2,ARG.HD(S1) ;PLACE IN THE NODE NAME BLOCK
MOVE S2,NODNAM ;PICK UP LOCAL NODE NAME
MOVEM S2,ARG.DA(S1) ;PLACE IN THE .NFDSM MESSAGE
;THE MESSAGE HAS BEEN BUILT. NOW BUILD THE MESSAGE QUEUE ENTRY
MOVE S1,NTSMSG ;NUMBER OF NODES TO RECEIVE THIS MSG
MOVX S2,MQ%REM ;THIS MSG HAS A RQE ASSOCIATED WITH IT
$CALL BLDMQE ;BUILD THE MESSAGE QUEUE ENTRY
MOVE P2,S1 ;SAVE THE ADDRESS OF THE MESSAGE QE
;THE MESSAGE QUEUE ENTRY HAS BEEN BUILT.
;CHECK THE STATUS OF THE NODES IN THE REMOTE QUEUE ENTRY TO DETERMINE
;WHICH NODES THE MESSAGE IS TO BE SENT TO.
MOVE T1,FIRNOD ;ADDRESS OF FIRST NODE BLOCK IN THE RQE
MOVE T3,NTSMSG ;PICK UP THE # OF NODES TO SEND MSG TO
MOVE T4,NNIMSG ;THE OFFSET VALUE FOR THIS NODE IN RQE
; (EQUAL TO THE # OF NODES IN IPCF MSG)
NTDS6: SKIPL S1,.RQNST(T1) ;WAITING FOR A RESPONSE?
JRST NTDS9 ;NO, IMPLIES DON'T SEND TO THIS NODE
;LINK THE REMOTE QUEUE ENTRY INTO THIS NODE'S REMOTE QUEUE
MOVE S1,.RQNDN(T1) ;PICK UP THE NODE NAME
$CALL SNAMNT ;PICK UP THE NODE TABLE ENTRY ADDRESS
HRLZM T4,.RQBLK(P1) ;PLACE OFFSET INTO LINK LIST WORD
SKIPN S1,.NRQLT(S2) ;IS THE NODE'S REMOTE QUEUE EMPTY?
JRST NTDS7 ;YES, ADD AS THE FIRST QUEUE ENTRY
STORE P1,.RQBLK(S1),RQ.NEA ;PLACE ADR OF NEW LAST RQE INTO OLD
JRST NTDS7A ;UPDATE THE LINK LIST
NTDS7: MOVEM P1,.NRQLH(S2) ;PLACE ADR OF NEW RQE INTO HEADER WORD
MOVEI S1,.NRQLH(S2) ;PICK UP HDR ADR WORD AS PREVIOUS ENTRY
NTDS7A: STORE S1,.RQNST(T1),RQ.ERR ;PLACE PREVIOUS ENTRY ADR IN THIS ENTRY
MOVEM P1,.NRQLT(S2) ;PLACE ADR OF NEW RQE INTO TRAILER WORD
;LINK THE MESSEAGE INTO THIS NODE'S MESSAGE QUEUE
MOVE S1,P2 ;LINK LIST WORD ADDRESS FOR THIS NODE
MOVE SEN,.NNSBA(S2) ;ADDRESS OF THIS NODE'S SENDER BLOCK
$CALL ADDMQE ;ADD ENTRY TO THIS NODE'S MESSAGE QUEUE
;CHECK IF THE SENDER IS AVAILABLE FOR A MESSAGE
SKIPE .SNFRE(SEN) ;IS THIS SENDER FREE TO SEND A MESSAGE?
$CALL SENMSG ;YES, PASS THE SENDER THE MESSAGE
;CHECK THE NEXT NODE
TDZA S1,S1 ;IMPLIES THIS NODE O.K. TO SEND MSG TO
NTDS9: SETO S1, ;CAN'T SEND A MESSAGE TO THIS NODE
ADDI T1,.RQNSZ ;ADR TO THE NEXT NODE IN THE RQE
ADDI P1,.RQBSZ ;ADR TO NEXT LINK LIST WORD IN RQE
SOS T4 ;DECREMENT THE OFFSET BY ONE
SKIPE S1 ;WAS THIS NODE O.K. TO SEND A MSG TO?
JRST NTDS6 ;NO, CHECK THE NEXT NODE
ADDI P2,.MQBSZ ;YES, ADR OF THE NEXT L.L. WORD IN MEQ
SOJG T3,NTDS6 ;ANY MORE NODES TO SEND THE MESSAGE TO?
;LINK THE REMOTE QUEUE ENTRY INTO THE GLOBAL REMOTE QUEUE
MOVE S1,IBLADR ;PICK UP THE INVARIANT BLOCK ADDRESS
$CALL ADDGRQ ;PLACE ENTRY ON GLOBAL REMOTE QUEUE
$RET ;RETURN TO THE CALLER
;THE MESSAGE IS TO BE SENT TO NO NODES. SEND FROM NEBULA DISMOUNT ACK
;MESSAGE TO MOUNTR.
NTD10: MOVE S1,IBLADR ;PICK UP THE INVARIANT BLOCK ADDRESS
$CALL ADDGRQ ;PLACE ENTRY ON GLOBAL REMOTE QUEUE
; SINCE SNDACK EXPECTS IT THERE
MOVE S1,IBLADR ;PICK UP THE INVARIANT BLOCK ADDRESS
$CALL SNDACK ;SEND DISMOUNT ACK MESSAGE TO MOUNTR
$RET ;FINISHED PROCESSING THE .NTDSM MESSAGE
SUBTTL SNDACK - SEND A TO NEBULA DISMOUNT ACK TO MOUNTR
;SNDACK builds a TO NEBULA DISMOUNT ACK message to be forwarded to
;MOUNTR by ORION. After the message is sent, the remote queue entry is
;deleted. SNDACK assumes that the remote queue entry has been delinked
;from all the node remote queues, but not the global remote queue.
;
;Call is: S1/ Address of the invariant block of the remote queue entry
;Returns: Message is sent and RQE is deleted
SNDACK: $SAVE <T1,T2,T3,P1,P2,P3,P4> ;SAVE THESE REGISTERS
;OBTAIN A PAGE FROM THE MEMORY MANAGER TO BUILD THE MESSAGE IN.
;THE ADDRESS OF THE PAGE WILL BE IN AC "MO"
MOVE P1,S1 ;SAVE THE ADR OF THE INVARIANT BLOCK
$CALL GETPAG ;PICK UP A PAGE FOR IPCF
;DETERMINE THE SIZE OF THE TO NEBULA DISMOUNT ACK MESSAGE TO BE SENT TO MOUNTR
LOAD S1,.RQNUM(P1),RQ.NTS ;PICK UP THE NUMBER OF NODES IN THE RQE
MOVE P3,S1 ;SAVE THE NUMBER OF NODES
IMULI S1,.STSLN ;MULTIPY BY THE SIZE OF THE STATUS BLK
ADDI S1,<.OHDRS+.STRLN+1> ;ADD IN THE HEADER + STRUCTURE NAME
; BLOCK + STATUS BLOCK HEADER SIZES
;BUILD THE MESSAGE HEADER
HRLS S1 ;PLACE MSG LENGTH IN THE EXPECTED PLACE
HRRI S1,.NTDAK ;PICK UP THE MESSAGE CODE
MOVEM S1,.MSTYP(MO) ;PLACE IN THE MESSAGE
SETZM .MSFLG(MO) ;NO BITS TURNED ON IN THE FLAG WORD
MOVE S1,.RQACK(P1) ;PICK UP MOUNTR'S ACK CODE
MOVEM S1,.MSCOD(MO) ;PLACE IN THE MESSAGE
MOVEI S1,2 ;ALWAYS TWO ARGUMENT BLOCKS
MOVEM S1,.OARGC(MO) ;NUMBER OF ARGUMENT BLOCKS
;BUILD THE STRUCTURE NAME BLOCK
MOVEI P2,.OHDRS(MO) ;POINT TO THE STRUCTURE NAME BLOCK
MOVE S1,[.STRLN,,.STRNM] ;PICK UP THE HEADER WORD
MOVEM S1,ARG.HD(P2) ;PLACE IN THE STRUCTURE NAME BLOCK
MOVE S1,.RQSTN(P1) ;PICK UP THE (SIXBIT) STRUCTURE NAME
MOVEM S1,ARG.DA(P2) ;PLACE IN THE STRUCTURE NAME BLOCK
;BUILD THE NODE STATUS BLOCK. FIRST BUILD THE HEADER WORD
MOVE S1,P3 ;PICK UP THE NUMBER OF NODES
IMULI S1,.STSLN ;CALCULATE THE SIZE NEEDED
AOS S1 ;INCLUDE THE HEADER WORD
HRLS S1 ;PLACE STATUS BLOCK SIZE WHERE EXPECTED
HRRI S1,.STSBK ;PICK UP THE BLOCK TYPE
ADDI P2,.STRLN ;POINT TO THE STATUS BLOCK HEADER
MOVEM S1,ARG.HD(P2) ;PLACE HEADER WORD INTO BLOCK HEADER
;BUILD THE REST OF THE NODE BLOCK
ADDI P2,ARG.DA ;POINT TO THE FIRST NODE NAME FIELD
MOVEI P4,.RQNIZ(P1) ;POINT TO THE FIRST NODE IN THE RQE
SETZ T1, ;CLEAR THE .OFLAG WORD
SNDAC2: MOVE S1,.RQNDN(P4) ;PICK UP THE NODE NAME
MOVEM S1,.STNNE(P2) ;PLACE IN THE NODE STATUS BLOCK
MOVE S1,.RQNST(P4) ;PICK UP THE NODE'S STATUS WORD
MOVEM S1,.STNST(P2) ;PLACE IN THE NODE STATUS BLOCK
TXNE S1,RQ%SSD ;STRUCTURE DISMOUNTED SUCCESSFULLY?
TXO T1,DS%SUC ;YES, INDICATE SO IN THE .OFLAG WORD
TXNN S1,RQ%SSD ;STRUCTURE DISMOUNTED SUCCESSSFULLY?
TXO T1,DS%FAI ;NO, INDICATE SO IN THE .OFLAG WORD
;POINT TO THE NEXT NODE FIELD
ADDI P4,.RQNSZ ;ADR OF THE NEXT NODE BLOCK IN THE RQE
ADDI P2,.STSLN ;ADR OF THE NXT NODE STS FLD IN THE MSG
SOJG P3,SNDAC2 ;CHECK OUT THE NEXT NODE STATUS
;ALL THE NODES' STATUS HAVE BEEN LOOKED AT. DETERMINE IF THE STRUCTURE
;WAS NOT SUCCESSFULLY DISMOUNTED FROM ONE OR MORE NODES. ALSO CHECK IF
;THE DISMOUNT REQUEST WAS CANCELLED.
TXNE T1,DS%FAI ;DID A DISMOUNT FAILURE OCCUR?
TXZ T1,DS%SUC ;YES, SO NEGATE ANY DISMOUNT SUCCESSES
MOVE S1,.RQSTS(P1) ;PICK UP RQE STATUS WORD
TXNE S1,RQ%CAN ;WAS THE DISMOUNT REQUEST CANCELLED?
TXO T1,DS%CAN ;YES, INDICATE SO
TXNE S1,RQ%SEC ;WAS SET EXCLUSIVE CANCELLED?
TXO T1,DS%SEC ;YES, INDICATE SO
TXNE S1,RQ%SEX ;DISMOUNT DUE SET STRUCTURE EXCLUSIVE?
TXO T1,DS%SEX ;YES, INDICATE SO
TXNE S1,RQ%DIS ;DISMOUNT DUE DISMOUNT/REMOVAL?
TXO T1,DS%DIS ;YES, INDICATE SO
MOVEM T1,.OFLAG(MO) ;SAVE THE STATUS IN THE MESSAGE
;BUILD THE SAB
MOVE S1,MO ;ADDRESS OF THE IPCF MESSAGE
MOVEI S2,PAGSIZ ;LENGTH OF THE IPCF MESSAGE
$CALL SNDORN ;SEND THE MESSAGE TO ORION
JUMPF S..OSF ;COULDN'T SEND THE MESSAGE TO ORION
;RELEASE THE REMOTE QUEUE ENTRY
MOVE S1,P1 ;PICK UP THE INVARIANT BLOCK ADDRESS
$CALL RELGRQ ;RELEASE THE REMOTE QUEUE ENTRY
$RET ;AND RETURN TO THE CALLER
SUBTTL NTMTS PROCESS A "TO NEBULA MOUNT" MESSAGE
;NTMTS validates the TO NEBULA MOUNT message and translates it into a
;FROM NEBULA MOUNT message which is then queued to the NEBULA sender
;of the node specified in the TO NEBULA MOUNT message.
;
;Call is: M/ Address of the TO NEBULA MOUNT message
;Returns true: FROM NEBULA MOUNT message built and queued to the NEBULA sender
;Returns false: Illegally formatted message
NTMTS: $SAVE <P1> ;SAVE THIS AC
;FIRST VALIDATE THE MESSAGE SYNTAX
$CALL CHKLEN ;CHECK FOR VALID IPCF MESSAGE LENGTH
JUMPF E$IML ;RETURN ON INVALID IPCF MESSAGE LENGTH
;**;[6046]At NTMTS:+6L remove 3 lines JCR 1/16/90
MOVEI P1,.OHDRS(M) ;POINT TO THE FIRST BLOCK
LOAD S1,ARG.HD(P1),AR.TYP ;PICK UP THE BLOCK TYPE
CAIE S1,.STALS ;IS THIS THE ALIAS BLOCK?
PJRST E$IBT ;NO, TELL ORION
LOAD S1,ARG.HD(P1),AR.LEN ;PICK UP THE BLOCK LENGTH
ADD P1,S1 ;[6007]POINT TO THE NEXT BLOCK
LOAD S1,ARG.HD(P1),AR.TYP ;PICK UP THE BLOCK TYPE
CAIE S1,.STRDV ;IS THIS A STRUCTURE BLOCK?
JRST NTMTS1 ;NO, CHECK FOR A NODE BLOCK
LOAD S1,ARG.HD(P1),AR.LEN ;PICK UP THE BLOCK LENGTH
ADD P1,S1 ;[6007]POINT TO THE NEXT BLOCK
LOAD S1,ARG.HD(P1),AR.TYP ;PICK UP THE BLOCK TYPE
NTMTS1: CAIE S1,.NDENM ;IS THIS A NODE BLOCK?
PJRST E$IBT ;NO, TELL ORION
LOAD S1,ARG.HD(P1),AR.LEN ;PICK UP THE BLOCK LENGTH
CAIE S1,.NDESZ ;THE CORRECT SIZE?
PJRST E$IBT ;NO, TELL ORION
;THE MESSAGE HAS A VALID SYNTAX. CHANGE THE MESSAGE FROM A TO NEBULA MOUNT
;MESSAGE TO A FROM NEBULA MOUNT MESSAGE.
MOVEI S1,.NFMTS ;PICK UP THE NEW MESSAGE CODE
STORE S1,.MSTYP(M),MS.TYP ;PLACE IN THE MESSAGE
MOVE S1,ARG.DA(P1) ;PICK UP NODE NAME TO SEND MESSAGE TO
MOVE S2,NODNAM ;PICK UP THE LOCAL NODE NAME
MOVEM S2,ARG.DA(P1) ;PLACE IN THE MESSAGE
;DETERMINE IF THE MESSAGE IS TO BE SENT TO A SINGLE NODE OR TO ALL THE
;REMOTE NODES.
CAMN S1,[-1] ;SEND THE MESSAGE TO ALL REMOTE NODE?
JRST NTMTS2 ;YES, GO SEND IT TO THEM
$CALL QSREMM ;QUEUE OR SEND THE IN BEHALF OF MESSAGE
JUMPF @S1 ;REMOTE NODE UNABLE TO RECEIVE THE MSG
$RET ;RETURN TO THE IPCF HANDLER
NTMTS2: $CALL QMREMM ;QUEUE OR SEND TO ALL REMOTE NODES
SETZM G$ERR ;INDICATE ALREADY REPORTED ANY ERRORS
$RET ;RETURN TO THE IPCF HANDLER
SUBTTL NFDAK - PROCESS A "FROM NEBULA DISMOUNT ACK" MESSAGE
;NFDAK forwards a FROM NEBULA DISMOUNT ACK message back to the node that
;made the original DISMOUNT request.
;
;Call is: M/ IPCF message buffer address
;Returns true: If the message was successfully sent or queued on
; the message queue
;Returns false: If the node that the message is to be forwarded to has
; left the cluster or is no longer able to receive messages
;Crashes: If the message is illegally formatted
; If the node table is inconsistent
;ENSURE THAT THE MESSAGE WAS CORRECTLY FORMATTED
NFDAK: $CALL CHKLEN ;CHECK FOR VALID IPCF MESSAGE LENGTH
JUMPF S..IMM ;ILLEGALLY FORMATTED MOUNTR MESSAGE
SKIPL S1,.OFLAG(M) ;MESSAGE INDICATES SUCCESS?
JRST NFDAK2 ;NO, CHECK IF FAIL FORMAT IS CORRECT
SKIPE .OARGC(M) ;YES, SUCCESS HAS NO ARGUMENT BLOCKS
PJRST S..IMM ;ILLEGALLY FORMATTED MOUNTR MESSAGE
JRST NFDAK3 ;MESSAGE FORMATTED CORRECTLY
NFDAK2: TXNN S1,NF.VER ;A VALID ERROR BIT IS TURNED ON?
PJRST S..IMM ;ILLEGALLY FORMATTED MOUNTR MESSAGE
SKIPG S1,.OARGC(M) ;NEEDS TO BE AN ARGUMENT BLOCK
PJRST S..IMM ;ILLEGALLY FORMATTED MOUNTR MESSAGE
CAIE S1,1 ;BUT ONLY ONE
PJRST S..IMM ;ILLEGALLY FORMATTED MOUNTR MESSAGE
MOVEI S1,.OHDRS(M) ;[6010]POINT TO THE ARGUMENT BLOCK
LOAD S2,ARG.HD(S1),AR.TYP ;PICK UP THE TYPE OF ARGUMENT BLOCK
CAIE S2,.ERRBK ;IS IT AN ERROR BLOCK?
PJRST S..IMM ;ILLEGALLY FORMATTED MOUNTR MESSAGE
;THE MESSAGE HAS VALID SYNTAX. CHECK IF THERE IS AN IBH QUEUE ENTRY FOR IT,
;IF THERE IS, THEN QUEUE THE MESSAGE TO BE SENT BACK TO THE REQUESTING NODE.
NFDAK3: $CALL QRIBHM ;QUEUE THE MESSAGE TO BE SENT
$RET ;PRESERVE THE T/F INDICATOR
SUBTTL NCDSM PROCESS A "NEBULA CANCEL DISMOUNT" MESSAGE
;NCDSM is called to cancel a NEBULA DISMOUNT message. This message is the
;result of an operator giving a CANCEL MOUNT-REQUEST or SET STRUCTURE
;SHARED command for a structure that is in the process of being dismounted
;remotely.
;NCDSM checks if there is a remote queue entry for the structure. If there
;is not, then the NEBULA DISMOUNT has already been processed and a
;TO NEBULA DISMOUNT ACK message has been sent to MOUNTR. MOUNTR will inform
;the operator of any nodes the structure has been dismounted from.
;If the remote queue entry is found, then a check is made for each node
;the message was sent to, to determine if the FROM NEBULA DISMOUNT
;message has been sent to that node. If it has not, then the message is
;cancelled.
;If all the nodes have responded to the message, then NCDSM sends a TO
;NEBULA DISMOUNT ACK message to MOUNTR indicating the state of the
;structure on each of the remote nodes.
;
;Call is: M/Address of the NEBULA CANCEL DISMOUNT message
;Returns true: The remote queue entry has been found and processed
;Returns false: The remote queue entry was not found
NCDSM: $SAVE <P1,P2,P3,P4,T1> ;SAVE THESE AC
;FIND THE REMOTE QUEUE ENTRY. THE SEARCH IS MADE USING THE ACK CODE
;PROVIDED BY MOUNTR. THE GLOBAL REMOTE QUEUE IS SEARCHED
MOVE S1,.MSCOD(M) ;PICK UP THE ACK CODE
$CALL FNDGRQ ;FIND THE REMOTE QUEUE ENTRY
JUMPF .POPJ ;NOT THERE, TOO LATE TO CANCEL
MOVE P1,S2 ;SAVE THE INVARIANT BLOCK ADDRESS
MOVE S1,.OFLAG(M) ;PICK UP REASON FOR THE CANCEL
IORM S1,.RQSTS(P1) ;SAVE CANCEL REASON IN REMOTE QE
;CHECK THE NODES THE FROM NEBULA DISMOUNT MESSAGE WAS SENT TO. IF A
;RESPONSE FROM A NODE HAS NOT YET BEEN RECEIVED, THEN A CHECK IS MADE
;IN THAT NODE'S MESSAGE QUEUE TO DETERMINE IF THE MESSAGE HAS YET
;BEEN SENT. IF IT HAS NOT, THEN THE MESSAGE IS CANCELLED.
LOAD P2,.RQNUM(P1),RQ.NTS ;PICK UP NUMBER OF NODES IN RQE
MOVE T1,P1 ;PICK UP THE INVARIANT BLOCK ADDRESS
SUB T1,P2 ;CALCULATE ADR OF 1ST LINK LIST WORD
MOVEI P3,.RQNIZ(P1) ;POINT TO THE FIRST NODE BLOCK
NCDSM2: SKIPL .RQNST(P3) ;RESPONSE RECEIVED FROM THIS NODE?
JRST NCDSM3 ;YES, CHECK THE NEXT NODE
MOVE S1,.RQNDN(P3) ;PICK UP THE SIXBIT NODE NAME
$CALL SNAMNT ;PICK UP THE NODE TABLE ENTRY
JUMPF S..NTI ;NODE TABLE INCONSISTENCY DETECTED
MOVE P4,S2 ;REMEMBER THE NODE TABLE ENTRY ADDRESS
MOVE S1,.RQACK(P1) ;PICK UP THE ACK CODE
MOVE SEN,.NNSBA(P4) ;PICK UP THE SENDER BLOCK ADDRESS
$CALL FNDMQE ;FIND THE MESSAGE QUEUE ENTRY
JUMPF NCDSM3 ;TOO LATE, MESSAGE ALREADY SENT
MOVX S1,RQ%SNR!RQ%CIT ;INDICATE MESSAGE CANCELED AND
XORM S1,.RQNST(P3) ;RESPONSE RECEIVED FOR THIS NODE
;DELINK THE REMOTE QUEUE ENTRY FROM THIS NODE'S REMOTE QUEUE. THEN
;DECREMENT THE NUMBER OF OUTSTANDING RESPONSES AND CHECK THE NEXT NODE
MOVE S1,T1 ;PICK UP LINK LIST WORD ADDRESS
MOVE S2,P3 ;PICK UP NODE BLOCK ADDRESS
$CALL RELNRQ ;REMOVE THE REMOTE QE FROM THIS NODE
SOS .RQNUM(P1) ;DECREMENT NUMBER OUTSTANDING RESPONSES
NCDSM3: ADDI P3,.RQNSZ ;POINT TO THE NEXT NODE BLOCK
ADDI T1,.RQBSZ ;POINT TO THE NEXT LINK LIST WORD
SOJG P2,NCDSM2 ;CHECK THE NEXT NODE, IF ANY
;ALL THE NODES HAVE BEEN CHECKED. IF THERE ARE NO MORE OUTSTANDING MESSAGES,
;THEN RETURN THE GLOBAL REMOTE QUEUE ENTRY AND BUILD AND SEND THE TO
;NEBULA DISMOUNT ACK TO MOUNTR.
LOAD S1,.RQNUM(P1),RQ.NOR ;PICK UP NUMBER OUTSTANDING RESPONSES
JUMPG S1,.RETT ;IF ANY OUTSTANDING RESPONSES, RETURN
MOVE S1,P1 ;PICK UP THE INVARIANT BLOCK
$CALL SNDACK ;SEND THE TO NEBULA DISMOUNT ACK
$RETT ;RETURN TO THE CALLER
SUBTTL NDISPY - PROCESS A WTO, ACK OR QUASAR SHOW MESSAGE
;NDISPY processes DISPLAY (.OMDSP), QUASAR SHOW ACK (.OMACS) and ORION
;TEXT (MT.TXT) messages. These messages are responses to a request made
;from a remote node (they are in behalf of responses). It is not necessary
;to check the syntax of these messages since the syntax is checked by both
;the local and requesting nodes' ORIONs. This routine forwards the message
;back to the node where the request originated from.
;
;Call is: M/ IPCF message buffer address
;Returns true: The message was successfully sent or queued on
; the message queue
;Returns false: If the node that the message is to be forwarded to has
; left the cluster or is no longer able to receive messages
;Crashes: If the node table is inconsistent
;ENSURE THAT THE MESSAGE HAS A VALID IPCF MESSAGE LENGTH. IF IT DOES NOT,
;THEN INFORM THE SENDER OF THE REQUEST ON THE REMOTE NODE OF THIS FACT.
QREXMG: SETOM EXESND ;[6012]REQUEST ORIGINALLY FROM EXEC
NDISPY: $CALL CHKLEN ;CHECK FOR VALID IPCF MESSAGE LENGTH
JUMPT NDISP2 ;SEND THE MESSAGE IF VALID MSG LENGTH
$CALL E$IML ;PLACE THE ERROR CODE IN G$ERR
$CALL BLDACK ;BUILD THE ERROR MESSAGE
DMOVE S1,.MSFLG(M) ;PICK UP THE FLAG AND ACK CODE WORDS
DMOVEM S1,.MSFLG(MO) ;PLACE IN THE ERROR MESSAGE
MOVE S1,MO ;PICK UP ERROR MESSAGE PAGE ADDRESS
MOVE S2,M ;PICK UP MESSAGE PAGE ADDRESS
$CALL XFRMSG ;COPY ERROR MESSAGE TO MESSAGE PAGE
$CALL RELPAG ;RETURN PAGE OF ERROR MESSAGE
;SEND OR QUEUE THE MESSAGE TO THE REMOTE NODE
NDISP2: $CALL QRIBHM ;QUEUE THE MESSAGE TO BE SENT
SETZM G$ERR ;INDICATE NO ACK MESSAGE TO BE SENT
$RET ;MESSAGE QUEUED OR SENT TO REMOTE NODE
;**;[6053]At NDISP2:+3L add routine NWTOX JCR 4/27/90
SUBTTL NWTOX - Process a WTO, WTOR or ACK Message
;[6053]NWTOX processes DISPLAY (.OMDSP) messages. These messages result from
;[6053]ACK, WTO or WTOR messages. In the cases where the .OMDSP message
;[6053]resulted from a WTO or WTOR message, it is possible that either
;[6053]the IBQ entry no longer exists or that the message is to be forwarded
;[6053]to more than one node. The first case is possible since a request
;[6053]may generate more than one WTO. The second case is possible due
;[6053]to the Broadcast WTO feature. The Broadcast WTO feature causes
;[6053]ORION to broadcast all its WTOs and WTORs to the nodes specified
;[6053]by the OPR ENABLE BROADCAST-MESSAGES command.
;[6053]
;[6053]Call is: M/IPCF message buffer address
;[6053]Returns true: The message was successfully sent or queued on
;[6053] the message queue to the specified node or nodes
;[6053]Returns false: The message was illegally formatted or the message
;[6053] was an ACK message and it could not be forwarded
;[6053]Crashes: If the node table is inconsistent
NWTOX: $SAVE <P1,P2> ;[6053]Save some scratch ACs
MOVE S1,.MSFLG(M) ;[6053]Pick up the flag word
TXNN S1,MF.WTO!MF.WTR ;[6053]Originally a WTO or WTOR?
JRST NWTO.4 ;[6053]No, was an ACK
MOVE S1,.MSCOD(M) ;[6053]Pick up the local ACK code
$CALL FNDIBH ;[6053]Find the IBQ entry
JUMPF NWTO.1 ;[6053]Don't care if no longer there
MOVE S1,S2 ;[6053]Place entry adr where expected
$CALL RELIBH ;[6053]Release the IBQ entry
NWTO.1: MOVEI S1,.NDENM ;[6053]Pick up the block type
$CALL N$ADJM ;[6053]Find and remove the block
$RETIF ;[6053]Shouldn't happen
MOVE P1,S2 ;[6053]Save the .NDENM block address
LOAD P2,0(P1),AR.LEN ;[6053]Pick up the block length
SOSG P2 ;[6053]Calculate the number of nodes
$RETF ;[6053]Shouldn't happen
NWTO.2: AOS P1 ;[6053]Point to the next node name
MOVE S1,0(P1) ;[6053]Pick up the next node name
$CALL SETPAR ;[6053]Check if can forward the msg
JUMPF NWTO.3 ;[6053]Can't, check the next node
TXO S2,MQ%IBH ;[6053]This msg is response to IBH msg
$CALL QUEMSG ;[6053]Send or queue the message
NWTO.3: SOJG P2,NWTO.2 ;[6053]Check the next node
SETZM G$ERR ;[6053]Indicate no ACK msg to be sent
$RETT ;[6053]Return to the caller
NWTO.4: $CALL QRIBHM ;[6053]Queue the message to be sent
SETZM G$ERR ;[6053]Indicate no ACK msg to be sent
$RET ;[6053]Msg queued or sent to remote node
SUBTTL NSHOW - PROCESS OPR SHOW MESSAGES
;NSHOW forwards OPR SHOW messages to the specifed remote nodes. These
;messages have the format that the remote QUASAR or ORION expects,
;except the message code is different and there is a node (.NDENM) block
;present that indicates the node or nodes that the message is to be
;forwarded to. NEBULA replaces the contents of the node block with the
;local node name which is used by ORION when logging the message and its
;response.
;
;Call is: M/Address of the SHOW IPCF message
;Returns true: The SHOW message was queued or sent to the remote node
; (or nodes)
;Returns false: The message was illegally formatted or the node is not
; known to be in the cluster
;CHECK IF THE MESSAGE HAS A VALID IPCF MESSAGE LENGTH SPECIFIED AND IF
;SO, IF THE NODE THE MESSAGE IS TO BE SENT TO IS KNOWN TO BE IN THE
;CLUSTER
NSHOW: $CALL CHKLEN ;CHECK FOR A VALID IPCF MESSAGE LENGTH
JUMPF E$IML ;INVALID LENGTH, INFORM THE OPERATOR
$CALL FNDNBK ;PICK UP THE NODE TO SEND MESSAGE TO
JUMPF E$NNF ;FAIL IF NO NODE BLOCK IN THE MESSAGE
;PLACE LOCAL NODE NAME IN THE MESSAGE
PUSH P,S1 ;SAVE THE ORIGINAL NODE NAME
MOVE S1,NODNAM ;PICK UP THE LOCAL NODE NAME
MOVEM S1,ARG.DA(S2) ;PLACE IN THE MESSAGE
POP P,S1 ;RESTORE THE ORIGINAL NODE NAME
;DETERMINE WHICH NODE OR NODES TO SEND THE MESSAGE TO. SEND OR QUEUE THE
;MESSAGE TO THE INDICATED NODE OR NODES
CAMN S1,[-1] ;SEND THE MESSAGE TO ALL REMOTE NODES?
JRST NSHOW2 ;YES, SEND THE MSG TO ALL REMOTE NODES
$CALL QSREMM ;NO, SEND THE MSG TO THE INDICATED NODE
JUMPF @S1 ;ERROR, INDICATE TO THE SENDER
$RET ;THE MESSAGE WAS SENT OR QUEUED
NSHOW2: $CALL QMREMM ;SEND THE MSG TO ALL THE REMOTE NODES
SETZM G$ERR ;INDICATE ALREADY REPORTED ANY ERRORS
$RET ;RETURN TO THE SENDER
SUBTTL NLIST - PROCESSES EXEC "INFORMATION OUTPUT" MESSAGE
;[6012]NLIST forwards the EXEC INFORMATION OUTPUT message to the indicated
;[6012]node. This message has the format that the remote QUASAR expects.
;[6012]
;[6012]Call is: M/Address of the IPCF INFORMATION OUTPUT message
;[6012]Returns true: The message was queued or sent to the indicated remote
;[6012] node
;[6012]Returns false: The message was illegally formatted or the node is not
;[6012] known to be in the cluster
;[6012]PICK UP AND SAVE THE EXEC'S PID IN CASE OF AN ERROR
NLIST: SETOM EXESND ;[6012]INDICATE MSG ORIGINALLY FROM EXEC
MOVEI S1,.LSPID ;[6012]PICK UP THE PID BLOCK CODE
$CALL N$FNDB ;[6012]FIND THE PID BLOCK
JUMPF .RETT ;[6012]NO PID BLOCK, DROP THE MESSAGE
MOVE S1,0(S1) ;[6012]PICK UP THE BLOCK
MOVEM S1,G$SND ;[6012]SAVE IN CASE OF AN ERROR
;[6012]CHECK IF THE MESSAGE HAS A VALID IPCF MESSAGE LENGTH SPECIFIED AND IF
;[6012]SO, IF THE NODE THE MESSAGE IS TO BE SENT TO IS KNOWN TO BE IN THE
;[6012]CLUSTER
$CALL CHKLEN ;[6012]CHECK FOR A VALID IPCF MSG LENGTH
JUMPF E$IML ;[6012]INVALID LENGTH, INFORM THE USER
$CALL FNDNBK ;[6012]PICK UP THE NODE TO SEND MSG TO
JUMPF E$NNF ;[6012]FAIL IF NO NODE BLOCK IN THE MSG
;[6012]PLACE LOCAL NODE NAME IN THE MESSAGE
PUSH P,S1 ;[6012]SAVE THE ORIGINAL NODE NAME
MOVE S1,NODNAM ;[6012]PICK UP THE LOCAL NODE NAME
MOVEM S1,ARG.DA(S2) ;[6012]PLACE IN THE MESSAGE
POP P,S1 ;[6012]RESTORE THE ORIGINAL NODE NAME
;[6012]SEND OR QUEUE THE MESSAGE TO THE INDICATED NODE
$CALL SETPAR ;[6012]DETERMINE IF CAN SEND MSG DIRECTLY
JUMPF @S1 ;[6012]ERROR, INDICATE TO THE SENDER
TXO S2,MQ%EXE ;[6012]INDICATE MSG FROM THE EXEC
$CALL QUEMSG ;[6012]SEND OR QUEUE THE MESSAGE
$RETT ;[6012]RETURN TO THE SENDER
SUBTTL NKILL - ROUTINE PROCESS AN EXEC CANCEL MESSAGE
;[6012]NKILL is called to process an EXEC CANCEL PRINT request.
;[6012]Call is: M/The message address
;[6012]Returns true: The message has been routed to the indicated remote node
;[6012]Returns false: The remote node is inaccessible or unknown, or the message
;[6012] was illegally formatted
NKILL: SETOM EXESND ;[6012]INDICATE THE MSG IS FROM THE EXEC
MOVE S1,KIL.PD(M) ;[6012]PICK UP THE EXEC'S PID
MOVEM S1,G$SND ;[6012]SAVE IN CASE OF AN ERROR
$CALL CHKLEN ;[6012]CHECK THE MESSAGE FORMAT
JUMPF E$IML ;[6012]IF ERROR, INDICATE SO
MOVE S1,KIL.ND(M) ;[6012]PICK UP NODE NAME TO SEND TO
MOVE S2,NODNAM ;[6012]PICK UP THE LOCAL NODE NAME
MOVEM S2,KIL.ND(M) ;[6012]SAVE IN THE MESSAGE
$CALL SETPAR ;[6012]DETERMINE QUEUE/SEND TO
JUMPF @S1 ;[6012]REPORT ANY ERRORS
TXO S2,MQ%EXE ;[6012]INDICATE MSG FROM THE EXEC
$CALL QUEMSG ;[6012]SEND OR QUEUE THE MESSAGE
$RETT ;[6012]RETURN TO THE CALLER
SUBTTL N$FNDB - ROUTINE TO FIND ANY BLOCK IN AN IPCF MESSAGE
;[6012]N$FNDB is called to find a specified block in an IPCF message.
;[6012]Call is: M/The message address
;[6012] S1/The block type of the block to be found
;[6012]Returns true: S1/The address of the block's data field
;[6012]Returns false: The block is not in the message
N$FNDB: $SAVE <P1,P2> ;[6012]SAVE THESE AC
MOVE P1,.OARGC(M) ;[6012]GET THE MESSAGE ARGUMENT COUNT
MOVE P2,S1 ;[6012]SAVE THE BLOCK TYPE
MOVEI S1,.OHDRS(M) ;[6012]POINT TO THE FIRST BLOCK
LOAD TF,.MSTYP(M),MS.CNT ;[6012]GET THE MESSAGE LENGTH
ADD TF,M ;[6012]POINT TO THE END OF THE MESSAGE
N$FN.1: LOAD S2,ARG.HD(S1),AR.TYP ;[6012]GET THIS BLOCK TYPE
CAMN S2,P2 ;[6012]IS THIS THE BLOCK?
JRST N$FN.2 ;[6012]YES, RETURN WITH BLOCK ADDRESS
LOAD S2,ARG.HD(S1),AR.LEN ;[6012]NO, GET THIS BLOCK'S LENGTH
ADD S1,S2 ;[6012]ADDRESS OF THE NEXT BLOCK
CAIG TF,0(S1) ;[6012]STILL WITHIN THE MESSAGE?
$RETF ;[6012]NO, RETURN BLOCK NOT FOUND
SOJG P1,N$FN.1 ;[6012]CHECK THE NEXT BLOCK
$RETF ;[6012]BLOCK NOT FOUND
N$FN.2: MOVEI S1,ARG.DA(S1) ;[6012]POINT TO THE DATA FIELD
$RETT ;[6012]AND RETURN
SUBTTL NSCLU - PROCESSES THE "SHOW CLUSTER-GALAXY" MESSAGE
;NSCLU processes the SHOW CLUSTER-GALAXY-LINK-STATUS message. This routine
;returns one of the following:
;1. The DECnet link status of the sender and listener to every remote
; node currently known by the local NEBULA to be in the cluster.
;2. The DECnet link status of the sender and listener to the remote
; node specified in the /NODE: switch.
;3. If the /CLUSTER-NODE switch was specified, then:
; a. If the name specified was the local node name, then 1. or 2.
; b. If the name specified was a known remote name in the cluster, then
; 1. or 2. from the remote node
; c. If -1 was specified, then 1. or 2. from all nodes in the cluster,
; including the local node
;NSCLU first checks the node table to determine if there is a connected link
;or if the remote node is not accessible. If neither of these conditions are
;true, then it checks the previously and currently known node (PACKN) table
;to determine if a connection was ever made.
;
;Call is: M/Address of the SHOW CLUSTER-GALAXY IPCF message.
;Returns true: Response to message built and sent back to the operator
; that made the request. If a remote node name (or -1) was
; specified in the /CLUSTER-NODE switch, then the message is
; forwarded to the indicate node (or all remote nodes)
;Returns false: Message invalidly formatted, node specified in the /NODE
; switch is not known to be currently in the cluster, or
; node from which the message came (the message was specified
; with the /CLUSTER-NODE switch) is no longer in communication
; with the local node.
NSCLU: $SAVE <P1,P2,P3,P4> ;SAVE THESE AC
;FIRST DETERMINE WHAT CONTEXT THE MESSAGE IS BEING PROCESSED IN. THE
;POSSIBLE CONTEXTS ARE:
;1. THE REQUEST WAS MADE FROM THE LOCAL NODE AND IS FOR ALL NODES.
;2. THE REQUEST WAS MADE FROM THE LOCAL NODE AND IS FOR A SPECIFIC NODE.
;3. THE REQUEST WAS MADE FROM THE LOCAL NODE AND THE MESSAGE IS TO BE FORWARDED
; TO A SPECIFIC REMOTE NODE
;4. THE REQUEST WAS MADE FROM THE LOCAL NODE AND IS FOR ALL NODES KNOWN TO
; THE LOCAL NODE AS WELL AS HAVING THE MESSAGE FORWARDED TO ALL REMOTE NODES
;5. THE REQUEST WAS MADE FROM A REMOTE NODE.
SKIPN P2,RENNUM ;ANY REMOTE NODES?
;**;[6045]At NSCLU:+13L replace 2 lines with 1 line JCR 15/90
PJRST E$NRN ;[6045]Indicate the error
SETOM LOCFLG ;ASSUME ALL NODES, LOCAL
SETZM REMFLG ;ASSUME MSG NOT TO BE FORWARDED
;VALIDATE THE ARGUMENT BLOCK COUNT
;**;[6045]At NSCLU:+21L add 2 lines JCR 1/15/90
MOVEI S1,.OCTXT ;[6045]Command text block
$CALL N$ADJM ;[6045]Adjust the message
SKIPGE S1,.OARGC(M) ;VALID MINIMUM ARGUMENT COUNT?
PJRST E$IAC ;NO, INDICATE TO ORION
;**;[6046]At NSCLU:+24L remove 2 lines JCR 1/16/90
SKIPN S1 ;ANY ARGUMENT BLOCKS?
JRST NSCLU3 ;NO, ALL NODES, LOCAL; BUILD THE MSG
MOVEI S2,.OHDRS(M) ;PICK UP ADDRESS OF FIRST ARGUMENT BLOCK
LOAD P1,ARG.HD(S2),AR.TYP ;PICK UP THE ARGUMENT TYPE
CAIE P1,.ORNOD ;IS THIS A NODE BLOCK?
JRST [ SOJG S1,E$IFM ;IF TWO BLOCKS, THEN ILLEGAL FORMAT
JRST NSCLU0 ] ;CHECK FOR CLUSTER-NODE BLOCK
LOAD P1,ARG.DA(S2) ;PICK UP THE NODE NAME
MOVEM P1,LOCFLG ;SAVE FOR LATER
SOJE S1,NSCLU2 ;PROCESS ONLY LOCALLY
LOAD P1,ARG.HD(S2),AR.LEN ;PICK UP THE BLOCK LENGTH
ADD S2,P1 ;POINT TO THE NEXT BLOCK
LOAD P1,ARG.HD(S2),AR.TYP ;PICK UP THE ARGUMENT TYPE
NSCLU0: CAIE P1,.NDENM ;CLUSTER-NODE BLOCK TYPE?
PJRST E$IBT ;INVALID BLOCK TYPE
LOAD P1,ARG.DA(S2) ;PICK UP THE NODE NAME
MOVEM P1,REMFLG ;STORE FOR LATER
;DETERMINE IF THE MESSAGE IS TO BE PROCESSED LOCALLY, REMOTELY OR BOTH
CAMN P1,[-1] ;PROCESS FOR LOCAL AND REMOTE NODES?
JRST NSCLU1 ;YES, CHECK FOR A SPECIFIC NODE
CAME P1,NODNAM ;WAS THE LOCAL NAME SPECIFIED?
JRST NSCL15 ;NO, GO FORWARD THE MSG REMOTELY
SETZM REMFLG ;YES, ZERO OUT THE REMOTE NODE FLAG
;CHECK IF A SPECIFIC NODE WAS SPECIFIED. IF SO, THEN CHECK IF IT IS VALID
NSCLU1: MOVE S1,LOCFLG ;PICK UP LOCAL NODE FLAG
CAMN S1,[-1] ;FOR A SPECIFIC NODE?
JRST NSCLU3 ;NO, CHECK ALL THE NODES
NSCLU2: MOVE S1,LOCFLG ;PICK UP THE NODE NAME WORD
;**;[6052]At NSCLU2:+1L change 1 line JCR 3/1/90
MOVEM S1,G$ARG3 ;[6052]Save node name in case of error
$CALL SNAMNT ;SEARCH NODE TABLE FOR THE NODE
JUMPF NSCL17 ;[6023]DETERMINE THE TYPE OF ERROR
MOVE P1,S2 ;SAVE THE NODE TABLE ENTRY
MOVEI P2,1 ;THE NODE TABLE SEARCH FOR ONLY 1 NODE
;PICK UP THE RESPONSE MESSAGE PAGE, BUILD THE GALAXY MESSAGE HEADER, DISPLAY
;(.ORDSP) BLOCK, TEXT (.CMTXT) BLOCK HEADER AND POINT TO THE DATA FIELD OF
;THE TEXT BLOCK
NSCLU3: MOVEI S1,[ASCIZ/ Cluster Status /] ;MESSAGE HEADER
$CALL SETPAG ;GET MESSAGE PAGE AND BUILD HEADERS
$CALL CRLF ;MAKE A BLANK LINE
;BUILD THE TEXT HEADER
$ASCII (< Node Sender Link Status Listener Link Status>)
$CALL CRLF ;NEXT DISPLAY LINE
$ASCII (< ------ ------------------ -------------------->)
$CALL CRLF ;NEXT DISPLAY LINE
;PICK UP AND PLACE THE DECNET LINK STATUS OF THE SENDER AND LISTENER OF
;EACH CURRENTLY KNOWN REMOTE NODE KNOWN TO BE IN THE CLUSTER. FIRST
;CHECK IF BOTH THE LISTENER AND SENDER HAVE DECNET CONNECTIONS. IF THEY
;DON'T, THEN CHECK IF THE REMOTE NODE IS CAPABLE OF BEING IN COMMUNICATION
;WITH THE LOCAL NODE.
SETO S1, ;PREPARE FOR THE TYPE CHECK
CAME S1,LOCFLG ;IS THE REQUEST FOR ONLY ONE NODE?
JRST NSCLU4 ;YES, SO POINTERS ALREADY SETUP
MOVEI P1,NODTBL ;POINT TO FIRST NODE TABLE ENTRY
MOVEI P4,MAXNOD ;PICK UP MAX NUMBER OF REMOTE NODES
NSCLU4: SKIPN .NNNAM(P1) ;IS THIS NODE TABLE ENTRY IN USE?
JRST NSCL13 ;NO, CHECK THE NEXT NODE TABLE ENTRY
$TEXT (DEPBYT,< ^N6L/.NNNAM(P1)/ ^A>) ;INCLUDE NODE NAME
SETZ S1, ;INDICATE NOT OR CAN'T CONNECT
MOVE S2,.NNSTA(P1) ;PICK UP THE NODE STATUS WORD
TXNE S2,NN%OKS ;SENDER AND LISTENER HAVE CONNECTIONS?
MOVEI S1,CONCON ;YES, INDICATE SO
TXNE S2,NN%COI!NN%DCN!NN%REL ;IS THIS NODE REACHABLE?
MOVEI S1,CNTCNT ;NO, INDICATE SO
SKIPE S1 ;YES, CHECK FOR NOT/NEVER CONNECTED
JRST NSCL11 ;GO PLACE DISPLAY LINE IN THE MESSAGE
;THE REMOTE NODE IS POTENTIALLY REACHABLE, BUT EITHER THE SENDER OR THE
;LISTENER OR BOTH CURRENTLY DO NOT HAVE OR NEVER HAVE HAD DECNET CONNECTIONS.
;FIRST CHECK THE DECNET LINK STATUS OF THE SENDER. IF THE SENDER DOES NOT
;HAVE A DECNET CONNECTION, THEN CHECK IF IT EVER HAS. (IT IS POSSIBLE FOR
;THE SENDER TO HAVE HAD A CONNECTION AND THEN LOST IT OR IT IS POSSIBLE
;THAT THE SENDER HAD A CONNECTION BUT THE REMOTE NODE CRASHED AND CAME BACK,
;BUT SINCE THE NODE CAME BACK THE SENDER HAS NOT BEEN ABLE TO MAKE A
;CONNECTION.)
;IF A SENDER HAS NEVER HAD A DECNET CONNECTION, THEN THIS IMPLIES THAT THE
;SENDER DOES NOT CURRENTLY HAVE A CONNECTION.
;IF A SENDER DOES NOT CURRENTLY HAVE A DECNET CONNECTION, THEN THIS DOES NOT
;IMPLY THAT THE SENDER NEVER HAD A DECNET CONNECTION.
;THE TABLE OF PREVIOUSLY AND CURRENTLY KNOWN NODES (PACKN) IS CHECKED TO
;DETERMINE IF THE SENDER HAS EVER HAD A DECNET CONNECTION TO THE REMOTE NODE.
;(NOTE: IT IS ASSUMED THAT THIS TABLE HAS AT LEAST ONE FREE ENTRY IN IT.)
NSCLU5: MOVEI S1,CNNECT ;ASSUME THE SENDER HAS A CONNECTION
TXNN S2,NN%SHO ;DOES THE SENDER HAVE A CONNECTION?
JRST NSCLU8 ;YES, DISPLAY SENDER STATUS
MOVE S1,.NNNAM(P1) ;PICK UP SIXBIT NAME OF REMOTE NODE
$CALL SRHPNE ;FIND THE PACKN TABLE ENTRY
JUMPT NSCLU7 ;IF SUCCESS, THEN THE ENTRY WAS FOUND
;THE ENTRY WAS NOT FOUND. THIS SHOULD NEVER HAPPEN. IF IT DOES, THEN THE
;STATUS DECNET LINK STATUS OF THE SENDER IS LISTED AS "UNKNOWN".
MOVEI S1,UNKSTS ;INDICATE UNKNOWN STATUS FOR SENDER
SETO P3, ;INDICATE NODE ENTRY NOT FOUND
JRST NSCLU8 ;CHECK THE LISTENER DECNET STATUS
;DETERMINE IF THE SENDER HAS NEVER HAD A DECNET CONNECTION. IF IT HAS, THEN
;INDICATE THE THE SENDER CURRENTLY DOES NOT HAVE A DECNET CONNECTION.
NSCLU7: MOVE P3,S2 ;SAVE THE PACKN ENTRY ADDRESS
MOVE S2,.LKSTS(P3) ;PICK UP SENDER STATUS FROM PACKN TBL
MOVEI S1,NOTCON ;ASSUME CURRENTLY NOT CONNECTED
TXNN S2,LK%SEN ;HAS SENDER EVER BEEN CONNECTED?
MOVEI S1,NEVCON ;NO, INDICATE SO
;PLACE THE SENDER STATUS IN THE MESSAGE AND THEN DETERMINE THE LISTENER'S
;DECNET LINK STATUS. FIRST CHECK IF THE LISTENER HAS A DECNET CONNECTION.
NSCLU8: $TEXT (DEPBYT,<^T20L/@LNKSTS(S1)/^A>) ;[6006]PLACE SENDER STATUS IN MSG
MOVEI S1,CNNECT ;ASSUME THE LISTENER HAS A CONNECTION
MOVE S2,.NNSTA(P1) ;PICK UP THE NODE'S STATUS WORD
TXNN S2,NN%LHO ;IS THE LISTENER CONNECTED?
JRST NSCL11 ;YES, DISPLAY LISTENER STATUS
;THE LISTENER DOES NOT HAVE A DECNET CONNECTION. DETERMINE IF THE LISTENER
;HAS EVER HAD A DECNET CONNECTION OR HAS, BUT CURRENTLY DOES NOT HAVE A
;CONNECTION
CAME P3,[-1] ;PACKN TABLE ENTRY FOR THIS NODE?
JRST NSCLU9 ;YES, PICK UP LISTENER CONNECTION STATUS
MOVEI S1,UNKSTS ;NO, INDICATE UNKNOWN STATUS
JRST NSCL11 ;GO DISPLAY THE LISTENER STATUS
NSCLU9: MOVE S2,.LKSTS(P3) ;PICK UP LISTENER CONNECTION STATUS
MOVEI S1,NOTCON ;ASSUME THE LISTENER IS NOT CONNECTED
TXNN S2,LK%LIS ;LISTENER EVER BEEN CONNECTED?
MOVEI S1,NEVCON ;NO, INDICATE SO
;THE LISTENER DECNET STATUS IS EITHER: CONNECTED, NOT CONNECTED, NEVER
;CONNECTED (OR UNKNOWN). PLACE THE APPROPRIATE TEXT IN THE DISPLAY LINE.
NSCL11: $TEXT (DEPBYT,<^T/@LNKSTS(S1)/^A>) ;PLACE LISTENER STATUS IN DISPLAY
$CALL CRLF ;START THE NEXT DISPLAY LINE
;IF THE SENDER DOES NOT HAVE A CONNECTION (ALSO INCLUDE THE CASE OF THE
;SENDER NOT EXISTING), THEN ALSO INCLUDE IF THE SENDER IS ENABLED OR NOT
;TO ATTEMPT DECNET CONNECTIONS AND WHETHER OR NOT THE SENDER IS ENABLED
;TO REPORT DECNET CONNECTION ATTEMPT FAILURES TO ORION.
CAIN S1,CNTCNT ;SENDER AND LISTENER HAVE CONNECTIONS?
JRST NSCL12 ;YES, CHECK THE NEXT NODE
MOVE S1,.NNSTA(P1) ;[6006]PICK UP THE NODE STATUS WORD
TXNN S1,NN%SHO ;DOES THIS SENDER HAVE A CONNECTION?
JRST NSCL12 ;YES, CHECK THE NEXT NODE
TXNN S1,NN%CCA ;[6006]SENDER ENABLED TO MAKE A CONNECTION?
$ASCII (< DECnet connection attempts enabled>)
TXNE S1,NN%CCA ;[6006]SENDER ENABLED TO MAKE A CONNECTION?
$ASCII (< DECnet connection attempts disabled>)
$CALL CRLF ;START THE NEXT DISPLAY LINE
TXNN S1,NN%DCO ;[6006]SENDER ENABLED TO REPORT FAILURES?
$ASCII (< Report connection failure attempts enabled>)
TXNE S1,NN%DCO ;[6006]SENDER ENABLED TO REPORT FAILURES?
$ASCII (< Report connection failure attempts disabled>)
$CALL CRLF ;START THE NEXT DISPLAY LINE
;DETERMINE IF ANY MORE NODES ARE TO BE CHECKED.
NSCL12: SOJE P2,NSCL14 ;IF NO MORE NODES, SEND THE RESPONSE
NSCL13: ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE TABLE ENTRY
SOJE P4,S..NTI ;NODE TABLE INCONSISTENCY DECTECTED
JRST NSCLU4 ;CHECK OUT THE NEXT NODE
;ALL THE NODES HAVE BEEN PROCESSED. CALULATE THE LENGTH OF THE TEXT BLOCK
;AND UPDATE THE MESSAGE LENGTH FIELD
NSCL14: HRRZ S1,BYTPTR ;PICK UP FINAL MESSAGE ADDRESS
SUB S1,BLKADR ;SUBTRACT START OF TEXT DATA FIELD
ADDI S1,ARG.DA+1 ;ACCOUNT FOR TEXT HEADER + 1
MOVSS S1 ;PLACE LENGTH WHERE EXPECTED IN MSG
MOVE S2,BLKADR ;PICK UP ADDRESS OF DATA FIELD
ADDM S1,-1(S2) ;PLACE LENGTH IN TEXT BLOCK HEADER
ADDM S1,.MSTYP(MO) ;UPDATE MESSAGE LENGTH FIELD
AOS .OARGC(MO) ;INCREMENT THE ARGUMENT COUNT
;SEND THE MESSAGE. IF THE SENDER IS FROM A REMOTE NODE, THEN SEND A
;DECNET MESSAGE TO THAT NODE, OTHERWISE SEND AN IPCF MESSAGE.
SKIPE REMORG ;DID THE MESSAGE ORIGINATE REMOTELY?
$RETT ;YES, RETURN TO LISTENER MSG PROCESSOR
$CALL ORNACK ;SEND THE MESSAGE TO ORION
;CHECK IF THE ORIGINAL MESSAGE IS TO BE FORWARDED TO ANY NODES
SKIPN REMFLG ;FORWARD THE REQUEST REMOTELY?
$RETT ;NO, RETURN TO THE IPCF MSG PROCESSOR
;REFORMAT THE ORIGINAL MESSAGE. SEND OR QUEUE THE MESSAGE TO THE INDICATED
;REMOTE NODES
;**;[6047]At NSCL15:+0L replace 28 lines with 16 lines JCR 1/16/90
NSCL15: MOVEI S1,.NSRCL ;[6047]Pick up the message type
$CALL SNDCLU ;[6047]Forward the message
$RET ;[6047]Preserve the return indicator
;[6047]The node name specified in the /NODE: switch is not known to NEBULA.
;[6047]Send the message remotely if so indicated, then send an error message
;[6047]locally to ORION.
NSCL17: SKIPN REMFLG ;[6047]Forward message remotely?
JRST NSCL18 ;[6047]No, set up error indicators
MOVEI S1,.NSRCL ;[6047]Pick up the message type
$CALL SNDCLU ;[6047]Forward the message
NSCL18: MOVE S1,LOCFLG ;[6047]Pick up node name specified
CAME S1,NODNAM ;[6047]Same as the local node name?
PJRST E$NSN ;[6047]No, indicate no such node
PJRST E$INS ;[6047]Can't specify local node name
SUBTTL NDRCF - ENABLE/DISABLE REPORT-CONNECTION-FAILURES
;NDRCF processes ENABLE/DISABLE REPORT-CONNECTION-FAILURES messages. If a
;sender to a node cannot obtain a DECnet connection to a node after so
;many attempts, then it informs ORION of this fact. However, it is possible
;for an operator to disable a sender from sending connection failure messages
;to ORION by giving the OPR>DISABLE REPORT-CONNECTION-FAILURES command.
;It is also possible for an operator to direct a sender to resume sending
;these messages with the OPR>ENABLE REPORT-CONNECTION-FAILURES command.
;The default is to send the connection failure messages.
;
;Call is: M/Address of the message
;Returns true: All the senders or a specified sender that do not have
; DECnet connections have been ENABLED or DISABLED from
; having their DECnet connection failures reported to the
; operators.
;Returns false: The message is illegally formated or an unknown node
; was specified
NDRCF: $SAVE <P1,P2,P3,P4,T1,T2,T3> ;SAVE THESE AC
;DETERMINE IF THE MESSAGE IS FOR ALL SENDERS OR THE SENDER OF A SPECIFIED
;NODE.
;**;[6052]At NDRCF:+5L replace 1 line with 12 lines JCR 3/1/90
MOVEI S1,.OCTXT ;[6052]Command text block
$CALL N$ADJM ;[6052]Adjust the message
SETZM REMFLG ;[6052]Assume no need to forward
$CALL FNDNBK ;[6052]Check for a cluster node block
JUMPF NDRC.1 ;[6052]None, so check for a node block
MOVEM S1,REMFLG ;[6052]Indicate need to forward
CAME S1,[-1] ;[6052]For all nodes?
JRST NDRC.3 ;[6052]No, so forward the message now
MOVE S1,.OARGC(M) ;[6052]Pick up the number of arg blocks
SOSA S1 ;[6052]Ignore the cluster node block
NDRC.1: MOVE S1,.OARGC(M) ;[6052]Pick up the number of arg blocks
SKIPG S1 ;[6052]A node block present?
JRST NDRCF2 ;NO, SO MESSAGE IS FOR ALL REMOTE NODES
;THE MESSAGE IS FOR A PARTICULAR NODE'S SENDER. CHECK THAT THE MESSAGE SYNTAX
;IS CORRECT. IF IT IS, THEN DETERMINE IF THE SPECIFIED NODE IS KNOWN.
;**;[6046]At NDRCF:+13L remove 2 lines JCR 1/16/90
LOAD S1,.OHDRS(M),AR.TYP ;PICK UP THE ARGUMENT BLOCK TYPE
CAIE S1,.ORNOD ;IS IT A NODE BLOCK?
PJRST E$IBT ;NO, REPORT THE ERROR TO THE OPERATOR
MOVE S1,<.OHDRS+ARG.DA>(M) ;PICK UP THE NODE NAME
;**;[6052]At NDRC.1:+14L replace 4 lines with 3 lines JCR 3/1/90
MOVEM S1,G$ARG3 ;[6052]Save it in case it is unknown
$CALL SNAMNT ;[6052]Find the node's node table entry
JUMPF NDRC.4 ;[6052]Report error if node is unknown
MOVE P3,S1 ;SAVE THE NODE NAME FOR THE ACK MESSAGE
MOVE P1,S2 ;SAVE THE NODE TABLE ENTRY ADDRESS
MOVEI P2,1 ;ONLY ONE NODE TABLE ENTRY TO SEARCH
JRST NDRCF3 ;CHECK IF SHOULD REPORT LINK ATTEMPTS
;ALL NODES WHOSE SENDERS CANNOT OBTAIN A DECNET CONNECTION ARE TO HAVE THEIR
;ATTEMPT EFFORTS REPORTED ENABLED OR DISABLED.
NDRCF2: SKIPG P2,RENNUM ;ARE THERE ANY KNOWN REMOTE NODES?
;**;[6040]At NDRCF2+1L Change one line JCR 3/9/89
JRST NDRC9A ;[6040]No, just set RCFFLG.
SETZ P3, ;INDICATE MESSAGE IS FOR ALL NODES
MOVEI P1,NODTBL ;PICK UP THE NODE TABLE ADDRESS
MOVEI P4,MAXNOD ;PICK UP MAXIMUM NUMBER OF REMOTE NODES
;SETUP THE SEARCH OF THE SENDERS AND IF THE MESSAGE IS FOR ENABLE OR
;DISABLE.
NDRCF3: MOVX T3,NN%DCO ;NODE TABLE ENABLE/DISABLE FLAG BIT
MOVX T1,LK%DIS ;PACKN TABLE ENABLE/DISABLE FLAG BIT
SETZB T2,RCFFLG ;ASSUME THE MESSAGE IS ENABLE
SKIPL .OFLAG(M) ;IS IT REALLY?
SETOB T2,RCFFLG ;NO, THE MESSAGE IS FOR DISABLE
;CHECK IF THE NODE HAS A SENDER THAT DOES NOT HAVE A CONNECTION. IF THE
;NODE DOES NOT HAVE A SENDER OR THE SENDER HAS A CONNECTION, THEN JUST
;UPDATE THE PACKN ENTRY FOR THE NODE.
NDRCF4: SKIPN .NNNAM(P1) ;IS THIS NODE TABLE ENTRY IN USE?
JRST NDRCF9 ;NO, CHECK THE NEXT NODE TABLE ENTRY
MOVE S1,.NNSTA(P1) ;PICK UP THE NODE'S STATUS WORD
TXNE S1,NN%COI!NN%DCN!NN%REL ;IS THERE A SENDER FOR THIS NODE?
JRST NDRCF6 ;NO, UPDATE THE PACKN TABLE ENTRY
TXNN S1,NN%SHO ;DOES THIS SENDER HAVE A CONNECTION?
JRST NDRCF6 ;YES, JUST UPDATE THE PACKN TABLE ENTRY
;THIS NODE HAS A SENDER AND IT HAS NOT YET MADE A DECNET CONNECTION.
;IF THE MESSAGE IS TO ENABLE REPORTING THE DECNET CONNECTION ATTEMPTS,
;THEN INDICATE THIS IN THE NODE TABLE STATUS WORD. OTHERWISE INDICATE
;THAT THE DECNET CONNECTION ATTEMPTS ARE NOT TO BE REPORTED.
JUMPE T2,NDRCF5 ;IF ENABLING, GO INDICATE SO
IORM T3,.NNSTA(P1) ;DISABLE REPORTING CONNECTION FAILURES
SKIPA ;SKIP ENABLING REPORTING
NDRCF5: ANDCAM T3,.NNSTA(P1) ;ENABLE REPORTING CONNECTION FAILURES
;UPDATE THE PACKN ENTRY FOR THIS NODE TO INDICATE IF THIS NODE'S SENDER'S
;CONNECTION FAILURE ATTEMPTS ARE TO BE REPORTED OR NOT.
NDRCF6: MOVE S1,.NNNAM(P1) ;PICK UP THE NODE NAME
$CALL SRHPNE ;PICK UP THE PACKN ENTRY ADDRESS
JUMPF NDRCF7 ;SHOULD NEVER HAPPEN, BUT DON'T CARE
JUMPE T2,NDRCF7 ;IF ENABLING, GO INDICATE SO
IORM T1,.LKSTS(S2) ;INDICATE DISABLING LINK ATTEMPTS
SKIPA ;DON'T CHANGE TO ENABLING LINK ATTEMPTS
NDRCF7: ANDCAM T1,.LKSTS(S2) ;INDICATE ENABLING LINK ATTEMPTS
;DETERMINE IF THERE ARE ANY MORE NODES TO CHECK
NDRCF8: SOJE P2,NDRC10 ;SEND MESSAGE IF NO MORE NODES TO CHECK
NDRCF9: ADDI P1,.NNNSZ ;CHECK THE NEXT NODE
SOJE P4,S..NTI ;NODE TABLE INCONSISTENT, IF NO ENTRIES
JRST NDRCF4 ;CHECK THE NEXT NODE
;**;[6040]AT NDRCF9:+4L add 11 lines JCR 3/9/89
;[6040]There are currently no known remote nodes in the cluster. Just set
;[6040]the global ENABLE/DISABLE REPORT-CONNECTION-FAILURES flag for any
;[6040]future nodes that may join the cluster.
NDRC9A: SETZM RCFFLG ;[6040]Assume ENABLE
MOVEI S1,NDRC12 ;[6040]Pick up ENABLE/DISABLE Table adr
SKIPGE .OFLAG(M) ;[6040]Is the message really ENABLE?
JRST NDRC11 ;[6040]Yes, send the response to ORION
SETOM RCFFLG ;[6040]No, indicate global DISABLE
AOS S1 ;[6040]Point to the DISABLE entry
JRST NDRC11 ;[6040]Send the response to ORION
;DETERMINE THE ACK MESSAGE TO BE SENT BACK TO THE OPERATOR
;**;[6052]At NDRC10:+0L replace 1 line with 6 lines JCR 3/1/90
NDRC10: SKIPL REMORG ;[6052]Request originate remotely?
JRST NDRC.2 ;[6052]No, so send ACK
MOVE S1,T2 ;[6052]Pick up the ENABLE/DISABLE flag
MOVE S2,P3 ;[6052]Pick up the node name
$RETT ;[6052]Return to the caller
NDRC.2: MOVEI S1,NDRC12 ;[6052]Pick up adr of ENABLE/DISABLE tbl
SKIPE T2 ;WAS THE MESSAGE ENABLED?
AOS S1 ;NO, INDICATE DISABLED
;INFORM THE OPERATOR OF THE RESULT OF THE COMMAND
JUMPE P3,NDRC11 ;SKIP IF THE MSG WAS FOR ALL SENDERS
$ACK (NEBULA report connection failures to node ^N/P3/ ^T/@0(S1)/,,,.MSCOD(M))
;**;[6052]AT NDRC.2:+8L replace 4 lines with 18 lines JCR 3/1/90
SKIPL REMFLG ;[6052]Need to send remotely?
$RETT ;[6052]No, return to the caller
JRST NDRC.3 ;[6052]Forward the message remotely
NDRC11: $ACK (NEBULA report connection failures ^T/@0(S1)/,,,.MSCOD(M));[6052]
SKIPL REMFLG ;[6052]Need to send remotely?
$RETT ;[6052]No, return to the caller
NDRC.3: MOVEI S1,.NDRCF ;[6052]Pick up the message code
$CALL SNDCLU ;[6052]Forward the message
$RET ;[6052]Return to the caller
NDRC.4: SKIPN REMFLG ;[6052]Forward message remotely?
JRST NDRC.5 ;[6052]No, set up error indicators
MOVEI S1,.NDRCF ;[6052]Pick up the message type
$CALL SNDCLU ;[6052]Forward the message
NDRC.5: MOVE S1,G$ARG3 ;[6052]Pick up node name specified
CAME S1,NODNAM ;[6052]Same as the local node name?
PJRST E$NSN ;[6052]No, indicate no such node
PJRST E$INS ;[6052]Can't specify local node name
NDRC12: [ASCIZ/enabled/]
[ASCIZ/disabled/]
SUBTTL NDDCA - ENABLE/DISABLE DECNET-CONNECTION-ATTEMPTS
;NDDCA processes ENABLE/DISABLE DECNET-CONNECTION-ATTEMPTS messages.
;If a sender to a node cannot obtain a DECnet connection to a node,
;then it will retry to obtain the connection at varying time intervals.
;It is possible for an operator to disable the sender from making any more
;connection attempts with the OPR>DISABLE DECNET-CONNECTION-ATTEMPTS
;command. It is also possible for an operator to re-enable the sender
;to attempt to make a DECnet connection with the OPR>ENABLE
;DECNET-CONNECTION-ATTEMPTS command.
;
;Call is: M/Address of the message
;Returns true: All the senders or a specified sender that do not have
; DECnet connections have been ENABLED or DISABLED to
; attempt to obtain DECnet connections.
;Returns false: Illegally formatted message or an unknown node specified
NDDCA: $SAVE <P1,P2,P3,P4,T1,T2,T3> ;SAVE THESE AC
;DETERMINE IF THE MESSAGE IS FOR ALL SENDERS OR THE SENDER OF A SPECIFIED
;NODE.
;**;[6052]At NDDCA:+5L replace 1 line with 12 lines JCR 3/1/90
MOVEI S1,.OCTXT ;[6052]Command text block
$CALL N$ADJM ;[6052]Adjust the message
SETZM REMFLG ;[6052]Assume no need to forward
$CALL FNDNBK ;[6052]Check for a cluster node block
JUMPF NDDC.1 ;[6052]None, so check for a node block
MOVEM S1,REMFLG ;[6052]Indicate need to forward
CAME S1,[-1] ;[6052]For all nodes?
JRST NDDC.3 ;[6052]No, so forward the message now
MOVE S1,.OARGC(M) ;[6052]Pick up the number of blocks
SOSA S1 ;[6052]Account for the cluster node blk
NDDC.1: MOVE S1,.OARGC(M) ;[6052]Pick up the number of arg blocks
SKIPG S1 ;[6052]Node block present?
JRST NDDCA2 ;NO, SO MESSAGE IS FOR ALL REMOTE NODES
;THE MESSAGE IS FOR A PARTICULAR NODE'S SENDER. CHECK THAT THE MESSAGE SYNTAX
;IS CORRECT. IF IT IS, THEN DETERMINE IF THE SPECIFIED NODE IS KNOWN.
;**;[6046]At NDDCA:+13L remove 2 lines JCR 1/16/90
LOAD S1,.OHDRS(M),AR.TYP ;PICK UP THE ARGUMENT BLOCK TYPE
CAIE S1,.ORNOD ;IS IT A NODE BLOCK?
PJRST E$IBT ;NO, REPORT THE ERROR TO THE OPERATOR
MOVE S1,<.OHDRS+ARG.DA>(M) ;PICK UP THE NODE NAME
;**;[6052]At NDDC.1:+12L replace 5 lines with 3 lines JCR 3/1/90
MOVEM S1,G$ARG3 ;[6052]Save it in case it is unknown
$CALL SNAMNT ;[6052]Find the node's node table entry
JUMPF NDDC.4 ;[6052]Not there
MOVE P3,S1 ;SAVE THE NODE NAME FOR THE ACK MESSAGE
MOVE P1,S2 ;SAVE THE NODE TABLE ENTRY ADDRESS
MOVEI P2,1 ;ONLY ONE NODE TABLE ENTRY TO SEARCH
JRST NDDCA3 ;CHECK IF SHOULD ENABLE LINK ATTEMPTS
;ALL NODES WHOSE SENDERS CANNOT OBTAIN A DECNET CONNECTION ARE TO BE ENABLED TO
;OR DISABLED FROM ATTEMPTING TO MAKE A DECNET CONNECTION.
NDDCA2: SKIPG P2,RENNUM ;ARE THERE ANY KNOWN REMOTE NODES?
PJRST E$NRN ;NO, TELL THE OPERATOR
SETZ P3, ;INDICATE MESSAGE IS FOR ALL NODES
MOVEI P1,NODTBL ;PICK UP THE NODE TABLE ADDRESS
MOVEI P4,MAXNOD ;PICK UP MAXIMUM NUMBER OF REMOTE NODES
;SET UP THE SEARCH OF THE SENDERS AND IF THE MESSAGE IS FOR ENABLE OR
;DISABLE.
NDDCA3: MOVX T3,NN%CCA ;NODE TABLE ENABLE/DISABLE FLAG BIT
MOVX T1,LK%CCA ;PACKN TABLE ENABLE/DISABLE FLAG BIT
SETZB T2,DCAFLG ;ASSUME THE MESSAGE IS ENABLE
SKIPL .OFLAG(M) ;IS IT REALLY?
SETOB T2,DCAFLG ;NO, THE MESSAGE IS FOR DISABLE
;CHECK IF THE NODE HAS A SENDER THAT DOES NOT HAVE A CONNECTION. IF THE
;NODE DOES NOT HAVE A SENDER OR THE SENDER HAS A CONNECTION, THEN JUST
;UPDATE THE PACKN ENTRY FOR THE NODE.
NDDCA4: SKIPN .NNNAM(P1) ;IS THIS NODE TABLE ENTRY IN USE?
JRST NDDCA9 ;NO, CHECK THE NEXT NODE TABLE ENTRY
MOVE S1,.NNSTA(P1) ;PICK UP THE NODE'S STATUS WORD
TXNE S1,NN%COI!NN%DCN!NN%REL ;IS THERE A SENDER FOR THIS NODE?
JRST NDDCA6 ;NO, JUST UPDATE THE PACKN TABLE ENTRY
TXNN S1,NN%SHO ;DOES THIS SENDER HAVE A CONNECTION?
JRST NDDCA6 ;YES, JUST UPDATE THE PACKN TABLE ENTRY
;THIS NODE HAS A SENDER AND IT HAS NOT YET MADE A DECNET CONNECTION.
;IF THE MESSAGE IS TO ENABLE DECNET CONNECTION ATTEMPTS, THEN INDICATE THIS
;IN THE NODE TABLE STATUS WORD. OTHERWISE, INDICATE THAT THE DECNET CONNECTION
;ATTEMPTS ARE TO BE ABORTED.
JUMPE T2,NDDCA5 ;IF ENABLING, GO INDICATE SO
IORM T3,.NNSTA(P1) ;DISABLE CONNECTION ATTEMPTS
JRST NDDCA6 ;SKIP ENABLING CONNECTION ATTEMPTS
NDDCA5: ANDCAM T3,.NNSTA(P1) ;ENABLE CONNECTION ATTEMPTS
;IF DECNET CONNECTION ATTEMPTS ARE BEING ENABLED, THEN INTERRUPT THE SENDER.
MOVE SEN,.NNSBA(P1) ;PICK UP SENDER BLOCK ADDRESS
MOVE S1,.SNHND(SEN) ;PICK UP THE SENDER'S HANDLE
MOVX S2,<1B2> ;PICK UP CHANNEL TO INTERRUPT SENDER ON
IIC% ;INTERRUPT SENDER TO ENABLE ATTEMPTS
ERJMP S..UII ;CRASH ON AN ERROR
;UPDATE THE PACKN ENTRY FOR THIS NODE TO INDICATE IF THIS NODE'S SENDER
;IS TO ATTEMPT TO OBTAIN A DECNET CONNECTION.
NDDCA6: MOVE S1,.NNNAM(P1) ;PICK UP THE NODE NAME
$CALL SRHPNE ;PICK UP THE PACKN ENTRY ADDRESS
JUMPF NDDCA7 ;SHOULD NEVER HAPPEN, BUT DON'T CARE
JUMPE T2,NDDCA7 ;IF ENABLING, GO INDICATE SO
IORM T1,.LKSTS(S2) ;INDICATE DISABLING CONNECTION ATTEMPTS
SKIPA ;SKIP ENABLING CONNECTION ATTEMPTS
NDDCA7: ANDCAM T1,.LKSTS(S2) ;INDICATE ENABLING CONNECTION ATTEMPTS
;DETERMINE IF THERE ARE ANY MORE NODES TO CHECK
NDDCA8: SOJE P2,NDDC10 ;SEND MESSAGE IF NO MORE NODES TO CHECK
NDDCA9: ADDI P1,.NNNSZ ;CHECK THE NEXT NODE
SOJE P4,S..NTI ;NODE TABLE INCONSISTENT, IF NO ENTRIES
JRST NDDCA4 ;CHECK THE NEXT NODE
;DETERMINE THE ACK MESSAGE TO BE SENT BACK TO THE OPERATOR
;**;[6052]At NDDC10:+0L replace 1 line with 6 lines JCR 3/1/90
NDDC10: SKIPL REMORG ;[6052]Request originate remotely?
JRST NDDC.2 ;[6052]No, so send ACK
MOVE S1,T2 ;[6052]Pick up the ENABLE/DISABLE flag
MOVE S2,P3 ;[6052]Pick up the node name
$RETT ;[6052]Return to the caller
NDDC.2: MOVEI S1,NDDC12 ;[6052]Pick up adr of ENABLE/DISABLE tbl
SKIPE T2 ;WAS THE MESSAGE ENABLED?
AOS S1 ;NO, INDICATE DISABLED
;INFORM THE OPERATOR OF THE RESULT OF THE COMMAND
JUMPE P3,NDDC11 ;SKIP IF THE MSG WAS FOR ALL SENDERS
$ACK (NEBULA connection attempts to node ^N/P3/ ^T/@0(S1)/,,,.MSCOD(M))
;**;[6052]At NDDC.2:+8L replace 4 lines with 19 lines JCR 3/1/90
SKIPL REMFLG ;[6052]Forward the message remotely?
$RETT ;[6052]No, return to the caller
JRST NDDC.3 ;[6052]Forward the message
NDDC11: $ACK (NEBULA connection attempts ^T/@0(S1)/,,,.MSCOD(M)) ;[6052]
SKIPL REMFLG ;[6052]Forward the message remotely?
$RETT ;[6052]No, return to the caller
NDDC.3: MOVEI S1,.NDDCA ;[6052]Pick up the message code
$CALL SNDCLU ;[6052]Forward the message
$RET ;[6052]Return to the caller
NDDC.4: SKIPN REMFLG ;[6052]Forward message remotely?
JRST NDDC.5 ;[6052]No, set up error indicators
MOVEI S1,.NDDCA ;[6052]Pick up the message type
$CALL SNDCLU ;[6052]Forward the message
NDDC.5: MOVE S1,G$ARG3 ;[6052]Pick up node name specified
CAME S1,NODNAM ;[6052]Same as the local node name?
PJRST E$NSN ;[6052]No, indicate no such node
PJRST E$INS ;[6052]Can't specify local node name
NDDC12: [ASCIZ/enabled/]
[ASCIZ/disabled/]
;**;[6045]At NDDC12:+1L add routine N$ADJM JCR 1/15/90
SUBTTL N$ADJM - Adjust NEBULA Message
;[6045]N$ADJM is called to remove a trailing block from a message.
;[6045]
;[6045]Call is: M/Message address
;[6045] S1/Block type to remove
;[6045]Returns true: The block has been removed from the message
;[6045] S2/The block address
;[6045]Returns false: The block was not found in the message
N$ADJM: $CALL N$FNDB ;[6045]Search the message
$RETIF ;[6045]Return now if none
MOVEI S2,-ARG.DA(S1) ;[6045]Save the block address
HLLZ S1,ARG.HD(S2) ;[6045]Pick up the block length
MOVNS S1 ;[6045]Negate it
ADDM S1,.MSTYP(M) ;[6045]Adjust the total message length
SOS .OARGC(M) ;[6045]Adjust the argument count
$RETT ;[6045]Return to the caller
;**;[6047]At N$ADJM:+8L add routine SNDCLU JCR 1/16/90
SUBTTL SNDCLU - Send a SHOW CLUSTER Message Remotely
;[6047]SNDCLU is called to forward SHOW CLUSTER, ENABLE/DISABLE DECNET-
;[6047]CONNECTION-ATTEMPTS, and ENABLE/DISABLE REPORT-CONNECTION-FAILURES
;[6047]that were specified with the /CLUSTER-NODE switch
;[6047]
;[6047]Call is: M/Address of the message to be forwarded
;[6047] S1/Message code
;[6047] REMFLG/Remote node name or "-1" for all remote nodes
;[6047]Returns true: The message was successfully queued or sent to all the
;[6047] indicated nodes
;[6047]Returns false: The message was not successfully queued or sent
;[6047] to all the indicated nodes
SNDCLU: STORE S1,.MSTYP(M),MS.TYP ;[6047]Save the message type
MOVEI S1,.NDESZ ;[6047]Pick up remote node block size
MOVSS S1 ;[6047]Place length in expected place
MOVNS S1 ;[6047]Negate the length
ADDM S1,.MSTYP(M) ;[6047]Decrement total message length
SOS .OARGC(M) ;[6047]Decrement the argument count
MOVE S1,REMFLG ;[6047]Pick up the remote node flag
CAMN S1,[-1] ;[6047]For all remote nodes?
JRST SNDC.1 ;[6047]Yes, send to all remote nodes
$CALL QSREMM ;[6047]No, send to the indicated node
$RETIT ;[6047]Return on success
$CALL 0(S1) ;[6047]Setup error indicators
$RET ;[6047]Preserve error return
SNDC.1: $CALL QMREMM ;[6047]Send to all the remote nodes
SETZM G$ERR ;[6047]QMREMM sends any error messages
$RET ;[6047]Preserve true/false indicator
SUBTTL SETPAG - SETUP MESSAGE HEADER FOR SHOW ACK MESSAGES
;SETPAG is called by routines that process SHOW messages directed at
;NEBULA for action. Currently, this includes only the message:
;SHOW CLUSTER-GALAXY-LINK-STATUS
;This routine gets the message page, builds the GALAXY header, the
;display (.ORDSP) block and sets up the TEXT (.CMTXT) block header.
;If the SHOW CLUSTER-GALAXY-LINK-STATUS message originated on a remote
;node, then two display blocks are built. The first display block
;indicates where the SHOW CLUSTER-GALAXY-LINK-STATUS message was processed
;and the second block is identical to the display block included in
;the message when it is processed locally.
;
;Call is: S1/Address of the OPR display header
; M/ Address of the IPCF message
;Returns: SHOW ACK message header and display block has been built
SETPAG: $SAVE <P1> ;SAVE THIS AC
;PICK UP THE MESSAGE RESPONSE PAGE AND BUILD THE GALAXY MESSAGE HEADER
;(NOTE: IF THE MESSAGE CAME FROM A REMOTE NODE, THEN INDICATE THIS IN THE
;.MSFLG FLAG WORD BY SETTING BIT MF.NEB.)
MOVE P1,S1 ;SAVE ADR OF DISPLAY HEADER STRING
$CALL GETPAG ;GET PAGE FOR RESPONSE MESSAGE
MOVE S1,[.OHDRS,,.OMACS] ;PICK UP MESSAGE TYPE WORD
MOVEM S1,.MSTYP(MO) ;PLACE IN THE RESPONSE MESSAGE
MOVE S1,.MSCOD(M) ;PICK UP OPR'S PID TO SEND RESPONSE TO
MOVEM S1,.MSCOD(MO) ;PLACE IN THE RESPONSE MESSAGE
MOVX S1,MF.NEB ;ASSUME THE MESSAGE ORIGINATED REMOTELY
SKIPE REMORG ;IS THIS A VALID ASSUMPTION?
MOVEM S1,.MSFLG(MO) ;YES, INDICATE THIS IN THE MESSAGE
MOVEI S1,.OHDRS(MO) ;POINT TO THE DISPLAY BLOCK
MOVE S2,P1 ;PICK UP THE DISPLAY TEXT ADDRESS
$CALL SETHDR ;BUILD THE DISPLAY BLOCK
;SET UP HEADER TO THE TEXT BLOCK
MOVEI S2,.CMTXT ;PICK UP TEXT BLOCK CODE
STORE S2,ARG.HD(S1),AR.TYP ;PLACE IN TEXT BLOCK HEADER
MOVEI S2,ARG.DA(S1) ;PICK UP START OF TEXT FIELD
MOVEM S2,BLKADR ;REMEMBER FOR TEXT FIELD LENGTH CALC
HRLI S2,(POINT 7,) ;MAKE POINTER TO TEXT FIELD
MOVEM S2,BYTPTR ;REMEMBER FOR $TEXT PROCESSING
$RET ;RETURN TO THE CALLER
SUBTTL SETHDR - BUILDS DISPLAY BLOCK FOR SHOW ACK MESSAGES
;SETHDR is called to build the DISPLAY (.ORDSP) block for SHOW ACK
;messages.
;
;Call is: S1/Address of the DISPLAY block
; S2/Address of the display text
; MO/Address of the SHOW ACK message being built
;Returns: DISPLAY block has been built
; S1/Points to start of the TEXT (.ORDSP) block
SETHDR: $SAVE <P1,P2> ;SAVE THESE AC
;BUILD THE DISPLAY BLOCK HEADER AND THE TIME THE MESSAGE WAS PROCEESED
;WORD (THIS IS ALWAYS THE FIRST WORD OF A DISPLAY BLOCK.
MOVE P2,S2 ;SAVE DISPLAY STRING ADDRESS
$CALL BDBHDR ;BUILD THE DISPLAY BLOCK HEADER
;PLACE THE DISPLAY HEADER STRING IN THE DISPLAY BLOCK, CALULATE THE LENGTH
;OF THE DISPLAY BLOCK AND SAVE THE LENGTH IN THE DISPLAY BLOCK HEADER
SKIPN REMORG ;MESSAGE FROM A REMOTE NODE?
$TEXT (DEPBYT,<^T/0(P2)/^A>) ;NO, PLACE DISPLAY STR IN DISPLAY BLOCK
SKIPE REMORG ;MESSAGE FROM A REMOTE NODE?
$TEXT (DEPBYT,<^I/@NODSTR/^A>) ;YES, PLACE DISPLAY STR IN DISPLAY BLK
;IF THE MESSAGE IS FROM A REMOTE NODE, ADD A SECOND DISPLAY BLOCK
SKIPN REMORG ;MESSAGE FROM A REMOTE NODE?
JRST SETHD2 ;NO, FINISH UP
HRRZ P1,BYTPTR ;PICK UP ADDRESS OF END OF DISPLAY BLK
SUBI P1,-1(S1) ;CALCULATE LENGTH OF DISPLAY BLOCK
STORE P1,ARG.HD(S1),AR.LEN ;STORE LENGTH OF DISPLAY BLOCK
ADD S1,P1 ;POINT TO THE NEXT DISPLAY BLOCK
MOVSS P1 ;PUT DISPLAY BLK LENGTH WHERE EXPECTED
ADDM P1,.MSTYP(MO) ;ADD TO MESSAGE LENGTH
$CALL BDBHDR ;BUILD THE SECOND DISPLAY BLOCK
$TEXT (DEPBYT,<^T/0(P2)/^A>) ;PLACE DISPLAY STR IN DISPLAY BLOCK
;POINT TO THE NEXT ARGUMENT BLOCK AND UPDATE MESSAGE LENGTH IN GALAXY HEADER
;WORD
SETHD2: HRRZ P1,BYTPTR ;PICK UP ADDRESS OF END OF DISPLAY BLK
SUBI P1,-1(S1) ;CALCULATE LENGTH OF DISPLAY BLOCK
STORE P1,ARG.HD(S1),AR.LEN ;STORE LENGTH OF DISPLAY BLOCK
ADD S1,P1 ;POINT TO THE NEXT ARGUMENT BLOCK
MOVSS P1 ;PUT DISPLAY BLK LENGTH WHERE EXPECTED
ADDM P1,.MSTYP(MO) ;UPDATE MESSAGE LENGTH FIELD
$RET ;RETURN TO THE CALLER
;**;[6045]At NODSTR:+0L change 1 line JCR 1/15/90
NODSTR: [ITEXT(< Received message from ^N/NODNAM/>)] ;[6045]
SUBTTL BDBHDR - BUILD DISPLAY BLOCK HEADER
;BDBHDR is called to build the display block header.
;
;Call is: S1/Address of the display block
; MO/Address of the message being built
;Returns: The display block header has been built
; S1/Address of the display block
BDBHDR: AOS .OARGC(MO) ;INCREMENT ARGUMENT BLOCK COUNT
MOVEI S2,.ORDSP ;PICK UP DISPLAY BLOCK CODE
STORE S2,ARG.HD(S1),AR.TYP ;PLACE IN THE BLOCK HEADER
MOVE S2,MSGTIM ;PICK UP TIME THIS MSG IS PROCESSED
MOVEM S2,ARG.DA(S1) ;PLACE IN 1ST WORD OF TEXT BLOCK
;BUILD THE BYTE POINTER TO THE DISPLAY BLOCK TEXT FIELD
MOVEI S2,ARG.DA+1(S1) ;POINT TO 2ND WORD OF THE DISPLAY BLOCK
HRLI S2,(POINT 7,) ;MAKE INTO A POINTER
MOVEM S2,BYTPTR ;SAVE FOR $TEXT PROCESSING
$RET ;RETURN TO THE CALLER
SUBTTL FNDNBK - FIND THE NODE BLOCK IN AN IPCF MESSAGE
;FNDNBK is called to find the node block of a SHOW message.
;
;Call is: M/Address of the IPCF SHOW message
;Returns true: The node block is present in the message
; S1/The SIXBIT name of the node to send the message to or
; -1 which indicates that the message is to be sent to
; all the remote nodes in the cluster
; S2/Address of the node block
;Returns false: The node block is not present in the message
FNDNBK: $SAVE <P1> ;SAVE THIS AC
;SETUP TO FIND THE NODE NAME ARGUMENT BLOCK BY DETERMINING THE NUMBER OF
;ARGUMENT BLOCKS AND THE ADDRESS OF THE FIRST ARGUMENT BLOCK.
;**;[6052]At FNDNBK:+5L replace 1 line with 2 lines JCR 3/1/90
SKIPG S1,.OARGC(M) ;[6052]Pick up the number of arg blocks
$RETF ;[6052]Return if none
MOVEI S2,.OHDRS(M) ;POINT TO THE FIRST ARGUMENT BLOCK
;FIND THE NODE NAME BLOCK AND RETURN THE NAME OF THE REMOTE NODE
FNDNB2: LOAD P1,ARG.HD(S2),AR.TYP ;PICK UP THE ARGUMENT BLOCK TYPE
CAIN P1,.NDENM ;IS THIS THE NODE BLOCK?
JRST FNDNB3 ;YES, RETURN THE REMOTE NODE NAME
LOAD P1,ARG.HD(S2),AR.LEN ;NO, PICK UP THE LENGTH OF THIS BLOCK
ADD S2,P1 ;POINT TO THE NEXT ARGUMENT BLOCK
SOJG S1,FNDNB2 ;CHECK OUT THE NEXT ARGUMENT BLOCK
$RETF ;ERROR, NO NODE BLOCK IN THE MESSAGE
FNDNB3: MOVE S1,ARG.DA(S2) ;PICK UP THE NODE NAME
$RETT ;RETURN THE NODE NAME TO THE CALLER
SUBTTL CHKLEN - CHECK THE VALIDITY OF AN IPCF MESSAGE
;CHKLEN is called as part of validating the syntax of an IPCF message.
;This routine checks if the size of an IPCF message, as indicated in the
;message length field of the IPCF message, is positive and less than or
;equal to a page.
;
;Call is: M/Address of the IPCF message
;Returns true: The indicated message length is valid
; S1/The indicated length of the message
;Returns false: The indicated message length is invalid
CHKLEN: LOAD S1,.MSTYP(M),MS.CNT ;PICK UP THE LENGTH OF MSG
SKIPG S1 ;POSITIVE LENGTH SPECIFIED?
$RETF ;INVALID MSG LENGTH SPECIFIED
CAILE S1,PAGSIZ ;NOT OVER A PAGE?
$RETF ;INVALID MSG LENGTH SPECIFIED
$RETT ;VALID MESSAGE SIZE SPECIFIED
SUBTTL QSREMM - SEND OR QUEUE REMOTE MESSAGES TO A SINGLE REMOTE NODE
;QSREMM is called by IPCF routines that process "remote" messages that
;will be sent to a single remote node. These routines first verify that the
;remote message has a valid syntax, then they change the format of the
;message, if necessary.
;After this, these routines call QSREMM which determines if the message should
;be placed on the sender's message queue to the remote node or if the
;message can be placed in the sender's message buffer and transferred
;directly to the remote node. This latter case is true if the sender is
;available to send a message and its message queue is empty.
;
;Call is: S1/Remote node name to send the message to
; M/Address of the IPCF remote message
;Returns true: Message has been queued to or sent to the remote node
;Returns false: The remote node does not exist or is unable to receive messages
; S1/Address of the error handling routine
QSREMM: $CALL SETPAR ;DETERMINE IF CAN SEND MSG DIRECTLY
JUMPF .POPJ ;NODE NOT ABLE TO RECEIVE MESSAGES
$CALL QUEMSG ;QUEUE OR SEND THE MESSAGE
$RETT ;RETURN TO THE CALLER
SUBTTL QMREMM - SEND OR QUEUE REMOTE MESSAGES TO MULTIPLE REMOTE NODES
;QMREMM is called by IPCF routines that process remote messages that
;will be sent to multiple remote nodes. (This occurs when the OPR
;/CLUSTER-NODE: switch specified a value of "*").
;These routines first verify that the remote message has a valid syntax,
;then they change the format, if necessary.
;After this, these routines call QMREMM which determines which nodes the
;message must be queued for, which nodes the message can be sent to and
;which nodes the message cannot be sent to. A message can be sent directly
;to a remote node if the sender to that node is available to send a message
;and its message queue is empty.
;If one or more nodes cannot receive the message, then an error
;(.OMACK) message is sent to the OPR that issued the message indicating for
;each node that the message could not be sent to the reason for the failure.
;
;Call is: M/Address of the IPCF remote message
;Returns true: Message has been queued to or sent to the remote nodes
;Returns false: No remote nodes are able to receive the message. (The
; sender of the message is informed of any nodes the message
; was not sent to.)
QMREMM: $CALL SEPALL ;DETERMINE IF CAN SEND MSG DIRECTLY
JUMPF .POPJ ;NO NODES ABLE TO RECEIVE MESSAGES
$CALL QUEMSG ;QUEUE OR SEND THE MESSAGE
$RETT ;RETURN TO THE CALLER
SUBTTL QRIBHM - SEND/QUEUE RESPONSES TO IBH MESSAGE TO REQUESTING NODE
;QRIBHM is called by IPCF routines that are processing the responses to IBH
;messages. All these routines first check the syntax of the
;response message, reformat (if necessary) the response message, then call
;QRIBHM. QRIBHM first finds the in behalf of queue entry corresponding to the
;response message. If the IBH queue entry is not found, then it is assumed that
;the requesting node has lost (or had lost and then regained) communication
;with the local node between the time the in behalf of message was received
;and the time NEBULA has received its response. (When a requesting node has
;lost communication with the local node, the local node, as part of its
;cleanup of the requesting node, deletes the requesting node's entries in
;the in behalf of queue.)
;If the in behalf of queue entry is found, then the original ACK code of the
;in behalf message is placed in the response message and the message is
;either queued to be sent to the requesting node or is sent directly to the
;requesting node if the requesting node's sender is available to send messages
;and it has no messages in its message queue.
;
;Call is: M/Reformatted IPCF in behalf of response message
;Returns true: The message was sent or queued
;Returns false: The in behalf of queue entry was not found (in this case the
; message is dropped by NEBULA)
;Crashes: Node table inconsistency detected
QRIBHM: $SAVE <P1,P2> ;[6012]SAVE THESE AC
;PICK UP THE IN BEHALF OF QUEUE ENTRY
MOVE S1,.MSCOD(M) ;PICK UP THE LOCAL ACK CODE
$CALL FNDIBH ;FIND THE IN BEHALF OF QUEUE ENTRY
;**;[6043]At QRIBHM:+6L replace 1 line with 20 lines JCR 11/29/89
JUMPT QRIBH1 ;[6043]Check if message can be forwarded
;[6043]Some OPR commands may result in more than one WTO or WTOR message being
;[6043]generated. Therefore, if the IBH queue entry is not found, then check
;[6043]if the message was originally a WTO or a WTOR. If it was, then forward
;[6043]the message to the indicated node.
LOAD S1,.MSTYP(M),MS.TYP ;[6043]Get the message type
CAIE S1,.OMDSP ;[6043]Is it a display message?
JRST QRIBH2 ;[6043]No, so quit now
LOAD S1,.MSFLG(M) ;[6043]Pick up the flag word
TXNN S1,MF.WTO!MF.WTR ;[6043]Originally a WTO or WTOR?
JRST QRIBH2 ;[6043]No, so quit now
MOVE S1,.OHDRS+ARG.DA(M) ;[6043]Pick up the node name
$CALL SETPAR ;[6043]Determine if can forward the msg
;**;[6050]At QRIBHM:+21L change 1 line JCR 2/9/90
$RETIF ;[6050]Quit if node no longer there
SETZM .MSCOD(M) ;[6043]Zero the PID
TXO S2,MQ%IBH ;[6043]This msg is response to IBH msg
$CALL QUEMSG ;[6043]Send or queue the message
$RETT ;[6043]Return to the caller
;DETERMINE IF THE MESSAGE CAN BE SENT TO THE NODE. (THIS SHOULD ALWAYS BE
;THE CASE. IF IT IS NOT, THEN THERE IS AN INCONSISTENCY IN THE NODE DATA
;BASE.)
;IF THE MESSAGE CAN BE SENT TO THE NODE, THEN DETERMINE
;IF THE MESSAGE CAN BE SENT DIRECTLY TO THE NODE OR IF IT MUST BE QUEUED
;ON THE NODE'S MESSAGE QUEUE.
;**;[6043]At QRIBHM:+25L change 1 line JCR 11/29/89
QRIBH1: MOVE P1,S2 ;[6043]Save the IBH QE address
MOVE S1,.IQNEN(P1) ;PICK UP THE REMOTE NODE NAME
$CALL SETPAR ;DETERMINE IF CAN SEND MSG DIRECTLY
JUMPF S..NTI ;CAN'T SEND TO NODE. INCONSISTENCY
;REPLACE THE LOCAL ACK CODE WITH THE ORIGINAL ACK CODE. IF THE REQUEST
;ORIGINATED FROM THE EXEC, THEN SAVE ITS PID IN THE MESSAGE. EITHER SEND
;THE MESSAGE TO THE REMOTE NODE OR QUEUE THE MESSAGE ON THE REMOTE
;NODE SENDER'S MESSAGE QUEUE, AND RELEASE THE IN BEHALF OF QUEUE ENTRY.
MOVE P2,.IQRNA(P1) ;PICK UP THE ORIGINAL ACK CODE
MOVEM P2,.MSCOD(M) ;PLACE IN THE MESSAGE
MOVE P2,.IQPID(P1) ;[6012]PICK UP A POSSIBLE EXEC PID
SKIPE EXESND ;[6012]REQUEST ORIGINALLY FROM EXEC?
MOVEM P2,.OFLAG(M) ;[6012]YES, PLACE ITS PID IN THE MESSAGE
TXO S2,MQ%IBH ;THIS MSG IS RESPONSE TO IBH MSG
$CALL QUEMSG ;SEND OR QUEUE THE MESSAGE
MOVE S1,.MSFLG(M) ;PICK UP THE FLAG WORD OF THIS MESSAGE
TXNE S1,MF.MOR ;MORE PAGES FOR THIS MESSAGE?
$RETT ;YES, DON'T DESTROY THE IBH QUEUE ENTRY
;**;[6037]At QRIBHM:+18L add 2 lines JYCW Oct-18-88
SOSE .IQNUM(P1) ;[6037]ANY MORE RESPONSES?
$RETT ;[6037]YES, KEEP THE IBH QUEUE ENTRY
MOVE S1,P1 ;PICK ADDRESS OF THE IBH QUEUE ENTRY
$CALL RELIBH ;RELEASE THE IBH QUEUE ENTRY
$RETT ;RETURN TO THE CALLER
;**;[6043]At QRIBH2:+0L change 1 line JCR 11/29/89
QRIBH2: $RETF ;[6043]Return to the caller
SUBTTL SETPAR - SETUP PARAMETERS FOR ROUTINE QUEMSG
;SETPAR is called to set up ACs S1 and S2, and tables NODSEN and NODMQ
;for routine QUEMSG. SETPAR is used when a message needs to be sent to
;only one node. For the case where a message is to be sent to all remote
;nodes (i.e., an OPR command was given with /CLUSTER-NODE:*), then routine
;SEPALL is called.
;
;Call is: S1/SIXBIT node name of node the message is to be sent to
;Returns true: S1/Number of nodes to send the message directly to
; (either 0 or 1)
; S2/Number of nodes to queue the message on the message queue
; (either 0 or 1)
; NODSEN/If (S1) = 1, then contains the node table entry address
; of the node that is to have the message sent directly to
; NODMQ/ If (S2) = 1, then contains the node table entry address
; of the node that is to have the message queued on its
; message queue
;Returns false: S1/Address of the error handling routine
SETPAR: $SAVE <P1> ;SAVE THIS AC
;FIRST CHECK IF THE NODE EXISTS
MOVE P1,S1 ;SAVE THE NODE NAME IN CASE OF ERROR
$CALL SNAMNT ;FIND THE NODE IN THE NODE TABLE
JUMPF SETPA4 ;NO SUCH NODE, INFORM ORION
;CHECK IF DECNET MESSAGES CAN BE SENT TO THIS NODE
SKIPL S1,.NNSTA(S2) ;O.K. TO SEND TO THIS NODE?
JRST SETPA5 ;NO, CAN'T SEND TO THIS NODE
;**;[6037]At SETPAR:+6L add 2 lines JYCW Oct-18-88
SKIPE NMFFLG ;[6037]NEW FORMAT?
TXNE S1,NN%PAS ;[6037]Post F.I GALAXY on remote node
JRST SETPA ;[6037]
TXZ S1,NN%OKS ;[6037]Clear O.K to send bit
TXO S1,NN%PAS ;[6037]SET NOT LATEST GALAXY BIT
JRST SETPA7 ;[6037]NO, CAN'T SEND TO THIS NODE
;CHECK IF THIS NODE'S MESSAGE QUEUE IS EMPTY AND IF IT IS, CHECK IF THE SENDER
;TO THE NODE IS BUSY. IF THE SENDER IS NOT BUSY, THEN INDICATE THAT THE
;MESSAGE CAN BE SENT DIRECTLY TO THE NODE WITHOUT FIRST PLACING THE MESSAGE
;ON THE NODE'S MESSAGE QUEUE
SETPA: MOVE SEN,.NNSBA(S2) ;[6037]PICK UP THE SENDER BLOCK ADDRESS
SKIPE .SNUSM(SEN) ;IS THE MESSAGE QUEUE EMPTY?
JRST SETPA2 ;NO, INDICATE MUST USE MESSAGE QUEUE
SKIPL .SNFRE(SEN) ;YES, IS THE SENDER FREE TO SEND A MSG?
JRST SETPA2 ;NO, INDICATE MUST USE MESSAGE QUEUE
;INDICATE THAT THE MESSAGE CAN BE SENT TO THE SENDER WITHOUT NEEDING TO PLACE
;THE MESSAGE ON THE NODE'S MESSAGE QUEUE.
MOVEM S2,NODSEN ;PLACE NODE TABLE ENTRY IN TABLE
MOVEI S1,1 ;ONE NODE TO SEND MESSAGE DIRECTLY TO
SETZ S2, ;NO NODES NEED MSG PLACED ON MSG QUEUE
JRST SETPA3 ;GO RETURN
;INDICATE THAT THE MESSAGE MUST BE PLACED ON THE NODE'S MESSAGE QUEUE
SETPA2: MOVEM S2,NODMQ ;PLACE NODE TABLE ENTRY IN TABLE
SETZ S1, ;NO NODES TO SEND MESSAGE DIRECTLY TO
MOVEI S2,1 ;ONE NODE NEEDS MSG PLACED ON MSG QUEUE
SETPA3: $RETT ;RETURN TO THE CALLER
;AN ERROR HAS BEEN DETECTED. EITHER THE NODE IS NO LONGER IN THE CLUSTER OR
;THE NODE IS NOT CAPABLE OF RECEIVING DECNET MESSAGES.
SETPA4: MOVEI S1,E$NSN ;NO SUCH NODE ERROR ROUTINE ADDRESS
;**;[6052]At SETPA4:+1L change 1 line JCR 3/1/90
MOVEM P1,G$ARG3 ;[6052]Save the node name for error handler
$RETF ;RETURN INDICATING FAILURE
SETPA5: MOVE S2,P1 ;PICK UP THE NODE NAME
$CALL USNERR ;PICK UP ADDRESS OF ERROR STRING
MOVEI S1,E$USN ;UNABLE TO SEND TO NODE ROUTINE ADDRESS
$RETF ;RETURN TO THE CALLER
;**;[6037]At SETPA5:+4L add routine SETPA7: JYCW Oct-18-88
SETPA7: MOVEM P1,G$ARG1 ;[6037]PICK UP THE NODE NAME
MOVEI S1,[ASCIZ/ because node is running
Field Image version 6 GALAXY and does not understand the command/]
MOVEM S1,G$ARG2 ;[6037]SAVE IT
MOVEI S1,E$USN ;UNABLE TO SEND TO NODE ROUTINE ADDRESS
$RETF ;RETURN TO THE CALLER
SUBTTL SEPALL - SET UP PARAMETERS FOR ROUTINE QUEMSG
;SEPALL is called to set up ACs S1 and S2, and tables NODSEN and NODMQ
;for routine QUEMSG. SEPALL is called when a message needs to be sent to
;all the remote nodes (i.e., an OPR command was given with /CLUSTER-NODE:*).
;
;Call is: No arguments
;
;Returns true: S1/Number of nodes to send the message directly to
; S2/Number of nodes to queue the message on the message queue
; NODSEN/If (S1) > 0, then contains the node table entry
; addresses of the nodes that are to have the message sent
; directly to them
; NODMQ/ If (S2) > 0, then contains the node table entry
; addresses of the nodes that are to have the message
; queued on their message queues
;Returns false: The message cannot be sent to any nodes. In this case, (as
; in the case where the message can be sent to some nodes, but
; not all nodes) an ACK message is sent to the OPR which made
; the request indicating which nodes the message was not sent to.
;Crashes: Node table inconsistency detected
SEPALL: $SAVE <P1,P2,P3,P4,T1,T2> ;SAVE THESE AC
;FIRST INITIALIZE THE POINTERS AND COUNTERS
SETZB S1,S2 ;NO NODES DIRECT SEND OR QUEUE THE MSG
SETO P1, ;CAN SEND TO ALL NODES
MOVEI P2,NODTBL ;POINT TO THE NODE TABLE
;**;[6053]At SEPALL:+7L replace 1 line with 2 lines JCR 4/27/90
SKIPG P3,RENNUM ;[6053]Pick up number of remote nodes
$RETF ;[6053]Quit now if none
MOVEI P4,MAXNOD ;PICK UP MAXIMUM NUMBER OF REMOTE NODES
;CHECK IF THE REMOTE NODE CAN RECEIVE DECNET MESSAGES
SEPAL2: SKIPN T1,.NNNAM(P2) ;IS THIS NODE TABLE ENTRY IN USE?
JRST SEPAL6 ;NO, CHECK THE NEXT NODE TABLE ENTRY
SKIPL T2,.NNSTA(P2) ;O.K. TO SEND TO THIS NODE?
JRST SEPAL4 ;NO, ADD THIS NODE TO THE ERROR LIST
;**;[6037]At SEPAL2:+4L add 2 lines JYCW Oct-18-88
SKIPE NMFFLG ;[6037]NEW FORMAT?
TXNE T2,NN%PAS ;[6037]POST F.I GALAXY ON REMOTE NODE
JRST SEPAL8 ;[6037]NO
TXZ T2,NN%OKS ;[6037]Clear O.K to send bit
TXO T2,NN%PAS ;[6037]SET NOT LATEST GALAXY BIT
JRST SEPAL4 ;[6037]NO, CAN'T SEND TO THIS NODE
;THE NODE CAN RECEIVE DECNET MESSAGES. CHECK IF THE MESSAGE CAN BE PLACED
;DIRECTLY IN THE SENDER'S MESSAGE BUFFER RATHER THAN ON THE MESSAGE QUEUE
SEPAL8: MOVE SEN,.NNSBA(P2) ;[6037]PICK UP THE SENDER BLOCK ADDRESS
SKIPE .SNUSM(SEN) ;IS THE MESSAGE QUEUE EMPTY?
JRST SEPAL3 ;NO, MUST QUEUE THE MESSAGE
SKIPL .SNFRE(SEN) ;IS THE SENDER AVAILABLE TO SEND?
JRST SEPAL3 ;NO, MUST QUEUE THE MESSAGE
;THE NODE CAN SEND THE MESSAGE DIRECTLY. PLACE ITS NODE TABLE ENTRY
;ADDRESS IN TABLE NODSEN
MOVEM P2,NODSEN(S1) ;PLACE NODE TABLE ENTRY ADR IN NODSEN
AOS S1 ;NUMBER OF NODES TO SEND MSG DIRECTLY
JRST SEPAL5 ;GO CHECK THE NEXT NODE
;THE NODE'S MESSAGE QUEUE IS EITHER NOT EMPTY OR THE SENDER TO THE NODE
;IS CURRENTLY PROCESSING A MESSAGE. PLACE THE NODE'S NODE TABLE ENTRY
;ADDRESS IN TABLE NODMQ
SEPAL3: MOVEM P2,NODMQ(S2) ;PLACE NODE TABLE ENTRY ADR IN NODMQ
AOS S2 ;NUMBER OF NODES TO QUEUE MESSAGE TO
JRST SEPAL5 ;GO CHECK THE NEXT NODE
;DECNET MESSAGES CANNOT BE SENT TO THIS NODE. BUILD AN ACK MESSAGE TO BE SENT
;BACK TO THE OPR THAT SENT THE MESSAGE INDICATING THE REASON WHY THE MESSAGE
;CANNOT BE SENT TO THIS NODE. IF THIS IS THE FIRST NODE THAT A MESSAGE CANNOT
;BE SENT TO, THEN BUILD THE GALAXY MESSAGE HEADER AND DISPLAY BLOCK
SEPAL4: DMOVEM S1,G$ARG1 ;SAVE THE NODE NUMBERS
AOSN P1 ;THE FIRST NODE THAT CAN'T SEND MSG TO?
$CALL BLDHAD ;YES, BUILD MSG HDR AND DISPLAY BLOCK
;PLACE THE ERROR TEXT STRING IN THE MESSAGE TEXT BLOCK
MOVE S1,T2 ;PICK UP THE ERROR BIT NUMBER
MOVE S2,T1 ;PICK UP THE NODE NAME
$CALL MOVERR ;PLACE THE ERROR REASON IN THE TEXT BLK
DMOVE S1,G$ARG1 ;RESTORE THE NODE NUMBERS
;PREPARE TO CHECK THE NEXT NODE
SEPAL5: SOJE P3,SEPAL7 ;QUIT IF NO MORE NODES TO CHECK
SEPAL6: SOJE P4,S..NTI ;IF ZERO, THEN NODE TABLE INCONSISTENT
ADDI P2,.NNNSZ ;POINT TO THE NEXT NODE TABLE ENTRY
JRST SEPAL2 ;GO CHECK THE NEXT NODE
;FINISHED, CHECK IF THE MESSAGE CANNOT BE SENT TO ANY NODES
SEPAL7: SKIPGE P1 ;ANY NODES THE MSG CAN'T BE SENT TO?
$RETT ;NO, SO RETURN TO THE IPCF MSG HANDLER
;THE MESSAGE CANNOT BE SENT TO ONE OR MORE NODES. INFORM ORION OF THIS.
;(NOTE: SEPALL ASSUMES THAT AC M CONTAINS THE ADDRESS OF THE ORIGINAL
;IPCF MESSAGE. ALSO, SEPALL ASSUMES THAT THE ORIGINAL MESSAGE CAME FROM
;AN OPR
SETZ P1, ;MAKE THE TEXT BLOCK ASCIZ
IDPB P1,BYTPTR ;ADD NULL TO END OF THE TEXT BLOCK
;FINISH BUILDING THE ACK MESSAGE. FIND AND STORE THE LENGTHS OF THE TEXT
;BLOCK AND THE MESSAGE.
HRRZ P1,BYTPTR ;PICK UP END OF TEXT BLOCK ADDRESS
MOVE P2,BLKADR ;PICK UP TEXT BLOCK ADDRESS
SUBI P1,-1(P2) ;FIND LENGTH-1 OF TEXT BLOCK
STORE P1,ARG.HD(P2),AR.LEN ;STORE LENGTH OF BLOCK IN TEXT BLK HDR
MOVSS P1 ;TEXT BLOCK LENGTH,,0
ADDM P1,.MSTYP(MO) ;CALCULATE AND STORE MESSAGE LENGTH
DMOVEM S1,P3 ;SAVE THE NODE NUMBERS
$CALL ORNACK ;SEND THE MESSAGE TO ORION
DMOVE S1,P3 ;RESTORE THE NODE NUMBERS
ADD P3,P4 ;# OF NODES THAT CAN RECEIVE THE MSG
SKIPG P3 ;CAN AT LEASE ONE NODE RECEIVE MSG?
$RETF ;NO, INDICATE MSG NOT SENT TO ANY NODE
$RETT ;MESSAGE SENT TO AT LEAST ONE NODE
SUBTTL BLDHAD - BUILD THE HEADER AND DISPLAY BLOCKS FOR ACK MESSAGE
;BLDHAD is called when an IPCF message processing routine that is processing
;a message to be sent to more than one remote node detects that the message
;cannot be sent to a remote node. This routine obtains a page and then builds
;the GALAXY message header, display (.WTTYP) block, and header word of the
;text (.WTTXT) block of the ACK (.OMACK) message that will be sent back to
;the OPR that sent the original message indicating the reason the message
;could not be delivered to all the nodes.
;
;Call is: M/Address of the IPCF Message
;Returns: MO/Address of the ACK (.OMACK) message
; BYTPTR/Byte Pointer to text field of text block
; BLKADR/Address of text block
BLDHAD:
;OBTAIN THE PAGE FOR THE ACK MESSAGE AND BUILD THE MESSAGE HEADER
$CALL BLDHDR ;GET MSG PAGE AND BUILD MSG HEADER
MOVX S1,MF.FAT ;INDICATE TO ORION THIS IS AN ERROR
IORM S1,.MSFLG(MO) ;INDICATE THIS IN THE MESSAGE FLAG WORD
MOVX S1,WT.NFO ;INDICATE NO FORMATTING BY ORION
IORM S1,.OFLAG(MO) ;INDICATE THIS IN THE MESSAGE
AOS .OARGC(MO) ;THIS MESSAGE HAS TWO ARGUMENT BLOCKS
;BUILD THE DISPLAY BLOCK
MOVEI S1,.OHDRS(MO) ;POINT TO THE DISPLAY BLOCK
MOVEI S2,.WTTYP ;PICK UP DISPLAY BLOCK CODE
STORE S2,ARG.HD(S1),AR.TYP ;PLACE IN THE DISPLAY BLOCK HEADER
MOVEI S2,ARG.DA(S1) ;POINT TO THE DATA FIELD
HRLI S2,(POINT 7,) ;MAKE INTO A POINTER
MOVEM S2,BYTPTR ;REMEMBER THE POINTER
MOVEI S2,[ASCIZ/Cannot send to the following:/]
$TEXT(DEPBYT,<^T/0(S2)/^A>) ;PLACE TEXT IN DISPLAY BLOCK
;CALCULATE LENGTH OF MESSAGE UP TO THIS POINT AND LENGTH OF THE DISPLAY BLOCK.
;PLACE BOTH IN THE MESSAGE
HRRZ S2,BYTPTR ;PICK UP ADDRESS OF END OF DISPLAY BLK
AOS S2 ;BUMP BY ONE FOR LENGTH CALCULATION
ANDI S2,777 ;GET RID OF PAGE # TO FIND MSG LENGTH
STORE S2,.MSTYP(MO),MS.CNT ;PLACE MSG LENGTH IN MESSAGE HEADER
SUBI S2,.OHDRS ;SUBTRACT MESSAGE HEADER LENGTH
STORE S2,ARG.HD+.OHDRS(MO),AR.LEN ;SAVE DISPLAY BLOCK LENGTH
ADD S1,S2 ;POINT TO THE TEXT (.WTTXT) BLOCK
;BUILD THE HEADER TYPE OF THE TEXT BLOCK
MOVEI S2,.WTTXT ;PICK UP TEXT BLOCK CODE
STORE S2,ARG.HD(S1),AR.TYP ;PLACE IN THE TEXT BLOCK HEADER WORD
MOVEM S1,BLKADR ;SAVE ADDRESS OF TEXT BLOCK
AOS S1 ;POINT TO TEXT BLOCK DATA FIELD
HRLI S1,(POINT 7,) ;MAKE INTO A BYTE POINTER
MOVEM S1,BYTPTR ;SAVE THE POINTER
$RET ;RETURN TO THE CALLER
SUBTTL MOVERR - PLACE ERROR REASON IN TEXT BLOCK
;MOVERR is called as part of the error handling when a message from an
;OPR cannot be sent to a remote node. This routine places the reason why
;a message cannot be sent into the text (.WTTXT) block of the ACK (.OMACK)
;message that will be sent to the OPR.
;
;Call is: S1/Error bit position from node table entry status word (.NNSTA)
; S2/Node name
;Returns: The error text string has been placed into the text block
MOVERR: $SAVE <P1> ;SAVE THIS AC
MOVE P1,S2 ;SAVE THE NODE NAME
JFFO S1,.+1 ;PICK UP DISPLACEMENT INTO ERROR TABLE
CAIL S2,NNLOW ;CHECK FOR LEGAL ERROR
CAILE S2,NNHIGH ;CHECK FOR LEGAL ERROR
SETZ S2, ;UNKNOWN ERROR
$TEXT (DEPBYT,< Node ^N6L/P1/^T/@REASON(S2)/>) ;[6001]
$RET ;RETURN TO THE CALLER
SUBTTL QUEMSG - SEND OR QUEUE A MESSAGE
;QUEMSG is called to place a processed IPCF message on the message queues
;of those nodes the message is to be sent to. If any of the nodes are
;available to send a message, then the first message of those nodes'
;message queues are placed in those nodes' sender buffers and those nodes
;are interrupted informing them that a message is available to send.
;However, if a node the message is to
;be sent to has an empty message queue and it is available to send a
;message, then the message is not placed on that node's message queue but
;rather is placed in the node's message buffer. The node's sender is then
;interrupted to inform it that there is a message available to send.
;
;Call is: S1/Number of nodes to send the message directly to
; S2/Flags,,Number of nodes to queue the message on the msg queues
; where the flags are:
; MQ%IBH message is response to an in behalf of message
; MQ%REM message has an entry in the remote queue
; MQ%EXE message is from the EXEC
; M/ Address of the processed IPCF message
; NODSEN: Table containing the node table entry addresses of
; those nodes to send the message directly to
; NODMQ: Table containing the node table entry addresses of
; those nodes to queue the message to
;
;Returns: The message has been queued or sent
QUEMSG: $SAVE <P1,P2,P3,P4,T1> ;SAVE THESE AC
;FIRST CHECK IF A MESSAGE QUEUE ENTRY MUST BE BUILT
MOVE P4,S1 ;SAVE # OF NODES TO SEND DIRECTLY TO
HRRZ S1,S2 ;PICK UP NUMBER OF NODES TO QUEUE TO
HLLZS T1,S2 ;ISOLATE AND SAVE THE FLAG BITS
SKIPG P1,S1 ;ANY NODES TO QUEUE TO?
JRST QUEMS3 ;NO, GO CHECK FOR DIRECT SENDS
;BUILD THE MESSAGE QUEUE ENTRY
$CALL BLDMQE ;BUILD THE MESSAGE QUEUE ENTRY
MOVE P2,S1 ;SAVE THE ADDRESS OF THE MQE
MOVEI P3,NODMQ ;PICK UP ADR OF NODE ENTRY ADDRESSES
;PLACE THE MESSAGE QUEUE ENTRY ON THE CURRENT NODE'S MESSAGE QUEUE
QUEMS2: MOVE S1,P2 ;PICK UP ADDRESS OF THE LINK LIST WORD
MOVE SEN,0(P3) ;PICK UP NODE TABLE ENTRY ADDRESS
MOVE SEN,.NNSBA(SEN) ;PICK UP SENDER BLOCK ADR FOR THIS NODE
$CALL ADDMQE ;ADD MQE TO THIS NODE'S MESSAGE QUEUE
;CHECK IF THE SENDER IS AVAILABLE TO SEND A MESSAGE
SKIPGE .SNFRE(SEN) ;SENDER AVAILABLE TO SEND A MESSAGE?
$CALL SENMSG ;YES, GIVE IT A MESSAGE
;PLACE THE MESSAGE QUEUE ENTRY ON THE NEXT NODE'S MESSAGE QUEUE
AOS P2 ;ADDRESS OF THE NEXT LINK LIST WORD
AOS P3 ;ADDRESS OF THE NEXT NODE TABLE ENTRY
SOJG P1,QUEMS2 ;ADD THE MQE TO NEXT NODE'S MSG QUEUE
;CHECK IF THERE ARE ANY NODES THAT THE MESSAGE CAN BE DIRECTLY SENT TO
;WITHOUT HAVING TO PUT THE MESSAGE ON THE MESSAGE QUEUE
QUEMS3: SKIPG P4 ;ANY NODES SEND MESSAGE DIRECTLY TO?
JRST QUEMS6 ;NO, SO ARE FINISHED
;SENDER READY FOR A MESSAGE AND ITS MESSAGE QUEUE IS EMPTY. TRANSFER THE
;MESSAGE FROM THE IPCF BUFFER TO THE SENDER'S MESSAGE BUFFER AND SEND THE
;MESSAGE TO THE SENDER. IF THE MESSAGE IS NOT A RESPONSE TO AN IN BEHALF OF
;MESSAGE, THEN CREATE A TIMER LIST ENTRY.
MOVEI P1,NODSEN ;PICK UP ADDRESS OF NODE TABLE ENTRIES
QUEMS4: MOVE SEN,0(P1) ;PICK UP NODE TABLE ENTRY ADDRESS
JUMPL T1,QUEMS5 ;RESPONSE TO AN IBH MESSAGE?
MOVE S1,SEN ;NO, PICK UP NODE TABLE ENTRY ADDRESS
MOVE S2,M ;PICK UP THE MESSAGE ADDRESS
$CALL SETTIM ;SET THE TIMER FOR THIS MESSAGE
QUEMS5: MOVE SEN,.NNSBA(SEN) ;PICK UP SENDER BLOCK ADDRESS
MOVE S1,M ;ADDRESS OF WHERE MSG IS LOCATED NOW
MOVE S2,.SNMSG(SEN) ;ADDRESS OF WHERE THE MSG IS TO GO
$CALL XFRMSG ;TRANSFER THE MESSAGE TO MSG BUFFER
$CALL SENMS5 ;PASS THE MESSAGE TO THE SENDER
AOS P1 ;POINT TO THE NEXT NODE TABLE ENTRY ADR
SOJG P4,QUEMS4 ;SEND THE MESSAGE TO THE NEXT NODE
QUEMS6: $RET ;FINISHED, RETURN TO THE CALLER
SUBTTL ORNACK - SEND AN ERROR ACK TO ORION
;ORNACK is called as part of cleaning up the message queue when a node has
;crashed or a listener or sender has crashed.
;
;Returns true: The message was sent successfully
;Returns false: The message was not sent
;SEND THE MESSAGE TO ORION
;(NOTE: THE .MSCOD WORD OF THE MESSAGE THAT IS SENT BY AN OPR CONTAINS
;THE PID OF THAT OPR.)
ORNACK: MOVE S1,MO ;PICK UP THE MESSAGE ADDRESS
MOVEI S2,PAGSIZ ;PICK UP THE MESSAGE SIZE
$CALL SNDORN ;SENDS THE ACK MESSAGE TO ORION
$RETIT ;SUCCESS, C%SEND RELEASED THE MSG PAGE
$CALL RELPAG ;ERROR, RELEASE MSG PAGE
$RETF ;RETURN FALSE TO CALLER
SUBTTL BLDACK Build an ACK message
;BLDACK is called to build an ACK message (.OMACK) to be sent
;to ORION when an error has been encountered while processing
;an IPCF message from an OPR that was to be sent to a single remote node
;or as part of cleaning up after communication to a remote node has
;been lost.
;
;Call is: M/ Address of original message
;Returns: ACK message has been built
; MO/Address of the ACK message
;OBTAIN THE PAGE TO BUILD THE ACK MESSAGE AND BUILD THE MESSAGE HEADER
;**;[6052]At BLDACK:+0L replace routine BLDACK with a new BLDACK JCR 3/1/90
BLDACK: $CALL BLDHDR ;[6052]Get msg page and build header
MOVE S1,G$ERR ;[6052]Pick up the error number
MOVE S2,STSTBL(S1) ;[6052]Pick up the flag word
MOVEM S2,.MSFLG(MO) ;[6052]Place in the message header
MOVEI S2,ARG.DA+.OHDRS(MO) ;[6052]Get place to store the text
HRLI S2,(POINT 7,0) ;[6052]Make a pointer
MOVEM S2,BYTPTR ;[6052]Save the pointer
$TEXT (BLDA.1,<^I/@TXTTBL(S1)/^0>) ;[6052]Place text in the message
MOVE S1,BYTPTR ;[6052]Pick up the updated byte pointer
HRRZS S1 ;[6052]Get the ending address
AOS S1 ;[6052]Bump it by 1
ANDI S1,777 ;[6052]Get the message length
STORE S1,.MSTYP(MO),MS.CNT ;[6052]Save count in the message
SUBI S1,.OHDRS ;[6052]Get the size of the block
STORE S1,ARG.HD+.OHDRS(MO),AR.LEN ;[6052]Save the argument length
MOVX S1,.WTTYP ;[6052]Get the text code
STORE S1,ARG.HD+.OHDRS(MO),AR.TYP ;[6052]Save as the argument type
SKIPL REMORG ;[6052]Request originate remotely?
$RET ;[6052]No, so return now
LOAD S1,.MSTYP(MO),MS.CNT ;[6052]Pick up the message size
ADD S1,MO ;[6052]Point to the message end
MOVE S2,[.NDESZ,,.WTNHD] ;[6052]Pick up the block header word
MOVEM S2,ARG.HD(S1) ;[6052]Place in the message
MOVE S2,NODNAM ;[6052]Pick up local node name
MOVEM S2,ARG.DA(S1) ;[6052]Place in the node block
HRLZI S1,.NDESZ ;[6052]Pick up cluster node block size
ADDM S1,.MSTYP(MO) ;[6052]Update message length
MOVX S1,MF.NEB ;[6052]Pick up remote origin bit
IORM S1,.MSFLG(MO) ;[6052]Set in the message
AOS .OARGC(MO) ;[6052]Update the argument count
$RET ;[6052]Return to the caller
BLDA.1: IDPB S1,BYTPTR ;[6052]Save the character
$RETT ;[6052]Return to the caller
SUBTTL TXTMOV - MOVE TEXT FROM ONE LOCATION TO ANOTHER
;TXTMOV moves ASCIZ text from one location to another.
;(Note: This routine does not copy to the new location the null byte.)
;Call is: S1/Address of the destination
; S2/Address of the source
;Returns: S1/Updated byte pointer
TXTMOV: HRLI S2,(POINT 7,0) ;MAKE A BYTE POINTER
HRLI S1,(POINT 7,0) ;BYTE POINTER FOR DESTINATION
MOVEM S2,BYTPTR ;SAVE THE SOURCE POINTER
TXTM.1: ILDB S2,BYTPTR ;GET FIRST BYTE OF DATA
JUMPE S2,TXTM.2 ;NULL BYTE ..EXIT
IDPB S2,S1 ;SAVE THE BYTE
JRST TXTM.1 ;GET NEXT BYTE
TXTM.2: IDPB S2,S1 ;SAVE THE NULL FOR ASCIZ
$RET ;RETURN
SUBTTL BLDHDR - BUILD THE MESSAGE HEADER FOR ACK MESSAGE
;BLDHDR obtains a page and builds the message header for an ACK
;message to be sent to the OPR whose request has resulted in an error.
;
;Call is: M/Address of the IPCF message
;Returns: MO/Address of the ACK message
BLDHDR: $CALL GETPAG ;GET THE PAGE FOR THE MESSAGE
MOVEI S1,.OMACK ;PICK UP ACK MESSAGE CODE
STORE S1,.MSTYP(MO),MS.TYP ;STORE IN MESSAGE HEADER
MOVE S1,.MSCOD(M) ;PICK UP MESSAGE CODE
MOVEM S1,.MSCOD(MO) ;PLACE IN THE MESSAGE
MOVX S1,WT.SJI ;SUPPRESS JOB INFORMATON ON DISPLAY
MOVEM S1,.OFLAG(MO) ;PLACE IN MESSAGE HEADER
AOS .OARGC(MO) ;BUMP ARGUMENT COUNT TO ONE
$RET ;RETURN TO THE CALLER
SUBTTL EREXEC - SEND AN ERROR MESSAGE TO THE EXEC
;[6013]EREXEC builds a text message to be sent to the EXEC after NEBULA detects
;[6013]an error in processing the original message or if communication to the
;[6013]node the original message was to be sent to has been lost.
;[6013]
;[6013]Call is: M/Address of the original IPCF message
;[6013] G$ERR/Error table offset
;[6013] G$SND/The EXEC's PID
;[6013]Returns: The error message has been sent to the EXEC
;[6013]BUILD THE COMMON HEADER PARTS AND DETERMINE THE EXEC MESSAGE TYPE
EREXEC: $SAVE <P1> ;[6013]SAVE THIS AC
MOVEI S1,.OHDRS ;[6013]PICK UP THE HEADER SIZE
STORE S1,G$MSG+.MSTYP,MS.CNT ;[6013]]PLACE IN THE MESSAGE HEADER
SETZM G$MSG+.OARGC ;[6013]NO ARGUMENTS YET
MOVE S1,.MSCOD(M) ;[6014]PICK UP THE EXEC'S UNIQUE CODE
MOVEM S1,G$MSG+.MSCOD ;[6014]STORE IN THE MESSAGE
LOAD S1,.MSTYP(M),MS.TYP ;[6013]PICK UP THE EXEC MESSAGE CODE
CAIE S1,.QOLIS ;[6013]A LIST MESSAGE?
JRST EREX.1 ;[6013]NO, THEN MUST BE A KILL MESSAGE
;[6013]BUILD A DISPLAY BLOCK AND MESSAGE TYPE .OMACS
SETZM G$MSG+.MSFLG ;[6014]ZERO OUT THE FLAG WORD
MOVX S1,WT.SJI+WT.NFO ;[6014]SUPPRESS JOB INFO
MOVEM S1,G$MSG+.OFLAG ;[6014]PLACE IN THE MESSAGE
MOVEI S1,G$MSG+.OHDRS+ARG.DA ;[6013]WHERE TO PLACE THE HEADER
HRLI S1,ERRHDR ;[6013]ADDRESS OF THE SOURCE TEXT
MOVEI S2,G$MSG+.OHDRS+ERRLEN-1;[6013]ADDRESS OF END OF THE TEXT
BLT S1,0(S2) ;[6013]COPY THE TEXT INTO THE MESSAGE
MOVE S1,[ERRLEN+1,,.ORDSP] ;[6013]PICK UP THE BLOCK HEADER WORD
MOVEM S1,G$MSG+.OHDRS ;[6013]PLACE IN THE MESSAGE
MOVEI S1,.OMACS ;[6013]PICK UP THE MESSAGE TYPE
STORE S1,G$MSG+.MSTYP,MS.TYP ;[6013]PLACE IN THE MESSAGE HEADER
MOVSI S1,ERRLEN+1 ;[6013]PICK UP THE LENGTH OF DISPLAY BLK
ADDM S1,G$MSG+.MSTYP ;[6013]ADD TO THE MESSAGE LENGTH
AOS G$MSG+.OARGC ;[6013]INCREMENT THE ARGUMENT COUNT
MOVEI P1,G$MSG+.OHDRS+ERRLEN+1;[6013]ADDRESS OF THE TEXT BLOCK
JRST EREX.2 ;[6013]JOIN THE COMMON CODE
;[6013]INDICATE A TEXT MESSAGE
EREX.1: LOAD S1,.MSFLG(M),MF.ACK ;[6013]PICK UP THE ACK CODE BIT
SKIPN S1 ;[6013]WAS AN ACK REQUESTED?
$RETT ;[6013]NO, RETURN NOW
MOVEI S1,.OMTXT ;[6013]PICK UP THE TEXT MESSAGE CODE
STORE S1,G$MSG+.MSTYP,MS.TYP ;[6013]STORE IN THE HEADER
MOVEI P1,G$MSG+.OHDRS ;[6013]POINT TO THE TEXT BLOCK
MOVE S1,G$ERR ;[6014]PICK UP THE ERROR OFFSET
MOVE S1,STSTBL(S1) ;[6014]PICK UP THE FLAG WORD
MOVEM S1,G$MSG+.MSFLG ;[6014]PLACE IN THE MESSAGE
;[6013]BUILD THE TEXT BLOCK
EREX.2: SETZM BYTPTR ;[6013]INDICATE NO TEXT YET
SETZM G$MSG+MSGLN-1 ;[6013]INDICATE BUFFER NOT EXHAUSTED
MOVEM P1,STABLK ;[6013]SAVE THE BLOCK ADDRESS
MOVE S1,G$ERR ;[6013]PICK UP THE ERROR OFFSET
$TEXT (DEPCHR,<^I/@TXTTBL(S1)/^A>) ;[6013]PLACE TEXT IN THE TEXT BLOCK
SETZ S1, ;[6013]PICK UP A NULL
$CALL DEPCHR ;[6013]AND PLACE IN THE MESSAGE
;[6013]FINISH BUILDING THE HEADER
AOS G$MSG+.OARGC ;[6013]INCREMENT THE ARGUMENT COUNT
SETZM G$MSG+.OFLAG ;[6013]ZERO THE OFLAG WORD
HRRZ S1,BYTPTR ;[6013]PICK UP THE MESSAGE END ADDRESS
SUBI S1,-1(P1) ;[6013]FIND THE TEXT BLOCK LENGTH
HRLZS S1 ;[6013]PLACE LENGTH IN EXPECTED PLACE
ADDM S1,G$MSG+.MSTYP ;[6013]ADD TO THE MESSAGE LENGTH
HRRI S1,.CMTXT ;[6013]PICK UP THE BLOCK TYPE
MOVEM S1,0(P1) ;[6013]PLACE IN THE TEXT BLOCK HEADER
;[6013]BUILD THE SAB AND SEND THE MESSAGE
LOAD S1,G$MSG+.MSTYP,MS.CNT ;[6013]PICK UP THE MESSAGE LENGTH
MOVEM S1,SAB+SAB.LN ;[6013]PLACE IN THE SAB
MOVEI S1,G$MSG ;[6013]PICK UP THE MESSAGE ADDRESS
MOVEM S1,SAB+SAB.MS ;[6013]PLACE IN THE SAB
MOVE S1,G$SND ;[6013]PICK UP THE EXEC'S PID
MOVEM S1,SAB+SAB.PD ;[6013]PLACE IN THE SAB
SETZM SAB+SAB.SI ;[6032]ZERO OUT SPECIAL INDEX
PJRST N$SEND ;[6013]SEND THE MESSAGE AND RETURN
ERRHDR: ASCIZ/NEBULA error message/
ERRLEN==.-ERRHDR
SUBTTL DEPCHR - INSERT AN ASCII CHARACTER IN AN EXEC ERROR MESSAGE
;[6013]DEPCHR is called to deposit an ASCII character in a error message being
;[6013]built to send to the EXEC sender of the original message.
;[6013]
;[6013]Call is: S1/Character to be deposited right justified
;[6013]Returns: The character has been deposited in the message
DEPCHR: SKIPE BYTPTR ;[6013]STRING STARTED YET?
JRST DEPC.1 ;[6013]YES, DEPOSIT THE CHARACTER
MOVE S2,STABLK ;[6013]]PICK UP .CMTXT BLOCK ADDRESS
AOS S2 ;[6013]ADDRESS OF THE DATA FIELD
HRLI S2,(POINT 7,) ;[6013]MAKE INTO A POINTER
MOVEM S2,BYTPTR ;[6013]SAVE
DEPC.1: SKIPN G$MSG+MSGLN-1 ;[6013]REACHED THE END OF THE BUFFER?
IDPB S1,BYTPTR ;[6013]NO, INCLUDE THIS CHARACTER
$RETT ;[6013]RETURN FOR THE NEXT ONE
SUBTTL SETTIM - SETUP A TIMER FOR DECNET MESSAGE
;SETTIM creates a timer list entry and sets up a timer for a message that
;is being sent to a remote node and which is not a response to an in behalf of
;request.
;
;Call is: S1/ Node table entry address of the node that the message is
; being sent to
; S2/Address of the message being sent to the remote node
;Returns: Timer list entry and timer have been created
;Crashes: Node table inconsistency detected
SETTIM: $SAVE <P1,P2> ;SAVE THESE AC
;FIRST CREATE A TIMER LIST ENTRY
DMOVEM S1,P1 ;SAVE NODE TABLE ENTRY AND MSG ADR
MOVE S1,.NTIML(P1) ;PICK UP TIMER LIST INDEX
$CALL L%LAST ;POSITION TO END OF THE TIMER LIST
MOVE S1,.NTIML(P1) ;PICK UP TIMER LIST INDEX AGAIN
MOVEI S2,.TMSIZ ;PICK UP SIZE OF TIMER LIST ENTRY
$CALL L%CENT ;CREATE A TIMER LIST ENTRY
JUMPF S..NTI ;NO TIMER LIST, NODE TABLE INCONSISTENT
MOVE P2,.MSCOD(P2) ;PICK UP THE ACK CODE
MOVEM P2,.TMACK(S2) ;SAVE THE MESSAGE ACK CODE
AOS S1,TIMCTR ;MAKE UDT UNIQUE
ADD S1,MSGTIM ;ADD TIME OF THIS IPCF SCHEDULING PASS
MOVEM S1,.TMUDT(S2) ;SAVE THE UDT IN THE TIMER LIST ENTRY
;START THE TIMER FOR THIS MESSAGE
MOVEI S2,TIMBLK ;PICK UP ADDRESS OF TIME EVENT ENTRY
MOVEM S1,.TITIM(S2) ;PLACE WAKEUP TIME IN TIME EVENT ENTRY
MOVEI S1,.TIMDT ;WAKEUP AT A SPECIFIC TIME
MOVEM S1,.TIFNC(S2) ;SAVE THE FUNCTION CODE IN T.E. ENTRY
MOVEI S1,PROTIM ;PICK UP WAKEUP PROCESSING ROUTINE ADR
MOVEM S1,.TIMPC(S2) ;SAVE ROUTINE ADDRESS IN T.E. ENTRY
MOVE S1,.NNNAM(P1) ;PICK UP NODE NAME MESSAGE IS GOING TO
MOVEM S1,.TIDAT(S2) ;SAVE NODE NAME IN TIME EVENT ENTRY
MOVEI S1,<.TIDAT+1> ;PICK UP SIZE OF ARGUMENT BLOCK
$CALL I%TIMR ;CREATE THE TIMER EVENT ENTRY
$RET ;RETURN TO THE CALLER
SUBTTL CLRTIM - CLEAR A TIMER UPON MESSAGE RESPONSE BEING RECEIVED
;CLRTIM is called when a response from a message to a remote node is
;received. This routine clears the timer that was set when the message
;was sent to the remote node.
;
;Call is: S1/Node table entry address of node message was
; S2/The ACK code (.MSCOD) of the message sent to the remote node
;Returns: Timer for the message has been cleared
;Crashes: Node table inconsistency detected
CLRTIM: $SAVE <P1> ;SAVE THIS AC
MOVE P1,S2 ;SAVE THE ACK CODE
;PICK UP THE TIMER LIST ENTRY
MOVE S1,.NTIML(S1) ;PICK UP THE TIMER LIST INDEX
$CALL L%FIRST ;PICK UP THE FIRST T.L. ENTRY
$RETIF ;[6011]RETURN IF NO T.L. ENTRY
CLRTI2: CAMN P1,.TMACK(S2) ;IS THIS THE TIMER LIST ENTRY?
JRST CLRTI3 ;YES, CLEAR THE TIMER
$CALL L%NEXT ;NO, PICK UP THE NEXT ENTRY
$RETIF ;[6011]RETURN IF NO T.L. ENTRY
JRST CLRTI2 ;CHECK THE NEXT ENTRY
;THE TIMER LIST ENTRY HAS BEEN FOUND. CLEAR THE TIMER FOR THIS ENTRY.
CLRTI3: MOVE P1,.TMUDT(S2) ;REMEMBER THE TIME TO SET OFF TIMER
$CALL L%DENT ;DELETE THE TIMER LIST ENTRY
MOVE S1,P1 ;PICK UP THE TIME TO SET OFF TIMER
MOVEI S2,PROTIM ;[6016]PICK UP ROUTINE ADDRESS
$CALL REMTIM ;CLEAR THE TIMER
$RET ;RETURN TO THE CALLER
SUBTTL REMTIM - CLEAR A TIMER
;REMTIM is called to clear a timer from a message sent to a node when
;the response to that message has been received from that node or as
;part of cleanup when communication to a node has been lost.
;REMTIM is also called to clear a timer that was set as a result of an INFO%
;JSYS error.
;The function to clear the timer (.TIMDD) will actually delete all timer
;event queue entries that have the same time as that specified in the clear
;timer request. If a routine address is specified, then only those timer
;event queue entries corresponding to that routine will be deleted.
;Call is: S1/ The time the timer is set to go off
; S2/ Routine address that is called when the timer goes off
;Returns: The timer has been cleared
REMTIM: $SAVE <P1> ;[6016]SAVE THIS AC
MOVE P1,S2 ;[6016]SAVE THE ROUTINE ADDRESS
MOVEI S2,TIMBLK ;PICK UP ADDRESS OF TIMER EVENT BLOCK
MOVEM S1,.TITIM(S2) ;PLACE TIME IN TIMER EVENT BLOCK
MOVEI S1,.TIMDD ;PICK UP FUNCTION CODE TO CLEAR TIMER
STORE S1,.TIFNC(S2),RHMASK ;PLACE FUNCTION CODE IN TIMER EVENT BLK
MOVEM P1,.TIMPC(S2) ;[6016]PLACE ROUTINE ADR IN TIMER BLOCK
MOVEI S1,.TIMPC+1(S2) ;[6016]ASSUME ROUTINE ADDRESS SPECIFIED
SKIPN P1 ;[6016]WAS A ROUTINE ADDRESS SPECIFIED?
MOVEI S1,.TITIM+1 ;[6016]NO, SO PICK UP CORRECT BLOCK SIZE
$CALL I%TIMR ;CLEAR THE TIMER
$RET ;RETURN TO THE CALLER
SUBTTL PROTIM - TIMER HAS GONE OFF, COMMUNICATION LOST TO REMOTE NODE
;PROTIM is called from I%SLP when a timer has gone off. This indicates that
;a message was sent to a remote node and no response to that message was
;received in TIMOUT amount of time. The assumption is made that communication
;to the remote node has been lost. The node data base to that node is cleared.
;If it is determined that the remote node can receive messages (i.e., it has
;a monitor of release 7 or later and has DECnet enabled), then the listener
;and sender to that node are restarted.
;
;Call is: S1/Length of timer event block from timer event queue
; S2/Address of timer event block from timer event queue
;Returns: Remote node's data base has been reset and restarted
; if remote node is still capable of receiving DECnet messages
;Crashes: The node table is inconsistent
PROTIM: $SAVE <P1> ;SAVE THIS AC
;DETERMINE THE NODE THAT COMMUNICATION HAS BEEN LOST TO
MOVE P1,.TIDAT(S2) ;PICK UP THE NODE NAME
MOVE S1,P1 ;PICK UP NODE NAME WHERE EXPECTED
$CALL SNAMNT ;FIND NODE TABLE ENTRY
JUMPF S..NTI ;NODE TABLE INCONSISTENCY
;RESET THE REMOTE NODE'S DATA BASE AND RESTART THE LISTENER AND SENDER
;TO THAT NODE IF IT IS STILL CAPABLE OF RECEIVING DECNET MESSAGES FROM
;THIS NODE.
MOVE S1,S2 ;PICK UP NODE TABLE ENTRY ADDRESS
$CALL KASNOD ;RESET NODE TABLE DATA BASE
JUMPF PROTI2 ;CAN'T SEND MESSAGES TO THIS NODE
$WTOJ (<Timeout to node ^N/P1/ detected>,<Forks have been restarted>,,<$WTFLG(WT.SJI)>)
$RET ;RETURN TO THE CALLER
PROTI2: $WTOJ (<Timeout to node ^N/P1/ detected>,<Forks cannot be restarted>,,<$WTFLG(WT.SJI)>)
$RET ;RETURN TO THE CALLER
SUBTTL SNDMSG - SEND MESSAGES TO AVAILABLE SENDERS
;SNDMSG is called during NEBULA's scheduling pass if a sender has indicated
;that it is available to send a message. This routine checks for
;senders that are available to send DECnet messages to their listeners.
;It first checks if the node the sender is sending to is able to receive
;messages. If it is, then a check is made to determine if the sender is
;available to send a message. If it is, then a check is made to determine
;if the sender's message queue has a message. If there is a message, then
;the message is moved from the message queue to the sender's message buffer
;and the sender is notified that there is a message available for it to send.
;
;Call is: No arguments
;Returns: After all the senders have been notified of any available
; messages
SNDMSG: $SAVE <P1,P2> ;SAVE THESE AC
SETZM SREADY ;RESET MESSAGE AVAILABLE FLAG
SETOM NBSCHD ;FORCE A SCHEDULING PASS
;SET UP THE NODE TABLE SEARCH FOR ELIGIBLE SENDERS TO SEND A MESSAGE
MOVEI P1,NODTBL ;PICK UP THE NODE TABLE ADDRESS
MOVEI P2,MAXNOD ;PICK UP MAX # OF NODE TABLE ENTRIES
;CHECK IF A NODE IS AVAILABLE TO RECEIVE MESSAGES, THEN IF A SENDER IS
;AVAILABLE TO SEND A MESSAGE AND THEN IF THERE ARE ANY MESSAGES TO SEND
SNDMS2: SKIPL .NNSTA(P1) ;O.K. TO SEND MESSAGES TO THIS NODE?
JRST SNDMS3 ;NO, CHECK THE NEXT NODE
MOVE SEN,.NNSBA(P1) ;PICK UP THE SENDER BLOCK ADDRESS
SKIPL .SNFRE(SEN) ;THIS SENDER AVAILABLE TO SEND A MSG?
JRST SNDMS3 ;NO, CHECK THE NEXT NODE
SKIPE .SNHWD(SEN) ;ANY MESSAGES FOR THIS SENDER?
$CALL SENMSG ;YES, NOTIFY THE SENDER
;CHECK FOR ANY MORE NODES TO SEND A MESSAGE TO
SNDMS3: ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE TABLE ENTRY
SOJG P2,SNDMS2 ;GO CHECK THE NEXT NODE
$RET ;RETURN TO THE CALLER
SUBTTL SENMSG - NOTIFY A SENDER OF A MESSAGE AVAILABLE
;SENMSG is called when a sender is available to send a message and there
;is a message in its message queue. The message is transferred from the
;message queue to the sender's message buffer and the sender is interrupted.
;
;Call is: SEN/Address of the sender block
;Returns true: Message is placed in the sender message buffer and the sender
; is interrupted
;Returns false: Message queue is empty
;Crashes: If the sender cannot be interrupted
SENMSG: $SAVE <P1,P2> ;SAVE THESE AC
;TRANSFER THE MESSAGE FROM THE SENDER'S MESSAGE QUEUE TO THE SENDER'S
;MESSAGE BUFFER
SKIPN P1,.SNHWD(SEN) ;PICK UP MESSAGE QUEUE HEADER WORD
JRST SENMS6 ;THE MSG QUEUE IS EMPTY, RETURN FALSE
LOAD P2,.MQBLK(P1),MQ.OFF ;PICK UP THE OFFSET TO INVARIANT BLOCK
ADD P2,P1 ;POINT TO THE INVARIANT BLOCK
LOAD S1,.MQNOM(P2),MQ.ADR ;PICK UP ADDRESS OF THE MESSAGE
MOVE S2,.SNMSG(SEN) ;PICK UP ADDRESS OF THE MESSAGE BUFFER
$CALL XFRMSG ;MOVE THE MESSAGE TO THE MESSAGE BUFFER
;DELETE THE MESSAGE ENTRY FROM THE MESSAGE QUEUE
LOAD S1,.MQBLK(P1),MQ.NEA ;PICK UP THE ADDRESS OF THE NEXT MQE
JUMPG S1,SENMS2 ;IS THIS THE LAST MESSAGE IN THE QUEUE?
SETZM .SNHWD(SEN) ;YES, ZERO THE LINK LIST HEADER WORD
SETZM .SNTWD(SEN) ;AND ZERO THE LINK LIST TRAILER WORD
SKIPA ;DON'T UPDATE THE LINK LIST HEADER WORD
SENMS2: MOVEM S1,.SNHWD(SEN) ;PLACE NEW FIRST ENTRY IN L.L. HDR WORD
SOS .SNUSM(SEN) ;UPDATE NUMBER OF MESSAGES IN MSG QUEUE
;IF THE MESSAGE IS NOT A RESPONSE TO AN IN BEHALF OF MESSAGE, THEN CREATE
;A TIMER LIST ENTRY AND A TIMER FOR THE MESSAGE.
SKIPGE S2,.MQNOM(P2) ;[6017]RESPONSE TO AN IN BEHALF OF MSG?
JRST SENMS3 ;YES, DON'T SET UP A TIMER
MOVE S1,.SNNTA(SEN) ;PICK UP THE NODE TABLE ENTRY ADDRESS
HRRZS S2 ;ISOLATE THE MESSAGE ADDRESS
$CALL SETTIM ;CREATE TIMER ENTRY AND START TIMER
;IF THE MESSAGE IS NOT TO BE SENT TO ANY ADDITIONAL NODES, THEN RETURN ITS
;MEMORY TO THE MEMORY MANAGER
SENMS3: LOAD S1,.MQNOM(P2),MQ.NUM ;NUMBER OF NODES LEFT TO THE MESSAGE TO
SOJG S1,SENMS4 ;ANY NODES LEFT TO SEND THE MESSAGE TO?
MOVE S1,P2 ;NO, PICK UP ADDRESS OF INVARIANT BLOCK
$CALL RELMQE ;AND RETURN THE MEQ TO THE MEMORY MGER
SKIPA ;DON'T UPDATE THE NODE COUNT
SENMS4: STORE S1,.MQNOM(P2),MQ.NUM ;UPDATE THE NUMBER OF NODES TO SEND MSG
;INTERRUPT THE SENDER THAT A MESSAGE IS AVAILABLE IN ITS MESSAGE BUFFER
;
;SENMS5 IS AN ENTRY POINT WHEN PROCESSING A MESSAGE THAT CAN BE SENT DIRECTLY
;TO THE SENDER WITHOUT THE NEED TO PLACE THE MESSAGE ON THE SENDER'S MESSAGE
;QUEUE
SENMS5: SETZM .SNFRE(SEN) ;INDICATE THAT THIS SENDER IS NOW BUSY
MOVE S1,.SNHND(SEN) ;PICK UP THE SENDER'S HANDLE
MOVX S2,<1B0> ;PICK UP CHANNEL TO INTERRUPT SENDER ON
IIC% ;INTERRUPT SENDER THAT MSG IS AVAILABLE
ERJMP S..UII ;CRASH ON AN ERROR
$RETT ;RETURN TRUE TO CALLER
SENMS6: $RETF ;MESSAGE QUEUE IS EMPTY
Repeat 0,<
SUBTTL CONSTS - CONNECTION FAILURE STATUS
;CONSTS is called during the NEBULA scheduling pass if a sender
;has interrupted the top fork to indicate that it has been unable
;to complete a DECnet connection to its remote node. This routine
;will determine which sender has indicated that it has been
;unsuccessful in completing a DECnet. It will then check if its
;failure to establish a DECnet connection should be reported to the
;operators. If its failure should be reported, then it sends a WTO
;message to ORION, otherwise, it does nothing.
;
;Call is: No arguments
;Returns true: All the senders have been checked and any WTO messages
; sent.
CONSTS: $SAVE <P1,P2> ;SAVE THESE AC
SETZM FCFFLG ;RESET FOR THE INTERRUPT HANDLER
SETOM NBSCHD ;FORCE ANOTHER SCHEDULING PASS
;SETUP THE SEARCH FOR THE SENDER THAT CANNOT OBTAIN A DECNET LINK
MOVEI P1,NODTBL ;PICK UP THE ADDRESS OF THE NODE TABLE
MOVEI P2,MAXNOD ;PICK UP MAXIMUM NUMBER OF REMOTE NODES
MOVE S2,RENNUM ;PICK UP NUMBER OF KNOWN REMOTE NODES
;CHECK THE SENDER OF EACH NODE. IF DECNET CONNECTION FAILURES TO THAT
;NODE ARE TO BE IGNORED, THEN GO CHECK THE NEXT NODE. OTHERWISE, CHECK
;IF THE SENDER OF THAT NODE HAS INDICATED THAT IT CANNOT OBTAIN A
;DECNET CONNECTION. IF IT HAS, THEN INFORM THE OPERATORS.
CONST2: SKIPN .NNNAM(P1) ;IS THIS NODE TABLE ENTRY IN USE?
JRST CONST4 ;NO, GO CHECK THE NEXT ENTRY
MOVE S1,.NNSTA(P1) ;PICK UP THE NODE STATUS WORD
TXNE S1,NN%DCO ;CONNECTION FAILURES DISABLED?
JRST CONST3 ;YES, CHECK THE NEXT NODE
SKIPN SEN,.NNSBA(P1) ;PICK UP THE SENDER BLOCK ADDRESS
JRST CONST3 ;NO SENDER FOR THIS NODE
SKIPL .SNCOL(SEN) ;SENDER CAN'T OBTAIN A CONNECTION?
JRST CONST3 ;NO, CHECK THE NEXT NODE
SETZM .SNCOL(SEN) ;YES, CLEAR THE CONNECT FAILURE FLAG
$WTOJ(<NEBULA can't make a connection>,<Sender to node ^N/.NNNAM(P1)/ has not been able to obtain a DECnet connection>,,<$WTFLG(WT.SJI)>)
CONST3: SOJE S2,.RETT ;IF NO MORE NODES TO CHECK, THEN DONE
CONST4: SOJE P2,S..NTI ;NODE TABLE INCONSISTENCY
ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE ENTRY
JRST CONST2 ;GO CHECK THE NEXT NODE'S SENDER
>; End of Repeat 0
SUBTTL GETMSG -PICK UP A MESSAGE FROM A LISTENER
;GETMSG is called by the scheduler as a result of a listener interrupting
;the top fork to indicate that it has a message from a remote node available
;to be picked up and acted upon by the top fork.
;
;Call is: No arguments
;Returns: The message has been picked up from the listener and acted on
GETMSG: $SAVE <P1,P2> ;SAVE THESE AC
SETOM NBSCHD ;FORCE ANOTHER SCHEDULING PASS
SETZM LREADY ;ZERO OUT THE MESSAGE AVAILABLE FLAG
;SET UP THE NODE TABLE TO SEARCH FOR LISTENERS WHICH HAVE A MESSAGE
MOVEI P1,NODTBL ;PICK UP THE NODE TABLE ADDRESS
MOVEI P2,MAXNOD ;PICK UP MAX # OF NODE TABLE ENTRIES
;CHECK IF THE REMOTE NODE IS CAPABLE OF SENDING MESSAGES. IF IT IS, THEN
;CHECK IF THE LISTENER ASSOCIATED WITH THAT NODE HAS A MESSAGE TO BE
;PICKED UP.
GETMS2: SKIPL .NNSTA(P1) ;O.K. TO RECEIVE MSG FROM THIS NODE?
JRST GETMS3 ;NO, CHECK THE NEXT NODE
MOVE LIS,.NNLBA(P1) ;PICK UP THE LISTENER BLOCK ADDRESS
SKIPE .LSAVA(LIS) ;DOES THIS LISTENER HAVE A MESSAGE?
JRST GETMS3 ;NO, CHECK THE NEXT NODE
;THE LISTENER HAS A MESSAGE TO BE PICKED UP. PICK UP THE MESSAGE AND PROCESS IT
$CALL PROMSG ;PICK UP AND PROCESS THE MESSAGE
;TELL THE LISTENER WE HAVE PICKED UP THE MESSAGE AND ARE READY FOR ANOTHER
MOVE S1,.LSHND(LIS) ;GET THE LISTENER'S FORK
MOVX S2,<1B2> ;WANT CHANNEL 0
SETOM .LSAVA(LIS) ;MESSAGE HAS BEEN PICKED UP
IIC% ;TELL LISTENER WE'RE READY
ERJMP S..UII ;CRASH IF CAN'T INTERRUPT LISTENER
;CHECK FOR ANY MORE NODES THAT MAY HAVE A MESSAGE AVAILABLE
GETMS3: ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE TABLE ENTRY
SOJG P2,GETMS2 ;GO CHECK THE NEXT NODE
$RET ;FINISHED WITH THE LISTENERS
SUBTTL PROMSG - PROCESS DECNET LISTENER MESSAGES DISPATCHER
;PROMSG is called from GETMSG to process the message a listener has
;available. PROMSG dispatches to the appropriate message handler to
;process the message.
;
;Call is: LIS/Listener block address
;Returns: The message has been processed.
PROMSG: $SAVE <P1> ;SAVE THIS AC
;DETERMINE WHICH NODE SENT THE MESSAGE AND SAVE THE NAME. SETUP TO
;SEARCH THE MESSAGE DISPATCH TABLE.
;**;[6045]At PROMSG:+5L add 1 line JCR 1/15/90
SETZM G$ERR ;[6045]Clear the error flag
MOVE S1,.LSNTA(LIS) ;PICK UP NODE TABLE ENTRY ADDRESS
MOVE S1,.NNNAM(S1) ;PICK UP THE NODE NAME
MOVEM S1,G$SND ;SAVE SO KNOW WHERE MESSAGE IS FROM
MOVE M,.LSMSG(LIS) ;PICK UP THE MESSAGE ADDRESS
LOAD S2,.MSTYP(M),MS.TYP ;GET THE MESSAGE TYPE
MOVSI S1,-NLMGT ;MAKE AOBJN POINTER FOR MSG TYPES
;PICK UP THE MESSAGE PROCESSING DISPATCH ADDRESS
PROMS2: HRRZ P1,LMGTAB(S1) ;GET A MESSAGE TYPE
CAMN S2,P1 ;MATCH?
JRST PROMS3 ;YES, WIN
AOBJN S1,PROMS2 ;NO, LOOP
JRST PROMS4 ;UNKNOWN MESSAGE TYPE, TELL ORION
;A KNOWN MESSAGE HAS BEEN RECEIVED, PROCESS IT
PROMS3: HLRZ P1,LMGTAB(S1) ;PICK UP THE PROCESSING ROUTINE ADR
$CALL @P1 ;DISPATCH THE MESSAGE PROCESSOR.
$RET
;AN UNKNOWN MESSAGE TYPE HAS BEEN RECEIVED. INFORM ORION
;**;[6037]At PROMS4:+0L add 2 lines JYCW Oct-18-88
PROMS4: TXNE S2,NEB%MS ;[6037]New format?
JRST LSIBH0 ;[6037]First determine # of replies
$WTOJ(<NEBULA received unknown message>,<Listener to node ^N/G$SND/ has received an unknown message type>,,<$WTFLG(WT.SJI)>)
$RET ;RETURN TO THE CALLER
LMGTAB: XWD LSIBHM,.NFDSM ;FROM NEBULA DISMOUNT
XWD LFDAK,.NFDAK ;FROM NEBULA DISMOUNT ACK
XWD LSIBHM,.NFMTS ;FROM NEBULA MOUNT
XWD RSPMSG,.OMDSP ;[6011]ACK OR WTO
XWD RSPMSG,.OMACS ;[6011]QUASAR SHOW ACK
XWD RSPMSG,MT.TXT ;[6011]ORION ACK
XWD LSIBHM,.NMSHS ;SHOW STATUS (.OMSHS)
XWD LSIBHM,.NDSHT ;[6001]SHOW STATUS TAPE (.ODSHT)
XWD LSIBHM,.NDSHD ;[6001]SHOW STATUS DISK (.ODSHD)
XWD LSIBHM,.NDSTR ;[6004]SHOW STATUS STRUCTURE (.ODSTR)
XWD LSIBHM,.NDSCD ;SHOW CONFIGURATION (.ODSCD)
XWD LSIBHM,.NMSHQ ;SHOW QUEUES (.OMSHQ)
XWD LSIBHM,.NMSHP ;SHOW PARAMETERS (.OMSHP)
XWD LSIBHM,.NMSHR ;SHOW ROUTE (.OMSHR)
XWD LSIBHM,.NMESS ;SHOW MESSAGES
XWD LSIBHM,.NSHOP ;SHOW OPERATORS
XWD NSRCL,.NSRCL ;SHOW CLUSTER-GALAXY/CLUSTER-NODE:
XWD EINFO,.QOLIS ;[6012]EXEC INFORMATION OUTPUT REQUEST
XWD REXSHW,.NMACS ;[6012]RESPONSE TO AN EXEC INFO REQUEST
XWD EKILL,.QOKIL ;[6012]EXEC CANCEL REQUEST
XWD REXKIL,.NMTXT ;[6012]RESPONSE TO AN EXEC CANCEL REQUEST
XWD RNEBAK,.NACKM ;[6016]REMOTE NEBULA ACK MESSAGE
XWD NRMACK,.NACKR ;[6016]NEBULA ACK RESPONSE MESSAGE
XWD LSIBHM,.NMSSN ;[6033]SHOW STATUS NETWORK (.OMSSN)
XWD LSIBHM,.NMSPN ;[6033]SHOW PARAMTER NETWORK (.OMSPN)
;**;[6043]At XWD LSIBHM,.NMSPN add 1 line JCR 11/29/89
XWD NRMACK,.OMNAK ;[6043]NULL ACK
;**;[6052]At LMGTAB:+26L add 3 lines JCR 3/1/90
XWD NRRCF,.NDRCF ;[6052]REPORT-CONNECTION-FAILURES
XWD NRDCA,.NDDCA ;[6052]DECNET-CONNECTION-ATTEMPTS
XWD RSPMSG,.OMACK ;[6052]ACK
NLMGT==.-LMGTAB
SUBTTL LFDAK - PROCESS A "FROM NEBULA DISMOUNT ACK" MESSAGE
;LFDAK is called from the listener message dispatcher to process a
;FROM NEBULA DISMOUNT ACK message received from a remote node in the
;cluster. A FROM NEBULA DISMOUNT ACK message is the response to a
;FROM NEBULA DISMOUNT message which requested the remote node to dismount
;a structure from that node. The FROM NEBULA DISMOUNT ACK message indicates
;the result of the dismount attempt, whether the dismount attempt succeeded
;or failed.
;This routine finds the remote queue entry that corresponds to the original
;FROM NEBULA DISMOUNT message and indicates in the node status word of
;the node from which the ACK has been received the status of the dismount
;attempt. If this is the last remaining response to the original FROM NEBULA
;DISMOUNT message, then a TO NEBULA DISMOUNT ACK message is built and
;sent to ORION to be forwarded to MOUNTR.
;
;Call is: M/Address of the FROM NEBULA DISMOUNT ACK message
; LIS/Listener block address
; G$SND/Node name from where the FROM NEBULA DISMOUNT ACK
; message originated
;Returns: The remote queue entry's node block corresponding to
; the node where the message orginated from is updated
; to indicate the status of the dismount attempt on that
; node.
;Crashes: A node data base inconsistency is detected
LFDAK: $SAVE <P1,P2,P3,P4> ;SAVE THESE AC
;FIND THE REMOTE QUEUE ENTRY CORRESPONDING TO THE ORIGINAL FROM NEBULA
;DISMOUNT MESSAGE USING THE ACK CODE OF THE ORIGINAL MESSAGE.
MOVE S1,G$SND ;PICK UP THE REMOTE NODE NAME
MOVE S2,.MSCOD(M) ;PICK UP THE ACK CODE
$CALL FNDNRQ ;FIND THE REMOTE QUEUE ENTRY
JUMPF S..NDI ;NODE DATA BASE INCONSISENCY
DMOVE P1,S1 ;SAVE THE INVARIANT BLOCK ADDRESS
; AND THE FORWARD LINK LIST WORD
;POINT TO THE INVARIANT BLOCK AND THE NODE BLOCK OF THE REMOTE NODE
LOAD P3,.RQBLK(P2),RQ.OFF ;PICK UP OFFSET TO INVARIANT BLOCK
LOAD S2,.RQNUM(P1),RQ.NTS ;PICK UP NUMBER OF NODE BLOCKS
SUB S2,P3 ;NODE BLOCK POSITION IN NODE BLOCK LIST
IMULI S2,.RQNSZ ;SIZE OF NODE BLOCK DISPLACEMENT
ADDI S1,.RQNIZ(S2) ;ADDRESS OF THE DESIRED NODE BLOCK
MOVE P3,S1 ;SAVE THIS ADDRESS
;INDICATE IN THE NODE BLOCK THE STATUS OF THE DISMOUNT ATTEMPT OF THE
;STRUCTURE ON THE REMOTE NODE.
MOVX S2,RQ%SNR!RQ%SSD ;ASSUME DISMOUNT WAS SUCCESSFUL
SKIPGE S1,.OFLAG(M) ;PICK UP STATUS FROM MESSAGE
JRST LFDAK2 ;THE STRUCTURE WAS DISMOUNTED
MOVX S2,RQ%SNR ;RESPONSE NOT RECEIVED, TURN OFF LATER
TXNE S1,FA%TER ;DID A MONITOR ERROR OCCUR?
TXO S2,RQ%TER ;YES, INDICATE IN THE STATUS WORD
TXNE S1,FA%MER ;DID A MOUNTR ERROR OCCUR?
TXO S2,RQ%MER ;YES, INDICATE IN THE STATUS WORD
TXNE S1,FA%OER ;DID AN ORION ERROR OCCUR?
TXO S2,RQ%OER ;YES, INDICATE IN THE STATUS WORD
TXNE S1,FA%NER ;DID A NEBULA ERROR OCCUR?
TXO S2,RQ%NER ;YES, INDICATE IN THE STATUS WORD
;PLACE IN THE NODE BLOCK STATUS WORD FOR THIS NODE IF THE STRUCTURE DISMOUNT
;WAS A SUCCESS OR THE COMPONENT THAT DETECTED AN ERROR. THEN DELINK THIS
;REMOTE QUEUE ENTRY FROM THE NODE'S REMOTE QUEUE
LFDAK2: XORM S2,.RQNST(P3) ;INDICATE DISMOUNT SUCCESS OR FAILURE
MOVE S1,P2 ;PICK UP ADR OF FORWARD LINK LIST WORD
MOVEI S2,.RQNST(P3) ;PICK UP ADR OF BACKWARD LINK LIST WORD
MOVE P4,.LSNTA(LIS) ;PICK UP ADR OF THE NODE TABLE ENTRY
$CALL RELNRQ ;DELINK THE RQE FROM THIS NODE'S RQ
;IF THE STRUCTURE WAS NOT DISMOUNTED ON THE REMOTE NODE, THEN PICK UP THE
;ERROR CODE AND PLACE IN THE ERROR CODE FIELD OF THE NODE BLOCK.
SKIPG .OARGC(M) ;IS THERE AN ERROR BLOCK PRESENT?
JRST LFDAK3 ;NO, STRUCTURE WAS DISMOUNTED
MOVE S1,.OHDRS+ARG.DA(M) ;PICK UP THE ERROR CODE
STORE S1,.RQNST(P3),RQ.ERR ;PLACE ERROR CODE IN NODE BLOCK
;CLEAR THE TIMER
LFDAK3: MOVE S1,.LSNTA(LIS) ;[6011]PICK UP THE NODE TABLE ENTRY ADR
MOVE S2,.MSCOD(M) ;[6011]PICK UP THE MESSAGE ACK CODE
$CALL CLRTIM ;[6011]CLEAR THE TIMER
;CHECK IF THIS IS THE LAST RESPONSE TO THE FROM NEBULA DISMOUNT MESSAGE.
;IF IT IS, THEN BUILD THE TO NEBULA DISMOUNT ACK MESSAGE AND SEND IT
;TO ORION TO BE FORWARDED TO MOUNTR.
SOS .RQNUM(P1) ;[6011]DECREMENT THE # OF REMAINING RESPONSES
LOAD S1,.RQNUM(P1),RQ.NOR ;PICK UP THE # OF REMAINING RESPONSES
SKIPE S1 ;ANY MORE RESPONSES?
$RET ;YES, SO ARE FINISHED
MOVE S1,P1 ;PICK UP THE INVARIANT BLOCK ADDRESS
$CALL SNDACK ;BUILD AND SEND TO NEBULA DISMOUNT ACK
$RET ; MESSAGE, RETURN
SUBTTL LSIBHM - PROCESS IN BEHALF OF MESSAGES FROM LISTENERS
;LSIBHM processes messages from listeners that request information
;or an action to be taken by the local node in behalf of a remote
;node. LSIBHM saves the remote node's name and the message ACK code
;in the in behalf of queue and forwards the message to ORION.
;
;Call is: M/Address of the message
; G$SND/Name of node that sent the message
;Returns: An in behalf of queue entry has been made for this message
; and the message has been forwarded to ORION
;Crashes: The message cannot be sent to ORION
;**;[6037]At LSIBHM:+0L add routine LSIBH0:
;**;[6041]At LSIBH0:+0L replace 9 lines with 8 lines JCR 9/26/89
LSIBH0: $SAVE <P1> ;[6041]Save a temporary
TXZ S2,NEB%MS ;[6041]Turn off the new format bit
MOVSI S1,-LUNITS ;[6041]Pick up the table length
LSIBH1: MOVE P1,MUNITS(S1) ;[6041]Pick up a message code
CAMN S2,P1 ;[6041]Are the codes the same?
JRST LSIBH ;[6041]Yes, find the number of units
AOBJN S1,LSIBH1 ;[6041]No, check the next code
JRST LSIBHM ;[6041]Message code not in the table
LSIBH: MOVEI S1,.OROBJ ;[6037]LOOK FOR THE OBJECT BLOCK
$CALL N$FNDB ;[6037]PICK UP THE OBJECT BLOCK
;**;[6044]At LSIBH:+2L change 4 lines JCR 12/16/89
;**;[6051]at LSIBH:+2L add 1 line JYCW 2/13/90
JUMPF LSIBHM ;[6051]No Object always 1 response.
HLRZ S2,OBJ.UN(S1) ;[6044]Pick up the upper limit
JUMPE S2,LSIBHM ;[6044]No upper limit
HRRZ S1,OBJ.UN(S1) ;[6044]Pick up the lower limit
SUB S2,S1 ;[6044]Find the difference
AOSA S1,S2 ;[6044]Make it the number of responses
;BUILD AN IN BEHALF OF QUEUE ENTRY FOR THIS MESSAGE AND LINK IT
;INTO THE IN BEHALF OF QUEUE
LSIBHM: MOVEI S1,1 ;[6037]ASSUME ONLY ONE RESPONSE
PUSH P,S1 ;[6037]SAVE THE NUMBER OF RESPONSES
MOVEI S1,.IQSIZ ;THE SIZE OF AN IBH QUEUE ENTRY
$CALL M%GMEM ;PICK UP THE MEMORY
MOVE S1,.MSCOD(M) ;PICK UP THE MESSAGE'S ACK CODE
MOVEM S1,.IQRNA(S2) ;SAVE AS THE REMOTE ACK CODE
AOS S1,LOCACK ;PICK UP THE LOCAL ACK CODE
MOVEM S1,.IQLNA(S2) ;SAVE IT IN THE IBH QUEUE ENTRY
MOVEM S1,.MSCOD(M) ;SAVE IT IN THE MESSAGE
MOVE S1,G$SND ;PICK UP THE REMOTE NODE NAME
MOVEM S1,.IQNEN(S2) ;SAVE AS THE IN BEHALF OF NODE
;**;[6037]At LSIBHM:+9L add 2 lines JYCW Oct-18-88
POP P,S1 ;[6037]PICK UP THE NUMBER OF RESPONSES
;**;[6041]At LSIBHM:+13L change 1 line JCR 9/26/89
HRRZM S1,.IQNUM(S2) ;[6041]Save it in the IBH queue entry
MOVE S1,S2 ;PICK UP ADDRESS OF THE IBH QUEUE ENTRY
$CALL ADDIBH ;ADD TO THE IN BEHALF OF QUEUE
; SEND THE MESSAGE TO ORION FOR PROCESSING ON THE LOCAL NODE
$CALL SENREM ;FORWARD THE MESSAGE TO ORION
JUMPF S..OSF ;CRASH IF CAN'T SEND THE MESSAGE
$RET ;PRESERVE THE T/F STATE
;**;[6041]At LSIBHM:+23L add 9 lines JCR 9/26/89
MUNITS: XWD 0,.OMSTA ;[6041]START message
XWD 0,.OMSHT ;[6041]SHUT message
XWD 0,.OMCON ;[6041]CONTINUE message
XWD 0,.OMPAU ;[6041]STOP message
XWD 0,.OMSET ;[6041]SET message
XWD 0,.OMELT ;[6041]ENABLE PRINT-LOGFILES message
XWD 0,.OMDLT ;[6041]DISABLE PRINT-LOGFILES message
LUNITS==.-MUNITS ;[6041]Length of multiple units table
SUBTTL EINFO - PROCESS AN IN BEHALF OF EXEC INFO OUTPUT MESSAGE
;[6012]EINFO processes the EXEC INFORMATION OUTPUT message that originated
;[6012]on a remote node in the cluster. EINFO saves the remote node's name,
;[6012]the message ACK code and the EXEC's PID in the in behalf of queue and
;[6012]forwards the message to ORION.
;[6012]
;[6012]Call is: M/Address of the message
;[6012] G$SND/Name of node that sent the message
;[6012]Returns: An in behalf of queue entry has been made for this message
;[6012] and the message has been forwarded to ORION
;[6012]Crashes: The message cannot be sent to ORION
;[6012]BUILD AN IN BEHALF OF QUEUE ENTRY FOR THIS MESSAGE AND LINK IT
;[6012]INTO THE IN BEHALF OF QUEUE
EINFO: $SAVE <P1> ;[6012]SAVE THIS AC
MOVEI S1,.LSPID ;[6012]PICK UP PID BLOCK CODE
$CALL N$FNDB ;[6012]FIND THE PID BLOCK
MOVE P1,0(S1) ;[6012]PICK UP THE PID
MOVEI S1,.IQSIZ ;[6012]THE SIZE OF AN IBH QUEUE ENTRY
$CALL M%GMEM ;[6012]PICK UP THE MEMORY
MOVE S1,.MSCOD(M) ;[6012]PICK UP THE MESSAGE'S ACK CODE
MOVEM S1,.IQRNA(S2) ;[6012]SAVE AS THE REMOTE ACK CODE
AOS S1,LOCACK ;[6012]PICK UP THE LOCAL ACK CODE
MOVEM S1,.IQLNA(S2) ;[6012]SAVE IT IN THE IBH QUEUE ENTRY
MOVEM S1,.MSCOD(M) ;[6012]SAVE IT IN THE MESSAGE
MOVE S1,G$SND ;[6012]PICK UP THE REMOTE NODE NAME
MOVEM S1,.IQNEN(S2) ;[6012]SAVE AS THE IN BEHALF OF NODE
MOVEM P1,.IQPID(S2) ;[6012]SAVE THE EXEC SENDER'S PID
MOVE S1,S2 ;[6012]PICK UP THE IBH QUEUE ENTRY ADR
$CALL ADDIBH ;[6012]ADD TO THE IN BEHALF OF QUEUE
;[6012] SEND THE MESSAGE TO QUASAR FOR PROCESSING ON THE LOCAL NODE
MOVE S1,M ;[6012]PICK UP THE MESSAGE ADDRESS
TXO S1,PT.KEE ;[6012]KEEP THE LISTENER PAGE
MOVEI S2,PAGSIZ ;[6012]PICK UP THE MESSAGE SIZE
$CALL SNDQSR ;[6012]FORWARD THE MESSAGE TO QUASAR
JUMPF S..QSF ;[6012]CRASH IF CAN'T SEND THE MESSAGE
$RET ;[6012]PRESERVE THE T/F STATE
SUBTTL EKILL - PROCESS AN IN BEHALF OF EXEC CANCEL MESSAGE
;[6012]EKILL processes the EXEC CANCEL PRINT message that originated
;[6012]FROM a remote node in the cluster. EKILL saves the remote node's name,
;[6012]the message ACK code and the EXEC's PID in the in behalf of queue and
;[6012]forwards the message to ORION.
;[6012]
;[6012]Call is: M/Address of the message
;[6012] G$SND/Name of node that sent the message
;[6012]Returns: An in behalf of queue entry has been made for this message
;[6012] and the message has been forwarded to ORION
;[6012]Crashes: The message cannot be sent to ORION
;[6012]BUILD AN IN BEHALF OF QUEUE ENTRY FOR THIS MESSAGE AND LINK IT
;[6012]INTO THE IN BEHALF OF QUEUE
EKILL: MOVEI S1,.IQSIZ ;[6012]PICK UP IBH QUEUE ENTRY SIZE
$CALL M%GMEM ;[6012]PICK UP THE IBH QUEUE ENTRY
MOVE S1,.MSCOD(M) ;[6012]PICK UP THE EXEC UNIQUE CODE
MOVEM S1,.IQRNA(S2) ;[6012]SAVE AS THE ORIGINAL ACK CODE
AOS S1,LOCACK ;[6012]PICK UP THE LOCAL ACK CODE
MOVEM S1,.IQLNA(S2) ;[6012]SAVE AS THE LOCAL ACK CODE
MOVEM S1,.MSCOD(M) ;[6012]SAVE IN THE MESSAGE
MOVE S1,G$SND ;[6012]PICK UP THE REQUESTOR'S NODE NAME
MOVEM S1,.IQNEN(S2) ;[6012]SAVE IN THE IBH QUEUE ENTRY
MOVE S1,KIL.PD(M) ;[6012]PICK UP THE EXEC'S PID
MOVEM S1,.IQPID(S2) ;[6012]SAVE IN THE IBH QUEUE ENTRY
MOVE S1,S2 ;[6012]]PICK UP THE IBH QUEUE ENTRY ADR
$CALL ADDIBH ;[6012]ADD TO THE IBH QUEUE
;[6012] SEND THE MESSAGE TO QUASAR FOR PROCESSING ON THE LOCAL NODE
MOVE S1,M ;[6012]PICK UP THE MESSAGE ADDRESS
TXO S1,PT.KEE ;[6012]KEEP THE LISTENER PAGE
MOVEI S2,PAGSIZ ;[6012]PICK UP THE MESSAGE SIZE
$CALL SNDQSR ;[6012]FORWARD THE MESSAGE TO QUASAR
JUMPF S..QSF ;[6012]CRASH IF CAN'T SEND THE MESSAGE
$RET ;[6012]PRESERVE THE T/F STATE
SUBTTL NSRCL - PROCESS REMOTE SHOW CLUSTER-STATUS MESSAGE
NSRCL: SETOM REMORG ;INDICATE REQUEST CAME REMOTELY
$CALL NSCLU ;BUILD THE MESSAGE
;**;[6052]At NSRCL:+2L replace 3 lines with 1 line JCR 3/1/90
JUMPT NSRC.1 ;[6052]On success send the reply
$CALL NSEACK ;BUILD THE ERROR ACK MESSAGE
MOVE MO,M ;SAVE THE MSG ADDRESS FOR LATER
NSRC.1: EXCH M,MO ;PLACE THE MESSAGE IN THE EXPECTED AC
MOVE S1,G$SND ;[6001]PICK UP REMOTE NODE NAME
$CALL SETPAR ;CHECK IF CAN SEND DIRECT OR MUST QUEUE
JUMPF NSRC.2 ;[6001]DON'T SEND ON AN ERROR
TXO S2,MQ%IBH ;INDICATE MSG WAS IN BEHALF OF
$CALL QUEMSG ;QUEUE OR SEND THE MESSAGE
NSRC.2: EXCH M,MO ;[6001]EXCHANGE THE MESSAGE ADDRESSES
CAME M,MO ;WAS THE MESSAGE AN ACK MESSAGE?
$CALL RELPAG ;NO, RELEASE THE RESPONSE MESSAGE PAGE
$RET ;RETURN TO THE CALLER
;**;[6052]After NSRC.2:+3L add routines NRRCF, NRDCA and FRDMSG JCR 3/1/90
SUBTTL NRRCF - Process a Remote REPORT-CONNECTION-FAILURES Message
;[6052]Routine NRRCF processes a REPORT-CONNECTION-FAILURES message that
;[6052]was sent from a remote NEBULA.
;[6052]
;[6052]Call is: M/REPORT-CONNECTION-FAILURES message address
;[6052]Returns true: The request was successfully processed and sent back
;[6052] to the requesting NEBULA.
;[6052]Returns false: An illegal or unknown node was specified; or the
;[6052] requesting node is no longer in the cluster.
NRRCF: SETOM REMORG ;[6052]Indicate request came remotely
$CALL NDRCF ;[6052]Process the message
JUMPT NRRC.1 ;[6052]Build a success .OMACK message
$CALL NSEACK ;[6052]Build an error MT.TXT message
JRST NRRC.4 ;[6052]Send the message
NRRC.1: MOVEM S2,G$ARG1 ;[6052]Save the node indicator
JUMPE S1,NRRC.2 ;[6052]ENABLE request?
SKIPE S2 ;[6052]No, for all nodes?
$CALL E$RDS ;[6052]No, for a particular node
SKIPN S2 ;[6052]For all nodes?
$CALL E$RDA ;[6052]Yes
JRST NRRC.3 ;[6052]Build the .OMACK message
NRRC.2: SKIPE S2 ;[6052]DISABLE, for all nodes?
$CALL E$RES ;[6052]No, for a particular node
SKIPN S2 ;[6052]For all nodes?
$CALL E$REA ;[6052]Yes
NRRC.3: $CALL NSEACK ;[6052]Build an MT.TXT message
MOVEI S1,.OMDSP ;[6052]Pick up display type
STORE S1,.MSTYP(MO),MS.TYP ;[6052]Store in the message header
NRRC.4: $CALL FRDMSG ;[6052]Forward the message to NEBULA
$RET ;[6052]Return to the caller
SUBTTL NRDCA - Process a Remote DECNET-CONNECTION-ATTEMPTS Message
;[6052]Routine NRDCA processes a DECNET-CONNECTION-ATTEMPTS message that
;[6052]was sent from a remote NEBULA.
;[6052]
;[6052]Call is: M/DECNET-CONNECTION-ATTEMPTS message address
;[6052]Returns true: The request was successfully processed and sent back
;[6052] to the requesting NEBULA.
;[6052]Returns false: An illegal or unknown node was specified; or the
;[6052] requesting node is no longer in the cluster.
NRDCA: SETOM REMORG ;[6052]Indicate request came remotely
$CALL NDDCA ;[6052]Process the message
JUMPT NRDC.1 ;[6052]Build a success .OMACK message
$CALL NSEACK ;[6052]Build an error MT.TXT message
JRST NRDC.4 ;[6052]Send the message
NRDC.1: MOVEM S2,G$ARG1 ;[6052]Save the node indicator
JUMPE S1,NRDC.2 ;[6052]ENABLE request?
SKIPE S2 ;[6052]No, for all nodes?
$CALL E$DDS ;[6052]No, for a particular node
SKIPN S2 ;[6052]For all nodes?
$CALL E$DDA ;[6052]Yes
JRST NRDC.3 ;[6052]Build the .OMACK message
NRDC.2: SKIPE S2 ;[6052]DISABLE, for all nodes?
$CALL E$DES ;[6052]No, for a particular node
SKIPN S2 ;[6052]For all nodes?
$CALL E$DEA ;[6052]Yes
NRDC.3: $CALL NSEACK ;[6052]Build an error MT.TXT message
;NRDC.3:$CALL BLDACK ;[6052]Build the .OMACK message
MOVEI S1,.OMDSP ;[6052]Pick up display type
STORE S1,.MSTYP(MO),MS.TYP ;[6052]Store in the message header
NRDC.4: $CALL FRDMSG ;[6052]Forward the message to NEBULA
$RET ;[6052]Return to the caller
SUBTTL FRDMSG - Forward a Message to a Remote NEBULA
;[6052]FRDMSG is called by routines NRRCF and NRDCA to send a message
;[6052]response back to NEBULA
;[6052]
;[6052]Call is: M/Address of message to be sent to NEBULA
;[6052]Returns true: The message was sent or queued
;[6052]Returns false: The message could not be sent
FRDMSG: MOVE S1,G$SND ;[6052]Pick up the remote node name
$CALL SETPAR ;[6052]Check if can send direct or queue
$RETIF ;[6052]Return on an error
TXO S2,MQ%IBH ;[6052]Indicate msg was in behalf of
$CALL QUEMSG ;[6052]Queue or send the message
$RETT ;[6052]Return to the caller
SUBTTL NSEACK - BUILD AN ACK MESSAGE REMOTELY
;NSEACK is called when NEBULA detects that a SHOW CLUSTER message that
;has been processed remotely has encountered an error. This routine builds
;an .OMDSP message to be forwarded to the original sender of the SHOW message.
;
;Call is: M/Address of the SHOW CLUSTER-STATUS message
;Returns: M/Address of the .OMDSP message
NSEACK: $SAVE <P1,P2> ;SAVE THESE AC
;BUILD THE GALAXY MESSAGE HEADER
MOVE S1,[.OHDRS,,MT.TXT] ;[6023]PICK UP THE HEADER WORD
MOVEM S1,.MSTYP(M) ;PLACE IN THE MESSAGE
MOVX S1,MF.NEB ;PICK UP THE NEBULA BIT
MOVEM S1,.MSFLG(M) ;PLACE IN THE MESSAGE
;**;[6052]At NSEACK:+8L replace 3 lines with 2 lines JCR 3/1/90
SETZM .OARGC(M) ;[6052]Reset the argument count
SETZM .OFLAG(M) ;[6052]Reset flag word
;BUILD THE FIRST DISPLAY BLOCK
MOVEI P1,.OHDRS+ARG.HD(M) ;ADDRESS OF THE BLOCK HEADER WORD
MOVEI S1,.ORDSP ;PICK UP THE BLOCK TYPE
STORE S1,ARG.HD(P1),AR.TYP ;[6023]PLACE IN THE MESSAGE
MOVEI S1,ARG.DA+1(P1) ;[6023]ADDRESS OF THE FIRST TEXT WORD
HRLI S1,(POINT 7,) ;MAKE INTO A POINTER
MOVEM S1,BYTPTR ;SAVE THE POINTER
$TEXT (DEPBYT,<^I/@NSEA.1/^0>) ;PLACE TEXT IN THE MESSAGE BLOCK
HRRZ S1,BYTPTR ;PICK UP THE END ADDRESS OF THE BLOCK
ANDI S1,777 ;ISOLATE THE PAGE OFFSET
SUBI S1,.OHDRS-1 ;FIND THE BLOCK LENGTH
STORE S1,ARG.HD(P1),AR.LEN ;PLACE IN THE MESSAGE
MOVE P2,S1 ;SAVE THE LENGTH FOR LATER
;**;[6052]At NSEACK:+27L add 1 line JCR 3/1/90
AOS .OARGC(M) ;[6052]Increment the argument count
;BUILD THE SECOND DISPLAY BLOCK
ADD P1,S1 ;ADDRESS OF THE NEXT DISPLAY BLOCK
MOVEI S2,.ORDSP ;PICK UP THE BLOCK TYPE
STORE S2,ARG.HD(P1),AR.TYP ;STORE THE BLOCK TYPE
MOVE S2,MSGTIM ;PICK UP THE TIME
MOVEM S2,ARG.DA(P1) ;SAVE IN THE BLOCK
MOVEI S1,ARG.DA+1(P1) ;ADDRESS OF THE START OF THE TEXT
HRLI S1,(POINT 7,) ;MAKE INTO A POINTER
MOVEM S1,BYTPTR ;SAVE THE POINTER
MOVE S1,G$ERR ;PICK UP THE ERROR OFFSET
$TEXT (DEPBYT,<^I/@TXTTBL(S1)/^0>) ;PLACE THE TEXT IN THE BLOCK
HRRZ S1,BYTPTR ;PICK UP THE END ADDRESS
ANDI S1,777 ;ISOLATE THE PAGE OFFSET
SUBI S1,.OHDRS-1(P2) ;FIND THE BLOCK LENGTH
STORE S1,ARG.HD(P1),AR.LEN ;PLACE IN THE BLOCK HEADER WORD
ADD S1,P2 ;FIND THE TOTAL MESSAGE LENGTH
MOVSS S1 ;PLACE IN THE EXPECTED PLACE
ADDM S1,.MSTYP(M) ;[6023]PLACE IN THE MESSAGE
;**;[6052]At NSEA.2:+7L add 1 line JCR 3/1/90
AOS .OARGC(M) ;[6052]Increment the argument count
$RET ;RETURN TO THE CALLER
;**;[6045]At NSEA.1:+0L change 1 line JCR 1/15/90
NSEA.1: [ITEXT(< Received message from ^N/NODNAM/::>)] ;[6045]
SUBTTL RSPMSG - RESPONSE TO A MESSAGE
;RSPMSG is called as part of processing responses to remote messages.
;RSPMSG clears the timer that was set when the message was sent to the
;remote node and then sends the message response to ORION.
;
;Call is: LIS/Address of the listener block
;Returns true: The message was sent successfully to ORION
;Returns false: The message was not sent to ORION
RSPMSG: MOVE S1,.LSNTA(LIS) ;[6011]PICK UP THE NODE TABLE ENTRY ADR
MOVE S2,.MSCOD(M) ;[6011]PICK UP THE ACK CODE
$CALL CLRTIM ;[6011]CLEAR THE TIMER
$CALL SENREM ;[6011]SEND THE MESSAGE TO ORION
$RET ;[6011]PRESERVE THE T/F INDICATOR
SUBTTL SENREM - SEND A MESSAGE FROM A REMOTE NODE TO ORION
;SENREM sends in behalf of messages and responses to requests made
;on a remote node that NEBULA does not need to act on (e.g., DISPLAY
;messages as opposed to the FROM NEBULA DISMOUNT ACK message) to ORION.
;SENREM sends the message to ORION.
;
;Call is: M/Address of the message to be sent to ORION
;Returns true: The message was sent successfully
;Returns false: The message was not sent
SENREM:
;SEND THE MESSAGE TO ORION
MOVE S1,M ;ADDRESS OF THE IPCF MESSAGE
TXO S1,PT.KEE ;INDICATE WANT TO KEEP PAGE AFTER SEND
MOVEI S2,PAGSIZ ;LENGTH OF THE IPCF MESSAGE
$CALL SNDORN ;SEND THE MESSAGE TO ORION
$RET ;PRESERVE THE T/F INDICATOR
SUBTTL REXSHW - RESPONSE TO AN EXEC REQUEST
;[6012]REXSHW is called as part of processing responses to EXEC requests.
;[6012]REXSHW clears the timer that was set when the message was sent to the
;[6012]remote node and then sends the message response to the EXEC that made
;[6012]the original request.
;[6012]
;[6012]Call is: LIS/Address of the listener block
;[6012]Returns true: The message was sent successfully to the EXEC
;[6012]Returns false: The message was not sent to the EXEC
REXSHW: SKIPA S1,[0] ;[6012]INDICATE INFO OUTPUT RESPONSE
REXKIL: SETOM S1, ;[6012]INDICATE CANCEL PRINTER RESPONSE
MOVEM S1,EXESHW ;[6012]SAVE FOR LATER
MOVE S1,.LSNTA(LIS) ;[6012]PICK UP THE NODE TABLE ENTRY ADR
MOVE S2,.MSCOD(M) ;[6012]PICK UP THE ACK CODE
$CALL CLRTIM ;[6012]CLEAR THE TIMER
MOVEM M,SAB+SAB.MS ;[6012]PLACE MESSAGE ADDRESS IN THE SAB
MOVEI S1,PAGSIZ ;[6012]PICK UP THE MESSAGE SIZE
MOVEM S1,SAB+SAB.LN ;[6012]PLACE IN THE SAB
SETZM SAB+SAB.SI ;[6012]ZERO OUT SPECIAL INDEX
MOVE S1,.OFLAG(M) ;[6012]PICK UP THE EXEC'S PID
SETZM .OFLAG(M) ;[6012]ZERO THE FLAG WORD
MOVEM S1,SAB+SAB.PD ;[6012]PLACE IN THE SAB
MOVEI S1,.OMACS ;[6012]PICK UP THE MESSAGE CODE
SKIPE EXESHW ;[6012]INFO PRINT RESPONSE?
MOVEI S1,.OMTXT ;[6012]NO, CANCEL PRINT RESPONSE
STORE S1,.MSTYP(M),MS.TYP ;[6012]PLACE IN THE MESSAGE
MOVE S1,.MSFLG(M) ;[6012]PICK UP THE FLAG WORD
TXZ S1,MF.NEB ;[6012]TURN OFF THE NEBULA BIT
MOVEM S1,.MSFLG(M) ;[6012]RESTORE THE UPDATED FLAG WORD
MOVEI S1,SAB.SZ ;[6012]PICK UP SIZE OF THE SAB
TXO S1,PT.KEE ;[6012]KEEP PAGE IN GLXMEM
MOVEI S2,SAB ;[6012]PICK UP ADDRESS OF THE SAB
$CALL C%SEND ;[6012]SEND THE MESSAGE
$RET ;[6012]PRESERVE THE T/F INDICATOR
SUBTTL RNEBAK - RESPOND TO A NEBULA ACK MESSAGE
;[6016]RNEBAK is called when a NEBULA ACK message has been received. RNEBAK
;[6016]sends a NEBULA ACK RESPONSE message back to the NEBULA that sent the
;[6016]ACK message.
;[6016]
;[6016]Call is: M/Address of the NEBULA ACK message
;[6016]Returns true: The NEBULA RESPONSE ACK message has been sent
;[6016]Returns false: The NEBULA RESPONSE ACK message could not be sent
RNEBAK: MOVEI M,NEBRSP ;[6016]NEBULA RESPONSE ACK MSG ADDRESS
MOVE S1,G$SND ;[6016]PICK UP NODE ACK MSG CAME FROM
$CALL SETPAR ;[6016]DETERMINE IF SEND DIRECT OR QUEUE
JUMPF .POPJ ;[6016]QUIT NOW IF CAN'T SEND THE MSG
TXO S2,MQ%IBH ;[6016]INDICATE AN IN BEHALF OF RESPONSE
$CALL QUEMSG ;[6016]SEND OR QUEUE THE MESSAGE
$RETT ;[6016]INDICATE SUCCESS
SUBTTL NRMACK - PROCESS A NEBULA ACK RESPONSE MESSAGE
;[6016]NRMACK is called when a NEBULA ACK RESPONSE message has been received.
;[6016]NRMACK clears the timer associated with the original NEBULA ACK
;[6016]message. The NEBULA ACK/NEBULA ACK RESPONSE messages mechanism ensures
;[6016]that a remote node that NEBULA believes that it has communication with
;[6016]actually does have communication with that node. For instance, if the
;[6016]remote node's NI is reloaded, the local NEBULA will not be interrupted
;[6016]to indicate that its links to that node are no longer connected.
;**;[6043]At NRMACK:-1L replace 2 lines with 9 lines JCR 11/29/89
;[6043]NRMACK is also called to process a NULL ACK message. NEBULA expects a
;[6043]response for each message that it sends to a remote NEBULA. However,
;[6043]it is possible that a message will not generate a response. For example,
;[6043]WTOR processing may not send a response. In order to clear the
;[6043]message return time, a Null ACK must be sent from the remote node.
;[6043]
;[6016]Call is: M/NEBULA ACK RESPONSE or NULL ACK message address
;[6043] LIS/Address of the listener block
;[6043]Returns: The message return timer has been cleared
NRMACK: MOVE S1,.LSNTA(LIS) ;[6016]PICK UP THE NODE TABLE ENTRY ADR
MOVE S2,.MSCOD(M) ;[6016]PICK UP THE ACK CODE
$CALL CLRTIM ;[6016]CLEAR THE TIMER
$RET ;[6016]RETURN TO THE CALLER
SUBTTL RESTAR - PROCESS CRASHED INFERIOR FORKS
;RESTAR is called by the scheduler when it detects that an inferior fork
;has crashed. It determines which fork has crashed, kills that fork and
;the other fork associated with the remote node. It then updates the
;remote queue, in behalf of queue and the message queue for that node.
;Finally, it determines if the remote node can potentially receive
;messages (i.e., it is still in the cluster, has DECnet enabled, and is
;running a monitor of release 7 or later.
;
;Call is: No arguments
;Returns: Senders and listeners have been updated
;Crashes: If there is a node table inconsistency
RESTAR: $SAVE <P1,P2,P3,P4> ;SAVE THESE AC
SETZM TRMFRK ;CLEAR THE INFERIOR FORK CRASHED FLAG
SETOM NBSCHD ;FORCE ANOTHER SCHEDULING PASS
MOVEI P1,NODTBL ;POINT TO THE NODE TABLE
SKIPG P2,RENNUM ;[6035]ANY NODES LEFT IN THE CLUSTER?
$RET ;[6035]NO, RETURN NOW
MOVEI P3,MAXNOD ;PICK UP NUMBER OF NODE TABLE ENTRIRES
;CHECK IF THE REMOTE NODE HAS A SENDER AND CHECK IF THE REMOTE NODE IS STILL
;IN THE CLUSTER.
RESTA2: SKIPN .NNNAM(P1) ;IS THIS NODE TABLE ENTRY IN USE?
JRST RESTA6 ;NO, CHECK THE NEXT NODE TABLE ENTRY
SKIPN .NNSBA(P1) ;NODE HAVE A SENDER (AND A LISTENER)?
JRST RESTA5 ;[6022]NO, CHECK THE NEXT NODE TABLE ENTRY
MOVE S1,.NNSTA(P1) ;PICK UP THE NODE STATUS WORD
TXNE S1,NN%SCS ;HAS THIS NODE LEFT THE CLUSTER?
JRST RESTA5 ;YES, LET ROUTINE TOPCHN DEAL WITH IT
;CHECK IF THE SENDER HAD A CONTROLLED CRASH, IF NOT, THEN CHECK IF IT HAD
;AN UNCONTROLLED CRASH.
MOVE S1,.NSSTA(P1) ;PICK UP THE SENDER STATUS WORD
TXNE S1,NS%SFC ;DID THIS SENDER CONTROLLED CRASH?
JRST RESTA3 ;YES, GO CLEAN UP
MOVE S1,.NNSBA(P1) ;PICK UP THE SENDER BLOCK ADDRESS
MOVE S1,.SNHND(S1) ;PICK UP THE SENDER'S HANDLE
$CALL INFSTS ;PICK UP THE SENDER'S STATUS
JUMPF RESTA3 ;THE SENDER IS HALTED OR DISMISSED
;THE SENDER TO THIS NODE IS O.K. CHECK THE LISTENER TO THIS NODE
MOVE S1,.NLSTA(P1) ;PICK UP THE LISTENER STATUS WORD
TXNE S1,NL%LFC ;DID THIS LISTENER CONTROLLED CRASH?
JRST RESTA3 ;YES, GO CLEAN UP
MOVE S1,.NNLBA(P1) ;PICK UP THE LISTENER ADDRESS BLOCK
MOVE S1,.LSHND(S1) ;PICK UP THE LISTENER'S HANDLE
$CALL INFSTS ;PICK UP THE LISTENER'S STATUS
JUMPT RESTA5 ;THIS NODE IS OK, CHECK THE NEXT NODE
;AT LEASE ONE INFERIOR FORK TO THE REMOTE NODE HAS CRASHED. KILL BOTH THE
;SENDER AND LISTENER TO THIS NODE. ALSO, UPDATE THE QUEUES TO THIS NODE.
;REBUILD THE NODE TABLE QUEUE ENTRY AND IF THE REMOTE NODE CAN RECEIVE
;MESSAGES FROM THIS NODE, THEN START UP A SENDER AND LISTENER FOR THIS NODE.
RESTA3: MOVE S1,P1 ;PICK UP THE NODE TABLE ENTRY ADDRESS
$CALL KASNOD ;RESET THE REMOTE NODE'S DATA BASE
JUMPF RESTA4 ;INFORM OPERATORS OF THE FAILURE
$WTOJ (<NEBULA forks crashed>,<^I/@RESTXS/>,,<$WTFLG(WT.SJI)>)
JRST RESTA5 ;GO CHECK FOR MORE NODES
RESTA4: $WTOJ (<NEBULA forks crashed>,<^I/@RESTXF/>,,<$WTFLG(WT.SJI)>)
;GO CHECK THE NEXT NODE, IF THERE ARE ANY MORE
RESTA5: SOJE P2,.POPJ ;RETURN IF NO MORE NODES
RESTA6: SOJE P3,S..NTI ;IF NO ENTRIES LEFT, CRASH
ADDI P1,.NNNSZ ;POINT TO THE NEXT NODE ENTRY
JRST RESTA2 ;CHECK THE NEXT NODE
RESTXS: [ITEXT(<DECnet forks to node ^N/.NNNAM(P1)/ crashed.
Forks have been restarted.>)]
RESTXF: [ITEXT(<DECnet forks to node ^N/.NNNAM(P1)/ crashed.
Forks cannot be restarted.>)]
SUBTTL INFSTS - DETERMINE THE STATUS OF AN INFERIOR FORK
;INFSTS determines the status of an inferior fork
;
;Call is: S1/Fork handle
;Returns true: The fork is not halted or dismissed
;Returns false: The fork is halted or dismissed
INFSTS: $SAVE <T1,T2> ;RFSTS% JSYS CHANGES THESE AC
RFSTS% ;GET THE STATUS OF THIS LISTENER
ERJMP .RETF ;INVALID HANDLE, ASSUME FORK IS GONE
TXZ S1,RF%FRZ ;CLEAR THE FROZEN FORK BIT
HLRZS S1 ;PLACE STATUS CODE IN RIGHT HALF
CAIE S1,.RFHLT ;IS THIS FORK HALTED?
CAIN S1,.RFFPT ;NO, IS THIS FORK DISMISSED?
INFST2: $RETF ;YES, FORK IS HALTED OR DISMISSED
$RETT ;FORK IS NOT HALTED OR DISMISSED
SUBTTL SNDORN - SEND AN IPCF MESSAGE TO ORION OR QUASAR
;SNDORN sends an IPCF message to ORION or QUASAR. If bit PT.KEE is set
;in the message address AC, then C%SEND will not replace the page in the
;free page pool.
;
;Call is: S1/PT.KEE,,The message address
; S2/The message length
;Returns true: The message was sent successfully
;Returns false: The message was not successfully sent
SNDORN: TDZA TF,TF ;FLAG TO SEND THE MESSAGE TO ORION
SNDQSR: SETOM TF ;FLAG TO SEND THE MESSAGE TO QUASAR
HRRZM S1,SAB+SAB.MS ;SAVE THE MESSAGE ADDRESS
MOVEM S2,SAB+SAB.LN ;SAVE THE MESSAGE LENGTH
MOVEI S2,SP.OPR ;GET ORION'S FLAG
SKIPE TF ;UNLESS THE MSG IS TO BE SENT TO QUASAR
MOVEI S2,SP.QSR ;THEN GET QUASAR'S FLAG
TXO S2,SI.FLG ;SET SPECIAL INDEX FLAG
STORE S2,SAB+SAB.SI ;AND STORE IT
SETZM SAB+SAB.PD ;CLEAR THE PID WORD
HRRI S1,SAB.SZ ;LOAD THE SIZE
MOVEI S2,SAB ;AND THE ADDRESS
$CALL C%SEND ;SEND THE MESSAGE
$RET ;PERSERVE THE TRUE/FALSE INDICATOR
SUBTTL N$SEND - ROUTINE TO SEND AN IPCF MESSAGE TO AN EXEC
;[6012]N$SEND is called to send a message to an EXEC
;[6012]
;[6012]Call is: SAB containing the SAB
;[6012]Returns true: The message was sent
;[6012]Returns false: The message was not sent
;[6012]SEND THE IPCF MESSAGE TO THE EXEC
N$SEND: MOVEI S1,SAB.SZ ;[6012]GET THE SAB LENGTH
MOVEI S2,SAB ;[6012]AND THE SAB ADDRESS
$CALL C%SEND ;[6012]SEND THE MESSAGE OFF
JUMPT .POPJ ;[6012]RETURN NOW IF MSG SENT
;[6012]HERE IF THE SEND FAILED
MOVE S2,SAB+SAB.LN ;[6012]GET THE MESSAGE LENGTH
CAIE S2,PAGSIZ ;[6012]SENDING A PAGE?
$RETF ;[6012]NO, JUST RETURN
MOVE S1,SAB+SAB.MS ;[6012]YES, GET THE PAGE ADDRESS
PUSHJ P,M%RPAG ;[6012]RETURN THE PAGE
$RETF ;[6012]AND RETURN
SUBTTL XFRMSG - TRANSFER IPCF MESSAGE FROM ONE BUFFER TO ANOTHER
;This routine transfers an IPCF message from one buffer to another
;
;Call is: S1/ Address where the IPCF message is currently located
; S2/ Address where the IPCF message is to be moved to
;Returns: Message has been transferred
XFRMSG: HRL S2,S1 ;SOURCE,,DESTINATION
LOAD S1,.MSTYP(S1),MS.CNT ;PICK UP THE MESSAGE LENGTH
ADD S1,S2 ;SIZE OF THE BLT + 1
BLT S2,-1(S1) ;TRANSFER THE MESSAGE
$RET ;AND RETURN TO THE CALLER
SUBTTL ADDMQE - ADD A MESSAGE TO A SENDER'S MESSAGE QUEUE
;ADDMQE adds a message queue entry to a sender's message queue
;
;Call is: SEN/Address of the sender block
; S1/ Adr of message queue entry link list word for
; this sender's node
;Returns: Message queue entry added to end of this node's message queue
ADDMQE: SKIPN S2,.SNTWD(SEN) ;ANY MESSAGES IN ITS MESSAGE QUEUE?
JRST ADDMQ2 ;NO, ADD AS THE FIRST MSG QUEUE ENTRY
STORE S1,.MQBLK(S2),MQ.NEA ;PLACE NEW ADR OF LAST QE IN L.L. WORD
SKIPA ;GO UPDATE THE LINK LIST TRAILER WORD
ADDMQ2: MOVEM S1,.SNHWD(SEN) ;UPDATE THE LINK LIST HEADER WORD
MOVEM S1,.SNTWD(SEN) ;UPDATE THE LINK LIST TRAILER WORD
AOS .SNUSM(SEN) ;INCREMENT THE MESSAGE COUNT
$RET ;AND RETURN TO THE CALLER
SUBTTL FNDMQE - FIND AND RETURN A MESSAGE QUEUE ENTRY
;FNDMQE is called as part of processing a CANCEL DISMOUNT
;message. For those nodes that a dismount message was sent to but
;no response has been received as indicated in the remote queue entry,
;the message queue of those nodes are checked to determine if the message
;has yet been sent. If the message is still in the message queue, then
;the message is deleted from the node's message queue. Once the message
;has been deleted from all the message queues, the message queue entry
;is returned to the memory manager.
;The message queue is searched by the ACK code of the original DISMOUNT
;message.
;
;Call is: S1/ACK code to find message queue entry by
; SEN/Address of the sender block
;Returns true: The message was found and deleted from the message queue
; (if this was the last node to send the message to, then
; the message queue entry is also returned to the memory
; manager).
;Returns false: The message queue entry was not found (i.e., the message
; has already been sent to the remote node).
FNDMQE: $SAVE <P1,P2,P3> ;SAVE THESE AC
;CHECK THIS NODE'S MESSAGE QUEUE FOR THE MESSAGE. BASE THE SEARCH ON THE
;ACK CODE PROVIDED BY MOUNTR AND STORED IN THE MESSAGE TO BE SENT
SKIPN .SNHWD(SEN) ;IS THE MESSAGE QUEUE EMPTY?
JRST FNDMQ7 ;YES, MESSAGE NOT FOUND RETURN FALSE
MOVEI P1,.SNHWD(SEN) ;MAKE P1 THE PREVIOUS ENTRY ADDRESS
FNDMQ2: LOAD P2,.MQBLK(P1),MQ.NEA ;MAKE P2 THE CURRENT ENTRY ADDRESS
JUMPE P2,FNDMQ7 ;RETURN FALSE IF NO MORE MESSAGE QE
LOAD S2,.MQBLK(P2),MQ.OFF ;PICK UP THE OFFSET TO INVARIANT BLOCK
ADD S2,P2 ;POINT TO THE INVARIANT BLOCK
LOAD P3,.MQNOM(S2),MQ.ADR ;POINT TO THE IPCF MESSAGE
CAMN S1,.MSCOD(P3) ;THE MESSAGE BEING SEARCHED FOR?
JRST FNDMQ3 ;YES, DELETE FROM MESSAGE QUEUE
MOVE P1,P2 ;MAKE THE CURRENT THE PREVIOUS
JRST FNDMQ2 ;CHECK THE MESSAGE QUEUE ENTRY
;THE MESSAGE HAS BEEN FOUND. DELETE THE MESSAGE FROM THIS NODE'S MESSAGE
;QUEUE
FNDMQ3: SOSE .SNUSM(SEN) ;ANY MORE MESSAGES IN THIS QUEUE?
JRST FNDMQ4 ;YES, UPDATE THE MESSAGE QUEUE
SETZM .SNHWD(SEN) ;ZERO THE MESSAGE QUEUE HEADER WORD
SETZM .SNTWD(SEN) ;ZERO THE MESSAGE QUEUE TRAILER WORD
JRST FNDMQ5 ;CHECK IF THE LAST NODE TO SEND MSG TO
;THE MESSAGE QUEUE WILL NOT BE EMPTY AFTER THIS QUEUE ENTRY IS REMOVED.
;UPDATE THE POINTERS
FNDMQ4: LOAD S1,.MQBLK(P2),MQ.NEA ;PICK UP ADDRESS OF THE NEXT MQE
SKIPN S1 ;IS THE DELETED ENTRY THE LAST ENTRY?
MOVEM P1,.SNTWD(SEN) ;YES, PLACE PREVIOUS ENTRY ADR IN TRAILER
STORE S1,.MQBLK(P1),MQ.NEA ;UPDATE PREVIOUS ENTRY NEXT ENTRY ADR
;THE MESSAGE QUEUE ENTRY HAS BEEN DELETED FROM THIS NODE'S MESSAGE QUEUE.
;CHECK IF THE MESSAGE IS TO BE SENT TO ANY MORE NODES. IF IT IS NOT, THEN
;RETURN THE MESSAGE QUEUE ENTRY TO THE MEMORY MANAGER.
FNDMQ5: LOAD S1,.MQNOM(S2),MQ.NUM ;PICK UP NUMBER OF NODES TO SEND MSG TO
SOJE S1,FNDMQ6 ;ANYMORE NODES TO SEND THE MESSAGE TO?
STORE S1,.MQNOM(S2),MQ.NUM ;YES, UPDATE NUMBER OF NODES
$RETT ;INDICATE THE MESSAGE WAS FOUND
FNDMQ6: MOVE S1,S2 ;PICK UP INVARIANT BLOCK ADDRESS
$CALL RELMQE ;RETURN THE MESSAGE QUEUE ENTRY
$RETT ;INDICATE THE MESSAGE WAS FOUND
FNDMQ7: $RETF ;THE MESSAGE WAS NOT FOUND
SUBTTL RELMQE - RETURN A MESSAGE QUEUE ENTRY TO MEMORY MANAGER
;RELMQE returns the memory used by a message queue entry and its
;corresponding message to the memory manager.
;(Note: If the sum of the memory required by the message queue entry
;and the message is greater than a page, then in general, the message
;memory location is not contiguous with the message queue entry,
;otherwise they are contiguous.)
;
;Call is: S1/Address of the message queue entry invariant block
;Returns: The message queue entry has been returned to the memory manager
RELMQE: $SAVE <P1> ;SAVE THIS AC
MOVE P1,S1 ;PICK UP ADDRESS OF THE INVARIANT BLOCK
;DETERMINE IF THE MESSAGE LOCATION IS NOT CONTIGUOUS WITH THE END OF THE
;MESSAGE QUEUE ENTRY. IF IT IS NOT CONTIGUOUS, THEN RETURN THE MEMORY OF
;THE MESSAGE SEPARATELY TO THE MEMORY MANAGER.
SKIPL .MQMEM(P1) ;DOES THE MESSAGE OCCUPY A PAGE?
JRST RELMQ2 ;NO, RETURN MQE AND MSG TOGETHER
LOAD S1,.MQNOM(P1),MQ.ADR ;YES, PICK UP THE PAGE ADDRESS
$CALL M%RPAG ;RETURN THE PAGE TO THE MEMORY MANAGER
;RETURN THE MESSAGE QUEUE ENTRY (AND MESSAGE, IF NOT A PAGE) TO THE
;MEMORY MANAGER
RELMQ2: LOAD S1,.MQMEM(P1),MQ.LEN ;PICK UP MEMORY BLOCK SIZE
LOAD S2,.MQMEM(P1),MQ.PTR ;PICK UP MEMORY BLOCK ADDRESS
$CALL M%RMEM ;RETURN THE MEMORY TO MEMORY MANAGER
$RET ;RETURN TO THE CALLER
SUBTTL BLDMQE - BUILD A MESSAGE QUEUE ENTRY
;BLDMQE builds a message queue entry. If the sum of the lengths of the message
;queue header and the message is less than or equal to a page, then the start
;of the message is contiguous with the end of the message queue header.
;Otherwise, the message is placed in a separate page that, in general, will
;not be contiguous with the end of the message queue header.
;
;Note: It is assumed in building the link list words that this message queue
; entry will be placed on the end of the message queue (i.e., field
; MQ.NEA of the link list word .MQBLK is zeroed).
;
;Call is: S1/Number of nodes to send the message to
; S2/Flag bits
; MQ%IBH This message is a response to an in behalf of message
; MQ%REM This message has an entry in the remote queue
; MQ%EXE This message is in behalf of an EXEC
; M/Address of the IPCF message
;Returns true: The message queue entry is built
; S1/ Address of the message queue entry
;Returns false: Illegal number of nodes specified
; S1/ The number of nodes specified
BLDMQE: $SAVE <P1,P2,P3,P4> ;SAVE THESE AC
CAILE S1,MAXNOD ;LESS THAN THE MAX NUMBER OF NODES?
$RETF ;NO, RETURN FALSE
SKIPG S1 ;POSITIVE NUMBER OF NODES?
$RETF ;NO, RETURN FALSE
;DETERMINE IF THE SUM OF THE MQE AND THE IPCF MESSAGE LENGTHS FITS IN A PAGE
DMOVEM S1,P1 ;SAVE THE NUMBER OF NODES AND FLAGS
IMULI S1,.MQBSZ ;SIZE OF THE LINK LIST WORDS
MOVE P4,S1 ;REMEMBER THIS TO FIND INVARIANT BLOCK
ADDI S1,.MQISZ ;OBTAIN MESSAGE QUEUE ENTRY SIZE
LOAD P3,.MSTYP(M),MS.CNT ;PICK UP SIZE OF THE IPCF MESSAGE
ADD P3,S1 ;ADD MQE SIZE TO MESSAGE SIZE
CAILE P3,PAGSIZ ;TOTAL LENGTH FITS IN A PAGE?
JRST BLDMQ2 ;NO, GET A PAGE FOR THE MESSAGE
;PREPARE THE MQE CONTIGUOUS WITH THE MESSAGE
MOVE S1,P3 ;PLACE MEMORY BLOCK SIZE WHERE EXPECTED
$CALL M%GMEM ;PICK UP THE MEMORY BLOCK
MOVE P3,S2 ;PICK UP THE MQE ADDRESS
ADDI P3,.MQISZ(P4) ;POINT TO THE MESSAGE
JRST BLDMQ3 ;JOIN COMMON CODE
;PREPARE THE MQE SEPARATE FROM THE MESSAGE
BLDMQ2: MOVE P3,S1 ;REMEMBER THE MQE SIZE
$CALL GETPAG ;GET A PAGE OF MEMORY
MOVE S1,P3 ;PICK UP MQE SIZE
MOVE P3,MO ;PICK UP MESSAGE ADDRESS
TXO P3,MQ%PAG ;INDICATE MESSAGE IS A PAGE
$CALL M%GMEM ;PICK UP MEMORY FOR THE MQE
;BUILD THE INVARIANT BLOCK
BLDMQ3: ADD P4,S2 ;POINT TO THE INVARIANT BLOCK
MOVEM P2,.MQNOM(P4) ;PLACE FLAGS IN THE INVARIANT BLOCK
STORE P1,.MQNOM(P4),MQ.NUM ;PLACE # OF NODES IN INVARIANT BLOCK
STORE P3,.MQNOM(P4),MQ.ADR ;PLACE MSG ADDRESS IN INVARIANT BLOCK
STORE S1,.MQMEM(P4),MQ.LEN ;SAVE GLXMEM LENGTH IN INVARIANT BLOCK
STORE S2,.MQMEM(P4),MQ.PTR ;SAVE GLXMEM ADDRESS IN INVARIANT BLOCK
HLLZ S1,P3 ;ISOLATE THE PAGE (MQ%PAG) BIT
IORM S1,.MQMEM(P4) ;INDICATE IF THE MSG IS A PAGE OR NOT
MOVE S1,G$SND ;[6012]ASSUME MESSAGE FROM THE EXEC
TXNE P2,MQ%EXE ;[6012]IS IT?
MOVEM S1,.MQPID(P4) ;[6012]YES, SAVE ITS PID
;NOW BUILD THE LINK LIST WORDS. PLACE THE OFFSETS IN THE LINK LIST WORDS
;AND ASSUME THIS MESSAGE QUEUE ENTRY WILL BE ADDED TO THE END OF THE
;MESSAGE QUEUE.
MOVE P2,S2 ;SAVE THE MQE ADDRESS FOR THE RETURN
BLDMQ4: HRLZM P1,0(S2) ;BUILD THE LINK LIST WORD FOR THIS NODE
ADDI S2,.MQBSZ ;POINT TO THE NEXT LINK LIST WORD
SOJG P1,BLDMQ4 ;BUILD THE NEXT LINK LIST WORD
;MOVE THE MESSAGE FROM THE IPCF BUFFER TO THE MESSAGE QUEUE BUFFER
MOVE S1,M ;ADDRESS OF THE IPCF MESSAGE
HRRZ S2,P3 ;ADDRESS OF THE MSG IN MQE
$CALL XFRMSG ;MOVE THE MESSAGE
MOVE S1,P2 ;RETURN THE MQE ADDRESS
$RETT ;RETURN TO THE CALLER
SUBTTL ADDIBH - ADD AN IN BEHALF OF QUEUE ENTRY
;ADDIBH adds an in behalf of queue entry to the end of the in behalf
;of queue.
;ADDIBH assumes that the link list word is zero (which is true since the
;queue entry is obtained from M%GMEM which zeros every word).
;
;Call is: S1/The address of the in behalf of queue entry
;Returns: The in behalf of queue entry has been added to the IBH queue.
;ADD THE ENTRY TO THE END OF THE IBH QUEUE. IF THE QUEUE IS EMPTY, THEN
;MAKE THE QUEUE HEADER WORD THE PREVIOUS ENTRY. UPDATE THE TRAILER WORD.
ADDIBH: SKIPN S2,IBQTRL ;PICK UP CONTENTS OF IBH TRAILER WORD
MOVEI S2,IBQHDR ;MAKE THE HEADER THE PREVIOUS ENTRY
STORE S1,.IQLNK(S2),IQ.NXT ;SAVE ADR NEW ENTRY IN PREVIOUS ENTRY
STORE S2,.IQLNK(S1),IQ.PRE ;SAVE ADR PREVIOUS ENTRY IN NEW ENTRY
MOVEM S1,IBQTRL ;SAVE ADR NEW ENTRY IN TRAILER WORD
$RET ;RETURN TO THE CALLER
SUBTTL FNDIBH - FIND AN IN BEHALF OF QUEUE ENTRY
;FNDIBH finds an in behalf of queue entry by searching on the ACK code.
;
;Call is: S1/Local ACK code of the IPCF message
;Returns true: S2/The address of the in behalf of queue entry
;Returns false: The queue entry was not found
FNDIBH: SKIPN S2,IBQHDR ;IS THE QUEUE EMPTY?
JRST FNDIB3 ;YES, GO RETURN FALSE
FNDIB2: CAMN S1,.IQLNA(S2) ;IS THIS THE ENTRY LOOKING FOR?
$RETT ;YES, RETURN TO THE CALLER
LOAD S2,.IQLNK(S2),IQ.NXT ;NO, GET THE NEXT ENTRY
SKIPE S2 ;THE LAST ENTRY?
JRST FNDIB2 ;NO, CHECK THE NEXT ENTRY
FNDIB3: $RETF ;YES, RETURN FALSE
SUBTTL RELIBH - RETURNS AN IN BEHALF OF QUEUE ENTRY
;RELIBH delinks an in behalf of queue entry and returns the entry's
;memory to the memory manager.
;
;Call is: S1/ Address of the in behalf of queue entry to be released
;Returns true: The in behalf of queue entry was released
;Returns false: The in behalf of queue entry was not found
RELIBH: $SAVE <P1> ;SAVE THIS AC
;SET UP THE NEW LINK POINTERS
SKIPN IBQHDR ;IS THE IBH QUEUE EMPTY?
JRST RELIB2 ;YES, ENTRY NOT FOUND
MOVE P1,S1 ;SAVE THE IBH QUEUE ENTRY
LOAD S1,.IQLNK(P1),IQ.NXT ;PICK UP NEXT ENTRY ADDRESS
LOAD S2,.IQLNK(P1),IQ.PRE ;PICK UP PREVIOUS ENTRY ADDRESS
STORE S1,.IQLNK(S2),IQ.NXT ;SAVE FORWARD PTER IN PREVIOUS ENTRY
SKIPE S1 ;IS THIS ENTRY THE LAST ONE?
STORE S2,.IQLNK(S1),IQ.PRE ;NO, SAVE PREVIOUS ENTRY IN FRDWD PTR
;CHECK IF THE ENTRY BEING DELETED IS THE LAST ENTRY IN THE IBH QUEUE
SKIPN S1 ;IS THE ENTRY THE LAST ENTRY?
MOVEM S2,IBQTRL ;YES, SO PREVIOUS ENTRY IS NOW LAST
;CHECK IF THE IN BEHALF OF QUEUE IS NOW EMPTY, IF SO, THEN ZERO OUT
;THE TRAILER HEADER WORD.
SKIPN IBQHDR ;IS THE IBH QUEUE NOW EMPTY?
SETZM IBQTRL ;YES, CLEAN THE TRAILER WORD
;RETURN THE MESSAGE QUEUE ENTRY TO THE MEMORY MANGAGER
MOVE S2,P1 ;PLACE ADDRESS IN THE EXPECTED PLACE
MOVEI S1,.IQSIZ ;PICK UP THE SIZE OF THE ENTRY
$CALL M%RMEM ;RETURN THE IBH QUEUE ENTRY
$RETT ;RETURN, THE QE HAS BEEN DELETED
RELIB2: $RETF ;QUEUE ENTRY NOT FOUND
SUBTTL ADDGRQ - ADD A REMOTE QUEUE ENTRY TO THE GLOBAL REMOTE QUEUE
;ADDGRQ adds a remote queue entry to the global remote queue. Every remote
;queue entry is linked into the global remote queue. This is done in the
;event that a CANCEL DISMOUNT message is received. To locate the
;corresponding remote queue entry, the ACK code is used and the global
;remote queue is searched. If there were not a global remote queue, the
;remote queue of each node would need to be searched.
;
;Call is: S1/The address of the remote queue entry invariant block
;Returns: The remote queue entry has been added to the global
; remote queue.
;ADD THE ENTRY TO THE END OF THE GLOBAL REMOTE QUEUE. IF THE QUEUE IS EMPTY,
;THEN MAKE THE QUEUE HEADER WORD THE PREVIOUS ENTRY. UPDATE THE TRAILER WORD.
ADDGRQ: SKIPN S2,REMTRL ;PICK UP CONTENTS OF TRAILER WORD
MOVEI S2,REMHDR ;MAKE THE HEADER THE PREVIOUS ENTRY
STORE S1,.RQLNK(S2),RQ.NXT ;SAVE ADR NEW ENTRY IN PREVIOUS ENTRY
STORE S2,.RQLNK(S1),RQ.PRE ;SAVE ADR PREVIOUS ENTRY IN NEW ENTRY
MOVEM S1,REMTRL ;SAVE ADR NEW ENTRY IN TRAILER WORD
$RET ;RETURN TO THE CALLER
SUBTTL FNDGRQ - FIND A GLOBAL REMOTE QUEUE ENTRY
;FNDGRQ finds a global remote queue entry by its ACK code.
;
;Call is: S1/ACK code provided by MOUNTR
;Returns true: S2/The address of the global remote queue entry's
; invariant block
;Returns false: The queue entry was not found
FNDGRQ: SKIPN S2,REMHDR ;IS THE QUEUE EMPTY?
JRST FNDGR3 ;YES, GO RETURN FALSE
FNDGR2: CAMN S1,.RQACK(S2) ;IS THIS THE ENTRY LOOKING FOR?
$RETT ;YES, RETURN TO THE CALLER
LOAD S2,.RQLNK(S2),RQ.NXT ;NO, GET THE NEXT ENTRY
SKIPE S2 ;THE LAST ENTRY?
JRST FNDGR2 ;NO, CHECK THE NEXT ENTRY
FNDGR3: $RETF ;YES, RETURN FALSE
SUBTTL RELGRQ - RETURNS A GLOBAL REMOTE QUEUE ENTRY
;RELGRQ delinks a global remote queue entry and returns the entry's
;memory to the memory manager. RELGRQ assumes that the remote queue
;entry has been removed from all the nodes' remote queues
;
;Call is: S1/ Address of the remote queue entry's invariant block
;Returns true: The global remote queue entry was released
;Returns false: The global remote queue entry was not found
RELGRQ: $SAVE <P1> ;SAVE THIS AC
;SET UP THE NEW LINK POINTERS
SKIPN REMHDR ;IS THE GLOBAL REMOTE QUEUE EMPTY?
JRST RELGR2 ;YES, ENTRY NOT FOUND
MOVE P1,S1 ;SAVE THE GLOBAL RQE INVARIANT BLK ADR
LOAD S1,.RQLNK(P1),RQ.NXT ;PICK UP NEXT ENTRY ADDRESS
LOAD S2,.RQLNK(P1),RQ.PRE ;PICK UP PREVIOUS ENTRY ADDRESS
STORE S1,.RQLNK(S2),RQ.NXT ;SAVE FORWARD PTER IN PREVIOUS ENTRY
SKIPE S1 ;IS THIS ENTRY THE LAST ONE?
STORE S2,.RQLNK(S1),RQ.PRE ;NO, SAVE PREVIOUS ENTRY IN FRDWD PTR
;CHECK IF THE ENTRY BEING DELETED IS THE LAST ENTRY IN THE GLOBAL REMOTE QUEUE
SKIPN S1 ;IS THE ENTRY THE LAST ENTRY?
MOVEM S2,REMTRL ;YES, SO PREVIOUS ENTRY IS NOW LAST
;CHECK IF THE GLOBAL REMOTE QUEUE IS NOW EMPTY, IF SO, THEN ZERO OUT
;THE TRAILER HEADER WORD.
SKIPN REMHDR ;IS THE QUEUE NOW EMPTY?
SETZM REMTRL ;YES, CLEAN THE TRAILER WORD
;RETURN THE GLOBAL REMOTE QUEUE ENTRY TO THE MEMORY MANGAGER
LOAD S1,.RQMEM(P1),RQ.LEN ;PICK UP LENGTH OF THE REMOTE QE
LOAD S2,.RQMEM(P1),RQ.ADR ;PICK UP ADDRESS OF THE REMOTE QE
$CALL M%RMEM ;RETURN THE REMOTE QUEUE ENTRY
$RETT ;RETURN, THE QE HAS BEEN DELETED
RELGR2: $RETF ;REMOTE QUEUE ENTRY NOT FOUND
SUBTTL FNDNRQ - FIND A NODE'S REMOTE QUEUE ENTRY
;FNDNRQ finds a node's remote queue entry by searching on the ACK code.
;
;Call is: S1/SIXBIT node name
; S2/ACK code of the original IPCF message
;Returns true: S1/The address of the invariant block
; S2/The address of the remote queue entry link list word
;Returns false: The queue entry was not found
FNDNRQ: $SAVE <P1> ;SAVE THIS AC
;FIND THE NODE TABLE ENTRY ADDRESS FOR THIS NODE, PICK UP THE NODE'S
;REMOTE QUEUE HEADER WORD. IF THIS NODE'S REMOTE QUEUE IS EMPTY, THEN RETURN
MOVE P1,S2 ;SAVE THE ACK CODE
$CALL SNAMNT ;PICK UP THE NODE TABLE ENTRY ADDRESS
JUMPF FNDNR3 ;RETURN IF NODE NOT FOUND
SKIPN S2,.NRQLH(S2) ;IS THIS NODE'S REMOTE QUEUE EMPTY?
JRST FNDNR3 ;YES, GO RETURN FALSE
;SEARCH FOR THE REMOTE QUEUE ENTRY BY USING THE ACK CODE
FNDNR2: LOAD S1,.RQBLK(S2),RQ.OFF ;PICK UP THE OFFSET
ADD S1,S2 ;POINT TO THE INVARIANT BLOCK
CAMN P1,.RQACK(S1) ;IS THIS THE ENTRY LOOKING FOR?
$RETT ;YES, RETURN TO THE CALLER
LOAD S2,.RQBLK(S2),RQ.NEA ;NO, GET THE NEXT ENTRY
SKIPE S2 ;THE LAST ENTRY?
JRST FNDNR2 ;NO, CHECK THE NEXT ENTRY
FNDNR3: $RETF ;YES, RETURN FALSE
SUBTTL RELNRQ - RETURNS A NODE'S REMOTE QUEUE ENTRY
;RELNRQ delinks a node's remote queue entry.
;
;Call is: S1/Address of the node's remote queue entry's forward
; link list word
; S2/Address of the node's remote queue entry's backwards
; link list word
; P4/Node table entry address
;Returns: The node's remote queue entry was released
RELNRQ: $SAVE <P1,P2,P3,P4> ;SAVE THESE AC
;SET UP THE NEW LINK POINTERS
LOAD P1,.RQBLK(S1),RQ.NEA ;PICK UP NEXT ENTRY ADDRESS
LOAD P2,.RQNST(S2),RQ.ERR ;PICK UP PREVIOUS ENTRY ADDRESS
STORE P1,.RQBLK(P2),RQ.NEA ;SAVE FORWARD PTER IN PREVIOUS ENTRY
JUMPE P1,RELNR2 ;IS THIS ENTRY THE LAST ONE?
;THE NEXT ENTRY'S PREVIOUS ENTRY LINK LIST WORD IS LOCATED IN THE NODE
;BLOCK. THEREFORE, THE NODE BLOCK MUST BE FOUND. THIS IS DONE BY ADDING
;THE NEXT ENTRY'S OFFSET TO ITS ADDRESS TO FIND THE INVARIANT BLOCK.
;THE SIZE OF THE INVARIANT BLOCK IS ADDED TO THIS TO POINT TO THE FIRST
;NODE BLOCK. THE POSITION OF THE NODE BLOCK IS FOUND BY NOTING THE
;RELATIONSHIP: NODE POSITION = NUMBER OF NODES - OFFSET.
;THIS VALUE IS MULTIPLIED BY THE SIZE OF A NODE BLOCK AND ADDED TO THE
;POINTER TO THE FIRST NODE BLOCK TO GET THE NODE BLOCK ADDRESS.
LOAD S1,.RQBLK(P1),RQ.OFF ;PICK UP NEXT ENTRY OFFSET VALUE
MOVE P3,S1 ;REMEMBER THE OFFSET
ADD S1,P1 ;POINT TO NEXT ENTRY INVARIANT BLOCK
LOAD S2,.RQNUM(S1),RQ.NTS ;PICK UP NUMBER OF NODES IN THE RQE
SUB S2,P3 ;POSITION OF NODE BLK IN NODE BLK LIST
IMULI S2,.RQNSZ ;CALCULATE THE BLOCK DISPLACEMENT
ADDI S1,.RQNIZ(S2) ;POINT TO THE DESIRED NODE BLOCK
STORE P2,.RQNST(S1),RQ.ERR ;SAVE PREVIOUS ENTRY IN THIS NODE'S
;PREVIOUS POINTER
SKIPA ;GO CHECK IF IBH QUEUE IS NOW EMPTY
RELNR2: MOVEM P2,.NRQLT(P4) ;PREVIOUS ENTRY IS NOW LAST
;CHECK IF THE NODE'S REMOTE QUEUE IS NOW EMPTY, IF SO, THEN ZERO OUT
;THE TRAILER HEADER WORD.
SKIPN .NRQLH(P4) ;IS THE IBH QUEUE NOW EMPTY?
SETZM .NRQLT(P4) ;YES, CLEAN THE TRAILER WORD
$RET ;RETURN, THE QE HAS BEEN DELETED
SUBTTL SNAMNT - SEARCH NODE TABLE BY NODE NAME
;SNAMNT searches the node table by using the SIXBIT node name
;
;Call is: S1/SIXBIT node name
;Returns true: S1/SIXBIT node name
; S2/Address of the node table entry for the found node
;Returns false: Node table entry not found
; S1/SIXBIT node name
; S2/-1
SNAMNT: SKIPG RENNUM ;ANY REMOTE NODES?
JRST SNAMN3 ;NO, RETURN NOW
$SAVE <P1> ;SAVE THIS AC
MOVEI S2,NODTBL ;PICK UP THE NODE TABLE ADDRESS
MOVEI P1,MAXNOD ;NUMBER OF ENTRIES IN NODE TABLE
SNAMN2: CAMN S1,.NNNAM(S2) ;DO THE NAMES MATCH?
$RETT ;YES, RETURN TRUE
ADDI S2,.NNNSZ ;POINT TO THE NEXT NODE ENTRY
SOJG P1,SNAMN2 ;CHECK OUT THE NEXT NODE ENTRY
SNAMN3: SETO S2, ;NODE NAME NOT FOUND IN THE NODE TABLE
$RETF ;RETURN FALSE
SUBTTL SNUMNT - SEARCH NODE TABLE BY NODE NUMBER
;SNUMNT searches the node table by using the cluster node number
;
;Call is: S1/Cluster node number
;Returns true: S1/Cluster node number
; S2/Address of the node table entry for the found node
;Returns false: S1/Cluster node number
; S2/-1
;
SNUMNT: $SAVE <P1,P2> ;SAVE THESE AC
MOVEI S2,NODTBL ;PICK UP ADDRESS OF THE NODE TABLE
MOVEI P1,MAXNOD ;MAX NUMBER OF ENTRIES IN NODE TABLE
SNUMN2: LOAD P2,.NNSTA(S2),NS.NUM ;PICK UP THE NODE NUMBER FOR THIS ENTRY
CAMN S1,P2 ;DO THE NODE NUMBERS MATCH?
$RETT ;YES, RETURN TRUE
ADDI S2,.NNNSZ ;NO, POINT TO THE NEXT ENTRY
SOJG P1,SNUMN2 ;CHECK THE NEXT NODE TABLE ENTRY
SETO S2, ;NODE NUMBER NOT FOUND IN NODE TABLE
$RETF ;RETURN FALSE
SUBTTL LISTEN - MESSAGE SERVER FOR A REMOTE NODE
;LISTEN exists as an inferior fork in NEBULA. A listener is started for
;every remote node known to NEBULA that is running a release 7 or later
;monitor and which has DECnet enabled. A listener picks up messages from
;a remote node. The messages are of two types:
;1. Requests to be processed on the listener's node
;2. Responses to requests that originated on the listener's node but
; were processed on the sender's node.
;A listener communicates with the top fork through software interrupts,
;the listener block and the node's status words in its node table entry.
;INITIALIZATION BLOCK AND PID BLOCK
LIB: $BUILD IB.SZ
$SET (IB.PRG,,%%.MOD) ;PROGRAM 'NEBULA'
$SET (IB.FLG,IP.STP,1) ;STOPCODES TO ORION
$EOB ;
LPIB: $BUILD PB.MNS ;
$SET (PB.HDR,PB.LEN,PB.MNS) ;PIB LENGTH,,0
$SET (PB.FLG,IP.RSE,1) ;RETURN ON SEND ERROR
$SET (PB.SYS,IP.BQT,-1) ;MAXIMUM SEND/RECEIVE IPCF QUOTA
$SET (PB.SYS,IP.MNP,^D1) ;NUMBER OF PIDS
$EOB ;
LISCHN: XWD 1,ACCEPT ;A DECNET CONNECTION REQUEST OCCURRED
XWD 1,MSGFSN ;MESSAGE FROM A SENDER IS AVAILABLE
XWD 1,MSGTTF ;TOP FORK READY TO PROCESS A MESSAGE
BLOCK ^D33 ;THESE CHANNELS ARE NOT USED
;SET UP GLXLIB, ENABLE CAPABILITIES, AND SET UP INTERRUPT SYSTEM
LISTEN: SKIPE DEBUGW ;DEBUGGING?
$CALL NEBDDT ;YES, SET UP FOR DEBUGGING
$CALL LISSET ;SET UP GLXLIB AND CAPABILITIES
$CALL LOPLNK ;OPEN A SRV: DEVICE
$CALL LISINT ;SET UP THE INTERRUPT SYSTEM
;WAIT FOR A CONNECTION REQUEST, FOR INCOMING DECNET MESSAGES AND FOR
;REQUESTS FROM THE TOP FORK FOR A MESSAGE.
LISTE2: SETZ S1, ;INDEFINITE TIME TO WAIT
$CALL I%SLP ;WAIT% UNTIL NEEDED
JRST LISTE2 ;WAIT% FOR THE NEXT EVENT
SUBTTL LISSET - INITIALIZE THE LISTENER'S GLXLIB AND CAPABILITIES
;LISSET is called by the listener at listener startup. This routine sets up
;GLXLIB, the listener's capabilities and disables the listener from receiving
;any IPCF messages.
;
;Call is: LIS/Address of the listener block
;Returns: GLXLIB setup and capabilities enabled
;Crashes: Unable to set up capabilities
LISSET: $SAVE <T1,T2> ;SAVE THESE AC, DESTROYED BY JSYS
;SET UP THE GLXLIB INITIALIZATION BLOCK IN THE LISTENER BLOCK
MOVSI S1,LIB ;PICK UP ADDRESS OF THE IB BLOCK
HRRI S1,.LSIBK(LIS) ;ADDRESS OF WHERE TO PLACE THE IB BLOCK
MOVEI S2,.LSIBK+IB.SZ(LIS) ;END ADDRESS + 1
BLT S1,-1(S2) ;MOVE THE IB BLOCK TO LISTENER BLOCK
MOVEI S1,.LSPIB(LIS) ;PICK UP THE PID ADDRESS
MOVEM S1,.LSIBK+IB.PIB(LIS) ;PLACE IN THE INITIALIZATION BLOCK
MOVSI S1,.LSLEV(LIS) ;ADDRESS OF THE INTERRUPT LEVEL TABLE
HRRI S1,LISCHN ;ADDRESS OF THE CHANNEL TABLE
MOVEM S1,.LSIBK+IB.INT(LIS) ;PLACE IN THE INITIALIZATION BLOCK
;SET UP THE PID BLOCK AND THE INTERRUPT LEVEL TABLE IN THE LISTENER BLOCK
MOVSI S1,LPIB ;PICK UP ADDRESS OF THE PID BLOCK
HRRI S1,.LSPIB(LIS) ;DESTINATION IS IN THE LISTENER BLOCK
MOVEI S2,.LSPIB+PB.MNS(LIS) ;END ADDRESS + 1
BLT S1,-1(S2) ;MOVE PID TABLE TO LISTENER BLOCK
MOVEI S1,.LSLEV(LIS) ;PICK UP ADR OF INTERRUPT LEVEL TABLE
MOVEI S2,.LS1PC(LIS) ;PICK UP ADR OF FIRST PC WORD
MOVEM S2,0(S1) ;PLACE PC ADR IN INTERRUPT LEVEL TABLE
AOS S1 ;POINT TO NEXT INTERRUPT LEVEL WORD
AOS S2 ;POINT TO NEXT PC WORD
MOVEM S2,0(S1) ;PLACE PC ADR IN INTERRUPT LEVEL TABLE
AOS S1 ;POINT TO NEXT INTERRUPT LEVEL WORD
AOS S2 ;POINT TO NEXT PC WORD
MOVEM S2,0(S1) ;PLACE PC ADR IN INTERRUPT LEVEL TABLE
;SET UP GLXLIB
MOVEI S1,IB.SZ ;PICK UP SIZE OF THE INITIALIZATION BLK
MOVEI S2,.LSIBK(LIS) ;PICK UP ADR OF THE INITIALIZATION BLK
$CALL I%INIT ;INITIALIZE GLXLIB
;ENABLE THE LISTENER'S CAPABILITIES TO BE THOSE OF THE TOP FORK AND GIVE IT
;THE CAPABILITY TO INTERRUPT THE TOP FORK.
MOVX S1,.FHSLF ;PICK UP THE LISTENER'S HANDLE
RPCAP%
ERJMP [$CALL INLCRH ;INDICATE A CONTROLLED CRASH
$STOP(LCC,Listener can't obtain capabilities) ]
TXO S2,SC%SUP ;CAPABILITY TO INTERRUPT TOP FORK
MOVE T1,S2 ;ENABLE ALL CAPABILITIES
MOVEI S1,.FHSLF ;PICK UP THE LISTENER'S HANDLE
EPCAP% ;ENABLE THE CAPABILITIES
ERJMP [$CALL INLCRH ;INDICATE A CONTROLLED CRASH
$STOP(LCE,Listener can't enable capabilities) ]
;DISABLE RECEIVING IPCF MESSAGES
MOVEI S1,.MUDIS ;DISABLE RECEIVING IPCF MESSAGES
MOVEM S1,.LSMUT(LIS) ;PLACE IN THE ARGUMENT BLOCK
MOVE S1,.LSPIB+PB.PID(LIS) ;PICK UP LISTENER'S PID
MOVEM S1,.LSMUT+1(LIS) ;PLACE IN THE ARGUMENT BLOCK
MOVEI S1,2 ;PICK UP SIZE OF ARGUMENT BLOCK
MOVEI S2,.LSMUT(LIS) ;PICK ADDRESS OF THE ARGUMENT BLOCK
MUTIL% ;DISABLE RECEIVING IPCF MESSAGES
ERJMP .+1 ;SHOULDN'T HAPPEN, BUT DON'T CARE
;CREATE THE MESSAGE LIST
$CALL L%CLST ;PICK UP THE MESSAGE LIST INDEX
MOVEM S1,.LSHWD(LIS) ;PLACE IN THE LISTENER BLOCK
$RET ;RETURN TO STARTUP
SUBTTL LOPLNK - OPEN A DECNET SRV: DEVICE
;LOPLNK is called during the listener's initialization to open a SRV:
;device. It is also called by ACCEPT if an MTOPR% error has occurred
;and the link must be re-opened.
;
;Call is: LIS/Address of the listener block
;Returns: The SRV: device has been open
;Crashes: Unable to obtain a JFN or open the SRV: device
LOPLNK: $SAVE <T1,T2,T3> ;SAVE THESE AC
;PICK UP THE SRV: JFN AND OPEN THE SRV: DEVICE
MOVX S1,GJ%SHT ;SHORT JFN
HRROI S2,.LSSRV(LIS) ;POINT TO THE DEVICE NAME
GTJFN%
ERJMP LOPLN5 ;CRASH IF CAN'T GET JFN
HRRZS S1 ;ISOLATE THE JFN
MOVEM S1,.LSJFN(LIS) ;SAVE THE JFN FOR LATER
MOVNI T3,^D60 ;[6021]NEGATIVE NUMBER OF OPEN TRIES
SKIPA ;[6021]SKIP THE FIRST TIME THROUGH
LOPLN3: MOVE S1,.LSJFN(LIS) ;[6021]PICK UP THE JFN
MOVX S2,<FLD(^D36,OF%BSZ)+OF%WR+OF%RD> ;OPEN FOR READ AND WRITE
OPENF%
ERJMP LOPLN4 ;RETRY ON AN ERROR
$RET ;RETURN TO THE CALLER
LOPLN4: AOSN T3 ;[6021]TIME TO QUIT?
JRST LOPLN5 ;[6021]YES, CRASH
MOVEI S1,MINTIM ;[6021]PICK UP THE TIME TO SLEEP
$CALL I%SLP ;[6021]DISMISS FOR AWHILE
JRST LOPLN3 ;[6021]RE-ATTEMPT TO OPEN THE LINK
LOPLN5: $CALL S%ERR ;[6021]PICK UP THE ERROR STRING
JUMPF LOPLN6 ;[6021]STOPCODE ON AN UNKNOWN ERROR
$WTOJ (<Unable to obtain DECnet connection>,<Listener for node ^N/.LSNME(LIS)/ has encountered an error.
The last error is: ^T/0(S1)/>,,<$WTFLG(WT.SJI)>)
$CALL INLCRH ;[6021]INDICATE A CONTROLLED CRASH
HALTF% ;[6021]HAVE TOP FORK RESTART
LOPLN6: $CALL INLCRH ;[6021]INDICATE A CONTROLLED CRASH
$STOP (LOD, LISTENER CAN'T OPEN DECNET DEVICE) ;[6021]
SUBTTL LISINT - SET UP THE LISTENER'S INTERRUPT SYSTEM
;LISINT is called by the listener during listener startup. LISINT sets up
;the listener's interrupt system.
;
;Call is: LIS/Address of the listener block
;Returns: The interrupt system has been set up
;Crashes: The interrupt system could not be set up
LISINT: $SAVE <T1,T2> ;SAVE THESE AC
MOVEI S1,.FHSLF ;PICK UP THE LISTENER'S HANDLE
SETO S2, ;INDICATE DISABLE ALL 36 CHANNELS
DIC% ;DISABLE THE CHANNELS
ERJMP .+1 ;SHOULDN'T HAPPEN, BUT IGNORE
CIS% ;CLEAR THE INTERRUPT SYSTEM
ERJMP .+1 ;SHOULDN'T HAPPEN, BUT IGNORE
MOVEI S1,.FHSLF ;PICK UP THE LISTENER'S HANDLE
HRLI S2,.LSLEV(LIS) ;PICK UP INTERRUPT LEVEL TABLE ADDRESS
HRRI S2,LISCHN ;PICK UP CHANNEL TABLE ADDRESS
SIR% ;SET UP THE INTERRUPT TABLE ADDRESSES
ERJMP LISIN2 ;CRASH IF CAN'T SET UP
MOVEI S1,.FHSLF ;PICK UP THE LISTENER'S HANDLE
EIR% ;ENABLE THE INTERRUPT SYSTEM
ERJMP LISIN2 ;CRASH IF CAN'T ENABLE INTERRUPT SYSTEM
MOVEI S1,.FHSLF ;PICK UP THE LISTENER'S HANDLE
MOVX S2,1B0+1B1+1B2 ;PICK UP CHANNELS TO ACTIVATE
AIC% ;ACTIVATE THE CHANNELS
ERJMP LISIN2 ;CRASH IF CAN'T ACTIVATE THE CHANNELS
MOVE S1,.LSJFN(LIS) ;PICK UP THE SRV: DEVICE JFN
MOVEI S2,.MOACN ;ENABLE SOFTWARE INTERRUPTS
MOVX T1,<FLD(0,MO%CDN)+FLD(1,MO%DAV)+FLD(.MONCI,MO%INA)>
MTOPR% ;CONNECT EVENT PENDING/DATA AVAILABLE
ERJMP LISIN2 ;CRASH IF CAN'T SET UP CHANNELS
$RETT ;RETURN TO LISTENER STARTUP
LISIN2: $CALL INLCRH ;INDICATE CONTROLLED CRASH
JRST S..CSI ;CANNOT SET UP THE INTERRUPT SYSTEM
SUBTTL ACCEPT - VALIDATE A DECNET CONNECTION REQUEST
;ACCEPT is the listener's interrupt handler for DECnet connection requests.
;ACCEPT validates a sender's request for a DECnet connection. The following
;three checks are made:
;1. The sender must be from the node that the listener expects the sender
; to be from.
;2. The sender's name must be passed as the USERID argument and must be
; in the form expected by the listener. the expected form is:
; SNODE$NEBULA$SN
; where SNODE is the sender's node name
;3. The optional data (BDATA) field must contain the value that results from
; the following algorithm:
; a. The listener's node name expressed in SIXBIT is rotated left by 3 bits
; b. This value is then converted into 4 octal 8 bit bytes
;If the sender fails to pass the three checks, then the sender's DECnet
;connection request is rejected with reason "Reject or disconnect by
;object" (error .DCX0). ORION is informed of the rejection and the
;bit NL%HMR (HELLO message received from a non-NEBULA) is set in the listener
;status word in the node table entry.
;If the sender passes the three checks, then its connection request is
;accepted, ORION is informed, bit NL%NRH (inform the top fork that a HELLO
;has been accepted) is set in the listener status word in the node table
;entry, and the top fork is interrupted to indicate that the listener has
;accepted a DECnet connection.
;
;Call is: LIS/Address of the listener block
;Returns: The connecton request has been accepted or rejected
;Crashes: Cannot obtain the information to validate the connection request
; or cannot interrupt the top fork
ACCEPT: $BGINT 1,
;FIRST DETERMINE IF THE CONNECTION REQUEST IF FROM THE EXPECTED NODE
MOVE S1,.LSJFN(LIS) ;PICK UP THE SRV: DEVICE JFN
MOVEI S2,.MORHN ;WANT THE SENDER'S NODE NAME
HRROI T1,.LSANN(LIS) ;WHERE TO PLACE THE NODE NAME
MTOPR% ;PICK UP THE SENDER'S NODE NAME
ERJMP ACCEP4 ;[6021]CHECK THE STATE OF THE LINK
HRROI S1,.LSANN(LIS) ;PICK UP THE SENDER'S NODE NAME
$CALL S%SIXB ;CHANGE IT TO SIXBIT
CAME S2,.LSNME(LIS) ;COMPARE WITH EXPECTED NODE NAME
JRST ACCEP3 ;NOT THE SAME, REJECT THIS REQUEST
;CHECK IF THE SENDER'S NAME IS VALID
MOVE S1,.LSJFN(LIS) ;PICK UP THE SRV: DEVICE JFN
MOVEI S2,.MORUS ;WANT THE SENDER'S USER NAME
HRROI T1,.LSUSR(LIS) ;WHERE TO PLACE THE USER NAME
MTOPR% ;PICK UP THE USER NAME
ERJMP ACCEP4 ;[6021]CHECK THE STATE OF THE LINK
HRROI S1,.LSSNE(LIS) ;POINT TO THE EXPECTED SENDER'S NAME
HRROI S2,.LSUSR(LIS) ;POINT TO THE SENDER'S NAME
$CALL S%SCMP ;COMPARE THE TWO NAMES
SKIPE S1 ;ARE THE NAMES THE SAME?
JRST ACCEP3 ;NO, SO REJECT THIS REQUEST
;CHECK THE OCTAL DATA FIELD
;**;[6037]Add the following:
;Check whether there is a PASSWORD with the connect initiate message.
;If there is a PASSWORD then we know that the remote node can handle the new
;message format. Include this inform in the node database.
MOVE S1,.LSJFN(LIS) ;[6037]Pick up the SRV: device JFN
MOVEI S2,.MORPW ;[6037]Want the PASSWORD
MOVE T1,[POINT 7,PASSWD] ;[6037]WHERE TO PLACE THE OCTAL DATA
MTOPR% ;[6037]Pick up the PASSWORD
ERJMP ACCEP4 ;[6037CRASH IF CAN'T OBTAIN INFORMATION
JUMPE T2,ACCEP7 ;[6037]NO PASSWORD
;Set a bit in the node data base to say that it is post field image
MOVE S1,.LSNTA(LIS) ;[6037]GET THE NODE ENTRY ADDRESS
MOVX S2,NN%PAS ;[6037]GET THE BIT
IORM S2,.NNSTA(S1) ;[6037]SET IT
;THE SENDER HAS PASSED THE VALIDITY CHECKS. ACCEPT THE DECNET CONNECTION
;REQUEST, NOTIFY THE TOP FORK OF THE CONNECTION AND NOTIFY ORION OF THE
;CONNECTION.
ACCEP7: MOVE S1,.LSJFN(LIS) ;[6037]PICK UP SRV: DEVICE JFN
MOVEI S2,.MOCC ;THE CONNECTION WILL BE ACCEPTED
SETZB T1,T2 ;NO OPTIONAL DATA
MTOPR% ;ACCEPT THE CONNECTION
ERJMP ACCEP4 ;[6021]CHECK THE STATE OF THE LINK
MOVE S1,.LSNTA(LIS) ;PICK UP NODE TABLE ENTRY ADDRESS
MOVX S2,NL%NRH ;INDICATE HAVE A CONNECTION
IORM S2,.NLSTA(S1) ;PLACE IN THE STATUS WORD
MOVEI S1,.FHSUP ;PICK UP THE TOP FORK'S HANDLE
MOVX S2,<1B3> ;ON THIS CHANNEL
IIC% ;TELL THE TOP FORK OF THE CONNECTION
ERJMP S..LCI ;CRASH IS CAN'T INTERRUPT TOP FORK
$WTOJ (<DECnet connection accepted>,<NEBULA's listener has accepted a DECnet connection from
node ^N/.LSNME(LIS)/>,,<$WTFLG(WT.SJI)>)
$DEBRK ;RETURN TO THE PREVIOUS CONTEXT
;THE SENDER'S DECNET CONNECTION REQUEST HAS BEEN DENIED OR AN ERROR HAS
;OCCURRED. REJECT
;CONNECTION, INDICATE THAT THE CONNECTION HAS BEEN REJECTED IN THE LISTENER'S
;STATUS WORD IN THE NODE TABLE ENTRY AND INFORM ORION OF THE REJECTION.
ACCEP3: MOVE S1,.LSJFN(LIS) ;PICK UP THE SRV: DEVICE JFN
MOVEI S2,.MOCLZ ;WILL REJECT THIS REQUEST
SETZB T1,T2 ;NO OPTIONAL DATA
MTOPR% ;REJECT THE REQUEST
ERJMP ACCEP4 ;[6021]CHECK THE STATE OF THE LINK
$WTOJ (<DECnet connection rejected>,<DECnet connection from node ^N/.LSNME(LIS)/ rejected>,,<$WTFLG(WT.SJI)>)
$DEBRK ;RETURN TO THE PREVIOUS CONTEXT
;A MTOPR% ERROR HAS OCCURRED. CLOSE THE JFN WITH ABORT AND RE-OPEN IT.
ACCEP4: MOVE S1,.LSJFN(LIS) ;[6021]PICK UP THE SRV: DEVICE JFN
CLOSF% ;[6021]CLOSE THE SRV: DEVICE
ERJMP ACCEP5 ;[6021]GIVE UP ON AN ERROR
$CALL LOPLNK ;[6021]RE-OPEN THE LINK
$DEBRK ;[6021]RETURN TO THE PREVIOUS CONTEXT
ACCEP5: $CALL INLCRH ;[6021]INDICATE A CONTROLLED CRASH
$STOP (CVC, LISTENER CAN'T VALIDATE A CONNECTION REQUEST) ;[6021]
SUBTTL MSGFSN - DECNET MESSAGE FROM SENDER IS AVAILABLE
;MSGFSN is the interrupt handler for processing DECnet messages from the
;sender. If the top fork is not busy and the listener message queue is
;empty, then the DECnet message is transferred to the listener message
;buffer and the top fork is notified. If the top fork is not busy and
;the listener message queue is not empty, then the message is placed on
;the end of the queue. The first message in the listener message queue
;is transferred to the listener message buffer and the top fork is notified.
;If the top fork is busy, then the message is placed on the message queue.
;Upon picking up the message the listener ACKs the remote sender.
;
;Call is: LIS/Address of the listener block
;Returns: The message has been processed
;Crashes: The link status cannot be obtained, the link is no longer connected,
; the message cannot be picked up, or the top fork cannot be notified
MSGFSN: $BGINT 1,
;CHECK IF THERE IS A MESSAGE
MOVE S1,.LSJFN(LIS) ;PICK UP THE SRV: DEVICE JFN
SIBE% ;IS THERE A MESSAGE?
JRST MSGFS1 ;YES, PICK IT UP
;CHECK FOR A SPURIOUS INTERRUPT
MOVE S1,.LSJFN(LIS) ;PICK UP THE SRV DEVICE JFN
MOVEI S2,.MORLS ;WANT TO CHECK THE LINK STATUS
MTOPR% ;PICK UP THE LINK STATUS
ERJMP [$CALL INLCRH ;INDICATE A CONTROLLED CRASH
JRST S..COL ] ;CAN'T OBTAIN THE LINK STATUS
MOVEM T1,.LSLNK(LIS) ;SAVE THE LINK STATUS
TXNE T1,MO%CON ;LINK STILL CONNECTED?
JRST MSGFS5 ;YES, A SPURIOUS INTERRUPT OCCURRED
JRST MSGFS6 ;NO, TELL ORION AND THEN CRASH
;CHECK IF THE TOP FORK IS READY TO PICK UP THE MESSAGE. IF IT IS AND THE
;MESSAGE QUEUE IS EMPTY, THEN PLACE THE MESSAGE IN THE MESSAGE BUFFER
MSGFS1: SKIPL .LSAVA(LIS) ;IS THE TOP FORK FREE?
JRST MSGFS4 ;NO, SO PLACE MESSAGE ON MESSAGE QUEUE
SKIPE .LSUSM(LIS) ;IS THE MESSAGE QUEUE EMPTY?
JRST MSGFS3 ;NO, PLACE MESSAGE ON MESSAGE QUEUE
MOVE S1,.LSJFN(LIS) ;PICK UP THE SRV: DEVICE JRN
MOVE S2,.LSMSG(LIS) ;PICK UP THE MESSAGE BUFFER ADDRESS
HRLI S2,(POINT 36) ;MAKE IT INTO A POINTER
MOVNI T1,PAGSIZ ;ASSUME MAXIMUM (DON'T TRUST SIBE%)
SINR% ;PICK UP THE MESSAGE
ERJMP [$CALL INLCRH ;INDICATE CRASH IN NODE STATUS WORD
JRST S..LUP ] ;SENDER UNABLE TO PICK UP MESSAGE
;SEND AN ACK TO THE SENDER AND INTERRUPT THE TOP FORK THAT A MESSAGE IS
;AVAILABLE
$CALL SENACK ;SEND THE ACK MESSAGE
MOVEI S1,.FHSUP ;PICK UP TOP FORK'S HANDLE
MOVX S2,<1B0> ;CHANNEL TO INTERRUPT ON
SETZM .LSAVA(LIS) ;INDICATE THAT THE TOP FORK IS BUSY
IIC% ;INTERRUPT THE TOP FORK
ERJMP [$CALL INLCRH ;INDICATE A CONTROLLED CRASH
JRST S..LCI ] ;CANNOT INTERRUPT THE TOP FORK
JRST MSGFS5 ;RETURN TO THE PREVIOUS CONTEXT
;THE TOP FORK IS FREE, BUT THE MESSAGE QUEUE IS NOT EMPTY. OBTAIN A PAGE
;FOR THE MESSAGE AND PICK IT UP. PLACE THE MESSAGE ON THE MESSAGE QUEUE.
;MOVE THE FIRST MESSAGE FROM THE MESSAGE QUEUE TO THE MESSAGE BUFFER AND
;INTERRUPT THE TOP FORK.
MSGFS3: $CALL GETSMG ;PICK UP THE MESSAGE AND QUEUE IT
$CALL XFRTOP ;PLACE A MSG IN MSG BUFFER, INFORM T.F.
JRST MSGFS5 ;RETURN TO THE PREVIOUS CONTEXT
;THE TOP FORK IS NOT FREE. IF THE MESSAGE IS VALID, THEN PLACE ON THE MESSAGE
;QUEUE.
MSGFS4: $CALL GETSMG ;PICK UP THE MESSAGE AND QUEUE IT
MSGFS5: $DEBRK ;RETURN TO THE PREVIOUS CONTEXT
;THE LINK IS NO LONGER CONNECTED. INFORM ORION OF THIS AND THEN CRASH
MSGFS6: $WTOJ (<NEBULA lost connection>,<NEBULA's listener to node ^N/.LSNME(LIS)/ has lost its DECnet connection>,,<$WTFLG(WT.SJI)>)
$CALL INLCRH ;INDICATE CRASH IN NODE STATUS WORD
HALTF ;CRASH
SUBTTL GETSMG - PICK UP MESSAGE FROM SENDER AND PLACE ON MESSAGE QUEUE
;GETSMG is called when a message is available from the sender and the
;listener's message queue is not empty. The message is picked up,
;placed on the message queue and an ACK message is sent to the sender.
;
;Call is: LIS/Address of the listener block
;Returns: The message has been placed on the message queue.
GETSMG: $SAVE <T1,T2> ;SAVE THESE AC
;PICK UP THE MESSAGE AND VALIDATE IT
$CALL GETPAG ;PICK UP A PAGE FROM MEMORY MANAGER
MOVE S2,MO ;PICK UP THE PAGE ADDRESS
HRLI S2,(POINT 36,) ;MAKE IT INTO A POINTER
MOVE S1,.LSJFN(LIS) ;PICK UP SRV: DEVICE JFN
MOVNI T1,PAGSIZ ;PICK UP MAXIMUM MESSAGE SIZE
SINR% ;PICK UP THE MESSAGE
ERJMP [$CALL INLCRH ;INDICATE CRASH IN NODE STATUS WORD
JRST S..LUP ] ;SENDER UNABLE TO PICK UP MESSAGE
;PLACE THE MESSAGE ON THE MESSAGE QUEUE AND ACK THE SENDER
$CALL ADDLME ;PLACE MESSAGE ON THE MESSAGE QUEUE
$CALL SENACK ;ACK THE SENDER
$RET ;RETURN TO THE CALLER
SUBTTL MSGTTF - TOP FORK READY FOR A MESSAGE FROM A LISTENER
;MSGTTF is the interrupt handler used when the top fork is free to process
;another message from the listener. MSGTTF first checks if the top fork
;is busy. (This can happen if a "DECnet message from the sender" interrupt
;happens to occur between the time the top fork has set its free to process
;a message flag (.LSAVA) and the time it interrupts the listener on this
;channel. The interrupt routine MSGFSN, in this case, detects that the top
;fork is not busy. MSGFSN then places a message in the message buffer, changes
;the state of the top fork to busy and interrupts the top fork.)
;If the top fork is not busy, then MSGTTF checks if the listener message
;queue is empty. If it is, then it quits, otherwise, it moves a message
;from the message queue to the listener message buffer and interrupts the
;top fork.
;
;Call is: LIS/Address of the listener block
;Returns: A message, if there is one and if the top fork is not busy,
; has been placed in the message buffer and the top fork has
; been notified of the message
;Crashes: The top fork cannot be interrupted
MSGTTF: $BGINT 1,
SKIPL .LSAVA(LIS) ;IS THE TOP FORK BUSY?
$DEBRK ;YES, SO QUIT NOW
SKIPN .LSUSM(LIS) ;NO, IS MESSAGE QUEUE EMPTY?
$DEBRK ;YES, SO QUIT NOW
$CALL XFRTOP ;GIVE A MESSAGE TO THE TOP FORK
$DEBRK ;RETURN TO THE PREVIOUS CONTEXT
SUBTTL XFRTOP - MOVE MESSAGE FROM MESSAGE QUEUE TO MESSAGE BUFFER
;XFRTOP is called to transfer a message from the listener's message queue
;to its message buffer and then to interrupt the top fork that there is
;a message available for it to process. The message is then deleted from
;the message queue.
;
;Call is: LIS/Address of the listener block
;Returns: A message has been placed in the listener buffer and the top
; fork has been notified
;Crashes: Unable to interrupt the top fork
;MOVE THE MESSAGE FROM THE MESSAGE QUEUE TO THE MESSAGE BUFFER
XFRTOP: MOVE S1,.LSHWD(LIS) ;PICK UP MESSAGE QUEUE INDEX
$CALL L%FIRST ;PICK UP ADDRESS OF THE MESSAGE
MOVE S1,S2 ;PLACE ADDRESS WHERE EXPECTED
MOVE S2,.LSMSG(LIS) ;PICK UP ADDRESS OF THE MESSAGE BUFFER
$CALL XFRMSG ;MOVE THE MESSAGE TO MESSAGE BUFFER
;INTERRUPT THE TOP FORK THAT A MESSAGE IS AVAILABLE
MOVEI S1,.FHSUP ;PICK UP THE TOP FORK'S HANDLE
MOVX S2,<1B0> ;INTERRUPT IT ON THIS CHANNEL
SETZM .LSAVA(LIS) ;TOP FORK IS NOW BUSY
IIC% ;INTERRUPT THE TOP FORK
ERJMP [$CALL INLCRH ;INDICATE A CONTROLLED CRASH
JRST S..LCI ] ;CANNOT INTERRUPT THE TOP FORK
;DELETE THE MESSAGE QUEUE ENTRY
$CALL RELLME ;DELETE THE MESSAGE QUEUE ENTRY
$RET ;RETURN TO THE CALLER
SUBTTL ADDLME - ADD A LISTENER MESSAGE QUEUE ENTRY
;ADDLME is called to add a message to the listener's message queue. The
;message queue is a link list of the messages that need to be picked up
;by the top fork.
;
;Call is: LIS/Address of the listener block
; MO/Address of the message page
;Returns: The message has been added to the listener's message queue
;ADD THE MESSAGE TO THE LISTENER'S MESSAGE QUEUE
ADDLME: MOVE S1,.LSHWD(LIS) ;PICK UP THE MESSAGE QUEUE INDEX
$CALL L%LAST ;POSITION TO THE LAST ENTRY
SKIPT ;IS THE MESSAGE QUEUE EMPTY?
MOVE S1,.LSHWD(LIS) ;YES, PICK UP MESSAGE QUEUE INDEX
LOAD S2,.MSTYP(MO),MS.CNT ;PICK UP THE LENGTH OF THE MESSAGE
$CALL L%CENT ;CREATE A MESSAGE QUEUE ENTRY
MOVE S1,MO ;PICK UP THE MESSAGE ADDRESS
$CALL XFRMSG ;COPY THE MESSAGE INTO THE MSG QUEUE
AOS .LSUSM(LIS) ;INCREMENT THE MESSAGE COUNT
MOVE S1,MO ;PICK UP THE MESSAGE ADDRESS
$CALL M%RPAG ;RELEASE THE MESSAGE PAGE
$RET ;RETURN TO THE CALLER
SUBTTL RELLME - DELETE AN ENTRY FROM THE LISTENER MESSAGE QUEUE
;RELLME is called to delete the first message from the listener message
;queue.
;
;Call is: LIS/Address of the listener block
;Returns: The message has been removed from the listener's message queue
; and the message page returned to the memory manager
RELLME:
;RETURN THE MESSAGE PAGE TO THE MEMORY MANAGER
MOVE S1,.LSHWD(LIS) ;PICK UP THE MESSAGE QUEUE INDEX
$CALL L%DENT ;RETURN THE MESSAGE QUEUE ENTRY
$CALL L%NEXT ;MAKE THE NEXT ENTRY THE FIRST ENTRY
SOS .LSUSM(LIS) ;DECREMENT THE NUMBER OF MESSAGES
$RET ;RETURN TO THE CALLER
SUBTTL LISCHK - LISTENER CHECKSUM AND ACK MESSAGE
repeat 0,<
;LISCHK is called when the listener has picked up a message. If checksumming
;is enabled on the sender's node and the listener's node, then a checksum of
;the message is performed. If the sender's and listener's checksums agree,
;then a success ACK message is sent to the sender. If the checksums do not
;agree, then a failure ACK message is sent.
;If checksumming is disabled, either on the sender's node or the listener's
;node, then a checksum is not performed and a success ACK message is sent
;to the sender.
;
;Call is: S1/Address of the message
;Returns true: The checksums match and a success ACK has been sent to the
; sender.
;Returns false: The checksums do not match and a failure ACK has been sent
; to the sender.
LISCHK: $SAVE <P1> ;SAVE THIS AC
SKIPN CHKSUMO ;CHECKSUMMING ENABLED ON LOCAL NODE?
JRST LISCH2 ;NO, SEND A SUCCESS ACK BACK TO SENDER
SKIPN P1,.MSCHS(S1) ;YES, CHECKSUMMING ENABLED REMOTELY?
JRST LISCH2 ;NO, SEND A SUCCESS ACK BACK TO SENDER
SETZM .MSCHS(S1) ;ZERO OUT THE CHECKSUM WORD
$CALL CHKSUM ;CALCULATE THE CHECKSUM
CAME P1,S1 ;DO THE CHECKSUMS AGREE?
JRST LISCH3 ;NO, SEND FAILURE ACK TO SENDER
LISCH2: $CALL ACKSUC ;SEND A SUCCESS ACK TO SENDER
$RETT ;INDICATE MESSAGE IS VALID
LISCH3: $CALL ACKFAI ;SEND A FAILURE ACK TO SENDER
$RETF ;INDICATE MESSAGE IS INVALID
>; end of repeat 0
SUBTTL SENACK - SEND AN ACK MESSAGE TO THE REMOTE SENDER
;SENACK is called to send an ACK to the sender upon receipt of a
;message from the sender.
;
;Call is: LIS/Address of the listener block
;Returns: The ACK message was sent
;Crashes: The ACK message could not be sent
SENACK: $SAVE <T1,T2> ;SAVE THESE AC
SETO T1, ;NEGATIVE LENGTH OF THE ACK MESSAGE
MOVE S1,.LSJFN(LIS) ;PICK UP SRV: DEVICE JFN
MOVEI S2,T1 ;ADDRESS OF THE MESSAGE
HRLI S2,(POINT 36,) ;MAKE IT INTO A POINTER
SOUTR% ;SEND THE MESSAGE TO THE SENDER
ERJMP ACKSU3 ;CRASH ON AN ERROR
$RET ;RETURN TO THE CALLER
ACKSU3: $CALL INLCRH ;INDICATE A CONTROLLED CRASH
$STOP (LUA, LISTENER UNABLE TO SEND AN ACK MESSAGE)
SUBTTL INLCRH - ROUTINE TO INDICATE LISTENER CONTROLLED CRASH
;INLCRH is called by the listener when it has detected a fatal error.
;INLCRH indicates in the node table entry's listener status word
;that the listener was aware it was going to crash. A RESET% is
;also performed to break the DECnet link.
;
;Call is: LIS/Address of the listener block
;Returns: Bit NL%LFC is set in the node entry's listener status word
;SET THE CONTROLLED LISTENER CRASH BIT IN THE NODE TABLE'S LISTENER STATUS WORD
INLCRH: DMOVEM S1,.LSERR(LIS) ;SAVE THE CONTEXT OF S1 AND S2
MOVE S1,.LSNTA(LIS) ;PICK UP THE NODE TABLE ENTRY
MOVX S2,NL%LFC ;PICK UP LISTENER FORK CRASHED BIT
IORM S2,.NLSTA(S1) ;INDICATE THAT THE LISTENER HAS CRASHED
MOVX S2,NN%IFC ;AN INFERIOR FORK HAS CRASHED
IORM S2,.NNSTA(S1) ;INDICATE IN THE NODE STATUS WORD
RESET% ;BREAK THE DECNET LINK
DMOVE S1,.LSERR(LIS) ;RESTORE CONTEXT OF S1 AND S2
$RET ;RETURN TO THE CALLER
SUBTTL SENDER - MESSAGE ROUTER TO A REMOTE NODE
;SENDER exists as an inferior fork in NEBULA. A sender is started for
;every remote node known to NEBULA that is running a release 7 or later
;monitor and which has DECnet enabled. A sender sends messages to a remote
;node's listener. The messages are of two types:
;1. Requests to be processed on the remote node.
;2. Responses to requests that originated on the remote node and were processed
; on the local node.
;A sender communicates with the top fork through software interrupts,
;the sender block and the node's status words in its node table entry.
;SYMBOL DEFINITIONS
MINTIM==5 ;MIN TIME BETWEEN CONNECTION ATTEMPTS
MAXTIM==5*^D60 ;MAX TIME BETWEEN CONNECTION ATTEMPTS
;INITIALIZATION BLOCK AND PID BLOCK
SIB: $BUILD IB.SZ ;
$SET (IB.PRG,,%%.MOD) ;PROGRAM 'NEBULA'
$SET (IB.FLG,IP.STP,1) ;STOPCODES TO ORION
$EOB ;
SPIB: $BUILD PB.MNS ;
$SET (PB.HDR,PB.LEN,PB.MNS) ;PIB LENGTH,,0
$SET (PB.FLG,IP.RSE,1) ;RETURN ON SEND ERROR
$SET (PB.SYS,IP.BQT,-1) ;MAXIMUM SEND/RECEIVE IPCF QUOTA
$SET (PB.SYS,IP.MNP,^D1) ;NUMBER OF PIDS
$EOB ;
SNDCHN: XWD 1,MSGTLI ;MESSAGE AVAILABLE TO SEND TO LISTENER
XWD 1,MSGFLI ;ACK MESSAGE FROM LISTENER
XWD 1,REPCON ;ENABLE DECNET-CONNECTION-ATTEMPTS
BLOCK ^D33 ;NO OTHER CHANNELS IN USE
;SENDER STARTUP CONSISTS OF SETTING UP GLXLIB AND CAPABILITIES, THE
;INTERRUPT SYSTEM AND CONNECTING TO THE REMOTE NODE'S LISTENER.
SENDER: SKIPE DEBUGW ;DEBUGGING?
$CALL NEBDDT ;YES, SET UP FOR DEBUGGING
$CALL SENSET ;SET UP GLXLIB AND CAPABILITIES
$CALL SENINT ;SET UP THE INTERRUPT SYSTEM
$CALL SOPLNK ;OPEN A CONNECTION TO THE LISTENER
;INFORM THE TOP FORK THAT A DECNET CONNECTION HAS BEEN OBTAINED. WAIT
;FOR ANY MESSAGES TO BE SENT TO THE LISTENER.
$CALL SENCON ;INFORM TOP FORK OF CONNECTION
SENDE2: SETZ S1, ;SLEEP UNTIL NEEDED
$CALL I%SLP ;WAIT%
JRST SENDE2 ;WAIT FOR SOMETHING ELSE TO DO
SUBTTL SENSET - INITIALIZE THE SENDER'S GLXLIB AND CAPABILITIES
;SENSET is called by the sender at sender startup. This routine sets up
;GLXLIB, the sender's capabilities and disables the sender from receiving
;any IPCF messages.
;
;Call is: SEN/Address of the sender block
;Returns: GLXLIB setup and capabilities enabled
;Crashes: Unable to set up capabilities
SENSET: $SAVE <T1,T2> ;SAVE THESE AC, DESTROYED BY JSYS
;SET UP THE GLXLIB INITIALIZATION BLOCK IN THE SENDER BLOCK
MOVSI S1,SIB ;PICK UP ADDRESS OF THE IB BLOCK
HRRI S1,.SNIBK(SEN) ;ADDRESS OF WHERE TO PLACE THE IB BLOCK
MOVEI S2,.SNIBK+IB.SZ(SEN) ;END ADDRESS + 1
BLT S1,-1(S2) ;MOVE THE IB BLOCK TO SENDER BLOCK
MOVEI S1,.SNPIB(SEN) ;PICK UP THE ADDRESS OF THE PIB BLOCK
MOVEM S1,.SNIBK+IB.PIB(SEN) ;PLACE IN THE INITIALIZATION BLOCK
MOVSI S1,.SNLEV(SEN) ;ADDRESS OF THE INTERRUPT LEVEL TABLE
HRRI S1,SNDCHN ;ADDRESS OF THE CHANNEL TABLE
MOVEM S1,.SNIBK+IB.INT(SEN) ;PLACE IN THE INITIALIZATION BLOCK
;SET UP THE PID BLOCK AND THE INTERRUPT LEVEL TABLE IN THE SENDER BLOCK
MOVSI S1,SPIB ;PICK UP ADDRESS OF THE PID BLOCK
HRRI S1,.SNPIB(SEN) ;DESTINATION IS IN THE SENDER BLOCK
MOVEI S2,.SNPIB+PB.MNS(SEN) ;END ADDRESS + 1
BLT S1,-1(S2) ;MOVE PID TABLE TO SENDER BLOCK
MOVEI S1,.SNLEV(SEN) ;PICK UP ADR OF INTERRUPT LEVEL TABLE
MOVEI S2,.SN1PC(SEN) ;PICK UP ADR OF FIRST PC WORD
MOVEM S2,0(S1) ;PLACE PC ADR IN INTERRUPT LEVEL TABLE
AOS S1 ;ADDRESS OF NEXT INTERRUPT LEVEL ENTRY
AOS S2 ;ADDRESS OF THE NEXT PC WORD
MOVEM S2,0(S1) ;PLACE PC ADR IN INTERRUPT LEVEL TABLE
AOS S1 ;ADDRESS OF NEXT INTERRUPT LEVEL ENTRY
AOS S2 ;ADDRESS OF THE NEXT PC WORD
MOVEM S2,0(S1) ;PLACE PC ADR IN INTERRUPT LEVEL TABLE
;SET UP GLXLIB
MOVEI S1,IB.SZ ;PICK UP SIZE OF THE INITIALIZATION BLK
MOVEI S2,.SNIBK(SEN) ;PICK UP ADR OF THE INITIALIZATION BLK
$CALL I%INIT ;INITIALIZE GLXLIB
;ENABLE THE SENDER'S CAPABILITIES TO BE THOSE OF THE TOP FORK AND GIVE IT
;THE CAPABILITY TO INTERRUPT THE TOP FORK.
MOVX S1,.FHSLF ;PICK UP THE SENDER'S HANDLE
RPCAP%
ERJMP [$CALL INSCRH ;INDICATE A CONTROLLED CRASH
$STOP(SCC,Sender can't obtain capabilities) ]
TXO S2,SC%SUP ;CAPABILITY TO INTERRUPT TOP FORK
MOVE T1,S2 ;ENABLE ALL CAPABILITIES
MOVEI S1,.FHSLF ;PICK UP THE SENDER'S HANDLE
EPCAP% ;ENABLE THE CAPABILITIES
ERJMP [$CALL INSCRH ;INDICATE A CONTROLLED CRASH
$STOP(SCE,Sender can't enable capabilities) ]
;DISABLE RECEIVING IPCF MESSAGES
MOVEI S1,.MUDIS ;DISABLE RECEIVING IPCF MESSAGES
MOVEM S1,.SNMUT(SEN) ;PLACE IN THE ARGUMENT BLOCK
MOVE S1,.SNPIB+PB.PID(SEN) ;PICK UP SENDER'S PID
MOVEM S1,.SNMUT+1(SEN) ;PLACE IN THE ARGUMENT BLOCK
MOVEI S1,2 ;PICK UP SIZE OF ARGUMENT BLOCK
MOVEI S2,.SNMUT(SEN) ;PICK ADDRESS OF THE ARGUMENT BLOCK
MUTIL% ;DISABLE RECEIVING IPCF MESSAGES
ERJMP .+1 ;SHOULDN'T HAPPEN, BUT DON'T CARE
$RET ;RETURN TO STARTUP
SUBTTL SENINT - SET UP THE SENDER'S INTERRUPT SYSTEM
;SENINT is called by the sender during sender startup. SENINT sets up
;the sender's interrupt system.
;
;Call is: SEN/Address of the sender block
;Returns: The interrupt system has been set up
;Crashes: The interrupt system could not be set up
SENINT: $SAVE <T1,T2> ;SAVE THESE AC, DESTROYED BY JSYS
;FIRST DISABLE AND THEN CLEAR THE INTERRUPT SYSTEM
MOVEI S1,.FHSLF ;PICK UP THE SENDER'S HANDLE
SETO S2, ;INDICATE DISABLE ALL 36 CHANNELS
DIC% ;DISABLE THE CHANNELS
ERJMP .+1 ;SHOULDN'T HAPPEN, BUT IGNORE
CIS% ;CLEAR THE INTERRUPT SYSTEM
ERJMP .+1 ;SHOULDN'T HAPPEN, BUT IGNORE
MOVEI S1,.FHSLF ;PICK UP THE SENDER'S HANDLE
HRLI S2,.SNLEV(SEN) ;PICK UP INTERRUPT LEVEL TABLE ADDRESS
HRRI S2,SNDCHN ;PICK UP CHANNEL TABLE ADDRESS
SIR% ;SET UP THE INTERRUPT TABLE ADDRESSES
ERJMP SENIN2 ;CRASH IF CAN'T SET UP
MOVEI S1,.FHSLF ;PICK UP THE SENDER'S HANDLE
EIR% ;ENABLE THE INTERRUPT SYSTEM
ERJMP SENIN2 ;CRASH IF CAN'T ENABLE INTERRUPT SYSTEM
MOVEI S1,.FHSLF ;PICK UP THE SENDER'S HANDLE
MOVX S2,1B0+1B1+1B2 ;PICK UP CHANNELS TO ACTIVATE
AIC% ;ACTIVATE THE CHANNELS
ERJMP SENIN2 ;CRASH IF CAN'T ACTIVATE THE CHANNELS
$RETT ;RETURN TO SENDER STARTUP
SENIN2: $CALL INSCRH ;INDICATE A CONTROLLED CRASH
JRST S..CSI ;CANNOT SET UP INTERRUPT SYSTEM
SUBTTL SOPLNK - OBTAIN A CONNECTION TO THE LISTENER
;SOPLNK is called during the sender's startup to open a DECnet connection
;to the remote node's listener. If a connection cannot be obtained, then
;SOPLNK will re-attempt to open the connection after a specified amount
;of time. Initially, the time between retries is MINTIM seconds. If
;after MAXTIM seconds a connection is still not obtained, then SOPLNK
;informs ORION. The time between retries is increased by MINTIM seconds
;and a connection is again attempted. This will continue until either
;a connection is obtained or until the time between retries is MAXTIM
;seconds. At this point, SOPLNK attempts to obtain a connection every
;MAXTIM seconds.
;It is possible for an operator to suppress SOPLNK from sending
;connection failure messages (and to later re-enable SOPLNK to send
;connection failure messages).
;It is also possible for an operator to cause SOPLNK to cease attempting
;to open a connection. An operator may also cause the sender to later
;re-attempt to open a connection.
;
;Call is: SEN/Address of the sender block
;Returns: Only if the connection has been obtained
;Crashes: Unable to obtain a DECnet JFN or open the DECnet link
SOPLNK: $SAVE <T1,T2,P1,P2,P3> ;SAVE THESE AC
;INITIALIZE THE ATTEMPT TO OBTAIN A DECNET CONNECTION TO THE LISTENER
MOVE P1,.SNNTA(SEN) ;PICK UP THE NODE TABLE ENTRY ADDRESS
MOVEI P2,MINTIM ;PICK UP INITIAL TIME BETWEEN RETRIES
SETZ P3, ;NUMBER OF ATTEMPTS TO OBTAIN THE LINK
;ATTEMPT TO OBTAIN THE DECNET CONNECTION. FIRST CHECK IF ATTEMPTS TO OBTAIN
;A CONNECTION ARE TO BE ABORTED.
SOPLN2: MOVE S1,.NNSTA(P1) ;PICK UP NODE STATUS WORD
TXNE S1,NN%CCA ;CEASE CONNECTION ATTEMPTS?
JRST SOPLN5 ;YES, QUIT TRYING
SKIPN .SNJFN(SEN) ;CURRENTLY HAVE A DECNET JFN?
$CALL SGTLNK ;NO, OBTAIN ONE AND OPENF
;CHECK THE STATUS OF THE LINK. IF THERE IS A CONNECTION, THEN ENABLE
;FOR DATA AVAILABLE INTERRUPTS.
$CALL SCKLNK ;CHECK THE LINK STATUS
JUMPF SOPLN3 ;DON'T HAVE A CONNECTION
MOVE S1,.SNJFN(SEN) ;PICK UP THE DECNET JFN
MOVEI S2,.MOACN ;PICK UP ACTIVATE FUNCTION
MOVX T1,<FLD(1,MO%DAV)+FLD(.MONCI,MO%CDN)+FLD(.MONCI,MO%INA)>
MTOPR% ;ENABLE FOR DATA AVAILABLE INTERRUPTS
ERJMP [ $CALL INSCRH ;INDICATE CONTROLLED CRASH
JRST S..CSI ] ;CAN'T ENABLE INTERRUPT SYSTEM
$WTOJ (<DECnet connection approved>,<NEBULA's sender has established communication to node ^N/.SNNME(SEN)/>,,<$WTFLG(WT.SJI)>)
$RETT ;RETURN TO SENDER STARTUP
;UNABLE TO OBTAIN THE CONNECTION. DETERMINE IF THE RETRY SHOULD BE INCREASED.
SOPLN3: AOS T1,P3 ;INCREMENT # TRIES AT THIS TIME INTERVAL
IMUL T1,P2 ;TIME BEEN TRYING AT THIS TIME INTERVAL
CAIGE T1,MAXTIM ;TIME TO INCREMENT THE TIME INTERVAL?
JRST SOPLN6 ;NO, DISMISS AND TRY AGAIN
;INCREMENT THE TIME BETWEEN RETRIES. FIRST CHECK IF THE CONNECTION FAILURE
;SHOULD BE REPORTED TO ORION. IF SO, THEN REPORT THE CONNECTION FAILURE.
MOVE S1,.NNSTA(P1) ;PICK UP THE NODE STATUS WORD
TXNE S1,NN%DCO ;NOTIFY ORION OF THE FAILURE?
JRST SOPLN4 ;NO, PICK UP NEW TIME INTERVAL
$CALL FNDCER ;GET THE CONNECTION ERROR
$WTOJ (<Sender connection failure>,<^I/@SOPLN7/^M^J^I/@SOPLN8/>,,<$WTFLG(WT.SJI)>)
;CALCULATE THE NEW TIME INTERVAL BETWEEN CONNECTION ATTEMPTS. THE MAXIMUM
;TIME BETWEEN RETRIES IS MAXTIM SECONDS.
SOPLN4: ADDI P2,MINTIM ;INCREMENT THE RETRY INTERVAL
CAILE P2,MAXTIM ;TIME INTERVAL AT A MAXIMUM?
MOVEI P2,MAXTIM ;YES, SET TO MAXIMUM
SKIPA ;DISMISS AND THEN TRY AGAIN
;AN OPERATOR HAS INDICATED THAT THE SENDER IS TO CEASE RETRYING TO
;OBTAIN A DECNET LINK TO THE LISTENER
SOPLN5: SETZ P2, ;DON'T RETRY TO GET A CONNECTION
;DISMISS UNTIL INDICATED
SETZ P3, ;NUMBER OF ATTEMPTS AT THIS INTERVAL
SOPLN6: MOVE S1,P2 ;PICK UP TIME TO DISMISS
$CALL I%SLP ;DISMISS OR WAIT% AS INDICATED
SKIPN P2 ;OPERATOR ENABLED CONNECTION ATTEMPTS?
MOVEI P2,MINTIM ;YES, START AT MINIMUM RETRY INTERVAL
JRST SOPLN2 ;ATTEMPT THE CONNECTION AGAIN
SOPLN7: [ITEXT(<NEBULA sender to node ^N/.NNNAM(P1)/ has not been able to obtain a
DECnet connection>)]
SOPLN8: [ITEXT(<Reason for failure: ^T/0(S1)/>)]
SUBTTL SGTLNK - OBTAIN DECNET JFN AND OPEN IT
;SGTLNK is called by routine SOPLNK to obtain a DECnet JFN to the remote
;node's listener and to open the connection
;
;Call is: SEN/Address of the sender block
;Returns: The JFN has been obtained and opened
SGTLNK: $SAVE <T1,T2,T3> ;[6002]SAVE THESE AC, DESTROYED BY JSYS
;GET THE JFN AND OPEN IT
MOVX S1,GJ%SHT ;SHORT JFN
HRROI S2,.SNDCN(SEN) ;PICK UP DECNET FILE NAME
GTJFN% ;PICK UP THE JFN
ERJMP SGTLN3 ;CRASH IF CAN'T GET JFN
HRRZS S1 ;ISOLATE THE JFN
MOVEM S1,.SNJFN(SEN) ;SAVE THE JFN IN SENDER BLOCK
MOVNI T3,^D60 ;[6002]NEGATIVE NUMBER OF OPEN TRIES
SKIPA ;[6002]ALREADY HAVE THE JFN
SGTLN1: MOVE S1,.SNJFN(SEN) ;[6002]PICK UP THE JFN
MOVX S2,<FLD(^D36,OF%BSZ)+OF%WR+OF%RD> ;OPEN FOR READ AND WRITE
OPENF% ;OPEN THE JFN
ERJMP SGTLN2 ;CRASH IF CAN'T OPEN JFN
$RET ;RETURN ON SUCCESS
SGTLN2: AOSN T3 ;[6002]TIME TO QUIT?
JRST SGTLN3 ;[6002]YES, CRASH
MOVEI S1,MINTIM ;[6002]PICK UP THE TIME TO SLEEP
$CALL I%SLP ;[6002]DISMISS FOR A WHILE
JRST SGTLN1 ;[6002]RE-ATTEMPT TO OPEN THE LINK
SGTLN3: $CALL S%ERR ;[6021]PICK UP THE ERROR STRING
JUMPF SGTLN4 ;[6021]STOPCODE ON AN UNKNOWN ERROR
$WTOJ (<Unable to obtain DECnet connection>,<Sender to node ^N/.SNNME(SEN)/ has encountered an error.
The last error is: ^T/0(S1)/>,,<$WTFLG(WT.SJI)>)
$CALL INSCRH ;[6021]INDICATE A CONTROLLED CRASH
HALTF% ;[6021]HAVE TOP FORK RESTART
SGTLN4: $CALL INSCRH ;[6021]INDICATE A CONTROLLED CRASH
$STOP (SOD, SENDER CAN'T OPEN DECNET DEVICE) ;[6021]
SUBTTL SCKLNK - CHECK THE STATUS OF THE SENDER'S LINK
;SCKLNK is called to check the status of the sender's DECnet link to
;the listener. If there is no connection, then the DECnet link is
;closed and the DECnet JFN released
;
;Call is: SEN/Address of the sender block
;Returns true: The DECnet link is connected
;Returns false: The DECnet link is waiting for a connection or there is
; no connection
;Crashes: Unable obtain the link status
SCKLNK: $SAVE <T1,T2> ;SAVE THESE AC, DESTROYED BY JSYS
;OBTAIN THE DECNET LINK STATUS.
MOVE S1,.SNJFN(SEN) ;PICK UP THE DECNET JFN
MOVEI S2,.MORLS ;WANT THE STATUS OF THE LINK
MTOPR% ;OBTAIN THE STATUS OF THE LINK
ERJMP [$CALL INSCRH ;INDICATE A CONTROLLED CRASH
JRST S..COL ] ;CANNOT OBTAIN THE LINK STATUS
MOVEM T1,.SNLNK(SEN) ;SAVE THE LINK STATUS IN SENDER BLOCK
;DETERMINE IF THE LINK IS CONNECTED. IF IT IS NOT, THEN CLOSE AND RELEASE
;THE JFN.
TXNE T1,MO%CON ;IS THE LINK CONNECTED?
$RETT ;YES, RETURN TRUE
TXNE T1,MO%WCC ;WAITING FOR A LINK?
$RETF ;YES, DON'T RELEASE THE JFN
MOVE S1,.SNJFN(SEN) ;PICK UP THE DECNET JFN
TXO S1,CZ%ABT ;CLOSE WITH ABORT
CLOSF% ;CLOSE THE DECNET LINK
ERJMP .+1 ;SHOULDN'T HAPPEN
MOVE S1,.SNJFN(SEN) ;PICK UP THE DECNET JFN AGAIN
RLJFN% ;RELEASE THE JFN
ERJMP .+1 ;SHOULDN'T HAPPEN
SETZM .SNJFN(SEN) ;INDICATE NO LONGER HAVE A JFN
$RETF ;INDICATE DON'T HAVE A LINK
SUBTTL FNDCER - DETERMINE THE DECNET CONNECTION ERROR
;FNDCER is called when a sender has not been able to make a DECnet
;connection to its listener. FNDCER finds the error text using
;the error code returned by the .MORLS function.
;
;Call is: SEN/Address of the sender block
;Returns true: A known error occurred
; S1/Address of the error string
;Returns false: An unknown error occurred
; S1/Address of unknown error string
FNDCER: $SAVE <P1> ;SAVE THIS AC
;PICK UP THE ERROR STRING USING THE ERROR CODE RETURNED BY .MORLS
HRRZ S1,.SNLNK(SEN) ;PICK UP THE ERROR CODE
MOVSI S2,-DNELEN ;PICK UP NEGATIVE LENGTH OF TABLE
FNDCE2: HLRZ P1,DNERR(S2) ;PICK UP THE ERROR CODE
CAME S1,P1 ;IS THIS THE ERROR?
AOBJN S2,FNDCE2 ;NO, CHECK THE NEXT ENTRY
SKIPL S2 ;WAS THE ENTRY FOUND?
JRST FNDCE3 ;NO, MAKE UNKNOWN ERROR
HRRZ S1,DNERR(S2) ;PICK UP ADDRESS OF ERROR TEXT
$RETT ;INDICATE A KNOWN ERROR
FNDCE3: MOVEI S1,[ASCIZ/Unknown error/] ;PICK UP ERROR ADDRESS
$RETF ;INDICATE AN UNKNOWN ERROR
DNERR:
;THE DECNET DISCONNECT CODES.
.DCX0,,[ASCIZ/Reject or disconnect by object/]
.DCX1,,[ASCIZ/Resource allocation failure/]
.DCX2,,[ASCIZ/Destination node does not exist/]
.DCX3,,[ASCIZ/Remote node shutting down/]
.DCX4,,[ASCIZ/Destination process does not exist/]
.DCX5,,[ASCIZ/Invalid process name field/]
.DCX6,,[ASCIZ/Object is busy/]
.DCX7,,[ASCIZ/Unspecified error/]
.DCX8,,[ASCIZ/Third party aborted link/]
.DCX9,,[ASCIZ/User abort (asynchronous disconnect)/]
.DCX10,,[ASCIZ/Invalid node name/]
.DCX11,,[ASCIZ/Local node shut down/]
.DCX21,,[ASCIZ/Connect initiate with illegal destination address/]
.DCX22,,[ASCIZ/Connect confirm with illegal destination address/]
.DCX23,,[ASCIZ/Connect initiate or connect confirm with zero source address/]
.DCX24,,[ASCIZ/Flow control violation/]
.DCX32,,[ASCIZ/Too many connections to node/]
.DCX33,,[ASCIZ/Too many connections to destination process/]
.DCX34,,[ASCIZ/Access not permitted/]
.DCX35,,[ASCIZ/Logical link services mismatch/]
.DCX36,,[ASCIZ/Invalid account/]
.DCX37,,[ASCIZ/Segment size too small/]
.DCX38,,[ASCIZ/No response from destination, process aborted/]
.DCX39,,[ASCIZ/No path to destination node/]
.DCX40,,[ASCIZ/Link aborted due to data loss/]
.DCX41,,[ASCIZ/Destination process does not exist/]
.DCX42,,[ASCIZ/Confirmation of disconnect initiate/]
.DCX43,,[ASCIZ/Image data field too long/]
DNELEN==.-DNERR ;LENGTH OF ERROR TABLE
SUBTTL SENCON - INDICATE TO TOP FORK THAT SENDER HAS A CONNECTION
;SENCON is called when the sender has obtained a DECnet connection.
;SENCON interrupts the top fork to indicate that it has obtained a DECnet
;connection.
;
;Call is: SEN/Address of the sender block
;Returns: The top fork has been informed of the sender's connection.
;Crashes: The top fork could not be interrupted.
SENCON: $SAVE <T1,T2> ;SAVE THESE AC, DESTROYED BY JSYS
;INDICATE IN THE SENDER STATUS WORD OF THE NODE TABLE ENTRY THAT THIS SENDER
;HAS A CONNECTION.
MOVE S1,.SNNTA(SEN) ;PICK UP THE NODE TABLE ENTRY ADDRESS
MOVX S2,NS%NRH ;SENDER HAS RECEIVED A HELLO
IORM S2,.NSSTA(S1) ;INDICATE IN THE STATUS WORD
MOVEI S1,.FHSUP ;PICK UP THE TOP FORK'S HANDLE
MOVX S2,<1B3> ;CHANNEL TO INTERRUPT TOP FORK ON
IIC% ;INTERRUPT THE TOP FORK
ERJMP [$CALL INSCRH ;INDICATE IT WAS A CONTROLLED CRASH
JRST S..SCI ] ;CRASH, IF CAN'T INTERRUPT TOP FORK
$RET ;RETURN TO THE CALLER
SUBTTL MSGTLI - SEND A MESSAGE TO THE LISTENER
;MSGTLI is the interrupt handler for sending messages to a listener.
;MSGTLI first checks that the link is still connected. If the link is
;still connected, then MSGTLI sends the message to the listener.
;
;Call is: SEN/Address of the sender block
;Returns: The message has been sent to the listener
;Crashes: The link is no longer connected
MSGTLI: $BGINT 1, ;SAVE THE CONTEXT
;CHECK THE STATUS, IF THE LINK IF STILL CONNECTED, THEN CHECKSUM THE
;MESSAGE AND SEND IT. IF THE LINK IS NOT CONNECTED, THEN INFORM ORION
;AND CRASH.
$CALL SCKLNK ;CHECK THE LINK STATUS
JUMPF MSGTL2 ;THE LINK IS GONE, INFORM THE OPERATOR
$CALL SSNDMG ;SEND THE MESSAGE
$DEBRK ;RETURN TO PREVIOUS CONTEXT
MSGTL2: MOVE S1,.SNNTA(SEN) ;PICK UP NODE TABLE ENTRY
$WTOJ (<Sender lost connection>,<NEBULA sender to node ^N/.NNNAM(S1)/ has lost
its DECnet connection>,,<$WTFLG(WT.SJI)>)
$CALL INSCRH ;INDICATE CRASH IN NODE STATUS WORD
JRST S..SLL ;SENDER LOST ITS LINK
SUBTTL CHKSUM - CHECKSUM DECNET MESSAGES
repeat 0,<
;CHKSUM checksums messages that the sender sends to the listener.
;The checksum is stored in the checksum word. The listener, upon
;receipt of the message, also checksums it. If the checksums agree,
;then the listener sends a success ACK back to the sender, otherwise,
;it sends an error ACK.
;If the sender's node does not have checksumming enabled, then the
;sender sends a zero as the checksum value. The listener, in this
;case, always returns a success ACK.
;If the listener's node does not have checksumming enabled, then it
;always sends a success ACK back.
;(Note: If the calculated checksum equals zero, then CHKSUM changes
; it to -1.)
;
;Call is: S1/Address of the message
;Returns true: The checksum has been calculated and placed in the message
; checksum word (.MSCHS).
; S1/Contains the checksum
CHKSUM: $SAVE <P1> ;SAVE THIS AC
;INITIALIZE THE CHECKSUM PARAMETERS
LOAD S2,.MSTYP(S1),MS.CNT ;PICK UP LENGTH OF THE MESSAGE
MOVSS S2 ;PLACE LENGTH FOR AOBJN
MOVNS S2 ;MAKE THE COUNTER
HRR S2,S1 ;COMPLETE THE AOBJN COUNTER
SETZ P1, ;SET CHECKSUM TO ZERO
JCRY0 .+1 ;CLEAR THE CARRY 0 BIT
;COMPUTE THE CHECKSUM
COMCH1: ADD P1,0(S2) ;ADD THE NEXT MESSAGE WORD TO CHECKSUM
JCRY0 [AOJA P1,.+1] ;ADD ONE IF CARRY 0 BIT IS SET
AOBJN S2,COMCH1 ;GO ADD IN THE NEXT MESSAGE WORD
;IF CHECKSUM IS 0, THEN MAKE -1
SKIPN P1 ;IF CHECKSUM NOT 0, THEN FINISHED
SETO P1, ;MAKE THE CHECKSUM -1
MOVEM P1,.MSCHS(S1) ;PLACE CHECKSUM IN THE MESSAGE
MOVE S1,P1 ;PLACE CHECKSUM IN RETURN AC
$RETT ;RETURN TO THE CALLER
> ;end of repeat 0
SUBTTL MSGFLI - PICKUP ACK MESSAGE FROM THE LISTENER
;MSGFLI is the interrupt handler for ACK messages from the listener.
;MSGFLI picks up the ACK message from the listener and then interrupts
;the top fork to indicate that the sender is ready for another message.
;
;Call is: SEN/Address of the sender block
;Returns: The ACK message has been processed
;Crashes: The link is no longer connected
MSGFLI: $BGINT 1, ;SAVE THE CONTEXT
;CHECK IF THERE IS A MESSAGE, IF THE INTERRUPT IS SPURIOUS OR IF THE
;LINK IS NO LONGER CONNECTED.
MOVE S1,.SNJFN(SEN) ;PICK UP THE DECNET JFN
SIBE% ;IS THERE AN ACK MESSAGE?
JRST MSGFL1 ;YES, PICK IT UP
$CALL SCKLNK ;IS THE LINK STILL CONNECTED?
JUMPT MSGFL3 ;YES, THE INTERRUPT IS SPURIOUS
JRST MSGFL4 ;NO, TREAT AS A FATAL ERROR
;CHECK IF THE MESSAGE NEEDS TO BE RESENT. IF IT DOES NOT, THEN INFORM
;THE TOP FORK THAT THE SENDER IF AVAILABLE TO SEND ANOTHER MESSAGE.
;OTHERWISE, RESEND THE MESSAGE TO THE LISTENER.
MSGFL1: MOVE S1,.SNJFN(SEN) ;PICK UP THE DCN: DEVICE JFN
MOVE S2,[POINT 36,T1] ;POINT TO THE MESSAGE BUFFER
SETO T1, ;NEGATIVE MESSAGE LENGTH
SINR% ;PICK UP THE MESSAGE
ERJMP MSGFL4 ;CONSIDER ANY ERRORS AS FATAL
MOVEI S1,.FHSUP ;PICK UP TOP FORK'S HANDLE
MOVX S2,<1B1> ;CHANNEL TO INTERRUPT TOP FORK ON
SETOM .SNFRE(SEN) ;INDICATE THAT SENDER IS AVAILABLE
IIC% ;INTERRUPT THE TOP FORK
ERJMP [$CALL INSCRH ;INDICATE A CONTROLLED CRASH
JRST S..SCI ] ;CAN'T INTERRUPT THE TOP FORK
MSGFL3: $DEBRK ;RETURN TO THE PREVIOUS CONTEXT
MSGFL4: $WTOJ (<NEBULA lost connection>,<NEBULA's sender to node ^N/.SNNME(SEN)/ has lost its DECnet connection>,,<$WTFLG(WT.SJI)>)
$CALL INSCRH ;INDICATE CRASH IN NODE STATUS WORD
HALTF ;CRASH
SUBTTL SSNDMG - SEND A MESSAGE TO A LISTENER
;SSNDMG is called to send a message to the listener. It sets up the SOUTR%
;call and sends the message.
;Call is: SEN/Address of the sender block
;Returns: The message was sent to the listener
;Crashes: The SOUTR% failed
SSNDMG: $SAVE <T1,T2> ;SAVE THESE AC, DESTROYED BY JSYS
;SET UP THE AC TO THE SOUTR% JSYS.
MOVE S1,.SNJFN(SEN) ;PICK UP THE DECNET JFN
MOVE S2,.SNMSG(SEN) ;PICK UP THE ADDRESS OF THE MESSAGE
HRLI S2,(POINT ^D36,) ;MAKE IT INTO A POINTER
LOAD T1,.MSTYP(S2),MS.CNT ;PICK UP THE LENGTH OF THE MESSAGE
;SEND THE MESSAGE
MOVNS T1 ;MAKE THE MESSAGE LENGTH NEGATIVE
SOUTR% ;SEND THE MESSAGE
ERJMP SSNDM2 ;CRASH ON AN ERROR
$RETT ;RETURN TO THE CALLER
SSNDM2: $CALL INSCRH ;INDICATE CRASH IN NODE STATUS WORD
$STOP (SUS, Sender unable to send message to the listener)
SUBTTL REPCON - ENABLE DECNET-CONNECTION-ATTEMPTS
;REPCON is the interrupt handler to re-enable the sender's attempts to
;connect to its listener. The top fork interrupts the sender on this
;channel as a result of receiving a message that came from an operator
;giving the OPR>ENABLE DECNET-CONNECTION-ATTEMPTS. The sender is only
;interrupted if it has not yet made a connection and its DECnet connection
;attempts have been disabled.
;REPCON merely forces the sender out of I%SLP.
;
;Returns: The sender is forced out of I%SLP
REPCON: $BGINT 1, ;SAVE THE PREVIOUS CONTEXT
$DEBRK ;FORCE OUT OF I%SLP
SUBTTL INSCRH - ROUTINE TO INDICATE SENDER CONTROLLED CRASH
;INSCRH is called by the sender when it has detected a fatal error.
;INSCRH indicates in the node table entry's sender status word
;that the sender was aware it was going to crash. A RESET% is
;also performed to break the DECnet link.
;
;Call is: SEN/Address of the sender block
;Returns: Bit NS%SFC is set in the node entry's sender status word
;SET THE CONTROLLED SENDER CRASH BIT IN THE NODE TABLE'S SENDER STATUS WORD
INSCRH: DMOVEM S1,.SNERR(SEN) ;SAVE THE CONTEXT OF S1 AND S2
MOVE S1,.SNNTA(SEN) ;PICK UP THE NODE TABLE ENTRY
MOVX S2,NS%SFC ;PICK UP SENDER FORK CRASHED BIT
IORM S2,.NSSTA(S1) ;INDICATE THAT THE SENDER HAS CRASHED
MOVX S2,NN%IFC ;AN INFERIOR FORK HAS CRASHED
IORM S2,.NNSTA(S1) ;INDICATE IN THE SENDER'S STATUS WORD
RESET% ;BREAK THE DECNET LINK
DMOVE S1,.SNERR(SEN) ;RESTORE CONTEXT OF S1 AND S2
$RET ;RETURN TO THE CALLER
SUBTTL NEBDDT - ROUTINE TO LOAD DDT IF DEBUGGING
;NEBDDT is called if NEBULA is running in a DEBUG environment.
;NEBDDT maps in and starts DDT
;
;Call is: No arguments
;Returns: DDT has been loaded
;Crashes: If unable to load DDT
NEBDDT: MOVX S1,GJ%OLD+GJ%SHT ;OLD FILE+SHORT JFN
HRROI S2,[ASCIZ/SYS:SDDT.EXE/] ;POINT TO DDT
GTJFN% ;GET DDT'S JFN
ERJMP NEBDD2 ;CRASH IF CAN'T GET DDT'S JFN
HRLI S1,.FHSLF ;PICK UP HANDLE
GET% ;LOAD DDT
ERJMP NEBDD2 ;CRASH IF CAN'T LOAD DDT
MOVE S1,116 ;GET CONTENTS OF .JBSYM
HRRZ S2,770001 ;GET ADDRESS OF WHERE TO PUT IT
MOVEM S1,0(S2) ;POINT DDT AT NEBULA'S SYMBOL TABLE
JRST 770000 ;AND ENTER DDT
GO: $RET ;RETURN
NEBDD2: $STOP (DDE, DDT ERROR) ;CRASH, IF CAN'T GET DDT
SUBTTL KASNOD - RESET A NODE'S DATA BASE
;KASNOD is called when a fatal error has occurred concerning a node.
;It is called when a sender or listener to that node has crashed.
;It is called when the response to a message sent to that node is not
;received in TIMOUT amount of time.
;KASNOD kills the inferior forks, updates the message, in behalf of,
;remote and timer queues. The node table entry for the node is also
;updated. If it is determined that the remote node can receive messages
;(i.e., it has a monitor of release 7 or later and has DECnet enabled),
;then a listener and sender are restarted for that node.
;
;Call is: S1/Node table entry of the node
;Returns true: The node can receive messages, a listener and sender have
; been restarted for the node
;Returns false: The node cannot receive messages. A listener and sender have
; not been restarted for the node
KASNOD: $SAVE <P1,P2,P3> ;SAVE THESE AC
;KILL THE INFERIOR FORKS, UPDATE THE QUEUES ASSOCIATED WITH THIS NODE
;AND REBUILD THE NODE TABLE ENTRY
MOVE P1,S1 ;SAVE THE NODE TABLE ENTRY ADDRESS
MOVE P2,.NNNAM(P1) ;SAVE THE NODE NAME
LOAD P3,.NNSTA(P1),NS.NUM ;SAVE THE NODE NUMBER
$CALL KILNOD ;KILL THE NODE
MOVEM P2,.NNNAM(P1) ;RESTORE NODE NAME TO NODE TABLE ENTRY
STORE P3,.NNSTA(P1),NS.NUM ;RESTORE NODE # TO NODE TABLE ENTRY
;CHECK THE STATUS OF THE REMOTE NODE TO DETERMINE IF A NEW SENDER AND LISTENER
;SHOULD BE STARTED FOR IT.
MOVE S1,P1 ;PICK UP THE NODE TABLE ENTRY ADDRESS
$CALL NODPAR ;CHECK IF THIS NODE CAN RECEIVE MSG
JUMPT KASN.1 ;[6016]JUMP IF CAN SEND MSG TO THIS NODE
MOVE S1,P1 ;[6016]PICK UP THE NODE TABLE ENTRY ADR
$CALL STINFO ;[6016]START THE INFO% JSYS TIMER
$RETF ;[6016]INDICATE CAN'T SEND MSG TO NODE
;THIS NODE IS OK TO START A SENDER AND LISTENER FOR. DETERMINE, AS INDICATED
;IN THE PACKN TABLE ENTRY FOR THIS NODE, WHETHER THE SENDER SHOULD NOTIFY
;ORION IF IT IS UNABLE TO MAKE A DECNET CONNECTION. ALSO DETERMINE IF THE
;SENDER SHOULD ATTEMPT TO OBTAIN A DECNET CONNECTION
KASN.1: MOVE S1,.NNNAM(P1) ;[6016]PICK UP THE NODE NAME
$CALL SRHPNE ;FIND THE PACKN ENTRY FOR THIS NODE
JUMPF [$STOP (PTI,PACKN TABLE INCONSISTENCY)]
MOVE S2,.LKSTS(S2) ;PICK UP THE PACKN STATUS WORD
SETZ S1, ;ASSUME NO BITS ARE SET
TXNE S2,LK%CCA ;ATTEMPT TO OBTAIN A DECNET CONNECTION?
TXO S1,NN%CCA ;NO, INDICATE IN THE NODE STATUS WORD
TXNE S2,LK%DIS ;REPORT CONNECTION FAILURES?
TXO S1,NN%DCO ;NO, INDICATE IN THE NODE STATUS WORD
IORM S1,.NSSTA(P1) ;UPDATE THE NODE TABLE STATUS WORD
;START UP THE LISTENER AND SENDER
MOVE S1,P1 ;PICK UP THE NODE TABLE ENTRY ADDRESS
$CALL STAINF ;START UP THE INFERIOR FORKS
$RETT ;THIS NODE CAN RECEIVE MESSAGES
SUBTTL STINFO - START AN INFO% JSYS FAILURE TIMER
;[6016]STINFO is called when the INFO% JSYS has failed. When a node first comes
;[6016]up and SCS% indicates this fact, it is possible that CLUDGR is not fully
;[6016]ready. This implies that an INFO% JSYS error indicating that a node
;[6016]is not running monitor release 7 or later is incorrect. Consequently,
;[6016]a timer is set up to IEMAX times with a timeout value of TIMOUT/5 in
;[6016]anticipation that CLUDGR will be ready.
;[6016]
;[6016]Call is: S1/Node table entry address
;[6016]Returns: An INFO% JSYS timer entry has been created
STINFO: $SAVE <P1> ;[6016]SAVE THIS AC
MOVE P1,S1 ;[6016]SAVE THE NODE TABLE ENTRY ADR
$CALL I%NOW ;[6016]PICK UP THE CURRENT TIME
ADDI S1,<TIMOUT/5> ;[6016]CALCULATE TIME TO INTERRUPT
MOVEM S1,.NIETM(P1) ;[6016]SAVE IN THE NODE TABLE ENTRY
MOVEI S2,TIMBLK ;[6016]PICK UP EVENT BLOCK ADDRESS
MOVEM S1,.TITIM(S2) ;[6016]SAVE THE WAKEUP TIME
MOVEI S1,.TIMDT ;[6016]WAKE UP AT A SPECIFIC TIME
MOVEM S1,.TIFNC(S2) ;[6016]SAVE IN THE TIMER EVENT BLOCK
MOVEI S1,IEPROC ;[6016]PICK UP TIMER ROUTINE ADDRESS
MOVEM S1,.TIMPC(S2) ;[6016]SAVE IN THE TIMER EVENT BLOCK
MOVEM P1,.TIDAT(S2) ;[6016]SAVE THE NODE TABLE ENTRY ADR
MOVEI S1,<.TIDAT+1> ;[6016]PICK UP THE TIMER BLOCK LENGTH
$CALL I%TIMR ;[6016]SET UP THE TIMER
AOS S1,.NIERC(P1) ;[6016]INCREMENT THE INFO% RETRY COUNT
CAIE S1,1 ;[6016]IS THIS THE FIRST TIMER?
$RET ;[6016]NO, SO RETURN NOW
$WTOJ (<NEBULA INFO% failure detected>,<Unable to obtain status of node ^N/.NNNAM(P1)/>,,<$WTFLG(WT.SJI)>)
$RET ;[6016]RETURN
SUBTTL IEPROC - INFO% JSYS ERROR TIMER EVENT PROCESSOR
;[6016]IEPROC is the INFO% JSYS error timer routine. IEPROC checks if the
;[6016]INFO% JSYS still reports an error in obtaining the status of the
;[6016]indicated remote node. If the INFO% JSYS still returns an error,
;[6016]then if the retry count has not exceeded IEMAX, then the INFO%
;[6016]error timer is reset. Otherwise, -1 is placed in the node entry
;[6016]word .NIETM to indicate that after IEMAX tries that the INFO% JSYS
;[6016]still indicated that NEBULA communication with the node is not
;[6016]possible.
;[6016]
;[6016]Call is: S1/Length of the timer event request block
;[6016] S2/Address of the timer event request block
;[6016]Returns: Timer has been set for another time or
;[6016] timer has not been reset due to maximum retry count or
;[6016] INFO% indicates that communication with the node is possible,
;[6016] in which case the node's node table entry status word indicates
;[6016] this and a listener and sender has been started for this node
;[6016]
;[6016](Note: ACs S1,S2 and T1-T4 are preserved by I%SLP which calls this
;[6016]routine.)
IEPROC: MOVE T1,.TIDAT(S2) ;[6016]PICK UP THE NODE TABLE ENTRY ADR
MOVE S1,T1 ;[6016]PLACE ADDRESS HERE FOR NODPAR
$CALL NODPAR ;[6016]DETERMINE THE NODE'S STATUS
JUMPT IEPR.2 ;[6016]CAN NOW COMMUNICATE WITH THE NODE
MOVE S1,.NIERC(T1) ;[6016]PICK UP RETRY COUNT
CAIGE S1,IEMAX ;[6016]REACHED THE MAXIMUM?
JRST IEPR.1 ;[6016]NO, SET THE TIMER AGAIN
SETOM .NIETM(T1) ;[6016]YES, INDICATE GIVING UP
$RET ;[6016]RETURN TO I%SLP
IEPR.1: MOVE S1,T1 ;[6016]PICK UP THE NODE TABLE ENTRY ADR
$CALL STINFO ;[6016]SET THE TIMER
$RET ;[6016]RETURN TO I%SLP
IEPR.2: SETZM .NIETM(T1) ;[6016]CLEAR THE INFO% TIMER WORD
SETZM .NIERC(T1) ;[6016]CLEAR THE INFO% RETRY COUNTER
MOVX S1,NN%DCN!NN%REL!NN%COI ;[6016]PICK UP THE ERROR BITS
ANDCAM S1,.NNSTA(T1) ;[6016]CLEAR THEM IN THE STATUS WORD
MOVE S1,T1 ;[6016]PICK UP THE NODE ENTRY TBL ADR
$CALL STAINF ;[6016]START UP THE INFERIOR FORKS
$RET ;[6016]RETURN TO I%SLP
SUBTTL TOPTMR - TOPOLOGY CHANGE TIMER
;[6016]TOPTMR is called to set up the cluster topology change timer. TOPTMR
;[6016]is called from routine TOPCHN as a result of TOPCHN being called
;[6016]at NEBULA startup time or as a consequence of TOPCHN being called
;[6016]as a result of the SCS% interrupt handler detecting that a node
;[6016]has joined the cluster. When the topology change timere goes off it
;[6016]calls routine TOPCHN. This is needed because at system startup time
;[6016]the node information returned by the CONFG% JSYS may not be accurate
;[6016]which can result in a node that is actually in the cluster not being
;[6016]reported as being in the cluster.
TOPTMR: $CALL I%NOW ;[6016]PICK UP THE CURRENT TIME
ADDI S1,TOPTRY ;[6016]CALCULATE TIME TO INTERRUPT
MOVEI S2,TIMBLK ;[6016]PICK UP EVENT BLOCK ADDRESS
MOVEM S1,.TITIM(S2) ;[6016]SAVE THE WAKEUP TIME
MOVEI S1,.TIMDT ;[6016]WAKE UP AT A SPECIFIC TIME
MOVEM S1,.TIFNC(S2) ;[6016]SAVE IN THE TIMER EVENT BLOCK
MOVEI S1,TOPCHN ;[6016]TOPOLOGY CHANGE ROUTINE ADDRESS
MOVEM S1,.TIMPC(S2) ;[6016]SAVE IN THE TIMER EVENT BLOCK
MOVEI S1,.TIDAT+1 ;[6016]PICK UP THE TIMER BLOCK LENGTH
$CALL I%TIMR ;[6016]SET UP THE TIMER
$RET ;[6016]RETURN
SUBTTL NEBTMR - NEBULA ACK MESSAGE TIMER
;[6016]NEBTMR is called to set up the timer to send the next NEBULA ACK
;[6016]message to all nodes in the cluster that are known to be in
;[6016]communication with the local NEBULA.
;[6016]
;[6016]Call is: No arguments
;[6016]Returns: The timer has been set up
NEBTMR: $CALL I%NOW ;[6016]PICK UP THE CURRENT TIME
ADDI S1,TIMOUT ;[6016]ADD THE TIME-OUT TIME
MOVEI S2,TIMBLK ;[6016]PICK UP TIMER BLOCK ADDRESS
MOVEM S1,.TITIM(S2) ;[6016]SAVE THE WAKEUP TIME
MOVEI S1,.TIMDT ;[6016]PICK UP THE FUNCTION CODE
MOVEM S1,.TIFNC(S2) ;[6016]SAVE IN THE TIMER BLOCK
MOVEI S1,NACKTM ;[6016]PICK UP TIMER PROCESSOR ADDRESS
MOVEM S1,.TIMPC(S2) ;[6016]]SAVE IN THE TIMER BLOCK
MOVEI S1,<.TIDAT+1> ;[6016]PICK UP TIMER BLOCK LENGTH
$CALL I%TIMR ;[6016]SET UP THE TIMER
$RET ;[6016]RETURN TO THE CALLER
SUBTTL NACKTM - NEBULA ACK MESSAGE TIMER PROCESSOR
;[6016]NACKTM is called by I%SLP when the NEBULA ACK message timer has gone
;[6016]off. NACKTM sends a NEBULA ACK message to all known nodes in the cluster
;[6016]capable of receiving messages.
;[6016]
;[6016]Call is: No arguments
;[6016]Returns: NEBULA ACK message has been sent to all nodes in the cluster
;[6016] known to be able to receive messages.
NACKTM: MOVEI M,NEBACK ;[6016]PICK UP THE MESSAGE ADDRESS
MOVEI S1,TIMOUT ;[6016]PICK UP THE TIMEOUT VALUE
MOVEM S1,TIMCTR ;[6016]SAVE FOR SETTING UP ANY TIMERS
$CALL I%NOW ;[6016]PICK UP IPCF MSG RECEPTION TIME
MOVEM S1,MSGTIM ;[6016]SAVE IT
$CALL QMREMM ;[6016]SEND THE ACK MESSAGES
$CALL NEBTMR ;[6016]SET THE NEBULA ACK MSG TIMER
$RET ;[6016]RETURN TO I%SLP
SUBTTL NODPAR - PICK UP THE ENVIRONMENT OF A REMOTE NODE
;NODPAR is called to pick up the software environment of a remote node.
;This is accomplished by using the INFO% JSYS to perform the CNFIG% function
;.CFINF on the remote node. If the INFO% JSYS fails with error INFX11
;(Remote node not running CLUDGR SYSAP), then the assumption is that the
;remote node is running a pre-release 7 monitor.
;A check is also made for DECnet enabled at the remote node.
;The status of the remote node is stored in the status word of the node's
;node table entry.
;
;Call is: S1/Node table (NODTBL) entry address of remote node to be
; checked
;Returns true: S2/Status word of the node
; O.K. to start a listener and sender to this node
;Returns false: S2/Status word of the node
; Not O.K. to start a listener and sender to this node
NODPAR: $SAVE <T1,T2,T3,T4> ;SAVE THESE AC
MOVE T3,S1 ;SAVE THE NODE TABLE ENTRY ADDRESS
MOVEI S1,INFBLK ;PICK UP THE ADDRESS OF THE INFO% BLK
MOVE S2,[.INCFG,,4] ;PICK UP INFO% FUNCTION/ARG BLK LENGTH
MOVEM S2,.INFUN(S1) ;PLACE IN THE INFO% ARGUMENT BLOCK
LOAD S2,.NNSTA(T3),NS.NUM ;PICK UP THE NODE NUMBER
MOVEM S2,.INCID(S1) ;PLACE IN THE INFO% ARGUMENT BLOCK
MOVEI S2,.CFINF ;PICK UP THE CNFIG% FUNCTION CODE
MOVEM S2,.INAC1(S1) ;PLACE IN THE INFO% ARGUMENT BLOCK
MOVEI S2,SWINFO ;PICK UP THE SOFTWARE STATUS BLK ADR
MOVEM S2,.INAC2(S1) ;PLACE IN THE INFO% ARGUMENT BLOCK
MOVEI T4,.CFILN ;THE CNFIG% ARGUMENT BLOCK SIZE
MOVEM T4,.CFLEN(S2) ;PLACE IN THE CNFIG% ARGUMENT BLOCK
INFO% ;PICK UP THE STATIC SOFTWARE INFO
ERJMP NODPA2 ;CAN'T OBTAIN REMOTE SOFTWARE INFO
SKIPGE S1 ;DID AN ERROR OCCUR ON THE REMOTE NODE?
JRST NODPA3 ;YES, ASSUME THE WORST
MOVEI S1,SWINFO ;PICK UP ADDRESS OF ARGUMENT BLOCK
MOVE T4,.CFISO(S1) ;PICK UP THE NODE STATIC SOFTWARE WRD
TXNE T4,CF%DCN ;DOES THE NODE HAVE DECNET
JRST NODPA6 ;YES, FINISHED
MOVE S2,.NNSTA(T3) ;PICK UP THE NODE STATUS WORD
TXO S2,NN%DCN ;NO, INDICATE SO
MOVEM S2,.NNSTA(T3) ;INDICATE NO DECNET IN THE STATUS WORD
JRST NODPA5 ;INDICATE NOT OK START LISTENER/SENDER
;INFO% COULD NOT OBTAIN INFORMATION ON THE REMOTE NODE.
;CHECK FOR ERROR INFX11. IF THIS IS THE ERROR, THEN ASSUME THE REMOTE NODE
;HAS A PRE-RELEASE 7 MONITOR. IT MAY BE THE CASE THAT A REMOTE NODE HAS
;A RELEASE 7 MONITOR BUT THE CLUDGR SYSAP IS NOT YET RUNNING. THEREFORE,
;THE BIT NN%COI MUST ALSO BE TURNED ON SO THAT THE NODE'S ENVIRONMENT CAN BE
;CHECKED LATER WHEN A TOPOLOGY CHANGE OCCURS. AT THAT TIME THE CLUDGR SYSAP
;MAY BE RUNNING
NODPA2: MOVEI S1,.FHSLF ;GET LATEST ERROR FOR NEBULA
GETER% ;PICK UP THE ERROR CODE
ERJMP NODPA3 ;ASSUME THE WORST
HRRZS S2 ;JUST WANT THE ERROR CODE
CAIN S2,INFX11 ;REMOTE NODE NOT SUPPLYING INFORMATION?
JRST NODPA4 ;YES, GO INDICATE SO
;AN INFO% JSYS ERROR OR A REMOTE CNFIG% JSYS ERROR HAS OCCURRED. ASSUME THE
;WORST, I.E., THE REMOTE NODE DOES NOT HAVE DECNET ENABLED AND IS RUNNING
;A PRE-RELEASE 7 MONITOR. ALSO, TURN ON BIT NN%COI WHICH INDICATES THAT THIS
;NODE'S STATUS SHOULD AGAIN BE ATTEMPTED TO BE PICKED UP AT THE NEXT CLUSTER
;TOPOLOGY CHANGE SINCE THE ERROR REPORTED THIS TIME MAY BE TRANSIENT.
NODPA3: MOVX S1,NN%DCN!NN%REL!NN%COI ;PICK UP THE ERROR BITS
SKIPA ;GO SET THESE BITS IN THE STATUS WORD
NODPA4: MOVX S1,NN%REL!NN%COI ;REMOTE NODE DOESN'T HAVE RELEASE 7
IORM S1,.NNSTA(T3) ;INDICATE ERROR IN STATUS WORD
MOVE S2,.NNSTA(T3) ;PICK UP STATUS WORD FOR RETURN
NODPA5: $RETF ;NOT OK TO START A LISTENER AND SENDER
NODPA6: $RETT ;OK TO START A LISTENER AND SENDER
SUBTTL CHKSTS - CHECK FOR DECNET AND RELEASE 7 MONITOR
;CHKSTS is called to check if a remote node has DECnet enabled
;and a monitor of release 7 or later. This information is obtained from
;the Node Table entry for the node.
;
;Call is: S1/Address of the Node Table entry
;Returns true: The node has DECnet and a monitor of release 7 or later.
; S1/Address of the Node Table entry
;Returns false: The node does not have DECnet and/or a release 7 monitor
; S1/Address of the Node Table entry
CHKSTS: MOVE S2,.NNSTA(S1) ;PICK UP THE NODE'S STATUS WORD
TXNE S2,NN%DCN!NN%REL ;HAS BOTH DECNET AND RELEASE 7?
$RETF ;NO, MISSING ONE OR BOTH
$RETT ;YES
SUBTTL FNDPNE - ADD AN ENTRY TO THE PACKN TABLE IF NECESSARY
;FNDPNE is called when routine TOPCHN detects that a node has entered
;the cluster. FNDPNE checks if the new node to the cluster already
;exists in the PACKN table. If it does not, then it is added.
;FNDPNE assumes there is at least one free entry in the PACKN table.
;
;If a sender is not to be started for this node, then there is no reason
;to check if ORION is to be informed of senders' DECnet connection attempt
;failures. However, if a sender is to be started for this node, then there
;are two cases:
;Case 1. The node is known to have previously been in the cluster.
; In this case, if this node's sender's DECnet connection attempt failures
;were not previously reported to ORION, then this will also be true now.
;Otherwise, this node's sender's DECnet connection attempt failures will be
;reported or not to ORION as indicated by the flag word RCFFLG which is
;affected by the OPR>ENABLE/DISABLE REPORT-CONNECTION-FAILURES command given
;without the /NODE: switch being included. (The default is to report DECnet
;connection attempt failures.)
;Case 2. The node has not been previously known to be in the cluster.
; In this case, this node's sender's DECnet connection attempt failures will
;be reported or not to ORION as indicated by flag word RCFFLG.
;
;Call is: S1/Node table entry address of the node that has joined the
; cluster
; S2/Flag word that indicates if a sender is to be started for
; this node or not
;Returns true: The node has an existing entry in the PACKN table
; S1/SIXBIT node name of node that has joined the cluster
; S2/PACKN table entry address of the node
;Returns false: The node does not have an existing entry in the PACKN table,
; but an entry has been added for it
; S1/SIXBIT node name of node that has joined the cluster
; S2/PACKN table entry address of the newly added node
;FIND THE PACKN ENTRY OF THE NODE THAT HAS JOINED THE CLUSTER. IF IT IS
;NOT FOUND, THEN ADD AN ENTRY FOR IT
FNDPNE: $SAVE <P1,P2,P3,P4> ;SAVE THESE AC
DMOVEM S1,P1 ;SAVE NODE TABLE ENTRY ADDRESS & FLAG
MOVE S1,.NNNAM(P1) ;PICK UP THE NODE NAME
$CALL SRHPNE ;CHECK IF THE NODE HAS ENTRY IN PACKN
DMOVEM S1,P3 ;SAVE NODE NAME/PACKN ADDRESS
JUMPT FNDPN3 ;THE NODE HAS PREVIOUSLY BEEN KNOWN
MOVEM S1,.NDNAM(S2) ;PLACE NODE NAME IN NEW PACKN ENTRY
SOS S1,NDLKFR ;DECREMENT NUMBER OF FREE PACKN ENTRIES
JUMPG S1,FNDPN2 ;AT LEASE ONE FREE ENTRY?
PUSH P,TF ;NO, SAVE TRUE/FALSE INDICATOR
$CALL EXPTAB ;NO MORE FREE ENTRIES, EXPAND PACKN
POP P,TF ;RESTORE TRUE/FALSE INDICATER
;IF A SENDER IS TO BE STARTED FOR THIS NODE, THEN DETERMINE IF ORION IS TO
;BE INFORMED IF THE SENDER DECNET CONNECTION ATTEMPTS FAIL.
FNDPN2: SKIPN P2 ;WILL A SENDER BE STARTED?
JRST FNDPN6 ;NO, SO RETURN
SKIPE RCFFLG ;CONNECTION FAILURES BEING REPORTED?
JRST FNDPN4 ;NO, SO INDICATE THIS
JRST FNDPN5 ;YES, CHECK FOR CONNECTION ATTEMPTS
;THE NODE IS KNOWN TO HAVE BEEN PREVIOUSLY IN THE CLUSTER. IF A SENDER IS
;NOT TO BE STARTED FOR IT THIS TIME, THEN RETURN. OTHERWISE, DETERMINE IF
;CONNECTION ATTEMPTS TO THE REMOTE NODE ARE TO BE TRIED AND, IF ON FAILURES,
;THE FAILURES ARE TO BE REPORTED TO ORION.
FNDPN3: SKIPN P2 ;WILL A SENDER BE STARTED?
JRST FNDPN6 ;NO, SO ARE FINISHED
FNDPN4: MOVX S1,LK%DIS ;ASSUME NOT REPORT CONNECTION FAILURES
SKIPE RCFFLG ;CURRENTLY, ARE FAILURES REPORTED?
IORM S1,.LKSTS(P4) ;NO, INDICATE IN THE PACKN ENTRY
;INDICATE IF THE SENDER'S FAILURE TO OBTAIN A DECNET CONNECTION SHOULD BE
;REPORTED OR NOT IN THE NODE'S NODE TABLE ENTRY STATUS WORD.
MOVX S1,NN%DCO ;ASSUME DISABLE FAILURE REPORTING
SKIPGE .LKSTS(P4) ;IS THIS A VALID ASSUMPTION?
IORM S1,.NNSTA(P1) ;YES, INDICATE IN NODE TABLE ENTRY
;INDICATE IF THE SENDER SHOULD ATTEMPT TO OBTAIN A DECNET CONNECTION OR NOT
FNDPN5: MOVX S1,LK%CCA ;ASSUME NOT ATTEMPT A CONNECTION
SKIPE DCAFLG ;IS THIS A VALID ASSUMPTION?
IORM S1,.LKSTS(P4) ;YES, INDICATE IN THE PACKN ENTRY
MOVX S1,NN%CCA ;ASSUME NOT ATTEMPT A CONNECTION
MOVE S2,.LKSTS(P4) ;PICK UP THE PACKN STATUS WORD
TXNE S2,LK%CCA ;ATTEMPT TO OBTAIN A DECNET CONNECTION?
IORM S1,.NNSTA(P1) ;NO, INDICATE IN THE NODE STATUS WORD
FNDPN6: DMOVE S1,P3 ;RESTORE NODE NAME/TABLE ADDRESS
$RET ;PRESERVE THE TRUE/FALSE RETURN
SUBTTL SRHPNE - CHECK IF A NODE HAS AN ENTRY IN THE PACKN TABLE
;SRHPNE is called to check if a node is in the PACKN table.
;SRHPNE assumes there is at least one free PACKN table entry.
;
;Call is: S1/SIXBIT node name
;Returns true: The node has an entry in the PACKN table
; S1/SIXBIT node name
; S2/Address of the PACKN entry for the node
;Returns false: The node does not have an entry in the PACKN table
; S1/SIXBIT node name
; S2/Address of the first free PACKN table
;FIND THE PACKN TABLE ENTRY FOR THE SPECIFIED NODE IF THERE IS ONE,
;ELSE INDICATE THERE IS NO PACKN TABLE ENTRY FOR THE SPECIFIED NODE.
SRHPNE: MOVE S2,NDLKST ;PICK ADDRESS OF THE PACKN TABLE
SRHPN2: CAMN S1,.NDNAM(S2) ;THE ENTRY BEING SEARCHED FOR?
JRST .RETT ;YES, INDICATE SUCCESS
ADDI S2,.NDLSZ ;NO, POINT TO THE NEXT PACKN ENTRY
SKIPE .NDNAM(S2) ;ANY MORE PACKN TABLE ENTRIES IN USE?
JRST SRHPN2 ;NO, CHECK THE NEXT PACKN TABLE ENTRY
$RETF ;NODE HAS NO PACKN TABLE ENTRY
SUBTTL USNERR - SET UP ARGUMENT WORDS FOR ACK MESSAGE PROCESSING
;USNERR is called when it is discovered during the processing of an IPCF
;message that is to be forwarded to a single remote node that the message
;cannot be sent to the remote node. USNERR sets up the node name and reason
;for not being able to send to the remote node parameters for the ACK
;message to be sent to the OPR that sent the original message.
;
;Call is: S1/Bit position of error in node table entry status word
; S2/Node name that message cannot be sent to
;Returns: Node name and reason of error has been placed where the
; error message handler expects them.
USNERR: MOVEM S2,G$ARG1 ;SAVE NODE NAME WHERE EXPECTED
JFFO S1,.+1 ;DETERMINE ERROR DISPLACEMENT
CAIL S2,NNLOW ;CHECK FOR LEGAL LOWER RANGE
CAILE S2,NNHIGH ;CHECK FOR LEGAL HIGHER RANGE
SETZ S2, ;UNKNOWN ERROR
MOVE S1,REASON(S2) ;PICK UP ADDRESS OF THE ERROR
MOVEM S1,G$ARG2 ;SAVE ADDRESS OF ASCIZ TEXT
$RETT ;RETURN TO THE CALLER
SUBTTL REASON - MESSAGE ERROR TABLE
;REASON is a table that indicates the reason a message could not be
;sent to a remote node. The error reason comes from the node table
;entry status word for the node.
REASON:
[ASCIZ/ Unknown error/]
[ASCIZ/ INFO% unable to obtain software information/] ;NN%COI
[ASCIZ/ DECnet is not enabled/] ;NN%DCN
[ASCIZ/ Monitor is pre-release 7/] ;NN%REL
[ASCIZ/ SCS% Detected that this node has left the cluster/] ;NN%SCS
[ASCIZ/ Sender waiting for HELLO message response/] ;NN%SHO
[ASCIZ/ Listener waiting for HELLO message/] ;NN%LHO
[ASCIZ/ Sender or listener in a fatal state/] ;NN%IFC
[ASCIZ//] ;[6037]
[ASCIZ//] ;[6037]
[ASCIZ/ is running Field Image version 6 GALAXY and does
not understand the command/] ;[6037]NN%PAS
;LNKSTS is a table that indicates the DECnet link status of senders. This
;table is used in support of the OPR>SHOW CLUSTER-GALAXY-LINK-STATUS
;command
CONCON==1 ;SENDER AND LISTENER HAVE CONNECTIONS
CNTCNT==2 ;SENDER AND LISTENER CANNOT CONNECT
CNNECT==3 ;SENDER OR LISTENER HAS A CONNECTION
NOTCON==4 ;SENDER OR LISTENER NOT CONNECTED
NEVCON==5 ;SENDER OR LISTENER NEVER CONNECTED
UNKSTS==6 ;SENDER OR LISTENER UNKNOWN STATUS
LNKSTS: EXP 0 ;THIS ENTRY IS NOT USED
[ASCIZ/Connected Connected/] ;[6006]
[ASCIZ/Cannot connect to Cannot connect to/] ;[6006]
[ASCIZ/Connected/]
[ASCIZ/Not connected/]
[ASCIZ/Never connected/]
[ASCIZ/Unknown/]
SUBTTL EXPTAB - EXPAND THE PACKN TABLE
;EXPTAB is called when it is determined that the PACKN table has no
;free entries. This routine will expand the PACKN table by
;adding MAXNOD free entries to it.
;
;Call is: No arguments
;Returns: The PACKN table has been expanded by MAXNOD free entries
EXPTAB: $SAVE <P1> ;SAVE THIS AC
;PICK UP THE MEMORY NEEDED FOR THE EXPANDED PACKN TABLE
MOVE S1,NDLKNM ;PICK UP NUMBER OF PACKN TABLE ENTRIES
ADDI S1,MAXNOD ;ADD MAXNOD ENTRIES TO THE ENTRY NUMBER
IMULI S1,.NDLSZ ;CALCULATE MEMORY NEEDED FOR NEW TABLE
$CALL M%GMEM ;PICK UP THE MEMORY FOR THE NEW TABLE
EXCH S2,NDLKST ;SAVE NEW ADDRESS, PICK UP THE OLD ADR
JUMPE S2,EXPTA1 ;IF FIRST TIME, THEN NO OLD TABLE
;COPY THE CONTENTS OF THE OLD PACKN TABLE INTO THE NEW PACKN TABLE
MOVE P1,S2 ;SAVE THE OLD TABLE ADDRESS
HRLS S2 ;PLACE OLD ADDRESS AS SOURCE ADDRESS
HRR S2,NDLKST ;PLACE NEW ADDRESS AS DESTINATION ADR
MOVE S1,NDLKNM ;PICK UP NUMBER OF ENTRIES IN OLD TBL
IMULI S1,.NDLSZ ;CALCULATE SIZE OF THE OLD TABLE
ADD S1,NDLKST ;ADD ADR NEW TABLE TO GET DEST ADR+1
BLT S2,-1(S1) ;COPY OLD TABLE TO NEW TABLE
;RETURN THE OLD TABLE'S MEMORY TO THE MEMORY MANAGER
MOVE S2,P1 ;PICK UP OLD PACKN TABLE ADDRESS
MOVE S1,NDLKNM ;PICK UP NUMBER OF ENTRIES IN OLD TBL
IMULI S1,.NDLSZ ;CALCULATE SIZE OF THE OLD TABLE
$CALL M%RMEM ;RETURN THE MEMORY TO THE MEMORY MGT
;UPDATE THE NUMBER OF ENTRIES IN USE AND THE NUMBER OF FREE ENTRIES IN THE
;NEW PACKN TABLE
EXPTA1: MOVEI S1,MAXNOD ;PICK UP THE NUMBER OF NEW ENTRIES
ADDM S1,NDLKNM ;ADD TO THE NUMBER OF EXISTING ENTRIES
ADDM S1,NDLKFR ;ADD TO THE NUMBER OF FREE ENTRIES
$RET ;RETURN TO THE CALLER
SUBTTL UTILITY ROUTINES FOR SHOW CLUSTER-GALAXY-LINK-STATUS
;The following routines are used in building the display for the response
;to the SHOW CLUSTER-GALAXY-LINK-STATUS command.
CRLF: PUSH P,S1 ;PRESERVE S1
MOVEI S1,[BYTE(7) 15,12,0,0,0] ;GET THE CRLF.
$CALL ASCOUT ;DUMP IT OUT
POP P,S1 ;RESTORE S1
$RETT ;AND RETURN
ASCOUI: PUSH P,S1 ;SAVE S1
HRRZ S1,@-1(P) ;GET THE ADRS OF THE MESSAGE
AOS -1(P) ;SKIP OVER THE ARG POINTER
$CALL ASCOUT ;DUMP IT OUT
POP P,S1 ;RESTORE S1
$RETT ;AND WIN
ASCOUT: $CALL .SAVE1 ;SAVE P1.
MOVE P1,S1 ;SAVE THE INPUT ADDRESS.
HRLI P1,(POINT 7,0) ;MAKE IT A BYTE POINTER.
ASCO.1: ILDB S1,P1 ;GET A BYTE.
JUMPE S1,.RETT ;DONE,,RETURN.
$CALL DEPBYT ;PUT IT OUT.
JRST ASCO.1 ;AND DO ANOTHER.
;DEPBYT is used by $TEXT in transferring ASCIZ text to the ACK message
DEPBYT: IDPB S1,BYTPTR ;PICK UP THE NEXT CHARACTER
$RETT ;RETURN TRUE
SUBTTL GETPAG - GET A PAGE FOR OUTGOING IPCF MESSAGE
;GETPAG obtains a page from the memory manager to be used to build an
;outgoing IPCF message.
;
;Call is: No arguments
;Returns: MO/ Address of the page for the outgoing IPCF message
GETPAG: $CALL M%GPAG ;PICK UP THE PAGE
MOVE MO,S1 ;PLACE THE ADDRESS IN MO
$RET ;RETURN TO THE CALLER
SUBTTL RELPAG - RELEASE OUTGOING IPCF PAGE
;This routine releases a page back to the memory manager in the event
;that the IPCF send of a message failed.
;
;Call is: MO/ Address of outgoing IPCF message page
;Returns: The page has been returned to the memory manager
RELPAG: MOVE S1,MO ;PICK UP THE MESSAGE ADDRESS
$CALL M%RPAG ;RELEASE THE PAGE
SETZ MO, ;TO AVOID CONFUSION
$RET ;RETURN TO THE CALLER
SUBTTL TABLES FOR ERROR CODES REPORTED
;DEFINE THE ERROR DISPATCH VECTOR
DEFINE X(SUFFIX,TEXT),<
E$'SUFFIX:: PUSHJ P,RPTERR ;DISPATCH TO ERROR HANDLER
> ;END OF DEFINE X
ERRTBL: ERRCDS ;EXPAND THE DISPATCH TABLE
ERRTEX: ERRTXT ;EXPAND TEXT MACROS
TXTERR==ERRTEX-ERRTBL+1 ;GET NUMBER OF FIRST TEXT ERROR
;DEFINE THE TEXT BLOCK TABLE
DEFINE X(SUFFIX,TEXT),<
EXP [ITEXT(<TEXT>)] ;[6013]TABLE OF MESSAGES
> ;END OF DEFINE X
TXTTBL:: EXP [BYTE (7)0] ;0 IS NOT REALLY AN ERROR
ERRCDS ;DEFINE THE REST OF THEM
TXTTEX: ERRTXT
;DEFINE THE .MSFLG TABLE
DEFINE X(SUFFIX,TEXT),<
MF.FAT!INSVL.(<SIXBIT\ SUFFIX\>,MF.SUF)
> ;END OF DEFINE X
STSTBL:: MF.NOM ;0 HAS NO TEXT ASSOCIATED
ERRCDS ;EXPAND THE REST NOW
ERRTXT ;EXPAND TEXT ERRORS
;HERE WHEN SOMEONE CALLS (OR EXITS THROUGH) ANY OF THE E$xxx ERROR CODES
;THIS ROUTINE STORES THE RELATIVE ERROR NUMBER INTO G$ERR
RPTERR:: EXCH T1,(P) ;SAVE T1, GET ERROR DISPATCH
TLZ T1,-1 ;CLEAR THE LEFT HALF
SUBI T1,ERRTBL ;CONVERT TO ERROR INDEX
CAIL T1,TXTERR ;CHECK FOR TEXT ERROR
TLO T1,400000 ;FLAG AS TXTERR
SKIPN G$ERR ;DON'T SAVE THIS IF ALREADY AN ERROR
MOVEM T1,G$ERR ;SET GLOBAL ERROR INDICATOR
POP P,T1 ;RESTORE T1 AND RETURN
$RETF ;PROPAGATE ERROR TO TOP LEVEL
SUBTTL COMMON STOPCODES
;These STOPCODES are called from more than one location in NEBULA's
;top fork.
$STOP (CTL, CLUSTER TOO LARGE)
$STOP (CSI, CAN'T SETUP INTERRUPT SYSTEM)
$STOP (SIF, SCS% INTERRUPT HANDLER ENCOUNTERED FATAL ERROR)
$STOP (NTI, NODE TABLE INCONSISTENCY)
$STOP (NDI, NODE DATA BASE INCONSISTENCY)
$STOP (IMM, ILLEGALLY FORMATED MOUNTR MESSAGE)
$STOP (OSF, SEND TO ORION FAILED)
$STOP (QSF, SEND TO QUASAR FAILED)
$STOP (SCI, SENDER CAN'T INTERRUPT THE TOP FORK)
$STOP (SLL, SENDER LOST ITS DECNEC LINK)
$STOP (LCI, LISTENER CAN'T INTERRUPT THE TOP FORK)
$STOP (COL, CAN'T OBTAIN THE LINK STATUS)
$STOP (LUP, LISTENER UNABLE TO PICK UP DECNET MESSAGE)
$STOP (COD, CAN'T SETUP DEBUGGING DECNET DEVICE NAME) ;[6003]
;AN INFERIOR FORK WAS NOT INTERRUPTED. THIS CAN ONLY HAPPEN IF THE
;PROCESS HANDLE IS INVALID (ERROR FRKHX1). THIS IN TURN CAN ONLY HAPPEN
;IF THE INFERIOR FORK WAS KILLED (KFORK%) OR THE SENDER BLOCK OR LISTENER
;BLOCK HAS BEEN CORRUPTED. BOTH OF THESE POSSIBILITIES IMPLY THAT NEBULA
;IS IN AN INCONSISTENT STATE AND SHOULD THEREFORE BE CRASHED.
$STOP (UII, UNABLE TO INTERRUPT AN INFERIOR FORK)
END NEBULA