Trailing-Edge
-
PDP-10 Archives
-
bb-l014t-bm_tops20_v7_0_atpch20
-
autopatch/nebula.x20
There is 1 other file named nebula.x20 in the archive. Click here to see a list.
TITLE NEBULA
SUBTTL STORAGE ALLOCATION AND DEFINITIONS
; COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1988.
; ALL RIGHTS RESERVED.
;
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
; ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
; INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
; COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
; OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
; TRANSFERRED.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
; AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
; CORPORATION.
;
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
; SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
SEARCH NEBMAC ;CHECK NEBULA'S LIBRARY
SEARCH GLXMAC ;CHECK GALAXY'S LIBRARY
SEARCH QSRMAC ;CHECK QUASAR'S LIBRARY
SEARCH ORNMAC ;CHECK ORION'S LIBRARY
SEARCH GALCNF ;GET CONFIGURATION DATA
SALL ;CLEAN LISTINGS
PROLOG (NEBULA) ;GENERATE THE NECESSARY GALAXY SYMBOLS
NEBVEC: BLDVEC (NEBMAC,NMC,L)
BLDVEC (GLXMAC,GMC,L)
BLDVEC (QSRMAC,QMC,L)
BLDVEC (ORNMAC,OMC,L)
BLDVEC (NEBULA,NEB,L)
NEBMAN==:6037 ;MAINTENANCE EDIT NUMBER
NEBDEV==:6036 ;DEVELOPMENT EDIT NUMBER
VERSIN (NEB) ;GENERATE EDIT NUMBER
NEBWHO==0
NEBVER==6
NEBMIN==0
NEBVRS==<VRSN.(NEB)>+NMCEDT+GMCEDT+QMCEDT+OMCEDT
.JBVER==137
LOC .JBVER
EXP NEBVRS
RELOC
SUBTTL Table of Contents
; Table of Contents for NEBULA
;
;
; Section Page
; 1. STORAGE ALLOCATION AND DEFINITIONS . . . . . . . . . . 1
; 2. Table of Contents. . . . . . . . . . . . . . . . . . . 3
; 3. REVISION HISTORY . . . . . . . . . . . . . . . . . . . 4
; 4. SYMBOL DEFINITONS. . . . . . . . . . . . . . . . . . . 5
; 5. RANDOM STORAGE AREA. . . . . . . . . . . . . . . . . . 6
; 6. RESIDENT JOB DATA BASE . . . . . . . . . . . . . . . . 7
; 7. PID AND INTERRUPT DEFINITION . . . . . . . . . . . . . 8
; 8. NEBULA STARTUP AND SCHEDULER . . . . . . . . . . . . . 9
; 9. NEBENV - CHECK THE NEBULA ENVIRONMENT. . . . . . . . . 10
; 10. NBINIT - GET NODE NAME, NODE NUMBER, AND SIZE OF NEBULA 11
; 11. WAIQSR - WAIT FOR QUASAR TO STARTUP. . . . . . . . . . 12
; 12. WAIORN - WAIT FOR ORION TO STARTUP . . . . . . . . . . 13
; 13. INTINI - . . . . . . . . . . . . . . . . . . . . . . . 14
; 14. NEBULA INTERRUPT HANDLERS. . . . . . . . . . . . . . . 15
; 15. NBSCS - TOPOLOGY CHANGE DECTECTED INTERRUPT HANDLER. . 16
; 16. NODINT - . . . . . . . . . . . . . . . . . . . . . . . 17
; 17. BLDLST - INITIALIZES PACKN TABLE . . . . . . . . . . . 18
; 18. GTNDAT - PICK UP THE NODE NAMES AND NUMBERS. . . . . . 19
; 19. STLAS - START UP THE LISTENERS AND SENDERS . . . . . . 20
; 20. STAINF - STARTUP A LISTENER AND SENDER TO A NODE . . . 21
; 21. BLDSRV - BUILD THE SRV: DEVICE NAME. . . . . . . . . . 22
; 22. STLIS - START UP THE LISTENER. . . . . . . . . . . . . 23
; 23. BLDDCN - BUILD THE DCN: DEVICE NAME. . . . . . . . . . 24
; 24. STSEN - START UP A SENDER. . . . . . . . . . . . . . . 25
; 25. CLUSTER TOPOLOGY CHANGE DETECTED . . . . . . . . . . . 26
; 26. KILNOD - DELETE A NODE FROM THE NODE DATA BASE . . . . 27
; 27. KILINF - KILL A NODE'S LISTENER AND SENDER . . . . . . 28
; 28. UPDQUE - UPDATE A NODE'S QUEUES. . . . . . . . . . . . 29
; 29. DELTIM - DELETE THE TIMER LIST AND TURN OFF TIMERS . . 30
; 30. UPDREM - CLEAN UP REMOTE QUEUE FOR SENDER/LISTENER CRASH 31
; 31. UPDIBH - CLEAN UP IBH QUEUE FOR SENDER/LISTENER . . . 32
; 32. UPDMSG - CLEAN UP MESSAGE QUEUE FOR SENDER/LISTENER . 33
; 33. BLDNEN - BUILD AN ENTRY IN THE NODE TABLE. . . . . . . 34
; 34. CHKDEC - INFERIOR FORK HAS A DECNET CONNECTION . . . . 35
; 35. CHKQUE - IPCF MESSAGE PROCESSING . . . . . . . . . . . 36
; 36. NTDSM - PROCESS A "TO NEBULA DISMOUNT" MESSAGE . . . . 37
; 37. SNDACK - SEND A TO NEBULA DISMOUNT ACK TO MOUNTR . . . 38
; 38. NTMTS. . . . . . . . . . . . . . . . . . . . . . . . . 39
; 39. NFDAK - PROCESS A "FROM NEBULA DISMOUNT ACK" MESSAGE . 40
; 40. NCDSM. . . . . . . . . . . . . . . . . . . . . . . . . 41
; 41. NDISPY . . . . . . . . . . . . . . . . . . . . . . . . 42
; 42. NSHOW - PROCESS OPR SHOW MESSAGES. . . . . . . . . . . 43
; 43. NLIST - PROCESSES EXEC "INFORMATION OUTPUT" MESSAGE. . 44
; 44. NKILL - ROUTINE PROCESS AN EXEC CANCEL MESSAGE . . . . 45
; 45. N$FNDB - ROUTINE TO FIND ANY BLOCK IN AN IPCF MESSAGE. 46
; 46. NSCLU - PROCESSES THE "SHOW CLUSTER-GALAXY" MESSAGE. . 47
; 47. NDRCF - ENABLE/DISABLE REPORT-CONNECTION-FAILURES. . . 48
; 48. NDDCA - ENABLE/DISABLE DECNET-CONNECTION-ATTEMPTS. . . 49
; 49. SETPAG - SETUP MESSAGE HEADER FOR SHOW ACK MESSAGES. . 50
; 50. SETHDR - BUILDS DISPLAY BLOCK FOR SHOW ACK MESSAGES. . 51
; 51. BDBHDR - BUILD DISPLAY BLOCK HEADER. . . . . . . . . . 52
; 52. FNDNBK - FIND THE NODE BLOCK IN AN IPCF MESSAGE. . . . 53
; 53. CHKLEN - CHECK THE VALIDITY OF AN IPCF MESSAGE . . . . 54
; 54. QSREMM - SEND OR QUEUE REMOTE MESSAGES TO A SINGLE REMOTE NODE 55
; 55. QMREMM - SEND OR QUEUE REMOTE MESSAGES TO MULTIPLE REMOTE NODES 56
; 56. QRIBHM - SEND/QUEUE RESPONSES TO IBH MESSAGE TO REQUESTING NODE 57
; 57. SETPAR - SETUP PARAMETERS FOR ROUTINE QUEMSG . . . . . 58
; 58. SEPALL - SET UP PARAMETERS FOR ROUTINE QUEMSG. . . . . 59
; 59. BLDHAD - BUILD THE HEADER AND DISPLAY BLOCKS FOR ACK MESSAGE 60
; 60. MOVERR - PLACE ERROR REASON IN TEXT BLOCK. . . . . . . 61
; 61. QUEMSG - SEND OR QUEUE A MESSAGE . . . . . . . . . . . 62
; 62. ORNACK - SEND AN ERROR ACK TO ORION. . . . . . . . . . 63
; 63. BLDACK . . . . . . . . . . . . . . . . . . . . . . . . 64
; 64. TXTMOV - MOVE TEXT FROM ONE LOCATION TO ANOTHER. . . . 65
; 65. BLDHDR - BUILD THE MESSAGE HEADER FOR ACK MESSAGE. . . 66
; 66. EREXEC - SEND AN ERROR MESSAGE TO THE EXEC . . . . . . 67
; 67. DEPCHR - INSERT AN ASCII CHARACTER IN AN EXEC ERROR MESSAGE 68
; 68. SETTIM - SETUP A TIMER FOR DECNET MESSAGE. . . . . . . 69
; 69. CLRTIM - CLEAR A TIMER UPON MESSAGE RESPONSE BEING RECEIVED 70
; 70. REMTIM - CLEAR A TIMER . . . . . . . . . . . . . . . . 71
; 71. PROTIM - TIMER HAS GONE OFF, COMMUNICATION LOST TO REMOTE NODE 72
; 72. SNDMSG - SEND MESSAGES TO AVAILABLE SENDERS. . . . . . 73
; 73. SENMSG - NOTIFY A SENDER OF A MESSAGE AVAILABLE. . . . 74
; 74. CONSTS - CONNECTION FAILURE STATUS . . . . . . . . . . 75
; 75. GETMSG -PICK UP A MESSAGE FROM A LISTENER. . . . . . . 76
; 76. PROMSG - PROCESS DECNET LISTENER MESSAGES DISPATCHER . 77
; 77. LFDAK - PROCESS A "FROM NEBULA DISMOUNT ACK" MESSAGE . 78
; 78. LSIBHM - PROCESS IN BEHALF OF MESSAGES FROM LISTENERS. 79
; 79. EINFO - PROCESS AN IN BEHALF OF EXEC INFO OUTPUT MESSAGE 80
; 80. EKILL - PROCESS AN IN BEHALF OF EXEC CANCEL MESSAGE. . 81
; 81. NSRCL - PROCESS REMOTE SHOW CLUSTER-STATUS MESSAGE . . 82
; 82. NSEACK - BUILD AN ACK MESSAGE REMOTELY . . . . . . . . 83
; 83. RSPMSG - RESPONSE TO A MESSAGE . . . . . . . . . . . . 84
; 84. SENREM - SEND A MESSAGE FROM A REMOTE NODE TO ORION. . 85
; 85. REXSHW - RESPONSE TO AN EXEC REQUEST . . . . . . . . . 86
; 86. RNEBAK - RESPOND TO A NEBULA ACK MESSAGE . . . . . . . 87
; 87. NRMACK - PROCESS A NEBULA ACK RESPONSE MESSAGE . . . . 88
; 88. RESTAR - PROCESS CRASHED INFERIOR FORKS. . . . . . . . 89
; 89. INFSTS - DETERMINE THE STATUS OF AN INFERIOR FORK. . . 90
; 90. SNDORN - SEND AN IPCF MESSAGE TO ORION OR QUASAR . . . 91
; 91. N$SEND - ROUTINE TO SEND AN IPCF MESSAGE TO AN EXEC. . 92
; 92. XFRMSG - TRANSFER IPCF MESSAGE FROM ONE BUFFER TO ANOTHER 93
; 93. ADDMQE - ADD A MESSAGE TO A SENDER'S MESSAGE QUEUE . . 94
; 94. FNDMQE - FIND AND RETURN A MESSAGE QUEUE ENTRY . . . . 95
; 95. RELMQE - RETURN A MESSAGE QUEUE ENTRY TO MEMORY MANAGER 96
; 96. BLDMQE - BUILD A MESSAGE QUEUE ENTRY . . . . . . . . . 97
; 97. ADDIBH - ADD AN IN BEHALF OF QUEUE ENTRY . . . . . . . 98
; 98. FNDIBH - FIND AN IN BEHALF OF QUEUE ENTRY. . . . . . . 99
; 99. RELIBH - RETURNS AN IN BEHALF OF QUEUE ENTRY . . . . . 100
; 100. ADDGRQ - ADD A REMOTE QUEUE ENTRY TO THE GLOBAL REMOTE QUEUE 101
; 101. FNDGRQ - FIND A GLOBAL REMOTE QUEUE ENTRY. . . . . . . 102
; 102. RELGRQ - RETURNS A GLOBAL REMOTE QUEUE ENTRY . . . . . 103
; 103. FNDNRQ - FIND A NODE'S REMOTE QUEUE ENTRY. . . . . . . 104
; 104. RELNRQ - RETURNS A NODE'S REMOTE QUEUE ENTRY . . . . . 105
; 105. SNAMNT - SEARCH NODE TABLE BY NODE NAME. . . . . . . . 106
; 106. SNUMNT - SEARCH NODE TABLE BY NODE NUMBER. . . . . . . 107
; 107. LISTEN - MESSAGE SERVER FOR A REMOTE NODE. . . . . . . 108
; 108. LISSET - INITIALIZE THE LISTENER'S GLXLIB AND CAPABILITIES 109
; 109. LOPLNK - OPEN A DECNET SRV: DEVICE . . . . . . . . . . 110
; 110. LISINT - SET UP THE LISTENER'S INTERRUPT SYSTEM. . . . 111
; 111. ACCEPT - VALIDATE A DECNET CONNECTION REQUEST. . . . . 112
; 112. MSGFSN - DECNET MESSAGE FROM SENDER IS AVAILABLE . . . 113
; 113. GETSMG - PICK UP MESSAGE FROM SENDER AND PLACE ON MESSAGE QUEUE 114
; 114. MSGTTF - TOP FORK READY FOR A MESSAGE FROM A LISTENER. 115
; 115. XFRTOP - MOVE MESSAGE FROM MESSAGE QUEUE TO MESSAGE BUFFER 116
; 116. ADDLME - ADD A LISTENER MESSAGE QUEUE ENTRY. . . . . . 117
; 117. RELLME - DELETE AN ENTRY FROM THE LISTENER MESSAGE QUEUE 118
; 118. LISCHK - LISTENER CHECKSUM AND ACK MESSAGE . . . . . . 119
; 119. SENACK - SEND AN ACK MESSAGE TO THE REMOTE SENDER. . . 120
; 120. INLCRH - ROUTINE TO INDICATE LISTENER CONTROLLED CRASH 121
; 121. SENDER - MESSAGE ROUTER TO A REMOTE NODE . . . . . . . 122
; 122. SENSET - INITIALIZE THE SENDER'S GLXLIB AND CAPABILITIES 123
; 123. SENINT - SET UP THE SENDER'S INTERRUPT SYSTEM. . . . . 124
; 124. SOPLNK - OBTAIN A CONNECTION TO THE LISTENER . . . . . 125
; 125. SGTLNK - OBTAIN DECNET JFN AND OPEN IT . . . . . . . . 126
; 126. SCKLNK - CHECK THE STATUS OF THE SENDER'S LINK . . . . 127
; 127. FNDCER - DETERMINE THE DECNET CONNECTION ERROR . . . . 128
; 128. SENCON - INDICATE TO TOP FORK THAT SENDER HAS A CONNECTION 129
; 129. MSGTLI - SEND A MESSAGE TO THE LISTENER. . . . . . . . 130
; 130. CHKSUM - CHECKSUM DECNET MESSAGES. . . . . . . . . . . 131
; 131. MSGFLI - PICKUP ACK MESSAGE FROM THE LISTENER. . . . . 132
; 132. SSNDMG - SEND A MESSAGE TO A LISTENER. . . . . . . . . 133
; 133. REPCON - ENABLE DECNET-CONNECTION-ATTEMPTS . . . . . . 134
; 134. INSCRH - ROUTINE TO INDICATE SENDER CONTROLLED CRASH . 135
; 135. NEBDDT - ROUTINE TO LOAD DDT IF DEBUGGING. . . . . . . 136
; 136. KASNOD - RESET A NODE'S DATA BASE. . . . . . . . . . . 137
; 137. STINFO - START AN INFO% JSYS FAILURE TIMER . . . . . . 138
; 138. IEPROC - INFO% JSYS ERROR TIMER EVENT PROCESSOR. . . . 139
; 139. TOPTMR - TOPOLOGY CHANGE TIMER . . . . . . . . . . . . 140
; 140. NEBTMR - NEBULA ACK MESSAGE TIMER. . . . . . . . . . . 141
; 141. NACKTM - NEBULA ACK MESSAGE TIMER PROCESSOR. . . . . . 142
; 142. NODPAR - PICK UP THE ENVIRONMENT OF A REMOTE NODE. . . 143
; 143. CHKSTS - CHECK FOR DECNET AND RELEASE 7 MONITOR. . . . 144
; 144. FNDPNE - ADD AN ENTRY TO THE PACKN TABLE IF NECESSARY. 145
; 145. SRHPNE - CHECK IF A NODE HAS AN ENTRY IN THE PACKN TABLE 146
; 146. USNERR - SET UP ARGUMENT WORDS FOR ACK MESSAGE PROCESSING 147
; 147. REASON - MESSAGE ERROR TABLE . . . . . . . . . . . . . 148
; 148. EXPTAB - EXPAND THE PACKN TABLE. . . . . . . . . . . . 149
; 149. UTILITY ROUTINES FOR SHOW CLUSTER-GALAXY-LINK-STATUS . 150
; 150. GETPAG - GET A PAGE FOR OUTGOING IPCF MESSAGE. . . . . 151
; 151. RELPAG - RELEASE OUTGOING IPCF PAGE. . . . . . . . . . 151
; 152. TABLES FOR ERROR CODES REPORTED. . . . . . . . . . . . 152
; 153. COMMON STOPCODES . . . . . . . . . . . . . . . . . . . 153
SUBTTL REVISION HISTORY
COMMENT \
***** Release 6.0 -- begin development edits *****
6000 6.1140 13-Dec-87
Create NEBULA as the cluster GALAXY message router.
6001 6.1142 17-Dec-87
Add support for the SHOW STATUS TAPE and SHOW STATUS DISK
commands.
6002 6.1144 17-Dec-87
If an OPENF% fails due to node name not assigned, then retry
every 5 seconds up to 5 minutes before crashing.
6003 6.1145 17-Dec-87
When debugging, use the first six characters of the user name
rather than "NEBULA" in the listener and sender names.
6004 6.1146 17-Dec-87
Add support for the SHOW STATUS STRUCTURE command
6005 6.1154 30-Dec-87
Change routine SGTLNK to check for error NSPX24 rather than error
NSPX25 if an OPENF% fails.
6006 6.1155 31-Dec-87
Clean up the display of the response to the SHOW CLUSTER command.
6007 6.1160 5-Jan-88
Cause routine NTMTS to increment the current block pointer correctly.
6010 6.1161 5-Jan-88
Cause routine NFDAK to correctly point to the error block.
6011 6.1170 21-Jan-88
Clear the timer when a response to a message has been received.
6012 6.1175 7-Feb-88
Add support for the EXEC commands INFORMATION OUTPUT/DESTINATION
and CANCEL PRINT/DESTINATION.
6013 6.1180 13-Feb-88
Clean up the creation of error messages that caused IQN crashes.
6014 6.1181 15-Feb-88
On encountering any errors forwarding INFORMATION OUTPUT/DESTINATION
and CANCEL PRINT/DESTINATION messages, send an error message to the EXEC
with the same format that the EXEC expects error messages from QUASAR.
6015 6.1183 16-Feb-88
HALTF% is Cluster GALAXY is not enabled.
6016 6.1192 23-Feb-88
Correct various timing problems encountered that involve CLUDGR not
fully initialized and the monitor's CI node data base not being fully
initialized. Add the NEBULA ACK/NEBULA ACK RESPONSE message mechanism.
6017 6.1194 23-Feb-88
Change routine SENMSG to use the correct AC when picking up the message
address when setting the message response timer.
6020 6.1200 29-Feb-88
If a DECnet OPENF% fails, then check for error NSPX13 (Access not
permitted. If this is the error, then try again.
6021 6.1201 29-Feb-88
Sender OPENF% failures can be due to a variety of transcient DECnet
problems, as can listener MTOPR% failures. For all OPENF% failures, retry
up to five minutes. For MTOPR% failures, CLOSF% the link and re-open the
link. If there is no success after the retries, then inform ORION and
HALTF%, but do not stopcode.
6022 6.1202 29-Feb-88
If a cluster topology change occurs and if no listener or sender
to a node has been started, do not cause routine RESTAR to erronously
send a WTO message to ORION stating that that node's sender and listener
has been restarted.
6023 6.1203 29-Feb-88
Correct the response message format to the command:
OPR>SHOW CLUSTER/NODE:FOO/CLUSTER-NODE:FOO
6024 6.1209 2-Mar-88
If a REMOTE DISMOUNT message cannot be sent to a remote node, then
indicate this in the remote queue entry with monitor error NSPX18 so that
MOUNTR can display the reason in its WTO message to ORION.
6025 6.1221 6-Mar--88
More of edit 6024. MOUNTR also requires bit RQ%TER set in order to
display the error string.
6026 6.1225 8-Mar-88
Update copyright notice.
6027 6.1239 26-Apr-88
If communication is lost to a remote NEBULA and if there is an
outstanding response to a dismount message from that NEBULA, then indicate
error SCLX08 (Unexpected state - no communication) in the TO NEBULA DISMOUNT
ACK message that is sent to MOUNTR.
Also, if NEBULA receives an unknown IPCF message, then log that fact with
ORION.
6030 6.1241 27-Apr-88
More of edit 6030. MOUNTR also requires bit RQ%TER set in order to
display the error string.
6031 6.1244 30-Apr-88
Update timer word MSGTIM during every scheduling pass rather than
only when an IPCF message is received.
6032 6.1245 3-May-88
Clear the SAB index word (SAB.SI) when sending a message to an EXEC,
otherwise, the message may be sent to QUASAR if the previous IPCF message
had been sent to QUASAR.
6033 6.1247 5-May-88
Add support for the SHOW STATUS NETWORK-NODE and SHOW PARAMETERS
NETWORK-NODE commands.
6034 6.1248 6-May-88
Cause NEBULA to wait for ORION to be running. If NEBULA starts up
before ORION does, then the first message NEBULA receives from ORION is
rejected.
6035 6.1252 10-May-88
Change routines RESTAR and CHKDEC to first check if there are any
remaining remote nodes in the cluster. If there are not, then have them
return. This prevents NTI crashes from occurring in the case where a node
has left the cluster and there are no longer any remote nodes in the cluster.
6036 6.1256 13-May-88
Cause NEBULA to wait for QUASAR to be running. If NEBULA starts up
before QUASAR does, then NEBULA rejects all messages from QUASAR since
QUASAR is not in its system PID table.
6037 6.1269 18-Oct-88
1. Implement the /CLUSTER-NODE switch with the rest of the OPR commands.
2. Include the PASSWORD in the connect initiate message. This is used to
determine whether the node is running Field Image Galaxy or post FI. Since
FI Galaxy don't support these OPR commands there is no need to send the
command to the node.
3. If the message is not defined in MSGTAB, then assume it is in the new
format. Since ORION should have already verify the message we can make
this assumption. The new message format is exactly the same as the ORION
message to QUASAR, except bit NEB%MS 1B0 will be lit.
4. Remember the number of responses associated with a Cluster command.
\ ;End of Revision History
SUBTTL SYMBOL DEFINITONS
PDSIZ==^D200 ;SIZE OF THE PUSH DOWN STACK
MAXNOD==7 ;MAXIMUM NUMBER OF REMOTE NODES
DBSIZ==2 ;SIZE OF SENDER/LISTENER DATA BASE
M==13 ;INCOMING IPCF MESSAGE ADDRESS
MO==14 ;OUTGOING IPCF MESSAGE
LIS==15 ;LISTENER DATA BASE ADDRESS
SEN==16 ;SENDER DATA BASE ADDRESS
NNMFLD==17B35 ;NODE NUMBER FIELD
VERNUM==700 ;MINIMUM VALID MONITER VERSION NUMBER
INFBSZ==6 ;INFO% JSYS BLOCK SIZE
SCSCN==4 ;SCS% CHANNEL NUMBER
SCSLEN==1+.SQDTA+SQ%CDT ;SIZE OF SCS% EVENT BLOCK
CNFLEN==1+3*<MAXNOD+1> ;ASCIZ NODE NAME BLOCK LENGTH
MSGLN==^D200 ;[6012]LENGTH OF EXEC ERROR MESSAGE
TIMOUT==<^D5*^D60*^D1000>/^D333 ;TIMEOUT VALUE FOR REMOTE NODE RESPONSE
TOPTRY==<^D3*^D60*^D1000>/^D333 ;[6016]TIME IN WHICH TO CHECK TOPOLOGY
TIMUP==5*^D60*^D1000 ;[6016]MIN MONITOR UPTIME FOR NO RECHECK
IEMAX==5 ;[6016]MAX TIMER TRIES ON INFO% ERROR
SUBTTL RANDOM STORAGE AREA
PDL: BLOCK PDSIZ ;PUSH DOWN STACK
NODNAM: BLOCK 1 ;THE LOCAL NODE NAME (SIXBIT)
NODNUM: BLOCK 1 ;THE LOCAL NODE NUMBER
RENNUM: BLOCK 1 ;NUMBER OF REMOTE NODES
NBSCHD: BLOCK 1 ;NEBULA SCHEDULING FLAG
NEBSIZ: BLOCK 1 ;THE NUMBER OF PAGES IN NEBULA
LOCACK: BLOCK 1 ;LOCAL ACK CODE FOR IBH MESSAGES
MSGTIM: BLOCK 1 ;TIME AN IPCF MESSAGE WAS PICKED UP
TIMCTR: BLOCK 1 ;MAKE UNIQUE UDT FOR TIMEOUT QUEUES
TIMBLK: BLOCK .TIDAT+1 ;SIZE OF THE TIMER EVENT QUEUE ENTRY
BYTPTR: BLOCK 1 ;SAVE AREA FOR A BYTE POINTER
G$ERR: BLOCK 1 ;ERROR DETECTED DURING IPCF PROCESSING
G$SND: BLOCK 1 ;PID OF IPCF MESSAGE SENDER
G$MSG: BLOCK MSGLN ;[6012]EXEC ERROR MESSAGE BUFFER
RCFFLG: BLOCK 1 ;REPORT-CONNECTION-FAILURES FLAG
DCAFLG: BLOCK 1 ;DECNET-CONNECTION-ATTEMPTS FLAG
STFLAG: EXP -1 ;NEBULA NOT RESTARTABLE FLAG
BLDTAB: EXP -1 ;NODE TABLE BEING BUILT AT STARTUP
SAB: BLOCK SAB.SZ ;IPCF SENDER ADDRESS BLOCK
SCSBLK: EXP 2 ;SCS% INTERRUPT ENABLED BLOCK SIZE
XWD .SIPAN,SCSCN ;ASSOCIATE SCS EVENTS WITH CHAN SCSCN
SCSEBK: BLOCK SCSLEN ;SCS% EVENT BLOCK
REMHDR: BLOCK 1 ;GLOBAL REMOTE QUEUE HEADER WORD
REMTRL: BLOCK 1 ;GLOBAL REMOTE QUEUE TRAILER WORD
IBQHDR: BLOCK 1 ;IN BEHALF OF QUEUE HEADER WORD
IBQTRL: BLOCK 1 ;IN BEHALF OF QUEUE TRAILER WORD
REMORG: BLOCK 1 ;MESSAGE ORIGINATED FROM A REMOTE NODE
REMFLG: BLOCK 1 ;PROCESS THE MESSAGE REMOTELY
LOCFLG: BLOCK 1 ;PROCESS THE MESSAGE LOCALLY
BLKADR: BLOCK 1 ;.WTTXT BLOCK ADDRESS, USED BY BLDHAD
NODDAT: BLOCK 3 ;NODE NAME PASSED AS OPTIONAL DATA
EXESND: BLOCK 1 ;[6012]MESSAGE FROM EXEC FLAG
EXESHW: BLOCK 1 ;[6012]EXEC SHOW/KILL RESPONSE FLAG
STABLK: BLOCK 1 ;[6013].CMTXT BLOCK ADDRESS
;**;[6037]At STABLK +1L add 1 line JYCw Oct-18-88
PASSWD: BLOCK 2 ;[6037]PASSWORD block
NMFFLG: BLOCK 1 ;[6037]New message format flag
;THE G$ARGX WORDS MUST BE CONTIGUOUS. ENSURE THIS BY DEFINING THEM WITH
;A MACRO
DEFINE CONCAT (X) <
G$ARG'X': BLOCK 1 ;;DEFINE THE ERROR WORD
>
DEFINE G$ARGX (A) <
IRP A,<IFE MAXNOD-A,<STOPI>
CONCAT A > ;;SETUP THE ERROR WORD
>
G$ARGX <1,2,3,4,5,6,7> ;SETUP THE ERROR BLOCK
; STORAGE USED BY NTDSM
NTSMSG: BLOCK 1 ;NUMBER OF NODES TO SEND MESSAGE TO
NNIMSG: BLOCK 1 ;NUMBER OF NODES IN IPCF MESSAGE
FIRNOD: BLOCK 1 ;ADDRESS OF FIRST NODE
LLWSIZ: BLOCK 1 ;SIZE OF LINK LIST BLOCK IN MSG QUEUE
MQMADR: BLOCK 1 ;ADDRESS OF MESSAGE IN MESSAGE QUEUE
STRLEN: BLOCK 1 ;LENGTH OF STRUCTURE NAME BLOCK
IBLADR: BLOCK 1 ;INVARIANT BLOCK ADDRESS
; STORAGE USED BY TOPCHN
CURNUM: BLOCK 1 ;CURRENT NUMBER OF NODES
;MACRO USED BY NSCLU
DEFINE $ASCII(MSG),<
PUSHJ P,ASCOUI ;;CALL THE IN-LINE ASCII OUTPUTTER
CAI [ASCIZ+MSG+] ;;AIM AT THE MESSAGE
>;END $ASCII DEFINE
NEBACK: 5,,.NACKM ;[6016]NEBULA ACK MESSAGE HEADER WORD
EXP 0,0,0,0 ;[6016]NEBULA ACK MESSAGE HEADER
NEBRSP: 5,,.NACKR ;[6016]NEBULA ACK RESPONSE MSG HDR WORD
EXP 0,0,0,0 ;[6016]NEBULA ACK RESPONSE MSG HEADER
SUBTTL RESIDENT JOB DATA BASE
SREADY: BLOCK 1 ;SENDER IS AVAILABLE FLAG
LREADY: BLOCK 1 ;LISTENER HAS MESSAGE FLAG
IREADY: BLOCK 1 ;AN INFERIOR FORK HAS DECNET CONNECTION
TRMFRK: BLOCK 1 ;AN INFERIOR FORK HAS TERMINATED
SCSFLG: BLOCK 1 ;A CLUSTER TOPOLOGY CHANGE DETECTED
ASZNAM: BLOCK CNFLEN ;ASCIZ NODE NAMES FROM CNFIG% .CFCND
SWINFO: BLOCK .CFILN ;STATIC SOFTWARE INFORMATION
INFBLK: BLOCK INFBSZ ;INFO% SOFTWARE INFORMATION BLOCK
;NNMTBL AND NDNTBL ARE USED DURING CLUSTER TOPOLOGY CHANGE PROCESSING BY
;ROUTINE TOPCHN. NODSEN AND NODMQ ARE USED DURING IPCF MESSAGE PROCESSING
;BY ROUTINES SETPAR, SEPALL AND QUEMSG. THESE TWO SETS OF TABLES MUST NOT
;BE USED CONCURRENTLY.
NNMTBL: NODSEN: BLOCK 2+MAXNOD ;NODE NUMBER TABLE
NDNTBL: NODMQ: BLOCK MAXNOD ;REMOTE (SIXBIT) NODE NAME TABLE
NODTBL: BLOCK MAXNOD*.NNNSZ ;NODE TABLE
RECHEK: BLOCK 1 ;[6016]RECHECK NODE NAME TABLE
NDLKST: BLOCK 1 ;PREVIOUSLY AND CURRENTLY KNOWN NODES
NDLKNM: BLOCK 1 ;NUMBER OF ENTRIES IN PACKN TABLE
NDLKFR: BLOCK 1 ;NUMBER OF FREE ENTRIES IN PACKN TABLE
SUBTTL PID AND INTERRUPT DEFINITION
INTVEC==:LEVTAB,,CHNTAB
IB: $BUILD IB.SZ ;
$SET (IB.PRG,,%%.MOD) ;PROGRAM 'NEBULA'
$SET (IB.FLG,IP.STP,1) ;STOPCODES TO ORION
$SET(IB.FLG,IB.SYS,NEB.JP) ;SET SYSTEM PROCESS
$SET (IB.PIB,,PIB) ;SET UP PIB ADDRESS
$SET (IB.INT,,INTVEC) ;SETUP INTERRUPT VECTOR ADDRESS
$EOB ;
PIB: $BUILD PB.MNS ;
$SET (PB.HDR,PB.LEN,PB.MNS) ;PIB LENGTH,,0
$SET (PB.FLG,IP.PSI,1) ;PSI ON
$SET (PB.FLG,IP.RSE,1) ;RETURN ON SEND ERROR
$SET (PB.FLG,IP.SPB,1) ;SEE IF IPCF SENDER WAS PRIVILEGED
$SET (PB.FLG,IP.JWP,1) ;JOB-WIDE PID
$SET (PB.INT,IP.CHN,2) ;IPCF INTERRUPT CHANNEL
$SET (PB.INT,IP.SPI,SP.NEB) ;SET UP SYSTEM PID
$SET (PB.SYS,IP.BQT,-1) ;MAXIMUM SEND/RECEIVE IPCF QUOTA
$SET (PB.SYS,IP.MNP,^D5) ;NUMBER OF PIDS
$EOB ;
LEVTAB: EXP LEV1PC ;INTRPT LEVEL 1 PC ADDRESS
EXP LEV2PC ;INTRPT LEVEL 2 PC ADDRESS
EXP LEV3PC ;INTRPT LEVEL 3 PC ADDRESS
CHNTAB: XWD 1,LISMSG ;LISTENER HAS A MESSAGE
XWD 1,SNDREA ;SENDER IS READY FOR A MESSAGE
XWD 1,NBIPCF ;IPCF HAS A MESSAGE
XWD 1,INFRDY ;INFERIOR FORK HAS DECNET CONNECTION
XWD 1,NBSCS ;SCS DETECTED A CLUSTER TOPOLOGY CHANGE
BLOCK ^D31 ;INFERIOR FORK TERMINATED ON CHANNEL 19
;ALL OTHER CHANNELS 0
LEV1PC: BLOCK 1 ;LEVEL 1 INTERRUPT PC
LEV2PC: BLOCK 1 ;LEVEL 2 INTERRUPT PC
LEV3PC: BLOCK 1 ;LEVEL 3 INTERRUPT PC
SUBTTL NEBULA STARTUP AND SCHEDULER
;SET UP NEBULA
NEBULA: RESET% ;THE USUAL
SINGLE< HALTF%> ;[6015]QUIT IF CLUSTER GALAXY NOT ENABLED
MOVE P,[IOWD PDSIZ,PDL] ;SET UP THE STACK.
AOSE STFLAG ;RESTARTING?
$STOP (NNR,NEBULA NOT RESTARTABLE)
MOVEI S1,IB.SZ ;GET THE INITIALIZATION BLOCK SIZE.
MOVEI S2,IB ;ADDRESS OF THE INITIALIZATION BLOCK
$CALL I%INIT ;SET UP GLXLIB
$CALL NEBENV ;CHECK THE NEBULA ENVIRONMENT
$CALL NBINIT ;GO SETUP CONSTANTS AND CAPABILITIES
$CALL WAIQSR ;[6036]WAIT FOR QUASAR TO START UP
$CALL WAIORN ;[6034]WAIT FOR ORION TO START UP
$CALL INTINI ;SET UP THE INTERRUPT SYSTEM.
$CALL NODINT ;INITIALIZE THE NODE DATA BASE
$CALL BLDLST ;SETUP AND BUILD THE PACKN TABLE
SKIPE RENNUM ;ANY REMOTE NODES?
$CALL STLAS ;YES, START UP THE LISTENERS/SENDERS
MAIN: SETZM NBSCHD ;SLEEP AFTER THIS PASS
$CALL I%NOW ;[6031]PICK UP THE CURRENT TIME
MOVEM S1,MSGTIM ;[6031]SAVE FOR LATER
SKIPE SCSFLG ;CLUSTER TOPOLOGY CHANGE OCCURRED?
$CALL TOPCHN ;YES, UPDATE THE NODE DATA BASE
SKIPE TRMFRK ;HAS A SENDER OR LISTENER CRASHED?
$CALL RESTAR ;YES, FIND OUT WHICH ONE
SKIPE IREADY ;INFERIOR FORK HAS A DECNET CONNECTION?
$CALL CHKDEC ;YES, FIND OUT WHICH ONE
$CALL CHKQUE ;CHECK FOR IPCF MESSAGES
SKIPE SREADY ;IS A SENDER AVAILABLE?
$CALL SNDMSG ;YES, FIND OUT WHICH SENDER
SKIPE LREADY ;DOES A LISTENER HAVE A MESSAGE?
$CALL GETMSG ;YES, PICK IT UP
SKIPE NBSCHD ;TIME FOR ANOTHER SCHEDULING PASS?
JRST MAIN ;YES, GO CHECK AGAIN
SETZ S1, ;SLEEP TILL WE'RE NEEDED
$CALL I%SLP ;DON'T WAKE UP UNTIL NEEDED
JRST MAIN ;CHECK OUT WHAT HAPPEN
SUBTTL NEBENV - CHECK THE NEBULA ENVIRONMENT
;NEBENV is called during NEBULA startup to determine if the local node
;has the following environment:
; DECnet enabled
; A monitor of release 7 or later
; Cluster GALAXY enabled
;
;If any of these attributes are not present, then NEBULA crashes.
;
;Call is: No arguments
;Returns true: Only if DECnet is enabled for this node, the monitor is
; release 7 or later, and the Cluster GALAXY option is enabled.
;Crashes: If cannot obtain the static software information, DECnet is
; not enabled, or the monitor is pre-release 7.
NEBENV: $SAVE <T1,T2> ;CONFG% JSYS CHANGES THESE AC
MOVEI S2,SWINFO ;PICK UP ARGUMENT BLOCK ADDRESS
MOVEI S1,.CFILN ;PICK UP THE LENGTH OF THE ARG BLOCK
MOVEM S1,.CFLEN(S2) ;PLACE IT IN THE ARGUMENT BLOCK
MOVEI S1,.CFINF ;PICK UP THE FUNCTION
CNFIG% ;GET THE SOFTWARE INFORMATION
ERJMP [$STOP (COS, CAN'T OBTAIN STATIC SOFTWARE INFORMATION)]
MOVEI S1,SWINFO ;PICK UP ARGUMENT BLOCK ADDRESS
MOVE S2,.CFISO(S1) ;PICK UP THE STATIC SOFTWARE OPTIONS
TLNN S2,(CF%DCN) ;IS DECNET INSTALLED?
$STOP (DNI, DECNET NOT INSTALLED) ;NO, TERMINATE NOW
HLRZ S2,.CFIVR(S1) ;PICK UP THE VERSION NUMBER
CAIGE S2,VERNUM ;RELEASE 7 OR LATER?
$STOP (IMV, INVALID MONITOR VERSION)
$RETT ;NEBULA IS IN THE CORRECT ENVIRONMENT
SUBTTL NBINIT - GET NODE NAME, NODE NUMBER, AND SIZE OF NEBULA
;NBINIT is called during NEBULA startup. This routine determines the
;name and cluster node number of this node (the local node).
;In addition, the size of NEBULA in pages is also determined. This is
;required when mapping a sender or listener.
;Also, the seed for the local ACK codes used in the in behalf of queue
;is determined and saved.
;
;Call is: No arguments
;Returns: Node name and number, NEBULA size determined and saved
;PICK UP THE NODE NAME AND NUMBER OF THE LOCAL NODE
NBINIT: $CALL I%HOST ;PICK UP THE HOST NAME AND NUMBER
MOVEM S1,NODNAM ;SAVE THE SIXBIT NODE NAME
MOVEM S2,NODNUM ;SAVE THE NODE NUMBER
;PICK UP AND SAVE THE SIZE OF NEBULA IN PAGES
SKIPE DEBUGW ;DEBUGGING?
SKIPN 116 ;AND ARE SYMBOLS DEFINED?
JRST NBIN.1 ;IF NO TO EITHER, THEN SKIP THIS
HLRO S1,116 ;GET AOBJN LENGTH
MOVMS S1 ;GET ABSOLUTE VALUE
HRRZ S2,116 ;GET SYMBOL TABLE START ADDRESS
ADDI S1,-1(S2) ;CALCULATE THE SYMBOL TABLE LENGTH
SKIPA ;SKIP OVER NORMAL CALCULATIONS
NBIN.1: HLRZ S1,.JBSA## ;GET THE PROGRAM END ADDRESS
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]Unknow, 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
XWD NDISPY,.OMDSP ;ACK 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)
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
MOVE P1,.OARGC(M) ;PICK UP THE ARGUMENT COUNT WORD
CAILE P1,.TNNMB ;BETTER BE THE CORRECT NUMBER
PJRST E$IAC ;IT'S NOT, TELL ORION
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
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?
JRST [ SETZM REMORG ;NO, INDICATE SO
PJRST E$NRN ] ;INDICATE THE ERROR
SETOM LOCFLG ;ASSUME ALL NODES, LOCAL
SETZM REMFLG ;ASSUME MSG NOT TO BE FORWARDED
;VALIDATE THE ARGUMENT BLOCK COUNT
SKIPGE S1,.OARGC(M) ;VALID MINIMUM ARGUMENT COUNT?
PJRST E$IAC ;NO, INDICATE TO ORION
CAILE S1,2 ;VALID MAXIMUM ARGUMENT COUNT?
PJRST E$IAC ;NO, INDICATE TO ORION
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
MOVEM S1,G$ARG1 ;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
NSCL15: MOVEI S1,.NDESZ ;PICK UP THE REMOTE NODE BLOCK SIZE
MOVSS S1 ;PLACE LENGTH IN EXPECTED PLACE
MOVNS S1 ;NEGATE THE LENGTH
ADDM S1,.MSTYP(M) ;DECREMENT THE TOTAL MESSAGE LENGTH
MOVEI S1,.NSRCL ;PICK UP THE MESSAGE TYPE
STORE S1,.MSTYP(M),MS.TYP ;PLACE IN THE MESSAGE
SOS .OARGC(M) ;DECREMENT THE ARGUMENT COUNT
MOVE S1,REMFLG ;PICK UP THE REMOTE NODE FLAG
CAMN S1,[-1] ;FOR ALL REMOTE NODES?
JRST NSCL16 ;YES, SEND TO ALL REMOTE NODES
$CALL QSREMM ;NO, SEND TO THE INDICATED NODE
JUMPF @S1 ;REPORT ANY ERRORS
$RET ;RETURN TO THE IPCF MESSAGE HANDLER
NSCL16: $CALL QMREMM ;SEND TO ALL THE REMOTE NODES
SETZM G$ERR ;INDICATE ALREADY REPORTED ANY ERRORS
$RET ;RETURN TO THE IPCF MESSAGE HANDLER
;THE NODE NAME SPECIFIED IN THE /NODE: SWITCH IS NOT KNOWN TO NEBULA.
;SEND AN ERROR MESSAGE
NSCL17: SKIPE REMFLG ;[6023]MSG ALSO TO BE SENT REMOTELY?
JRST NSCL15 ;[6023]YES, SEND THE MESSAGE REMOTELY
MOVE S1,LOCFLG ;[6023]PICK UP NODE NAME SPECIFIED
CAME S1,NODNAM ;[6023]SAME AS THE LOCAL NODE NAME?
PJRST E$NSN ;[6023]NO, INDICATE NO SUCH NODE
PJRST E$INS ;[6023]CAN'T SPECIFY THE 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 ilegally formatede 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.
SKIPG S1,.OARGC(M) ;ANY ARGUMENT BLOCKS 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.
CAIE S1,1 ;CHECK FOR ONE ARGUMENT BLOCK
PJRST E$IAC ;MORE THAN ONE, REPORT THE ERROR
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
MOVEM S1,G$ARG1 ;SAVE IT IN CASE IT IS UNKNOWN
$CALL SNAMNT ;FIND THE NODE'S NODE TABLE ENTRY
JUMPF E$NSN ;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?
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
;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
;DETERMINE THE ACK MESSAGE TO BE SENT BACK TO THE OPERATOR
NDRC10: MOVEI S1,NDRC12 ;PICK UP ADDRESS OF ENABLE/DISABEL 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))
$RETT ;RETURN TO THE CALLER
NDRC11: $ACK (NEBULA report connection failures ^T/@0(S1)/,,,.MSCOD(M))
$RETT ;RETURN TO THE CALLER
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.
SKIPG S1,.OARGC(M) ;ANY ARGUMENT BLOCKS 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.
CAIE S1,1 ;CHECK FOR ONE ARGUMENT BLOCK
PJRST E$IAC ;MORE THAN ONE, REPORT THE ERROR
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
MOVEM S1,G$ARG1 ;SAVE IT IN CASE IT IS UNKNOWN
$CALL SNAMNT ;FIND THE NODE'S NODE TABLE ENTRY
JUMPF E$NSN ;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 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
NDDC10: MOVEI S1,NDDC12 ;PICK UP ADDRESS OF ENABLE/DISABEL 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))
$RETT ;RETURN TO THE CALLER
NDDC11: $ACK (NEBULA connection attempts ^T/@0(S1)/,,,.MSCOD(M))
$RETT ;RETURN TO THE CALLER
NDDC12: [ASCIZ/enabled/]
[ASCIZ/disabled/]
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
NODSTR: [ITEXT(< Received message from ^N/NODNAM/>)] ;[6001]
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.
MOVE S1,.OARGC(M) ;PICK UP THE NUMBER OF ARGUMENT BLOCKS
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
JUMPF QRIBH2 ;NODE HAS LEFT THE CLUSTER
;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.
MOVE P1,S2 ;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
QRIBH2: $RET ;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
MOVEM P1,G$ARG1 ;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
MOVE P3,RENNUM ;PICK UP THE NUMBER OF REMOTE NODES
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
BLDACK: $CALL BLDHDR ;GET MSG PAGE AND BUILD HEADER
;FINISH BUILDING THE MESSAGE HEADER
MOVE S1,G$ERR ;PICK UP ERROR NUMBER
MOVE S2,STSTBL(S1) ;PICK UP FLAG WORD
MOVEM S2,.MSFLG(MO) ;PLACE IN MESSAGE HEADER
SKIPGE G$ERR ;ITEXT PRESENT IN THE ERROR CODE
JRST BLDAC3 ;YES, BUILD THE TEXT BLOCK THAT WAY
;THE TEXT BLOCK IS INVARIANT. PLACE IN THE MESSAGE
MOVE S2,TXTTBL(S1) ;PICK UP THE TEXT BLOCK ADDRESS
MOVEI S1,ARG.DA+.OHDRS(MO) ;PICK UP THE DATA FIELD ADDRESS
$CALL TXTMOV ;PLACE THE ERROR MSG IN TEXT BLOCK
;FINISH OFF BUILDING THE MESSAGE
BLDAC2: HRRZS S1 ;GET ENDING ADDRESS
AOS S1 ;BUMP IT BY 1
ANDI S1,777 ;GET MESSAGE LENGTH
STORE S1,.MSTYP(MO),MS.CNT ;SAVE COUNT IN MESSAGE
SUBI S1,.OHDRS ;GET SIZE OF BLOCK
STORE S1,ARG.HD+.OHDRS(MO),AR.LEN ;SAVE ARGUMENT LENGTH
MOVX S1,.WTTYP ;GET TEXT CODE
STORE S1,ARG.HD+.OHDRS(MO),AR.TYP ;SAVE ARGUMENT TYPE
$RET ;RETURN
;THE TEXT BLOCK HAS VARIABLE DATA.
BLDAC3: MOVEI S2,ARG.DA+.OHDRS(MO) ;GET PLACE TO STORE TEXT
HRLI S2,(POINT 7,0) ;MAKE A POINTER
MOVEM S2,BYTPTR ;SAVE THE POINTER
$TEXT (BLDAC4,<^I/@TXTTBL(S1)/^0>) ;[6013]PLACE TEXT IN MESSAGE
MOVE S1,BYTPTR ;GET BYTPTR
JRST BLDAC2 ;FINISH OFF THE MESSAGE
BLDAC4: IDPB S1,BYTPTR ;SAVE THE CHARACTER
$RETT ;RETURN TRUE
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.
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)
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:
LSIBH0: TXZ S2,NEB%MS ;[6037]TURN OFF THE NEW FORMAT BIT
CAIN S2,.OMSTA ;[6037]A START MESSAGE?
JRST LSIBH ;[6037]YES
CAIN S2,.OMSHT ;[6037]NO, A SHUTDOWN MESSAGE?
JRST LSIBH ;[6037]NOT A START OR SHUTDOWN
CAIE S2,.OMCON ;[6037]A CONTINUE MESSAGE?
CAIN S2,.OMPAU ;[6037]A STOP MESSAGE?
SKIPA ;[6037]YES, FIND THE # OF RESPONSES
JRST LSIBHM ;[6037]NOT A START OR SHUTDOWN
LSIBH: MOVEI S1,.OROBJ ;[6037]LOOK FOR THE OBJECT BLOCK
$CALL N$FNDB ;[6037]PICK UP THE OBJECT BLOCK
HLRZ S2,OBJ.UN(S1) ;[6037]PICK UP THE UPPER LIMIT
HRRZ S1,OBJ.UN(S1) ;[6037]PICK UP THE LOWER LIMIT
SUBI S1,-1(S2) ;[6037]FIND THE NUMBER OF RESPONSES
SKIPA ;[6037]DON'T RESET THE # OF RESPONSES
;BUILD AN IN BEHALF OF QUEUE ENTRY FOR THIS MESSAGE AND LINK IT
;[JCR]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
MOVEM S1,.IQNUM(S2) ;[6037]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
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
JUMPT NSRC.1 ;ON SUCCESS SEND THE REPLY
SKIPN REMORG ;ANY REMOTE NODES STILL IN THE CLUSTER?
$RET ;NO, SO RETURN NOW
$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
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
MOVX S1,WT.SJI!WT.NFO ;[6023]PICK UP THE FLAG WORDS
MOVEM S1,.OFLAG(M) ;[6023]PLACE IN THE FLAG WORD
AOS .OARGC(M) ;INCREMENT THE ARGUMENT COUNT
;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
;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
$RET ;RETURN TO THE CALLER
NSEA.1: [ITEXT(< Received message from ^N/NODNAM/::>)]
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.
;[6016]
;[6016]Call is: M/NEBULA ACK RESPONSE message address
;[6016]Returns: The original NEBULA ACK message 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