1
0
mirror of https://github.com/PDP-10/stacken.git synced 2026-02-21 14:47:36 +00:00
Files
PDP-10.stacken/files/stacken-tape-backup/dskb:10_7/mon/scaser.mac
Lars Brinkhoff 6e18f5ebef Extract files from tape images.
Some tapes could not be extracted.
2021-01-29 10:47:33 +01:00

5034 lines
166 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
TITLE SCASER - SYSTEM COMMUNICATIONS ARCHITECTURE SERVICE V37
SUBTTL JOSEPH A. DZIEDZIC/JAD 05-JAN-88
SEARCH F,S,SCAPRM,MACSYM,BTSPRM
$RELOC
$XHIGH
PURGEACS ;PURGE DEFAULT (TOPS-10) AC NAMES
T20SYM ;SWITCH TO TOPS-20 AC NAMES
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1986,1988.
;ALL RIGHTS RESERVED.
.CPYRT<1984,1988>
XP VSCASR,37 ;VERSION NUMBER FOR GLOB AND MAP
;BASED ON TOPS-20 "SCAMPI" MODIFIED TO SUPPORT MULTIPLE PATHS
SCASER:!ENTRY SCASER ;LOAD IF LIBRARY SEARCH
SUBTTL PARAMETERS
KLPX9==602033 ;TOPS-20 ERROR CODE
SUBTTL TABLE X
TABLEX:
;Connect
FLD(.BSCNP,X.BSTAT)+FLD(.CSCSE,X.CSTAT) ;Closed
X.ERR ;Listening
X.ERR ;Connect_sent
X.ERR ;Connect_received
X.ERR ;Connect_ACK
X.ERR ;Accept_sent
X.ERR ;Reject_sent
X.ERR ;Open
X.ERR ;Disconnect_sent
X.ERR ;Disconnect_rec
X.ERR ;Disconnect_ACK
X.ERR ;disconnect_match
;Listen
FLD(.CSLIS,X.CSTAT) ;Closed
0 ;Listening
X.ERR ;Connect_sent
X.ERR ;Connect_received
X.ERR ;Connect_ACK
X.ERR ;Accept_sent
X.ERR ;Reject_sent
X.ERR ;Open
X.ERR ;Disconnect_sent
X.ERR ;Disconnect_rec
X.ERR ;Disconnect_ACK
X.ERR ;disconnect_match
;Accept
X.ERR ;Closed
X.ERR ;Listening
X.ERR ;Connect_sent
FLD(.BSACP,X.BSTAT) ;Connect_received
X.ERR ;Connect_ACK
X.ERR ;Accept_sent
X.ERR ;Reject_sent
X.ERR ;Open
X.ERR ;Disconnect_sent
X.ERR ;Disconnect_rec
X.ERR ;Disconnect_ACK
X.ERR ;disconnect_match
;Reject
X.ERR ;Closed
X.ERR ;Listening
X.ERR ;Connect_sent
FLD(.BSRPN,X.BSTAT) ;Connect_received
X.ERR ;Connect_ACK
X.ERR ;Accept_sent
X.ERR ;Reject_sent
X.ERR ;Open
X.ERR ;Disconnect_sent
X.ERR ;Disconnect_rec
X.ERR ;Disconnect_ACK
X.ERR ;disconnect_match
;Disconnect
0 ;Closed (no change)
FLD(.CSCLO,X.CSTAT) ;Listening
FLD(.CSCLO,X.CSTAT) ;Connect_sent
FLD(.BSRPN,X.BSTAT)+FLD(.CSRJS,X.CSTAT) ;Connect_received
FLD(.CSCLO,X.CSTAT) ;Connect_ACK
FLD(.CSCLO,X.CSTAT) ;Accept_sent
FLD(.CSCLO,X.CSTAT) ;Reject_sent
FLD(.BSDPN,X.BSTAT)+FLD(.CSDSE,X.CSTAT) ;Open
0 ;Disconnect_sent (no change)
FLD(.BSDPN,X.BSTAT)+FLD(.CSDMC,X.CSTAT) ;Disconnect_rec
0 ;Disconnect_ACK (no change)
0 ;Disconnect_match (no change)
SUBTTL Table Y
;For each block state, this table provides the op code to send and the
;new connection state
; * * * *
;Disagrees with corporate spec when block state is connect_pending. We
;have already set the connection state to .CSCSE in order to ensure that
;if a connection's state is "closed", the sysap never expects to hear
;about it again. If this is not changed, there is potential for the sysap
;to call SC.DIS between the time that the connection state is set and
;the message is actually sent. That sets the state to closed. We can't
;change it to connect_sent when the message is finally sent, because
;we'd lose track of the fact that the sysap had closed it.
; * * * *
TABLEY: 0 ;Not used
0 ;Free (1)
0 ;Allocate (2)
; FLD(.STORQ,Y.OP)+FLD(.CSCSE,Y.STAT) ;Connect_pending (3)
FLD(.STORQ,Y.OP) ;Connect_pending (3)
FLD(.STARQ,Y.OP)+FLD(.CSACS,Y.STAT) ;Accept_pending (4)
FLD(.STRRQ,Y.OP)+FLD(.CSRJS,Y.STAT) ;Reject_pending (5)
FLD(.STCRQ,Y.OP) ;Credit_pending (state doesn't change) (6)
FLD(.STDRQ,Y.OP) ;Disconnect_pending (state already set) (7)
YSIZE==:.-TABLEY
SUBTTL Table Z
;This table indicates, for a given op code, the length of its message,
;the priority for sending it, and the expected response.
TABLEZ:
FLD(.LNORQ,Z.LEN)+FLD(KLPMED,Z.PRI)+FLD(.STORS,Z.RSP) ;Connect_req
FLD(.LNORS,Z.LEN)+FLD(KLPMED,Z.PRI) ;CONNECT_RSP
FLD(.LNARQ,Z.LEN)+FLD(KLPMED,Z.PRI)+FLD(.STARS,Z.RSP) ;ACCEPT_REQ
FLD(.LNARS,Z.LEN)+FLD(KLPMED,Z.PRI) ;ACCEPT_RSP
FLD(.LNRRQ,Z.LEN)+FLD(KLPMED,Z.PRI)+FLD(.STRRS,Z.RSP) ;REJECT_REQ
FLD(.LNRRS,Z.LEN)+FLD(KLPMED,Z.PRI) ;REJECT_RSP
FLD(.LNDRQ,Z.LEN)+FLD(KLPDRG,Z.PRI)+FLD(.STDRS,Z.RSP) ;DISCONNECT_REQ
FLD(.LNDRS,Z.LEN)+FLD(KLPMED,Z.PRI) ;DISCONNECT_RSP
FLD(.LNCRQ,Z.LEN)+FLD(KLPHI,Z.PRI)+FLD(.STCRS,Z.RSP) ;CREDIT_REQ
FLD(.LNCRS,Z.LEN)+FLD(KLPMED,Z.PRI) ;CREDIT_RSP
SUBTTL Table K
;This table indicates, for a given incoming op code and current state
;of a connection, whether the event is legal, and if it is, what the new
;state and returned op code should be
TABLEK:
;Received Connect_req
FLD(.STORS,K.OP) ;Closed
FLD(.STORS,K.OP)+FLD(.CSCRE,K.STAT) ;Listening
K.ERR ;Connect request was sent (CONNECT_SENT)
K.ERR ;Connect request was received (CONNECT_REC)
K.ERR ;Connect response was received (CONNECT_ACK)
K.ERR ;Accept request was sent (ACCEPT_SENT)
K.ERR ;Reject request was sent (REJECT_SENT)
K.ERR ;Connection is open (OPEN)
K.ERR ;Disconnect request was sent (DISCONNECT_SENT)
K.ERR ;Disconnect request received (DISCONNECT_REC)
K.ERR ;Disconnect response received (DISCONNECT_ACK)
K.ERR ;Waiting for disconnect response (DISCONNECT_MATCH)
;Received connect_response
FLD(.CSCLO,K.STAT) ;Closed
K.ERR ;Listening
FLD(.CSCAK,K.STAT)+K.CHK ;Connect_sent
K.ERR ;Connect_received
K.ERR ;Connect response was received (CONNECT_ACK)
K.ERR ;Accept request was sent (ACCEPT_SENT)
K.ERR ;Reject request was sent (REJECT_SENT)
K.ERR ;Connection is open (OPEN)
K.ERR ;Disconnect request was sent (DISCONNECT_SENT)
K.ERR ;Disconnect request received (DISCONNECT_REC)
K.ERR ;Disconnect response received (DISCONNECT_ACK)
K.ERR ;Waiting for disconnect response (DISCONNECT_MATCH)
;Received accept-request
FLD(.STARS,K.OP)+FLD(.CSCLO,K.STAT) ;Closed
K.ERR ;Listening
K.ERR ;Connect_sent
K.ERR ;Connect_received
FLD(.STARS,K.OP)+FLD(.CSOPN,K.STAT) ;Connect_ACK
K.ERR ;Accept_sent
K.ERR ;Reject_sent
K.ERR ;Open
K.ERR ;Disconnect_sent
K.ERR ;Disconnect_rec
K.ERR ;Disconnect_ACK
K.ERR ;disconnect_match
;Received accept_response
FLD(.STDRQ,K.OP)+FLD(.CSCLO,K.STAT) ;CLosed (special case *)
K.ERR ;Listening
K.ERR ;Connect_sent
K.ERR ;Connect_received
K.ERR ;Connect_ACK
FLD(.CSOPN,K.STAT)+K.CHK ;Accept_sent
K.ERR ;Reject_sent
K.ERR ;Open
K.ERR ;Disconnect_sent
K.ERR ;Disconnect_rec
K.ERR ;Disconnect_ACK
K.ERR ;disconnect_match
;Received reject_request
FLD(.STRRS,K.OP)+FLD(.CSCLO,K.STAT) ;Closed
K.ERR ;Listening
K.ERR ;Connect_sent
K.ERR ;Connect_received
FLD(.STRRS,K.OP)+FLD(.CSCLO,K.STAT) ;Connect_ACK
K.ERR ;Accept_sent
K.ERR ;Reject_sent
K.ERR ;Open
K.ERR ;Disconnect_sent
K.ERR ;Disconnect_rec
K.ERR ;Disconnect_ACK
K.ERR ;disconnect_match
;Received reject_response
FLD(.CSCLO,K.STAT) ;Closed
K.ERR ;Listening
K.ERR ;Connect_sent
K.ERR ;Connect_received
K.ERR ;Connect_ACK
K.ERR ;Accept_sent
FLD(.CSCLO,K.STAT)+K.CHK ;Reject_sent
K.ERR ;Open
K.ERR ;Disconnect_sent
K.ERR ;Disconnect_rec
K.ERR ;Disconnect_ACK
K.ERR ;disconnect_match
;Received disconnect_request
FLD(.STDRS,K.OP)+FLD(.CSCLO,K.STAT) ;Closed
K.ERR ;Listening
K.ERR ;Connect_sent
K.ERR ;Connect_received
K.ERR ;Connect_ACK
K.ERR ;Accept_sent
K.ERR ;Reject_sent
FLD(.STDRS,K.OP)+FLD(.CSDRE,K.STAT) ;Open
FLD(.STDRS,K.OP)+FLD(.CSDMC,K.STAT) ;Disconnect_sent
K.ERR ;Disconnect_rec
FLD(.STDRS,K.OP)+FLD(.CSCLO,K.STAT) ;Disconnect_ACK
K.ERR ;disconnect_match
;received disconnect_response
FLD(.CSCLO,K.STAT) ;Closed
K.ERR ;Listening
K.ERR ;Connect_sent
K.ERR ;Connect_received
K.ERR ;Connect_ACK
K.ERR ;Accept_sent
K.ERR ;Reject_sent
K.ERR ;Open
FLD(.CSDAK,K.STAT)+K.CHK ;Disconnect_sent
K.ERR ;Disconnect_rec
K.ERR ;Disconnect_ACK
FLD(.CSCLO,K.STAT)+K.CHK ;disconnect_match
;Received credit_request
FLD(.STCRS,K.OP) ;Closed
K.ERR ;Listening
K.ERR ;Connect_sent
K.ERR ;Connect_received
K.ERR ;Connect_ACK
K.ERR ;Accept_sent
K.ERR ;Reject_sent
FLD(.STCRS,K.OP) ;Open
FLD(.STCRS,K.OP) ;Disconnect_sent
K.ERR ;Disconnect_rec
FLD(.STCRS,K.OP) ;Disconnect_ACK
K.ERR ;disconnect_match
;Received credit_response
0 ;Closed
K.ERR ;Listening
K.ERR ;Connect_sent
K.ERR ;Connect_received
K.ERR ;Connect_ACK
K.ERR ;Accept_sent
K.ERR ;Reject_sent
K.CHK ;Open
0 ;Disconnect_sent
K.CHK ;Disconnect_rec
0 ;Disconnect_ACK
0 ;disconnect_match
SUBTTL Tables for state machine
;Table X - used when sysap calls SCA. For each event, provides new connection
;and block state. Also allows checking for invalid state
DEFSTR X.ERR,TABLEX,0,1 ;Error flag
DEFSTR X.BSTAT,TABLEX,17,17 ;New block state
DEFSTR X.CSTAT,TABLEX,35,18 ;New connection state
;In some cases, the connection state is set when the request is sent,
;rather than when the sysap calls SCA.
EV.CON==:0 ;SC.CON
EV.LIS==:1 ;SC.LIS
EV.ACC==:2 ;SC.ACC
EV.REJ==:3 ;SC.REJ
EV.DIS==:4 ;SC.DIS
;DEFSTRs for table Y. For each block state, provides op code to
;send and new connection state
DEFSTR (Y.OP,TABLEY,17,18)
DEFSTR (Y.STAT,TABLEY,35,18)
;Defstrs for table Z. For each op code to be sent, provides length, priority,
;and expected response
DEFSTR Z.LEN,TABLEZ,17,18
DEFSTR Z.PRI,TABLEZ,20,3
DEFSTR Z.RSP,TABLEZ,35,15
;Defstrs for table K. For each incoming packet, provides op code of response
;and new connection state. Also allows checking for protocol violations
DEFSTR (K.ERR,TABLEK,0,1)
DEFSTR (K.CHK,TABLEK,1,1)
DEFSTR (K.OP,TABLEK,17,16)
DEFSTR (K.STAT,TABLEK,35,18)
SUBTTL INITIALIZATION
;ROUTINE TO INITIALIZE THE WORLD OF SCA.
;CALL:
; PUSHJ P,SCA
;RETURN:
; CPOPJ ALWAYS
$XSENT (SC.INI::) ;EXTENDED HIGH SEG ROUTINE
PUSHJ P,SAVPQ## ;SAVE ALL THE REGISTERS
SETZM MFQCNT ;ZERO FREE QUEUE BUFFER COUNT
SETZM TOPMFQ ;ZERO THE FLINK FOR THE FREE QUEUE
XMOVEI T1,TOPMFQ ;GET A POINTER TO THE FLINK
MOVEM T1,BOTMFQ ;INIT BLINK AS A POINTER TO FLINK
SETZM DFQCNT ;ZERO DATAGRAM QUEUE BUFFER COUNT
SETZM TOPDFQ ;ZERO THE FLINK FOR THE DATAGRAM QUEUE
XMOVEI T1,TOPDFQ ;GET A POINTER TO THE FLINK
MOVEM T1,BOTDFQ ;INIT BLINK AS A POINTER TO FLINK
SETZM TOPDC ;ZERO THE FLINK FOR THE "DON'T CARE" QUEUE
XMOVEI T1,TOPDC ;GET A POINTER TO THE FLINK
MOVEM T1,BOTDC ;INIT BLINK AS A POINTER TO FLINK
MOVEI T1,1 ;GET A PAGE
PUSHJ P,PGRSKD## ; OF RESIDENT SPACE
BUG. (HLT,SCANPC,SCASER,SOFT,<No page for CID table>,,)
PUSH P,T1 ;SAVE ITS ADDRESS A BIT
MOVE T2,T1 ;MOVE THE ADDRESS TO THE PROPER AC
AOS T3,T1 ;GET ADDRESS +1
MOVEI T1,PG.BDY ;NUMBER OF WORDS TO MOVE
SETZM (T2) ;ZERO THE FIRST ONE
EXTEND T1,[XBLT] ;ZERO THE REMAINDER
POP P,T1 ;GET PAGE ADDRESS BACK
MOVEM T1,CIDTAB ;SAVE THE ADDRESS OF THE CID TABLE
ADDI T1,PAGSIZ/2 ;POINT TO HALFWAY THROUGH THE TABLE
MOVEM T1,UBTTAB ;SAVE AS ADDRESS OF THE UNIQUENESS TABLE
RDTIME T1 ;READ TIME BASE (SUITABLE RANDOM NUMBER)
LSH T2,^L<C%CIDL>-1-14 ;STRIP HIGH ORDER BITS LEAVING LOW
LSH T2,-^L<C%CIDL>-1 ; BITS MODULO CONNECT-ID TABLE LENGTH
AOS T2 ;MAKE IT IN RANGE 1-C%CIDL
MOVEM T2,NXTIDX ;SAVE AS NEXT INDEX INTO CID TABLE
SETZM CIDRFL ;NOT DOING CIDTAB RECYCLING YET
SETONE UBITS,T1 ;SET ALL BITS IN THE UNIQUENESS BITS FIELD
LSH T1,-<C%RMBU> ;RIGHT JUSTIFY SAID BITS
MOVEM T1,UNQBTS ;STORE AS THE UNIQUENESS BITS
AOS UNQBTS ;INIT AS ONE MORE THAN THE FIRST UNIQUENESS BITS
SETZM UNQRFL ;NOT DOING CID BITS RECYCLING YET
;SET BUFFER THRESHOLDS AND SET INITIAL BUFFER LEVELS
IFN FTOPS10,<
MOVEI T1,M.CPU## ;NUMBER OF CPUS IN CONFIGURATION
IMULM T1,DGTRSH ;ADJUST DATAGRAM THRESHOLD ON A PER-CPU BASIS
IMULM T1,MGTRSH ;DITTO FOR MESSAGE THRESHOLD
>; END IFN FTOPS10
SETZM PBCNT ;ZERO COUNT OF PATHS ONLINE
PUSHJ P,SC.SBT ;SET MSG AND DG BUFFER THRESHOLDS
MOVE T1,MINMSG ;GET MINIMUM NUMBER OF MSG BUFFERS
IDIVI T1,C%MGPG ;MAKE NUMBER OF BUFFERS INTO NUMBER OF PAGES
SKIPE T2 ;IS THERE A REMAINDER?
AOS T1 ;YES, ROUND UP
PUSHJ P,PGRSKD## ;GET THE BUFFER SPACE
PUSHJ P,SCADIE ;IF WE CAN'T INIT, DIE
MOVX T2,C%MGSZ ;GET THE BUFFER SIZE WE DESIRE
PUSHJ P,SC.BBF ;BREAK THE SPACE INTO BUFFER-SIZED PIECES
MOVEM T1,TOPMFQ ;SET UP THE POINTER TO THE TOP OF THE FREE QUEUE
MOVEM T2,BOTMFQ ; AND THE POINTER TO THE BOTTOM OF THE FREE QUEUE
ADDM T3,MFQCNT ;UPDATE THE COUNT OF BUFFERS IN THE QUEUE
ADDM T3,TOTMGB ; AND THE TOTAL NUMBER OF BUFFERS CREATED
MOVE T1,MINDG ;GET MINIMUM NUMBER OF DG BUFFERS
IDIVI T1,C%DGPG ;MAKE NUMBER OF BUFFERS INTO NUMBER OF PAGES
SKIPE T2 ;IS THERE A REMAINDER?
AOS T1 ;YES, ROUND UP
PUSHJ P,PGRSKD## ;GET THE BUFFER SPACE
PUSHJ P,SCADIE ;IF WE CAN'T INIT, DIE
MOVX T2,C%DGSZ ;GET THE BUFFER SIZE WE DESIRE
PUSHJ P,SC.BBF ;BREAK THE SPACE INTO BUFFER-SIZED PIECES
MOVEM T1,TOPDFQ ;SET UP THE POINTER TO THE TOP OF THE FREE QUEUE
MOVEM T2,BOTDFQ ; AND THE POINTER TO THE BOTTOM OF THE FREE QUEUE
ADDM T3,DFQCNT ;UPDATE THE COUNT OF BUFFERS IN THE QUEUE
ADDM T3,TOTDGB ; AND THE TOTAL NUMBER OF BUFFERS CREATED
;SET UP THE SOFTWARE INCARNATION NUMBER
PUSHJ P,BTAVAL## ;IS THE BOOTSTRAP AVAILABLE?
TDZA T1,T1 ;NO, NO BIG DEAL, USE ZERO
AOS T1,.BTSIN(T2) ;YES, BUMP AND GET NEW INCARNATION NUMBER
MOVEM T1,SCASIN ;SAVE FOR FUTURE REFERENCE
;ALLOCATE THE NOTIFICATION TABLE
MOVEI T1,1 ;WE ONLY NEED ONE BUFFER
PUSHJ P,SC.ABF ;ALLOCATE ONE
BUG. (HLT,SCANBN,SCASER,SOFT,<No buffer for notification table>,,)
MOVEM T1,NOTTAB ;SAVE THE ADDRESS OF THE LIST
;CALL THE INITIALIZATION ROUTINE OF THE VARIOUS SYSAP'S
MOVSI P1,-C%SYTL ;-VE LENGTH OF THE TABLE
SKIPE INITAB(P1) ;IS THERE AN ENTRY FOR THIS INDEX?
PUSHJ P,@INITAB(P1) ;YES, CALL THE ROUTINE
AOBJN P1,.-2 ;LOOP FOR THE REMAINDER
POPJ P, ;RETURN
;TABLE OF MONITOR SYSAP'S TO INITIALIZE DURING SCA INITIALIZATION.
INITAB: IFIW MSCINI## ;MSCP DISK INTERFACE
IFIW SCSINI## ;THE SCS. UUO
C%SYTL==.-INITAB ;LENGTH OF INITIALIZATION TABLE
;A GENERAL BUG. FOR ERRORS DURING INITIALIZATION
SCADIE: BUG. (HLT,SCACCI,SCASER,SOFT,<Cannot complete initialization>,,)
JRST SCADIE ;IN CASE SOMEONE TRIES TO CONTINUE
;A GENERAL BUG. FOR ERRORS WHICH "SHOULD NEVER HAPPEN"
BUG. (HLT,SCAFOO,SCASER,SOFT,<Oh foo!>,,)
SUBTTL SYSAP NOTIFICATION REQUEST
;ROUTINE CALLED BY A SYSAP TO ADD AN ENTRY TO THE NOTIFICATION TABLE.
;CALL:
; BLCAL. (SS.SNA,<SS.ADR>)
;
;WHERE:
; SS.ADR - ADDRESS OF ROUTINE TO CALL
;
;RETURN:
; CPOPJ ON ERRORS
; CPOPJ1 ON SUCCESS
$XBSUB (SC.SNA::,<SS.ADR>)
SAVEAC <P1,P5> ;FREE UP A PAIR OF AC'S
MOVE T1,NOTTAB ;GET THE ADDRESS OF THE NOTIFICATION TABLE
MOVX T2,C%MGSZ-1 ;GET ITS SIZE
MOVE T3,SS.ADR ;GET THE CALLER'S RECALL ADDRESS
CIOFF ;PREVENT RACES
SNA.01: SKIPN 0(T1) ;LOOK FOR AN OPEN SLOT IN THE TABLE
JRST SNA.02 ;FOUND ONE
SOSLE T2 ;ANY ROOM LEFT IN TABLE?
AOJA T1,SNA.01 ;YES, LOOP FOR REMAINDER
CION ;GIVE UP THE INTERLOCK
BUG. (CHK,SCANLF,SCASER,SOFT,<Notice table full>,,)
RETBAD (.SCNRT) ;ERROR RETURN
SNA.02: MOVEM T3,0(T1) ;SAVE THE ADDRESS IN THE TABLE
;LOOP OVER ALL PATH BLOCKS GIVING AN ONLINE CALLBACK FOR THOSE
;VC'S WHICH ARE OPEN. DO THIS WITH SCA INTERLOCK TO PREVENT
;MULTIPLE ONLINE CALLBACKS.
MOVSI P1,-C%PBLL ;LENGTH OF PATH BLOCK LIST
SNA.03: SKIPN P5,PBLIST(P1) ;IS THERE A PATH BLOCK HERE?
JRST SNA.04 ;NO
IFN FTMP,<
MOVE T1,.PBCPU(P5) ;YES, WHICH CPU DOES IT LIVE ON?
CAME T1,.CPCPN## ;"THIS" CPU?
JRST SNA.04 ;NO
>; END IFN FTMP
LOAD T1,PBVCST,(P5) ;GET VC STATE
CAIE T1,VC.OPN ;IS VC OPEN?
JRST SNA.04 ;NO
MOVX T1,.SSNCO ;SAY WHY WE ARE CALLING
LOAD T2,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
PUSHJ P,@SS.ADR ;CALL THE SYSAP
SNA.04: AOBJN P1,SNA.03 ;LOOP FOR REMAINING PATH BLOCKS
PJRST CINPJ1 ;GIVE UP THE INTERLOCK AND SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL CONNECTION MANAGEMENT - CONNECT
;ROUTINE TO ALLOCATE A CONNECTION BLOCK AND REQUEST A CONNECTION.
;CALL:
; BLCAL. (SC.CON,<SS.SPN,SS.DPN,SS.PBI,SS.MSC,SS.MRC,SS.ADR,SS.SID,SS.DTA,SS.BFR,SS.DGB>)
;
;WHERE:
; SS.SPN - ADDRESS OF SOURCE PROCESS NAME
; SS.DPN - ADDRESS OF DESTINATION PROCESS NAME
; SS.PBI - PATH BLOCK INDEX OF PATH TO USE
; SS.MSC - MINIMUM SEND CREDIT
; SS.MRC - MINIMUM RECEIVE CREDIT
; SS.ADR - ADDRESS OF ROUTINE TO CALL ON CONDITION CHANGES
; SS.SID - SIX BITS OF CONNECT ID SET BY THE SYSAP
; SS.DTA - (OPTIONAL) ADDRESS OF SYSAP CONNECTION DATA
; SS.BFR - NUMBER OF BUFFERS TO QUEUE FOR MESSAGE RECEPTION
; SS.DGB - NUMBER OF DATAGRAM BUFFERS TO QUEUE
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS WITH:
; T1/ CONNECT ID
$XBSUB (SC.CON::,<SS.SPN,SS.DPN,SS.PBI,SS.MSC,SS.MRC,SS.ADR,SS.SID,SS.DTA,SS.BFR,SS.DGB>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
SKIPLE P5,SS.PBI ;GET PATH BLOCK INDEX
CAIL P5,C%PBLL ;CHECK FOR INVALID
RETBAD (.SCIPI) ;ERROR
SKIPN P5,PBLIST-1(P5) ;GET PATH BLOCK ADDRESS
RETBAD (.SCIPI) ;ERROR
;ALLOCATE A CONNECTION BLOCK AND INITIALIZE WITH COMMON DATA
MOVE T1,SS.SID ;GET THE SYSAP CID BITS
PUSHJ P,SC.ACB ;ALLOCATE AND INITIALIZE A CONNECTION BLOCK
RETBAD () ;ERROR, PASS ALONG ERROR CODE
MOVEM P5,.CBPBK(P1) ;STORE PATH BLOCK ADDRESS IN CB
MOVEI T1,EV.CON ;EVENT IS CONNECT CALL
PUSHJ P,SC.OUT ;GET NEW CONNECTION/BLOCK STATES
BUG. (HLT,SCACFO,SCASER,SOFT,<SC.CON received failure from SC.OUT>,,)
DMOVE P2,T1 ;SAVE NEW STATES FOR LATER
;STORE ADDRESS FOR CALLING THE SYSAP INTO THE CONNECTION BLOCK
MOVE T1,SS.ADR ;GET CONDITION CHANGE CALL ADDRESS
MOVEM T1,.CBADR(P1) ;STORE
;CREDIT THRESHOLDS
MOVE T1,SS.MSC ;GET THE MINIMUM SEND CREDIT
STOR T1,CBMNSC,(P1) ;STORE
;STORE SOURCE AND DESTINATION PROCESS NAMES AND CONNECTION DATA
MOVE T1,SS.SPN ;GET THE ADDRESS OF THE SOURCE PROCESS NAME
MOVE T2,SS.DPN ; AND THE DESTINATION PROCESS NAME
MOVE T3,SS.DTA ; AND THE ADDRESS OF THE CONNECTION DATA
PUSHJ P,SC.SDM ;MOVE THE STRINGS AND DATA INTO THE CONNECT BLOCK
;STORE THE INITIAL NUMBER OF BUFFERS TO BE QUEUED
MOVE T1,SS.BFR ;NUMBER OF MESSAGE BUFFERS
STOR T1,CBIMB,(P1) ;STORE
MOVE T1,SS.DGB ;NUMBER OF DATAGRAM BUFFERS
STOR T1,CBIDB,(P1) ;STORE
;STORE THE CONNECTION STATE
SKIPE P3 ;IF WE NEED TO CHANGE IT,
STOR P3,CBCNST,(P1) ; STORE NEW STATE
PUSHJ P,SC.LOK ;LOCK THE CONNECTION BLOCK
;LINK THE CONNECTION BLOCK ONTO THE PATH BLOCK LIST
PUSHJ P,SC.LCB ;LINK THE CB
JRST CON.E1 ;VC IS CLOSED, RETURN ERROR
MOVE P3,.CBSCI(P1) ;GET THE CONNECT ID WHILE BLOCK IS LOCKED
;SEND THE REQUEST NOW, OR QUEUE IT FOR LATER
SKIPN T1,P2 ;GET THE NEW BLOCK STATE
JRST CON.02 ;NO CHANGE, SKIP THIS
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
PUSHJ P,SC.SNM ;SEND THE MESSAGE IF POSSIBLE
SKIPA ;SKIP OVER CALL TO SC.ULK
;LOAD UP THE RETURNED DATA AND RETURN TO CALLER
CON.02: PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
MOVE T1,P3 ;GET THE SOURCE CONNECT ID
JRST CPOPJ1## ;SKIP RETURN
;HERE WHEN VC IS CLOSED; DON'T OPEN THE CONNECTION
CON.E1: MOVE P3,T1 ;SAVE THE ERROR CODE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
PUSHJ P,SC.RCB ;RELEASE THE CONNECTION BLOCK
MOVE T1,P3 ;GET THE ERROR CODE BACK
RETBAD () ;PASS ERROR ALONG TO CALLER
ENDBS. ;END OF BLSUB. RANGE
SUBTTL CONNECTION MANAGEMENT - LISTEN
;ROUTINE TO LISTEN FOR A CONNECTION.
;CALL:
; BLCAL. (SC.LIS,<SS.SPN,SS.DPN,SS.PBI,SS.ADR,SS.SID,SS.MSC,SS.MRC>)
;
;WHERE:
; SS.SPN - ADDRESS OF SOURCE PROCESS NAME
; SS.DPN - ADDRESS OF DESTINATION PROCESS NAME
; SS.PBI - PATH BLOCK INDEX OF PATH TO USE
; SS.ADR - ADDRESS OF ROUTINE TO CALL ON CONDITION CHANGES
; SS.SID - SIX BITS OF CONNECT ID SET BY THE SYSAP
; SS.MSC - MINIMUM SEND CREDIT
; SS.MRC - MINIMUM RECEIVE CREDIT
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS WITH:
; T1/ CONNECT ID
;
;A ZERO IN SS.DPN AND -1 IN SS.PBI INDICATES A CONNECT FROM ANYONE IS
;ACCEPTABLE. A BYTE POINTER IN SS.DPN AND A PBI IN SS.PBI INDICATE
;A LISTEN FOR A PARTICULAR NODE ON A PARTICULAR PATH.
$XBSUB (SC.LIS::,<SS.SPN,SS.DPN,SS.PBI,SS.ADR,SS.SID,SS.MSC,SS.MRC>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
SKIPE P5,SS.PBI ;GET PATH BLOCK INDEX (ALLOW -1 HERE)
CAIL P5,C%PBLL ;CHECK FOR INVALID
RETBAD (.SCIPI) ;ERROR
JUMPG P5,LIS.01 ;PROCEED IF PBI SPECIFIED
CAME P5,[-1] ;LISTEN TO ANYONE?
RETBAD (.SCIPI) ;NO, ERROR
SETZ P5, ;GET THE "DON'T CARE" PBI
LIS.01: SKIPN P5,PBLIST-1(P5) ;GET PATH BLOCK ADDRESS
RETBAD (.SCIPI) ;ERROR
;ALLOCATE A CONNECTION BLOCK AND INITIALIZE WITH COMMON DATA
MOVE T1,SS.SID ;GET THE SYSAP CID BITS
PUSHJ P,SC.ACB ;ALLOCATE A CONNECTION BLOCK
RETBAD () ;ERROR, PASS ALONG ERROR CODE
MOVEM P5,.CBPBK(P1) ;STORE PATH BLOCK ADDRESS IN CB
MOVEI T1,EV.LIS ;EVENT IS LISTEN CALL
PUSHJ P,SC.OUT ;GET NEW CONNECTION/BLOCK STATES
BUG. (HLT,SCALFO,SCASER,SOFT,<SC.LIS received failure from SC.OUT>,,)
DMOVE P2,T1 ;SAVE NEW STATES
;STORE ADDRESS FOR CALLING THE SYSAP INTO THE CONNECTION BLOCK
MOVE T1,SS.ADR ;GET CONDITION CHANGE CALL ADDRESS
MOVEM T1,.CBADR(P1) ;STORE
;CREDIT THRESHOLDS
MOVE T1,SS.MSC ;GET MINIMUM SEND CREDIT
STOR T1,CBMNSC,(P1) ;STORE
;MOVE THE SOURCE AND DESTINATION PROCESS NAMES
MOVE T1,SS.SPN ;GET THE ADDRESS OF THE SOURCE PROCESS NAME
MOVE T2,SS.DPN ; AND THE DESTINATION PROCESS NAME
SETZ T3, ;THERE IS NO CONNECTION DATA ON A LISTEN
PUSHJ P,SC.SDM ;MOVE THE STRINGS INTO THE CONNECT BLOCK
;STORE THE CONNECTION STATE
SKIPE P3 ;IF WE NEED TO CHANGE IT,
STOR P3,CBCNST,(P1) ; STORE NEW STATE
PUSHJ P,SC.LOK ;LOCK THE CONNECTION BLOCK
;LINK THE CONNECTION BLOCK ONTO THE PATH BLOCK LIST
PUSHJ P,SC.LCB ;LINK THE CONNECTION BLOCK
JRST LIS.E1 ;VC IS CLOSED
MOVE P3,.CBSCI(P1) ;GET THE CONNECT ID WHILE BLOCK IS LOCKED
;SEND THE REQUEST NOW, OR QUEUE IT FOR LATER
JUMPL P5,LIS.02 ;SKIP THIS STUFF FOR "DON'T CARE" LISTENER
SKIPN T1,P2 ;GET THE NEW BLOCK STATE
JRST LIS.02 ;NO CHANGE, SKIP THIS
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
PUSHJ P,SC.SNM ;SEND THE MESSAGE IF POSSIBLE
SKIPA ;SKIP OVER CALL TO SC.ULK
;LOAD UP THE RETURNED DATA AND RETURN TO CALLER
LIS.02: PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
MOVE T1,P3 ;GET SOURCE CONNECT ID
JRST CPOPJ1## ;SKIP RETURN
;HERE ON AN ERROR RETURN FROM SC.LCB
LIS.E1: MOVE P3,T1 ;SAVE THE ERROR CODE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
PUSHJ P,SC.RCB ;RETURN THE CONNECTION BLOCK
MOVE T1,P3 ;GET THE ERROR CODE BACK
RETBAD () ;PASS ERROR ALONG TO CALLER
ENDBS. ;END OF BLSUB. RANGE
SUBTTL CONNECTION MANAGEMENT - ACCEPT
;ROUTINE TO ACCEPT A REQUEST FOR A CONNECTION.
;CALL:
; BLCAL. (SC.ACC,<SS.CID,SS.DTA,SS.BFR,SS.DGB>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.DTA - ADDRESS OF INITIAL CONNECTION DATA (OR ZERO)
; SS.BFR - NUMBER OF BUFFERS TO BE QUEUED FOR MESSAGE RECEPTION
; SS.DGB - NUMBER OF BUFFERS TO QUEUE FOR DATAGRAM RECEPTION
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.ACC::,<SS.CID,SS.DTA,SS.BFR,SS.DGB>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET THE CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
MOVEI T1,EV.ACC ;EVENT IS ACCEPT CALL
PUSHJ P,SC.OUT ;GET NEW CONNECTION/BLOCK STATES
RETBAD (,<PUSHJ P,SC.ULK>) ;PASS ALONG THE ERROR
DMOVE P2,T1 ;SAVE NEW STATES
;STORE OPTIONAL DATA TO BE SENT TO THE OTHER END
SKIPN T2,SS.DTA ;IS THERE ANY DATA TO MOVE?
JRST ACC.01 ;NO
MOVX T1,C%CDLW ;YES, GET ITS LENGTH IN WORDS
XMOVEI T3,.CBDTA(P1) ;DESTINATION ADDRESS IN CB
EXTEND T1,[XBLT] ;COPY THE DATA
;STORE THE INITIAL NUMBER OF BUFFERS TO BE QUEUED
ACC.01: MOVE T1,SS.BFR ;NUMBER OF MESSAGE BUFFERS
STOR T1,CBIMB,(P1) ;STORE
MOVE T1,SS.DGB ;NUMBER OF DATAGRAM BUFFERS
STOR T1,CBIDB,(P1) ;STORE
;STORE THE CONNECTION STATE
SKIPE P3 ;IF WE NEED TO CHANGE IT,
STOR P3,CBCNST,(P1) ; STORE NEW STATE
;SEND THE REQUEST NOW, OR QUEUE IT FOR LATER
SKIPN T1,P2 ;GET THE NEW BLOCK STATE
JRST ACC.02 ;NO CHANGE, SKIP THIS
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
PUSHJ P,SC.SNM ;SEND THE MESSAGE IF POSSIBLE
JRST CPOPJ1## ;SKIP RETURN
ACC.02: PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL CONNECTION MANAGEMENT - REJECT
;ROUTINE TO REJECT A CONNECTION REQUEST.
;CALL:
; BLCAL. (SC.REJ,<SS.CID,SS.RJR>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.RJR - REJECT REASON CODE
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.REJ::,<SS.CID,SS.RJR>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
;SEE IF THE CURRENT STATE IS CORRECT, AND GET NEW CONNECTION AND BLOCK STATES
MOVEI T1,EV.REJ ;EVENT IS REJECT CALL
PUSHJ P,SC.OUT ;SORT OUT THE CONNECT/BLOCK STATES
RETBAD (,<PUSHJ P,SC.ULK>) ;PASS ALONG THE ERROR
;COPY CALLER'S REASON INTO THE CONNECTION BLOCK
MOVE T3,SS.RJR ;GET THE REJECT REASON
STOR T3,CBSDRE,(P1) ;STORE IN CB
;STORE CONNECTION AND BLOCK STATES AND SEND MESSAGE, IF ANY
SKIPE T2 ;SKIP IF NO STATE CHANGE
STOR T2,CBCNST,(P1) ; ELSE STORE NEW CONNECT STATE
JUMPE T1,REJ.01 ;JUMP IF THERE ISN'T A NEW BLOCK STATE
PUSHJ P,SC.SCA ;SET THE NEW BLOCK STATE AND QUEUE MESSAGE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
PUSHJ P,SC.SNM ;SEND THE MESSAGE IF POSSIBLE
JRST CPOPJ1## ;SKIP RETURN
REJ.01: PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL CONNECTION MANAGEMENT - DISCONNECT
;ROUTINE TO CLOSE A CONNECTION.
;CALL:
; BLCAL. (SC.DIS,<SS.CID,SS.DIR>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.DIR - DISCONNECT REASON
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.DIS::,<SS.CID,SS.DIR>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
CIOFF ;DON'T LET STATE CHANGE UNTIL WE CAN LOCK CB
MOVE T1,SS.CID ;GET CONNECT ID
PUSHJ P,SC.CSC ;CHECK FOR VALIDITY
RETBAD (,<CION>) ;PASS ALONG THE ERROR
;SEE IF THE CURRENT STATE IS CORRECT, AND GET NEW CONNECTION AND BLOCK STATES
MOVEI T1,EV.DIS ;EVENT IS DISCONNECT CALL
PUSHJ P,SC.OUT ;SORT OUT THE CONNECT/BLOCK STATES
RETBAD (,<CION>) ;PASS ALONG THE ERROR
DMOVE P2,T1 ;SAVE NEW STATES
;COPY CALLER'S REASON INTO THE CONNECTION BLOCK
MOVE T1,SS.DIR ;GET THE DISCONNECT REASON
STOR T1,CBSDRE,(P1) ;STORE IN CB
;WE'VE DONE ALL WE CAN IF SOMEONE HAS THE CB LOCKED
MOVX T1,CB.DIS ;SET THIS BIT IF WE HAVE TO WAIT
PUSHJ P,SC.HNR ;SEE IF LOCK IS LOCKED
JRST CINPJ1 ;AT INTERRUPT LEVEL AND SOMEONE HAS THE LOCK
;WE GOT THE LOCK. IF THE OLD STATE WAS "LISTEN" INDICATE PROTOCOL COMPLETE
LOAD T1,CBCNST,(P1) ;GET CONNECT STATE
CAIE T1,.CSLIS ;LISTEN?
JRST DIS.01 ;NO
MOVEI T1,.CSCLO ;FORCE ITS STATE TO "CLOSED"
STOR T1,CBCNST,(P1) ;...
PUSHJ P,SC.PTC ;DECLARE PROTOCOL COMPLETE
JRST CINPJ1 ;TURN PI'S BACK ON AND SKIP RETURN
;STORE CONNECTION AND BLOCK STATES AND SEND MESSAGE, IF ANY
DIS.01: SKIPE P3 ;SKIP IF NO STATE CHANGE
STOR P3,CBCNST,(P1) ; ELSE STORE NEW CONNECT STATE
SKIPN T1,P2 ;IS THERE A NEW BLOCK STATE?
PJRST CINPJ1 ;NO, TURN PI'S BACK ON AND SKIP RETURN
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
CION ;TURN PI'S BACK ON
PUSHJ P,SC.SNM ;SEND THE MESSAGE IF POSSIBLE
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
;ROUTINE TO FINISH FUNCTION OF SC.DIS WHEN UNLOCKING A CONNECTION BLOCK.
;CALL:
; P1/ ADDRESS OF CONNECTION BLOCK
; P5/ ADDRESS OF PATH BLOCK
; PUSHJ P,SC.FN2
;RETURN:
; CPOPJ ALWAYS
;THIS ROUTINE IS CALLED WHEN THE OWNER OF A CONNECTION BLOCK IS ABOUT TO
;UNLOCK IT AND THE CB.DIS BIT WAS SET. THE CB IS STILL LOCKED, AND WE
;RETURN IT IN THAT CONDITION. SINCE THE BLOCK IS STILL LOCKED, WE DON'T
;CALL SC.SNM, BUT INSTEAD SET A BIT SO THE UNLOCKER WILL DO SO.
SC.FN2: MOVX T1,CB.DIS ;GET THE BIT
ANDCAM T1,.CBFLG(P1) ;SHOW THIS HAS COMPLETED
;IF OLD STATE WAS "LISTEN", INDICATE PROTOCOL IS COMPLETE
LOAD T1,CBCNST,(P1) ;GET OLD STATE
CAIE T1,.CSLIS ;LISTENING?
JRST FN2.01 ;NO
MOVEI T1,.CSCLO ;FORCE ITS STATE TO "CLOSED"
STOR T1,CBCNST,(P1) ;...
PUSHJ P,SC.PTC ;DECLARE PROTOCOL COMPLETE
PJRST SC.SRB ;SET REAP BIT AND RETURN
;CONNECTION STATE MAY HAVE CHANGED SINCE SC.DIS WAS FIRST CALLED.
;MAKE SURE A DISCONNECT IS STILL LEGAL, AND GET NEW STATES.
FN2.01: MOVEI T1,EV.DIS ;EVENT IS DISCONNECT CALL
PUSHJ P,SC.OUT ;GET NEW STATES
BUG. (HLT,SCAFN2,SCASER,SOFT,<Can't complete deferred call to SC.DIS>,,)
;STORE CONNECTION AND BLOCK STATES. IF NEW BLOCK STATE IS NON-ZERO,
;WE WANT TO SEND A DISCONNECT_REQUEST. QUEUE THE BLOCK, AND FLAG THE
;UNLOCK CODE TO CALL SC.SNM.
SKIPE T2 ;ZERO MEANS NO CHANGE
STOR T2,CBCNST,(P1) ;STORE NEW CONNECTION STATE
JUMPE T1,CPOPJ## ;RETURN IF NO NEW STATE
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
MOVX T1,CB.SNM ;INDICATE CALL TO SC.SNM WAS DEFERRED
IORM T1,.CBFLG(P1) ;...
POPJ P, ;RETURN
SUBTTL DATAGRAM SERVICE - SEND DATAGRAM
;ROUTINE TO SEND A DATAGRAM.
;CALL:
; BLCAL. (SC.SDG,<SS.CID,SS.FLG,SS.LDG,SS.ADG,SS.PRI,SS.PTH>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.FLG - FLAG WORD
; SS.LDG - LENGTH OF DATAGRAM
; SS.ADG - ADDRESS OF DATAGRAM
; SS.PRI - PRIORITY FOR PACKET SEND
; SS.PTH - PATH TO SEND THE PACKET ON
; 0 - AUTO PATH SELECT
; 1 - PATH A
; 2 - PATH B
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.SDG::,<SS.CID,SS.FLG,SS.LDG,SS.ADG,SS.PRI,SS.PTH>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
LOAD T1,CBCNST,(P1) ;GET THE CONNECT STATE
CAIE T1,.CSOPN ;IS THE CONNECTION OPEN?
RETBAD (.SCSWS,<PUSHJ P,SC.ULK>) ;NO, RETURN AN ERROR
MOVE T1,SS.LDG ;GET THE LENGTH OF THE DATAGRAM
MOVX T2,F.SPM ;GET THE HIGH DENSITY FLAG
TDNE T2,SS.FLG ;IS IT SET IN CALLER'S FLAGS?
JRST SDG.01 ;YES
ADDI T1,C%OVHD ;ADD OVERHEAD SIZE IN BYTES
CAILE T1,C%BYTD ;IS THE DATAGRAM LARGER THAN I CAN SEND?
RETBAD (.SCPTL,<PUSHJ P,SC.ULK>) ;YES, GIVE AN ERROR
JRST SDG.02 ;CONTINUE
SDG.01: ADDI T1,C%OVHW ;ADD OVERHEAD SIZE IN WORDS
CAILE T1,C%WORD ;IS THE DATAGRAM LARGER THAN I CAN SEND?
RETBAD (.SCPTL,<PUSHJ P,SC.ULK>) ;YES, GIVE AN ERROR
SDG.02: MOVEM T1,SS.LDG ;STORE FOR LATER PPD CALL
;ADD THE SCA HEADER TO THE MESSAGE WE HAVE BEEN PASSED
MOVE P2,SS.ADG ;GET ADDRESS IN STANDARD REGISTER
SETZRO MH$CDT,(P2) ;ZERO THE CREDIT FIELD
MOVEI P3,.STADG ;MESSAGE TYPE = DATAGRAM
STOR P3,MH$MSG,(P2) ;STORE
MOVE T1,.CBDCI(P1) ;GET DESTINATION CONNECT ID
MOVEM T1,.MHDCI(P2) ;STORE
MOVE T1,.CBSCI(P1) ;GET SOURCE CONNECT ID
MOVEM T1,.MHSCI(P2) ;STORE
;IF THE SYSAP WANTS THE BUFFER BACK, COUNT THIS AMONG ITS QUEUED BUFFERS
MOVX T1,F.RTB ;PACKET RETURN STATUS FLAG
TDNE T1,SS.FLG ;IS SCA GETTING THIS PACKET BACK?
AOSA .CBNPO(P1) ;YES, INCREMENT COUNT OF OUTSTANDING PACKETS
AOS .CBDGR(P1) ;NO, COUNT THIS AS QUEUED FOR INCOMING DATAGRAM
;CALL THE PORT DRIVER WITH THE DATA
PUSHJ P,SC.ROU ;SWAP THE HEADER FOR OUTPUT
LOAD T1,PBPBI,(P5) ;GET PATH BLOCK INDEX
BLCAL. (PPDSDG##,<T1,P2,SS.LDG,SS.FLG,SS.PRI,SS.PTH>) ;SEND THE PACKET
JRST SDG.E1 ;HANDLE PPD FAILURE
AOS SNDTAB(P3) ;INCREMENT SEND COUNT FOR THIS TYPE OF PACKET
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST CPOPJ1## ;SUCCESS
SDG.E1: MOVX T2,F.RTB ;DID WE BUMP THE PENDING PACKET COUNT?
TDNN T2,SS.FLG ;...
JRST SDG.E2 ;NO
SOSGE .CBNPO(P1) ;YES, PACKET SEND FAILED, FIX COUNT
BUG. (HLT,SCANP1,SCASER,SOFT,<.CBNPO has gone negative>,,)
JRST SDG.E3 ;JOIN COMMON EXIT
SDG.E2: MOVEI T1,1 ;NO, WE COUNTED THIS AS QUEUED FOR INPUT
PUSHJ P,SC.ALD ;GET A BUFFER FROM SCA
JRST SDG.E3 ;COULDN'T
LOAD T2,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDQDB##,<T2,T1>) ;GIVE THE BUFFERS TO THE PPD
SDG.E3: PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
ENDBS. ;END OF BLSUB. RANGE
SUBTTL MESSAGE SERVICE - SEND MESSAGE
;ROUTINE TO SEND A MESSAGE.
;CALL:
; BLCAL. (SC.SMG,<SS.CID,SS.FLG,SS.LMG,SS.AMG,SS.PRI,SS.TSH,SS.PTH>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.FLG - FLAG WORD
; SS.LMG - LENGTH OF MESSAGE
; SS.AMG - ADDRESS OF MESSAGE
; SS.PRI - PRIORITY FOR PACKET SEND
; SS.TSH - SEND CREDIT THRESHOLD
; SS.PTH - PATH TO SEND THE PACKET ON
; 0 - AUTO PATH SELECT
; 1 - PATH A
; 2 - PATH B
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.SMG::,<SS.CID,SS.FLG,SS.LMG,SS.AMG,SS.PRI,SS.TSH,SS.PTH>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK THE CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
LOAD T1,CBCNST,(P1) ;GET THE CONNECT STATE
CAIE T1,.CSOPN ;IS THE CONNECTION OPEN?
RETBAD (.SCSWS,<PUSHJ P,SC.ULK>) ;NO, RETURN AN ERROR
MOVE T1,SS.LMG ;GET THE LENGTH OF THE MESSAGE
MOVX T2,F.SPM ;GET THE HIGH DENSITY FLAG
TDNE T2,SS.FLG ;IS IT SET IN CALLER'S FLAGS?
JRST SMG.01 ;YES
ADDI T1,C%OVHD ;ADD OVERHEAD SIZE IN BYTES
CAILE T1,C%BYTM ;IS THE MESSAGE LARGER THAN I CAN SEND?
RETBAD (.SCPTL,<PUSHJ P,SC.ULK>) ;YES, GIVE AN ERROR
JRST SMG.02 ;CONTINUE
SMG.01: ADDI T1,C%OVHW ;ADD OVERHEAD SIZE IN WORDS
CAILE T1,C%WORM ;IS THE MESSAGE LARGER THAN I CAN SEND?
RETBAD (.SCPTL,<PUSHJ P,SC.ULK>) ;YES, GIVE AN ERROR
SMG.02: MOVEM T1,SS.LMG ;STORE FOR LATER PPD CALL
SOS T1,.CBSCD(P1) ;DECREMENT SEND CREDIT
CAML T1,SS.TSH ;DO WE HAVE MORE THAN THRESHOLD?
JRST SMG.03 ;YES
AOS .CBSCD(P1) ;NO, PUT IT BACK WHERE WE FOUND IT
MOVX T1,CB.NNC ;SET THE FLAG TO NOTIFY ON CREDIT GAIN
IORM T1,.CBFLG(P1) ;...
RETBAD (.SCNEC,<PUSHJ P,SC.ULK>) ;RETURN WITH ERROR CODE
SMG.03: CIOFF ;PREVENT RACES
MOVX T1,F.RTB ;DOES THE SYSAP WANT HIS BUFFER BACK?
TDNE T1,SS.FLG ;...
JRST SMG.04 ;YES
AOS T2,.CBPRC(P1) ;NO, INCREMENT PENDING RECEIVE CREDIT
SKIPG T2 ;HAD WE BEEN WAITING TO CANCEL SOME?
AOS .CBRTC(P1) ;YES, COUNT THIS AS RECEIVE CREDIT
SMG.04: SKIPG T2,.CBPRC(P1) ;IS PENDING RECEIVE CREDIT NOW POSITIVE?
JRST [SETZ T2, ;NO, NO CREDIT IN THE PACKET
JRST SMG.05] ;CONTINUE
ADDM T2,.CBRCD(P1) ;YES, ADD THIS INTO RECEIVE CREDIT
SETZM .CBPRC(P1) ;IT'S NO LONGER PENDING
SMG.05: CION ;OK TO INTERRUPT
;ADD THE SCA HEADER TO THE MESSAGE WE HAVE BEEN PASSED
;CREDIT COUNT STILL IN T2
MOVE P2,SS.AMG ;GET ADDRESS IN STANDARD REGISTER
STOR T2,MH$CDT,(P2) ;STORE THE CREDIT COUNT
MOVEI P3,.STAMG ;MESSAGE TYPE = MESSAGE
STOR P3,MH$MSG,(P2) ;STORE
MOVE T1,.CBDCI(P1) ;GET DESTINATION CONNECT ID
MOVEM T1,.MHDCI(P2) ;STORE
MOVE T1,.CBSCI(P1) ;GET SOURCE CONNECT ID
MOVEM T1,.MHSCI(P2) ;STORE
;IF THE SYSAP WANTS THE BUFFER BACK, COUNT THIS AMONG ITS QUEUED BUFFERS
MOVX T1,F.RTB ;PACKET RETURN STATUS FLAG
TDNE T1,SS.FLG ;IS SCA GETTING THIS PACKET BACK?
AOS .CBNPO(P1) ;YES, INCREMENT COUNT OF OUTSTANDING PACKETS
;CALL THE PORT DRIVER WITH THE DATA
PUSHJ P,SC.ROU ;SWAP THE HEADER FOR OUTPUT
LOAD T1,PBPBI,(P5) ;GET PATH BLOCK INDEX
BLCAL. (PPDSMS##,<T1,P2,SS.LMG,SS.FLG,SS.PRI,SS.PTH>) ;SEND THE PACKET
JRST SMG.E1 ;HANDLE PPD FAILURE
AOS SNDTAB(P3) ;BUMP THE SENT MESSAGE COUNT
;WE MAY HAVE INCREMENT RETURN_CREDIT. IF SO, RECLAIM A BUFFER.
PUSHJ P,SC.GCB ;GET A CANCELED BUFFER, IF ANY
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST CPOPJ1## ;SUCCESS
;HERE ON AN ERROR FROM THE PORT DRIVER
SMG.E1: AOS .CBSCD(P1) ;WE DIDN'T USE THE SEND CREDIT AFTER ALL
CIOFF ;PREVENT RACES
LOAD T2,MH$CDT,(P2) ;GET CREDIT FIELD BACK FROM THE PACKET
ADDM T2,.CBPRC(P1) ;TURN IT BACK INTO PENDING CREDIT
MOVNS T2 ;GET NEGATIVE COUNT
ADDM T2,.CBRCD(P1) ;UPDATE THE CREDIT COUNT IN THE CB
CION ;OK TO INTERRUPT
MOVX T2,F.RTB ;DID WE BUMP THE PENDING PACKET COUNT?
TDNN T2,SS.FLG ;...
JRST SMG.E2 ;NO
SOSGE .CBNPO(P1) ;YES, PACKET SEND FAILED, FIX THE COUNT
BUG. (HLT,SCANP2,SCASER,SOFT,<.CBNPO has gone negative>,,)
JRST SMG.E3 ;JOIN COMMON EXIT
SMG.E2: MOVEI T1,1 ;WE COUNTED THIS AS QUEUED FOR INPUT
PUSHJ P,SC.ABF ;GET A BUFFER FROM SCA
JRST SMG.E3 ;ERROR
LOAD T2,PBPBI,(P5) ;GET PATH BLOCK INDEX
BLCAL. (PPDQMB##,<T2,T1>) ;GIVE THE BUFFER TO THE PORT
SMG.E3: PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
ENDBS. ;END OF BLSUB. RANGE
SUBTTL DATAGRAM SERVICE - RECEIVE DATAGRAM
;ROUTINE TO QUEUE BUFFERS FOR DATAGRAM RECEPTION.
;CALL:
; BLCAL. (SC.RDG,<SS.CID,SS.NUM,SS.ADR>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.NUM - NUMBER OF BUFFERS TO QUEUE IF SS.ADR IS ZERO
; IGNORED IF SS.ADR IS NON-ZERO
; SS.ADR - ADDRESS OF THE BUFFER TO QUEUE
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.RDG::,<SS.CID,SS.NUM,SS.ADR>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET THE CONNECTION ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK THE CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
MOVEI T2,1 ;ASSUME CALLER IS SUPPLYING THE BUFFER
SKIPE T1,SS.ADR ;IS THERE A BUFFER WE NEED TO QUEUE?
JRST RDG.01 ;YES
MOVE T1,SS.NUM ;GET THE NUMBER THEY DESIRE
PUSHJ P,SC.ALD ;ALLOCATE THEM
RETBAD (,<PUSHJ P,SC.ULK>) ;IT WAS A NICE TRY
SKIPA ;DON'T ZERO FLINK
RDG.01: SETZM (T1) ;ENSURE LINK TO NEXT BUFFER IS ZERO
PUSHJ P,SC.QDB ;QUEUE THE BUFFERS TO THE PORT
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL MESSAGE SERVICE - RECEIVE MESSAGE
;ROUTINE TO QUEUE BUFFERS FOR MESSAGE RECEPTION.
;CALL:
; BLCAL. (SC.RMG,<SS.CID,SS.NUM,SS.ADR>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.NUM - NUMBER OF BUFFERS TO QUEUE IF SS.ADR IS ZERO
; IGNORED IF SS.ADR IS NON-ZERO
; SS.ADR - ADDRESS OF THE BUFFER TO QUEUE
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.RMG::,<SS.CID,SS.NUM,SS.ADR>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET THE USER'S CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK THE CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
MOVEI T2,1 ;ASSUME CALLER IS SUPPLYING THE BUFFER
SKIPE T1,SS.ADR ;IS THERE A BUFFER WE NEED TO QUEUE?
JRST RMG.01 ;YES
MOVE T1,SS.NUM ;GET THE NUMBER THEY DESIRE
PUSHJ P,SC.ABF ;ALLOCATE THEM
RETBAD (,<PUSHJ P,SC.ULK>) ;IT WAS A NICE TRY
SKIPA ;DON'T ZERO FLINK
RMG.01: SETZM (T1) ;ENSURE LINK TO NEXT BUFFER IS ZERO
;IF WE HAD BEEN WAITING TO CANCEL SOME BUFFERS, INCREMENT RETURN CREDIT
;FOR AS MANY BUFFERS AS POSSIBLE
MOVE P3,T2 ;SAVE THE NUMBER OF BUFFERS
LOAD T2,PBPBI,(P5) ;GET PATH BLOCK INDEX
BLCAL. (PPDQMB##,<T2,T1>) ;GIVE THE BUFFER TO THE PORT
CIOFF ;PREVENT RACES
MOVE T2,.CBPRC(P1) ;SAVE CURRENT PENDING RECEIVE CREDIT
ADDM P3,.CBPRC(P1) ;UPDATE TO INCLUDE ANY NEW BUFFERS
JUMPGE T2,RMG.02 ;IF ALWAYS POSITIVE, NOTHING ELSE TO DO
SKIPG .CBPRC(P1) ;PREVIOUSLY NEGATIVE, IS IT STILL?
JRST [ADDM P3,.CBRTC(P1) ;YES, RECLAIM ALL THE BUFFERS, THEN
JRST RMG.02] ;CONTINUE
MOVMS T2 ;NO, TAKE ONLY THE NUMBER WE WANTED
ADDM T2,.CBRTC(P1) ;...
;WE MAY WANT TO SEND A CREDIT_REQUEST. SC.CDT WILL QUEUE THE CONNECTION
;BLOCK TO THE PATH BLOCK WORK QUEUE IF WE NEED TO SEND THE REQUEST. IF
;SO, WE MUST CALL SC.SNM TO DO THE SENDING AFTER WE UNLOCK THE CONNECTION
;BLOCK.
RMG.02: CION ;OK TO INTERRUPT
PUSHJ P,SC.GCB ;GET CANCELED BUFFER, IF ANY
SETO P3, ;ASSUME WE'LL NEED TO SEND SOMETHING
PUSHJ P,SC.CDT ;QUEUE CREDIT REQUEST IF NEEDED
SETZ P3, ;DON'T NEED TO SEND A MESSAGE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
SKIPE P3 ;SKIP IF WE DON'T NEED TO SEND A MESSAGE
PUSHJ P,SC.SNM ;SEND NEXT MESSAGE
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL DATAGRAM SERVICE - CANCEL RECEIVE DATAGRAM
;ROUTINE TO DEQUEUE A DATAGRAM BUFFER.
;CALL:
; BLCAL. (SC.CRD,<SS.CID,SS.NUM>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.NUM - NUMBER OF BUFFERS TO DEQUEUE
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.CRD::,<SS.CID,SS.NUM>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
SKIPE T1,SS.NUM ;GET NUMBER OF BUFFERS DESIRED
JRST CRD.01 ;GO GET THEM
PUSHJ P,SC.ULK ;NOTHING TO DO, UNLOCK CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
CRD.01: SOSL .CBDGR(P1) ;DECREMENT COUNT OF QUEUED BUFFERS
JRST CRD.02 ;MORE LEFT, CONTINUE
AOS .CBDGR(P1) ;DIDN'T HAVE ENOUGH, RESTORE COUNT
RETBAD (.SCNEB,<PUSHJ P,SC.ULK>) ;RETURN FAILURE
CRD.02: LOAD T1,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDDDB##,<T1>) ;DEQUEUE A DATAGRAM BUFFER
RETBAD (,<PUSHJ P,SC.ULK>) ;PASS ALONG THE ERROR
PUSHJ P,SC.RLD ;RETURN THE BUFFER TO THE SCA POOL
SOSLE SS.NUM ;DECREMENT COUNT TO DEQUEUE
JRST CRD.01 ;MORE TO DO, LOOP TO DEQUEUE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL MESSAGE SERVICE - CANCEL RECEIVE MESSAGE
;ROUTINE TO DEQUEUE A MESSAGE BUFFER.
;CALL:
; BLCAL. (SC.CRM,<SS.CID,SS.NUM>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.NUM - NUMBER OF BUFFERS TO DEQUEUE
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.CRM::,<SS.CID,SS.NUM>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
MOVN T1,SS.NUM ;GET -VE NUMBER OF BUFFERS
JUMPN T1,CRM.01 ;JUMP IF WE NEED MORE
PUSHJ P,SC.ULK ;NOTHING TO DO, UNLOCK CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
;DECREMENT PENDING RECEIVE CREDIT BY THE NUMBER THE SYSAP WANTS BACK.
;IF WE HAD A POSITIVE COUNT, WE CAN CLAIM SOME (MAYBE ALL) OF THE
;BUFFERS WITHOUT ASKING PERMISSION.
CRM.01: CIOFF ;PREVENT RACES
MOVE T2,.CBPRC(P1) ;SAVE CURRENT PENDING RECEIVE COUNT
ADDM T1,.CBPRC(P1) ;DECREMENT IT BY NUMBER DESIRED
JUMPLE T2,CRM.02 ;IF ALREADY NEGATIVE, CAN'T RECLAIM ANY
SKIPGE .CBPRC(P1) ;DID WE HAVE ENOUGH ALREADY PENDING?
JRST [ADDM T2,.CBRTC(P1) ;NO, CLEAM THE ONES WE HAD PENDING
JRST CRM.02] ;CONTINUE
MOVE T1,SS.NUM ;YES, GET NUMBER WE WANTED
ADDM T1,.CBRTC(P1) ; AND COUNT ALL AS RETURN CREDIT
;WE MAY NEED TO SEND A CREDIT_REQUEST. IF SO, SC.CD5 WILL QUEUE
;THE PACKET. WE MUST CAUSE IT TO BE SENT AFTER UNLOCKING THE
;CONNECTION BLOCK.
CRM.02: CION ;OK TO INTERRUPT
PUSHJ P,SC.GCB ;GET CANCELED BUFFER, IF ANY
SETO P3, ;ASSUME WE'LL NEED TO SEND SOMETHING
PUSHJ P,SC.CD5 ;QUEUE CREDIT REQUEST IF NEEDED
SETZ P3, ;DON'T NEED TO SEND A MESSAGE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
SKIPE P3 ;SKIP IF WE DON'T NEED TO SEND A MESSAGE
PUSHJ P,SC.SNM ;SEND THE NEXT MESSAGE
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL DMA SERVICE - MAP A BUFFER
;ROUTINE TO DEFINE A BUFFER FOR THE PORT TO USE.
;CALL:
; BLCAL. (SC.MAP,<SS.BLK>)
;
;WHERE:
; SS.BLK - ADDRESS OF FIRST ENTRY IN A CHAIN OF BUFFER DESCRIPTOR BLOCKS
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS WITH:
; T1/ BUFFER NAME
$CSUB ;ENTRY POINT
SC.MAP::PJRST PPDMAP## ;CALLING CONVENTIONS ARE THE SAME FOR PPDMAP
SUBTTL DMA SERVICE - UNMAP A BUFFER
;ROUTINE TO UNMAP A NAMED BUFFER.
;CALL:
; BLCAL. (SC.UMP,<SS.NAM>)
;
;WHERE:
; SS.NAM - BUFFER NAME RETURNED BY A CALL TO SC.MAP
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$CSUB ;ENTRY POINT
SC.UMP::PJRST PPDUMP## ;CALLING CONVENTIONS ARE THE SAME FOR PPDUMP
SUBTTL DMA SERVICE - REQUEST DATA
;ROUTINE TO REQUEST THE START OF DATA TRANSMISSION BY A REMOTE PORT.
;CALL:
; BLCAL. (SS.REQ,<SS.CID,SS.SNM,SS.RNM,SS.SOF,SS.ROF>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.SNM - SENDER'S BUFFER NAME
; SS.RNM - RECEIVER'S BUFFER NAME
; SS.SOF - BYTE OFFSET INTO SENDER'S BUFFER
; SS.ROF - BYTE OFFSET INTO RECEIVER'S BUFFER
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.REQ::,<SS.CID,SS.SNM,SS.RNM,SS.SOF,SS.ROF>)
SETO T1, ;INDICATE REQUEST
JRST SC.SNR ;JOIN COMMON CODE
SUBTTL DMA SERVICE - SEND DATA
;ROUTINE TO SEND BLOCK DATA FROM A NAMED BUFFER.
;CALL:
; BLCAL. (SS.REQ,<SS.CID,SS.SNM,SS.RNM,SS.SOF,SS.ROF>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.SNM - SENDER'S BUFFER NAME
; SS.RNM - RECEIVER'S BUFFER NAME
; SS.SOF - BYTE OFFSET INTO SENDER'S BUFFER
; SS.ROF - BYTE OFFSET INTO RECEIVER'S BUFFER
;
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
$XBSUB (SC.SND::,<SS.CID,SS.SNM,SS.RNM,SS.SOF,SS.ROF>)
SETZ T1, ;INDICATE SEND
SC.SNR: PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE P3,T1 ;SAVE SEND/REQUEST FLAG
MOVE T1,SS.CID ;GET CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
LOAD T1,CBCNST,(P1) ;GET THE CONNECT STATE
CAIE T1,.CSOPN ;IS THE CONNECTION OPEN?
RETBAD (.SCSWS,<PUSHJ P,SC.ULK>) ;NO, GIVE AN ERROR
;DON'T SEND IF WE DON'T HAVE ENOUGH SEND CREDIT
SOS T1,.CBSCD(P1) ;DECREMENT SEND CREDIT
CAIL T1,1 ;DO WE HAVE MORE THAN THE THRESHOLD?
JRST SNR.01 ;YES
AOS .CBSCD(P1) ;NO, PUT IT BACK
MOVX T1,CB.NNC ;INDICATE WAITING FOR CREDIT NOTIFY
IORM T1,.CBFLG(P1) ;...
RETBAD (.SCNEC,<PUSHJ P,SC.ULK>) ;RETURN "NOT ENOUGH CREDIT"
;SEND/REQUEST THE DATA
SNR.01: JUMPN P3,SNR.02 ;JUMP IF REQUEST
BLCAL. (PPDSND##,<SS.SNM,SS.RNM,SS.SOF,SS.ROF,SS.CID>)
JRST SNR.E1 ;ERROR
JRST SNR.03 ;SUCCESS
SNR.02: BLCAL. (PPDREQ##,<SS.SNM,SS.RNM,SS.SOF,SS.ROF,SS.CID>)
JRST SNR.E1 ;ERROR
SNR.03: PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
;HERE IF SEND FAILED; CAN ONLY HAPPEN IF VC CLOSED
SNR.E1: AOS .CBSCD(P1) ;BUMP THE CREDIT, WE DIDN'T SEND AFTER ALL
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
ENDBS. ;END OF BLSUB. RANGE
SUBTTL STATE POLLING - CONNECT STATE POLL
;ROUTINE TO RETURN THE STATUS OF A CONNECTION.
;CALL:
; BLCAL. (SC.CSP,<SS.CID,SS.ADR>)
;
;WHERE:
; SS.CID - CONNECT ID
; SS.ADR - ADDRESS OF BLOCK IN WHICH TO RETURN DATA
;
;RETURN:
; CPOPJ ON ERROR WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS WITH:
; T1/ CONNECT ID
; T2/ ADDRESS OF BLOCK IN WHICH DATA WAS RETURNED
$XBSUB (SC.CSP::,<SS.CID,SS.ADR>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE T1,SS.CID ;GET CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK CONNECTION BLOCK
RETBAD () ;PASS ALONG THE ERROR
MOVE T1,SS.ADR ;GET ADDRESS OF WHERE TO RETURN DATA
LOAD T2,CBCNST,(P1) ;GET THE CONNECT STATE
STOR T2,CDCST,(T1) ;STORE
MOVE T2,.CBDCI(P1) ;GET THE DESTINATION CONNECT ID
MOVEM T2,.CDDCI(T1) ;STORE
DMOVE T2,.CBDPN(P1) ;GET FIRST AND SECOND WORD OF DESTINATION NAME
DMOVEM T2,.CDDPN(T1) ;STORE
DMOVE T2,.CBDPN+2(P1) ;GET THIRD AND FOURTH WORD OF DESTINATION NAME
DMOVEM T2,.CDDPN+2(T1) ;STORE
MOVE T2,.CBPBK(P1) ;GET PATH BLOCK ADDRESS
LOAD T2,PBDPN,(T2) ;GET NODE NUMBER
MOVEM T2,.CDNOD(T1) ;STORE
LOAD T2,CBDDRE,(P1) ;GET DESTINATION DISCONNECT REASON
STOR T2,CDDREA,(T1) ;STORE
LOAD T2,CBSDRE,(P1) ;GET SOURCE DISCONNECT REASON
STOR T2,CDSREA,(T1) ;STORE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
MOVE T2,T1 ;COPY BLOCK ADDRESS TO T2
MOVE T1,SS.CID ;GET CONNECT ID
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL CONFIGURATION SERVICES - RETURN DESTINATION CONNECT ID
;ROUTINE TO RETURN THE DESTINATION CONNECT ID FOR A CONNECTION.
;CALL:
; BLCAL. (SC.DCI,<SS.CID>)
;
;WHERE:
; SS.CID - SOURCE CONNECT ID
;
;RETURN:
; CPOPJ ALWAYS
$XBSUB (SC.DCI::,<SS.CID>)
SAVEAC <P1,P5> ;SAVE THE AC'S SC.CAL TROUNCES
MOVE T1,SS.CID ;GET THE CONNECT ID
PUSHJ P,SC.CAL ;CHECK VALIDITY AND LOCK BLOCK
RETBAD () ;RETURN FAILURE
MOVE T1,.CBDCI(P1) ;GET THE DESTINATION CONNECT ID
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL CONFIGURATION SERVICES
;ROUTINE TO RETURN CONFIGURATION INFORMATION FOR A SYSTEM.
;CALL:
; BLCAL. (SC.RSB,<SS.SBI>)
;
;WHERE:
; SS.SBI - SYSTEM BLOCK INDEX
;
;RETURN:
; CPOPJ ON ERROR WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS WITH:
; T1/ ADDRESS OF RETURNED CONFIGURATION BLOCK
;NOTE: IT IS THE CALLER'S RESPONSIBILITY TO RETURN THE SPACE
;USED BY THE CONFIGURATION BLOCK (I.E., CALL GIVSWS).
$XBSUB (SC.RSB::,<SS.SBI>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED AC'S WE USE HERE
SKIPLE T1,SS.SBI ;GET THE CALLER'S SBI, CHECK FOR -VE OR ZERO
CAIL T1,C%SBLL ;OR OUT OF RANGE
RETBAD (.SCISI) ;ERROR
SKIPN P4,SBLIST-1(T1) ;GET SYSTEM BLOCK ADDRESS
RETBAD (.SCISI) ;ERROR
MOVEI T2,.RSLEN ;LENGTH OF THE BLOCK
PUSHJ P,GETSWS## ;GET THE SPACE
RETBAD () ;NO FREE CORE, ERROR
MOVE P1,T1 ;COPY ADDRESS OF BLOCK TO A SAFER AC
LOAD T1,SBPBI,(P4) ;GET FIRST PATH BLOCK INDEX
STOR T1,RSPBI,(P1) ;STORE
LOAD T1,SBDPC,(P4) ;GET DESTINATION PORT COUNT
STOR T1,RSDPC,(P1) ;STORE
LOAD T1,SBDPN,(P4) ;GET THE DESTINATION PORT NUMBER
STOR T1,RSDPN,(P1) ;STORE
MOVEI T1,.RSBLE-.RSDSA ;NUMBER OF WORDS TO MOVE
XMOVEI T2,.SBDSA(P4) ;SOURCE ADDRESS
XMOVEI T3,.RSDSA(P1) ;DESTINATION ADDRESS
EXTEND T1,[XBLT] ;MOVE THE DATA
MOVE T1,P1 ;GET THE BLOCK ADDRESS WHERE ADVERTISED
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
;ROUTINE TO RETURN CONFIGURATION INFORMATION FOR A PATH.
;CALL:
; BLCAL. (SC.RPB,<SS.PBI>)
;
;WHERE:
; SS.PBI - PATH BLOCK INDEX
;
;RETURN:
; CPOPJ ON ERROR WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS WITH:
; T1/ ADDRESS OF RETURNED CONFIGURATION BLOCK
;NOTE: IT IS THE CALLER'S RESPONSIBILITY TO RETURN THE SPACE
;USED BY THE CONFIGURATION BLOCK (I.E., CALL GIVSWS).
$XBSUB (SC.RPB::,<SS.PBI>)
PUSHJ P,SAVP## ;SAVE THE PRESERVED AC'S WE USE HERE
SKIPLE T1,SS.PBI ;GET THE CALLER'S PBI, CHECK FOR -VE OR ZERO
CAIL T1,C%PBLL ;OR OUT OF RANGE
RETBAD (.SCIPI) ;ERROR
SKIPN P5,PBLIST-1(T1) ;GET PATH BLOCK ADDRESS
RETBAD (.SCIPI) ;ERROR
MOVEI T2,.RPLEN ;LENGTH OF BLOCK WE DESIRE
PUSHJ P,GETSWS## ;GET THE SPACE
RETBAD () ;NO FREE SPACE, ERROR
MOVE P1,T1 ;COPY ADDRESS TO SAFER AC
LOAD T1,PBVCST,(P5) ;GET VIRTUAL CIRCUIT STATE
STOR T1,RPVCST,(P1) ;STORE
LOAD T1,PBDPN,(P5) ;GET DESTINATION PORT NUMBER
STOR T1,RPDPN,(P1) ;STORE
LOAD T1,PBNPI,(P5) ;GET NEXT PATH BLOCK INDEX
STOR T1,RPNPI,(P1) ;STORE
LOAD T1,PBSBI,(P5) ;GET SYSTEM BLOCK INDEX
STOR T1,RPSBI,(P1) ;STORE
MOVEI T1,4 ;NUMBER OF WORDS OF PORT CHARACTERISTICS
XMOVEI T2,.PBDPC(P5) ;SOURCE ADDRESS
XMOVEI T3,.RPDPC(P1) ;DESTINATION ADDRESS
EXTEND T1,[XBLT] ;MOVE THE DATA
MOVE T1,P1 ;GET THE BLOCK ADDRESS WHERE ADVERTISED
JRST CPOPJ1## ;SKIP RETURN
ENDBS. ;END OF BLSUB. RANGE
SUBTTL ENTRY FROM PORT DRIVER - NODE ONLINE
;ROUTINE CALLED BY THE PHYSICAL PORT DRIVER WHEN A NODE COMES ONLINE.
;CALL:
; BLCAL. (SC.ONL,<SS.PBI>)
;
;WHERE:
; SS.PBI - PATH BLOCK INDEX OF NODE ONLINE
;
;RETURN:
; CPOPJ ALWAYS
$XBSUB (SC.ONL::,<SS.PBI>)
PUSHJ P,SAVP## ;SAVE THE P REGISTERS
SKIPLE T1,SS.PBI ;CHECK FOR VALID PBI
CAIL T1,C%PBLL ;...
XCT SCAFOO ;INVALID PBI?
SKIPN P5,PBLIST-1(T1) ;GET THE PATH BLOCK ADDRESS
XCT SCAFOO ;DUH?
SETZM .PBFLG(P5) ;CLEAR ANY RESIDUAL FLAGS
SETZM .PBTIM(P5) ;INDICATE WE HAVE NOT SPOKEN TO THE PB YET
;SEE IF THERE ARE ENOUGH BUFFERS AROUND OR IF WE NEED MORE.
;ALSO UPDATE THE MINIMUM NUMBER OF BUFFERS WE SHOULD HAVE.
AOS T1,PBCNT ;COUNT ONLINE PATHS
CAILE T1,C%PBLL ;SANITY CHECK THE RESULT
XCT SCAFOO ;DUH?
PUSHJ P,SC.SBT ;SET BUFFER THRESHOLDS BASED ON NEW PATH COUNT
MOVE T1,MINMSG ;NUMBER OF MESSAGE BUFFERS WE SHOULD HAVE
MOVE T2,MINDG ;NUMBER OF DATAGRAM BUFFERS WE SHOULD HAVE
CAMG T1,MFQCNT ;DO WE HAVE ENOUGH MESSAGE BUFFERS?
CAMLE T2,DFQCNT ;YES, DO WE HAVE ENOUGH DATAGRAM BUFFERS?
AOS CIBUF ;ASK SC.DEF TO RUN
;ALLOCATE A BUFFER FOR INCOMING MESSAGES (GIVE TO THE PORT), AND
;A BUFFER FOR OUTGOING MESSAGES (QUEUE TO PATH BLOCK).
MOVEI T1,1 ;GET ONE BUFFER
PUSHJ P,SC.ABF ; FOR THE OUTBOUND BUFFER
JRST ONL.E1 ;ERROR
MOVEM T1,.PBOBB(P5) ;STORE ITS ADDRESS
MOVEI T1,1 ;GET ANOTHER MESSAGE BUFFER
PUSHJ P,SC.ABF ;ALLOCATE IT
JRST ONL.E1 ;NOT AVAILABLE, DIE
BLCAL. (PPDQMB##,<SS.PBI,T1>) ;QUEUE THE MESSAGE BUFFERS
IFN FTINFO,<
PUSHJ P,PTHONL ;TELL CTY PATH IS ONLINE
>; END IFN FTINFO
;LOOP OVER ENTRIES IN THE NOTIFICATION TABLE TELLING EVERYONE A
;NEW PATH HAS COME ONLINE.
MOVE P1,NOTTAB ;GET THE ADDRESS OF THE NOTIFICATION TABLE
ONL.01: SKIPN 0(P1) ;IS THERE AN ENTRY?
POPJ P, ;NO, WE ARE DONE
MOVX T1,.SSNCO ;REASON = NODE CAME ONLINE
MOVE T2,SS.PBI ;GET THE PATH BLOCK INDEX
PUSHJ P,@0(P1) ;CALL THE SYSAP ABOUT THIS NEW NODE
JFCL ;CATCH SILLY SKIP RETURNS
AOJA P1,ONL.01 ;LOOP FOR THE REMAINING SYSAP'S
ONL.E1: BUG. (HLT,SCASCQ,SCASER,SOFT,<SCA credit queue failed>,,)
SUBTTL ENTRY FROM PORT DRIVER - NODE OFFLINE
;ROUTINE CALLED BY THE PHYSICAL PORT DRIVER WHEN A NODE GOES OFFLINE.
;CALL:
; BLCAL. (SC.ERR,<SS.PBI>)
;
;WHERE:
; SS.PBI - PATH BLOCK INDEX
;
;RETURN:
; CPOPJ ALWAYS
$XBSUB (SC.ERR::,<SS.PBI>)
PUSHJ P,SAVP## ;SAVE THE P REGISTRS
SKIPLE T1,SS.PBI ;CHECK FOR VALID PBI
CAIL T1,C%PBLL ;...
XCT SCAFOO ;FOO
SKIPN P5,PBLIST-1(T1) ;GET THE PATH BLOCK ADDRESS
XCT SCAFOO ;FOO
CIOFF ;PREVENT RACES
;SEE IF WE ALREADY COUNTED THIS PATH AS GOING OFFLINE. IF NOT, SET
;THE FLAG SAYING WE DID, AND DECREMENT THE COUNT OF PATHS ONLINE.
MOVX T1,PB.OFL ;GET THE OFFLINE FLAG
TDNN T1,.PBFLG(P5) ;HAS THIS PATH BEEN MARKED OFFLINE?
JRST ERR.01 ;NO
LOAD T1,PBDPN,(P5) ;YES, GET NODE NUMBER
BUG. (CHK,SCAOF2,SCASER,SOFT,<Duplicate offline for a node>,<<T1,NODE>>,)
CION ;OK TO INTERRUPT
JRST ERR.09 ;LET PPD OPEN THE VC AGAIN
ERR.01: IORM T1,.PBFLG(P5) ;SET THE FLAG FOR LATER
SOSL PBCNT ;DECREMENT THE ONLINE PATH COUNT
JRST ERR.02 ;ALL IS WELL
BUG. (CHK,SCANSC,SCASER,SOFT,<Negative path count>,,)
SETZM PBCNT ;TRY TO RECOVER
;LOOP OVER ALL CONNECTIONS ON THE PB AND MARK THEM AS CLOSED.
ERR.02: SKIPN P1,.PBFCB(P5) ;GET THE ADDRESS OF THE FIRST CB
JRST ERR.06 ;NO CONNECTS TO MARK
ERR.03: MOVX T1,CB.CVC ;INDICATE VC WAS CLOSED
IORM T1,.CBFLG(P1) ;...
MOVX T1,CB.ERR ;IS THE CB LOCKED?
PUSHJ P,SC.HNR ;...
JRST [AOS .PBCLC(P5) ;YES, COUNT ANOTHER LOCKED CB
JRST ERR.05] ;SKIP TO NEXT
LOAD T2,CBCNST,(P1) ;GET CURRENT STATE
MOVEI T1,.CSCLO ;NEW STATE WILL BE "CLOSED"
STOR T1,CBCNST,(P1) ;STORE AS NEW CONNECT STATE
CAIN T2,.CSCLO ;WAS IT ALREADY CLOSED?
JRST ERR.04 ;YES
MOVX T1,.SSPBC ;GET THE NOTIFICATION CODE
MOVE T2,.CBSCI(P1) ;GET SOURCE CONNECT ID
PUSHJ P,@.CBADR(P1) ;NOTIFY THE SYSAP OF THE DISASTER
ERR.04: SETZM .CBRQC(P1) ;WE'LL NEVER GET CREDIT_RESPONSE NOW SO
; CLEAR THIS SO WE CAN REAP
PUSHJ P,SC.PTC ;DECLARE PROTOCOL AS COMPLETE
ERR.05: SKIPE P1,.CBANB(P1) ;IS THERE A NEXT CONNECT BLOCK
JRST ERR.03 ;YES, LOOP FOR IT
ERR.06: PUSHJ P,SC.SBT ;SET NEW BUFFER THRESHOLDS BASED ON ACTIVE PATHS
;IF THERE WERE PENDING CONNECT_REQUEST OR ACCEPT_REQUEST MESSAGES THAT
;REQUIRED BUFFERS, THIS PATH MAY HAVE BEEN MARKED AS STUCK. THESE MESSAGES
;WILL NO LONGER BE SENT. CLEAR THE "STUCK" BIT, AND GET RID OF THE QUEUE
;OF CONNECTION BLOCKS NEEDED TO SEND REQUESTS.
MOVE T1,SS.PBI ;GET PATH BLOCK INDEX
MOVE T1,BITTBL##(T1) ;GET THE BIT
ANDCAM T1,PBSTUK ;AND SHOW THIS PATH IS NO LONGER STUCK ON BUFFERS
XMOVEI T1,.PBTWQ(P5) ;GET THE TOP OF THE WORK QUEUE
MOVEM T1,.PBBWQ(P5) ;INIT TAIL AS POINTER TO HEAD
SETZM .PBTWQ(P5) ;INIT HEAD AS ZERO
CION ;OK TO DIDDLE STUFF AGAIN
IFN FTINFO,<
PUSHJ P,PTHOFL ;TELL THE CTY
>; END IFN FTINFO
;WHEN PATH CAME ONLINE WE GOT 2 BUFFERS FROM THE SCA POOL FOR SENDING
;AND RECEIVING SCS CONTROL MESSAGES. GIVE THEM BACK TO SCA NOW.
SETZ P2, ;GET A ZERO
EXCH P2,.PBOBB(P5) ;IS THE OUTBOUND BUFFER STILL AROUND?
JUMPE P2,ERR.07 ;NO
MOVE T1,P2 ;YES, GET ITS ADDRESS
PUSHJ P,SC.RBF ;RETURN IT TO THE SCA POOL
ERR.07: BLCAL. (PPDDMB##,<SS.PBI>) ;DEQUEUE A MESSAGE BUFFER
JRST ERR.08 ;COULDN'T, TELL THE POOR BLOKE
PUSHJ P,SC.RBF ;RETURN THE BUFFER TO SCA
JUMPN P2,ERR.09 ;DID WE HAVE AN OUTBOUND BUFFER?
BLCAL. (PPDDMB##,<SS.PBI>) ;DEQUEUE A MESSAGE BUFFER
JRST ERR.08 ;COULDN'T, TELL THE POOR BLOKE
PUSHJ P,SC.RBF ;RETURN THE BUFFER TO SCA
JRST ERR.09 ;SKIP PAST THE ERROR
;THE PORT RAN OUT OF BUFFERS. IN THEORY, WE PUT TWO BUFFERS ON THE QUEUE
;WHEN THIS PATH CAME ONLINE, SO WE SHOULD BE ABLE TO TAKE TWO OFF.
ERR.08: LOAD T1,PBDPN,(P5) ;GET THE DESTINATION NODE
BUG. (CHK,SCANMB,SCASER,SOFT,<Can't return SCS control message buffer>,<<T1,NODE>>,)
;THE -20 GIVES EVERYONE A .SSPBC CALLBACK HERE WITH A CID OF ZERO.
ERR.09: SKIPN .PBCLC(P5) ;ANY LOCKED CONNECTIONS?
JRST ERR.10 ;NO, SO OK TO OPEN THE VC
MOVX T1,PB.OVC ;INDICATE WAITING TO OPEN
IORM T1,.PBFLG(P5) ;...
POPJ P, ;RETURN
ERR.10: BLCAL. (PPDOVC##,<SS.PBI>) ;ASK PPD TO OPEN THE VC
POPJ P, ;RETURN
ENDBS. ;END OF BLSUB. RANGE
;ROUTINE TO FINISH FUNCTION OF SC.ERR WHEN UNLOCKING A CONNECTION BLOCK.
;CALL:
; P1/ ADDRESS OF CONNECTION BLOCK
; P5/ ADDRESS OF PATH BLOCK
; PUSHJ P,SC.FN1
;RETURN:
; CPOPJ ALWAYS
SC.FN1: MOVX T1,CB.ERR ;GET THE BIT
ANDCAM T1,.PBFLG(P5) ;SHOW THIS HAS COMPLETED
LOAD T2,CBCNST,(P1) ;GET CURRENT STATE
MOVEI T1,.CSCLO ;NEW STATE WILL BE "CLOSED"
STOR T1,CBCNST,(P1) ;STORE AS NEW STATE
CAIN T2,.CSCLO ;WAS IT ALREADY CLOSED?
JRST FN1.01 ;YES
MOVX T1,.SSPBC ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
CIOFF ;MAKE SURE SYSAP IS NOT INTERRUPTED
PUSHJ P,@.CBADR(P1) ;NOTIFY THE SYSAP OF THE DISASTER
CION ;OK TO INTERRUPT AGAIN
FN1.01: PJRST SC.PTC ;DECLARE PROTOCOL COMPLETE AND RETURN
SUBTTL ENTRY FROM PORT DRIVER - DMA OPERATION COMPLETE
;HERE WHEN THE PORT NOTICED THAT A DMA OPERATION HAS COMPLETED.
;CALL:
; BLCAL. (<SS.BNM,SS.CID>)
;
;WHERE:
; SS.BNM - BUFFER NAME
; SS.CID - CONNECT ID
;
;RETURN:
; CPOPJ ALWAYS
$XBSUB (SC.DMA::,<SS.BNM,SS.CID>)
PUSHJ P,SAVE1## ;SAVE P1
MOVE T1,SS.CID ;GET THE CONNECT ID
PUSHJ P,SC.CSC ;CHECK FOR VALIDITY
POPJ P, ;ERROR
LOAD T1,CBCNST,(P1) ;GET THE CONNECT STATE
CAIE T1,.CSOPN ;IS IT OPEN?
POPJ P, ;NO, IGNORE IT
AOS .CBSCD(P1) ;GIVE BACK THE CREDIT WE TOOK AT THE START
MOVX T1,.SSDMA ;SAY WHY WE ARE CALLING
MOVE T2,SS.CID ;GET THE CONNECT ID
MOVE T3,SS.BNM ;GET THE BUFFER NAME
PUSHJ P,@.CBADR(P1) ;NOTIFY SYSAP OF HIS DMA COMPLETION
;WE'VE JUST INCREMENTED SEND CREDIT. IF THE SYSAP HAD BEEN TOLD
;"NOT ENOUGH CREDITS" ON A PREVIOUS ATTEMPT AT SENDING, WE NEED
;TO TELL HIM TO TRY AGAIN.
MOVX T1,CB.NNC ;DOES SYSAP NEED NOTIFICATION?
TDNN T1,.CBFLG(P1) ;...
POPJ P, ;NO, RETURN NOW
ANDCAM T1,.CBFLG(P1) ;YES, BUT IT DOESN'T ANY LONGER
MOVX T1,.SSCIA ;SAY WHY WE ARE CALLING
MOVE T2,SS.CID ;GET THE CONNECT ID
MOVE T3,.CBSCD(P1) ;SHOW THE SEND CREDIT
MOVE T4,.CBRCD(P1) ;SHOW THE RECEIVE CREDIT
PJRST @.CBADR(P1) ;CALL THE SYSAP AND RETURN
SUBTTL ENTRY FROM PORT DRIVER - MESSAGE AVAILABLE INTERRUPT
;ROUTINE CALLED FROM THE PPD WHEN IT HAS A MESSAGE IT DECIDED SCA
;NEEDS TO SEE. THE VARIOUS TYPES WHICH GET HERE ARE:
; 1. APPLICATION DATAGRAMS (PASSED TO SYSAP)
; 2. APPLICATION MESSAGES (PASSED TO SYSAP)
; 3. SCA CONTROL MESSAGES (PROCESSED BY SCASER)
;CALL:
; BLCAL. (SC.INT,<SS.PBI,SS.PKT,SS.LEN,SS.FLG>)
;
;WHERE:
; SS.PBI - PATH BLOCK INDEX
; SS.PKT - PACKET ADDRESS
; SS.LEN - PACKET LENGTH
; SS.FLG - FLAGS
;
;RETURN:
; CPOPJ ALWAYS
$XBSUB (SC.INT::,<SS.PBI,SS.PKT,SS.LEN,SS.FLG>)
PUSHJ P,SAVP## ;SAVE THE P REGISTERS
SKIPLE T1,SS.PBI ;CHECK FOR VALID PBI
CAIL T1,C%PBLL ;...
XCT SCAFOO ;FOO
SKIPN P5,PBLIST-1(T1) ;GET THE PATH BLOCK ADDRESS
XCT SCAFOO ;FOO
MOVE P2,SS.PKT ;GET PACKET ADDRESS
PUSHJ P,SC.RIN ;SWAP THE HEADER BYTES
MOVE T2,SS.FLG ;GET THE FLAGS
TXNN T2,F.RSP ;IS THIS A REMOTE PACKET?
JRST INT.RP ;YES
;BUFFER IS BEING RETURNED AFTER A SEND. RETURN IT TO THE POOL
;OR GIVE IT TO THE SYSAP.
LOAD T3,MH$MSG,(P2) ;GET THE PACKET TYPE
CAIE T3,.STADG ;IS THIS AN APPLICATION DATAGRAM
CAIN T3,.STAMG ; OR MESSAGE?
JRST INT.MS ;HANDLE THE RETURN OF A SYSAP BUFFER
;BUFFER HAD BEEN SENT BY SCA. THIS SHOULD NEVER HAPPEN.
MOVE T1,P2 ;GET THE PACKET ADDRESS
PJRST SC.RBF ;RETURN THE BUFFER AND RETURN TO PPD
;HERE TO RETURN A LOCALLY GENERATED SYSAP MESSAGE BUFFER TO ITS OWNER
INT.MS: $LDCID P1,.MHSCI(P2) ;GET THE CB ADDRESS FROM THE CID
SOSGE .CBNPO(P1) ;DECREMENT THE COUNT OF OUTSTANDING PACKETS
BUG. (HLT,SCANP3,SCASER,SOFT,<.CBNPO has gone negative>,,)
MOVX T1,.SSMSC ;TELL THE SYSAP WHY WE ARE CALLING
MOVE T2,.MHSCI(P2) ;INDICATE WHICH CONNECTION
MOVE T3,P2 ;GET THE PACKET ADDRESS
PJRST @.CBADR(P1) ;CALL THE SYSAP ABOUT HIS BUFFER AND RETURN TO PPD
;HERE ON A REMOTELY GENERATED PACKET. THE MESSAGE HANDLERS ARE
;CALLED WITH THE FOLLOWING AC'S SET UP:
;
; T1/ FLAGS
; T2/ PACKET LENGTH
; P1/ CB ADDRESS
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
;ALL MESSAGE HANDLERS RETURN CPOPJ ALWAYS
INT.RP: MOVE T1,DATE## ;GET NOW
MOVEM T1,.PBTIM(P5) ;STORE WHEN LAST MESSAGE WAS RECEIVED
MOVX T1,PB.TMG ;CLEAR TIMED MESSAGE FLAG
ANDCAM T1,.PBFLG(P5) ;...
MOVE T1,SS.FLG ;GET THE FLAGS
MOVE T2,SS.LEN ;GET THE PACKET LENGTH
LOAD T3,MH$MSG,(P2) ;GET THE MESSAGE TYPE
CAIL T3,.STLST ;IS THE PACKET ONE WE KNOW ABOUT?
JRST INT.E1 ;NO
AOS RECTAB(T3) ;COUNT THE MESSAGE WE JUST RECEIVED
PJRST @DSPTAB(T3) ;DISPATCH BASED ON MESSAGE TYPE AND RETURN
;HERE WHEN A BAD MESSAGE WAS RECEIVED FROM THE REMOTE SCA.
INT.E1: LOAD T1,PBDPN,(P5) ;GET THE DESTINATION NODE NUMBER
MOVE T2,.CBSCI(P1) ;GET CONNECT ID
BUG. (CHK,SCABMT,SCASER,SOFT,<Bad message type from remote node>,<<T1,NODE>,<T2,CID>,<T3,OPCODE>>,)
PJRST SC.CVC ;CLOSE THE VC AND RETURN
ENDBS. ;END OF BLSUB. RANGE
;DISPATCH TABLE FOR RECEIVED PACKETS
DSPTAB: $DISPA ;GENERATE THE DISPATCH TABLE
SUBTTL MESSAGE HANDLERS - CONNECT REQUEST
SC.ORQ: PUSHJ P,SC.INC ;DO CHECK ON VC CLOSED
JRST SC.RIB ;IGNORE THIS PACKET
PUSHJ P,SC.SCM ;SEARCH FOR A CONNECTION MATCH
JRST ORQ.NM ;NO MATCH, SAY SO
;COPY DATA FROM THE PACKET INTO THE CONNECTION BLOCK
LOAD T1,MH$CDT,(P2) ;GET THE CREDIT FROM THE MESSAGE HADER
MOVEM T1,.CBSCD(P1) ;STORE AS SEND CREDIT
MOVE T1,.MHSCI(P2) ;GET THE SOURCE CONNECT ID
MOVEM T1,.CBDCI(P1) ;STORE IN CB AS DESTINATION CONNECT ID
LOAD T1,MH$MCR,(P2) ;GET THE MINIMUM CREDIT FROM THE MESSAGE HEADER
STOR T1,CBMNRC,(P1) ;STORE
MOVEI T1,C%PNLW ;NUMBER OF WORDS TO MOVE
XMOVEI T2,.MGSPN(P2) ;SOURCE
XMOVEI T3,.CBDPN(P1) ;DESTINATION
EXTEND T1,[XBLT] ;MOVE THE DESTINATION PROCESS NAME
MOVEI T1,C%PNLW ;NUMBER OF WORDS TO MOVE
XMOVEI T2,.MGSDT(P2) ;SOURCE
XMOVEI T3,.CBDTA(P1) ;DESTINATION
EXTEND T1,[XBLT] ;MOVE THE CONNECTION DATA
;BUILD A CONNECT_RESPONSE
MOVEI T1,.CMCMT ;GET THE "MATCH" STATUS
STOR T1,MH$STS,(P2) ;STORE IN MESSAGE
MOVEI T1,.STORS ;GET THE CONNECT_RESPONSE MESSAGE TYPE
PUSHJ P,SC.RSP ;SEND THE RESPONSE
JRST SC.RIB ;FAILED, RETURN BUFFER TO FREE QUEUE
;UPDATE CONNECTION STATE TO CONNECT_RECEIVED
MOVEI T1,.CSCRE ;GET THE CONNECT_RECEIVED STATE
STOR T1,CBCNST,(P1) ;SET THE NEW STATE
;NOW TELL THE SYSAP SOMEONE CONNECTED TO HIS LISTEN
MOVX T1,.SSCTL ;TELL THE REASON
MOVE T2,.CBSCI(P1) ;SOURCE CONNECT ID
XMOVEI T3,.CBDTA(P1) ;POINT TO THE CONNECTION DATA
PJRST @.CBADR(P1) ;CALL THE SYSAP AND RETURN
;HERE IF WE DIDN'T FIND A MATCH FOR THE PROCESS NAME. BUILD THE
;RESPONSE HERE BECAUSE WE WANT TO ZERO THE SOURCE CONNECT ID AND
;THE STANDARD ROUTINE WON'T LIKE THAT.
ORQ.NM: SETZRO MH$CDT,(P2) ;ZERO THE CREDIT FIELD OF THE MESSAGE HEADER
MOVEI T1,.STORS ;GET THE CONNECT_RSP MESSAGE TYPE
STOR T1,MH$MSG,(P2) ;STORE
MOVE T1,.MHSCI(P2) ;GET THE SOURCE CONNECT ID
MOVEM T1,.MHDCI(P2) ;"RETURN TO SENDER ..."
SETZM .MHSCI(P2) ; "ADDRESS UNKNOWN ..."
SETZRO MH$MCR,(P2) ;ZERO MINIMUM CREDIT FIELD FOR SAFETY
MOVEI T1,.CMCNM ;SAY WE FOUND NO CONNECTION MATCH
STOR T1,MH$STS,(P2) ;PUT THE STATUS INFO IN THE MESSAGE HEADER
PUSHJ P,SC.PAK ;SEND THE RESPONSE
JRST SC.RIB ;FAILED, RETURN BUFFER TO THE FREE QUEUE
POPJ P, ;RETURN
SUBTTL MESSAGE HANDLERS - CONNECT RESPONSE
SC.ORS: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE AND OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND RETURN
;IF STATE WE CLOSED, OUR END DISCONNECTED AFTER REQUESTING CONNECTION.
;DON'T NEED TO UPDATE STATE. IF OTHER SIDE SAID "MATCH", WAIT FOR THE
;ACCEPT OF REJECT TO COME IN. IF IT SAID "NO MATCH", WE'RE DONE.
LOAD T2,CBCNST,(P1) ;GET THE OLD STATE
LOAD T3,MH$STS,(P2) ;GET THE MATCH/NO MATCH CODE
CAIE T2,.CSCLO ;WAS IT CLOSED ALREADY?
JRST ORS.01 ;NO
CAIE T3,.CMCMT ;IT WAS CLOSED, IS THIS A MATCH?
PUSHJ P,SC.PTC ;NO, END OF PROTOCOL, THEN
JRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
;HERE WHEN STATE WASN'T CLOSED; THIS IS THE NORMAL CASE. IF THE OTHER
;SIDE SAID "NO MATCH", TELL THE SYSAP THE CONNECTION FAILED, AND MARK
;PROTOCOL COMPLETE. OTHERWISE, UPDATE THE STATE AND WAIT FOR THE ACCEPT
;OR REJECT.
ORS.01: CAIE T3,.CMCMT ;NOT CLOSED, IS THIS A MATCH?
JRST ORS.02 ;NO
MOVE T2,.MHSCI(P2) ;GET SOURCE CONNECT ID FROM PACKET
MOVEM T2,.CBDCI(P1) ;STORE AS DESTINATION CONNECT ID
STOR T1,CBCNST,(P1) ;STORE AS THE NEW CONNECTION STATE
JRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
ORS.02: MOVEI T1,.CSCLO ;NO MATCH, NEW STATE IS CLOSED
STOR T1,CBCNST,(P1) ;STORE THE NEW STATE
MOVX T1,.SSCRA ;SAY WHY WE ARE CALLING THE SYSAP
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
SETZ T3, ;SAY WE WERE REJECTED
LOAD T4,MH$STS,(P2) ;GET REASON CODE FOR REJECTION
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
PUSHJ P,SC.PTC ;DECLARE PROTOCOL COMPLETE
JRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
SUBTTL MESSAGE HANDLERS - ACCEPT REQUEST
SC.ARQ: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE AND OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND QUIT
MOVE P4,T1 ;SAVE NEW STATE
MOVE P3,T2 ;SAVE OPCODE OF RESPONSE
;IF THE CONNECTION IS CURRENTLY CLOSED, THE SYSAP CHANGED ITS MIND
;AFTER SENDING A CONNECT_REQUEST.
LOAD T1,CBCNST,(P1) ;IF THE CURRENT STATE IS CLOSED, WE WANT TO
CAIN T1,.CSCLO ; TO SEND AN ACCEPT_RESPONSE WITH THE
JRST ARQ.NG ; "NO MATCH" CODE
;COPY DATA FROM THE PACKET INTO THE CONNECT BLOCK
;THE NEXT TWO LINES ARE REQUIRED TO TALK TO VMS - THE CONNECT ID
;THEY SEND US WITH THE CONNECT_RESPONSE ISN'T USEFUL. FOR NOW,
;THE COPY THAT REMAINS IN SC.ORS IN CASE THERE'S SOMETHING WRONG
;WITH THIS NEW APPROACH.
MOVE T1,.MHSCI(P2) ;GET SOURCE CONNECT ID
MOVEM T1,.CBDCI(P1) ;STORE IN CONNECT BLOCK
LOAD T1,MH$CDT,(P2) ;GET THE CREDIT FIELD
ADDM T1,.CBSCD(P1) ;UPDATE THE SEND CREDIT
LOAD T1,MH$MCR,(P2) ;GET THE MINIMUM CREDIT
STOR T1,CBMNRC,(P1) ;STORE AS MINIMUM RECEIVE CREDIT
MOVEI T1,C%SDTW ;NUMBER OF WORDS TO MOVE
XMOVEI T2,.MGSDT(P2) ;SOURCE ADDRESS OF CONNECT DATA
XMOVEI T3,.CBDTA(P1) ;DESTINATION ADDRESS OF CONNECT DATA
EXTEND T1,[XBLT] ;MOVE THE CONNECT DATA
;BUILD AND SEND THE ACCEPT_RESPONSE MESSAGE
MOVX T1,.CMCMT ;GET THE UNIVERSAL MATCH CODE
STOR T1,MH$STS,(P2) ;STORE
MOVE T1,P3 ;GET THE OPCODE
PUSHJ P,SC.RSP ;SEND THE RESPONSE
JRST SC.RIB ;FAILED, RETURN THE BUFFER TO THE FREE QUEUE
;SET NEW STATE
STOR P4,CBCNST,(P1) ;STORE CONNECTION STATE RETURNED ABOVE
;NOTIFY THE SYSAP ABOUT WHAT HAS HAPPENED
MOVX T1,.SSCRA ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
SETO T3, ;INDICATE CONNECTION ACCEPTED
XMOVEI T4,.CBDTA(P1) ;GET THE ADDRESS OF THE CONNECTION DATA
PJRST @.CBADR(P1) ;CALL THE SYSAP AND RETURN
;SEND ACCEPT_RESPONSE BECAUSE OUR SIDE DISCONNECTED.
ARQ.NG: MOVE T1,P3 ;GET THE OPCODE FOR ACCEPT_RSP
LOAD T2,CBSDRE,(P1) ;GET SYSAP'S REASON FOR DISCONNECTING
STOR T2,MH$STS,(P2) ;STORE AS THE STATUS
PUSHJ P,SC.RSP ;SEND THE RESPONSE
JRST SC.RIB ;FAILED, RETURN THE BUFFER TO THE FREE QUEUE
PJRST SC.PTC ;DECLARE PROTOCL COMPLETE AND RETURN
SUBTTL MESSAGE HANDLERS - ACCEPT RESPONSE
SC.ARS: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE & OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND QUIT
LOAD T2,CBCNST,(P1) ;GET OLD CONNECT STATE
LOAD T3,MH$STS,(P2) ;GET THE STATUS WORD FROM THE PACKET
CAIE T2,.CSCLO ;WAS IT CLOSED?
JRST ARS.02 ;NO
CAIE T3,.CMCMT ;IS THE STATUS MATCH?
JRST ARS.01 ;NO
MOVEI T1,.BSDPN ;YES, NEW BLOCK STATE IS DISCONNECT_PENDING
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
PJRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
ARS.01: PUSHJ P,SC.PTC ;DECLARE PROTOCOL COMPLETE
PJRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
;HERE WHEN STATE WAS NOT CLOSED (NORMAL CASE). IF MATCH, TELL THE
;SYSAP IT'S OK TO SEND DATA. IF NO MATCH, THE OTHER SIDE CHANGED
;ITS MIND. TELL THE SYSAP AND DECLARE PROTOCOL COMPLETE.
ARS.02: CAIE T3,.CMCMT ;MATCH?
JRST ARS.03 ;NO
STOR T1,CBCNST,(P1) ;STORE NEW CONNECTION STATE
MOVX T1,.SSOSD ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET SOURCE CONNECT ID
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
PJRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
ARS.03: MOVX T1,.CSCLO ;GET THE CLOSED STATE
STOR T1,CBCNST,(P1) ;STORE AS THE NEW STATE
MOVX T1,.SSRID ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET SOURCE CONNECT ID
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
PUSHJ P,SC.PTC ;DECLARE PROTOCOL COMPLETE
PJRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
SUBTTL MESSAGE HANDLERS - REJECT REQUEST
SC.RRQ: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE AND OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND QUIT
MOVE P3,T1 ;SAVE NEW STATE FOR LATER
;GET REASON FOR REJECTION FROM THE PACKET AND STORE IN THE CB
LOAD T1,MH$STS,(P2) ;GET THE REJECT REASON
STOR T1,CBDDRE,(P1) ;STORE
;BUILD THE RESPONSE IN THE BUFFER WE HAVE FROM THE REJECT_REQUEST
MOVE T1,T2 ;GET OPCODE RETURNED ABOVE
PUSHJ P,SC.RSP ;SEND THE RESPONSE
JRST SC.RIB ;FAILED, RETURN THE BUFFER TO THE FREE QUEUE
;POKE THE SYSAP WITH ITS RESPONSE TO OUR CONNECT.
LOAD T1,CBCNST,(P1) ;GET CURRENT CONNECT STATE
CAIN T1,.CSCLO ;CLOSED?
PJRST SC.PTC ;YES, SYSAP DOESN'T WANT TO KNOW ANYMORE
STOR P3,CBCNST,(P1) ;STORE NEW CONNECT STATE
MOVX T1,.SSCRA ;WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
SETZ T3, ;INDICATE THE CONNECTION WAS REJECTED
LOAD T4,CBDDRE,(P1) ;GET THE REASON FOR THE REJECT
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
PJRST SC.PTC ;DECLARE PROTOCOL COMPLETE AND RETURN
SUBTTL MESSAGE HANDLERS - REJECT RESPONSE
SC.RRS: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE AND OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND QUIT
;SET NEW STATE
STOR T1,CBCNST,(P1) ;SET STATE AS RETURNED ABOVE
PUSHJ P,SC.PTC ;DECLARE PROTOCOL COMPLETE
JRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
SUBTTL MESSAGE HANDLERS - DISCONNECT REQUEST
SC.DRQ: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE AND OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND QUIT
MOVE P3,T1 ;SAVE NEW STATE
;COPY REASON FOR DISCONNECT FROM PACKET TO CONNECT BLOCK
LOAD T1,MH$STS,(P2) ;GET THE DISCONNECT REASON
STOR T1,CBDDRE,(P1) ;STORE IN CB
;SEND A DISCONNECT_RSP
MOVE T1,T2 ;GET OPCODE AS RETURNED ABOVE
PUSHJ P,SC.RSP ;SEND THE RESPONSE
JRST SC.RIB ;FAILED, RETURN THE BUFFER TO THE FREE QUEUE
;HONOR THE CB LOCK. IT IT'S LOCKED, SET A FLAG, SO WHEN THE OWNER
;UNLOCKS THE BLOCK THIS FUNCTION WILL BE COMPLETED.
MOVX T1,CB.DRQ ;GET THE FLAG
PUSHJ P,SC.HNR ;HONOR THE LOCK
POPJ P, ;NOTHING ELSE WE CAN DO NOW
;STORE NEW STATE AS RETURNED ABOVE.
STOR P3,CBCNST,(P1) ;STORE NEW STATE
;IF THE NEW STATE IS DISCONNECT_RECEIVED, PREVIOUS STATE WAS OPEN.
;THIS MEANS THE OTHER SIDE INITIATED THE DISCONNECT.
CAIN P3,.CSDRE ;IS THE STATE DISCONNECT RECEIVED?
JRST DRQ.01 ;YES, GO HANDLE THAT
;HERE WHEN NEW STATE IS NOT DISCONNECT_RECEIVED. IF NEW STATE IS CLOSED,
;PROTOCOL IS COMPLETE. THIS HAPPENS WHEN WE INITIATE THE DISCONNECTION,
;AND THE OTHER SIDE RESPONDS WITH A DISCONNECT_REQUEST.
CAIN P3,.CSCLO ;IS THE NEW STATE CLOSED?
PUSHJ P,SC.PTC ;YES, DECLARE PROTOCOL COMPLETE
POPJ P, ;RETURN
;HERE WHEN NEW STATE IS DISCONNECT_RECEIVED. CORPORATE SCA SPEC SAYS
;THE SYSAP SHOULD BE REQUIRED TO DO A DISCONNECT. WE FAKE IT BY SETTING
;THE STATE AND SENDING THE MESSAGE. SET THE STATE BEFORE CALLING THE
;SYSAP, SO IF THE SYSAP DOES A SC.DIS BEFORE RETURNING WE WON'T SEND
;TWO DISCONNECT_REQUESTS.
DRQ.01: MOVEI T1,.CSDMC ;NEW CONNECTION STATE IS DISCONNECT_MATCH
STOR T1,CBCNST,(P1) ;STORE NEW STATE
;TELL THE SYSAP THE OTHER SIDE HUNG UP
MOVX T1,.SSRID ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
LOAD T3,CBDDRE,(P1) ;GET THE REASON FROM THE PACKET STATUS FIELD
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
;SET BLOCK STATE TO DISCONNECT_PEND TO CAUSE DISCONNECT_REQUEST TO BE SENT
MOVEI T1,.BSDPN ;NEW BLOCK STATE
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
PJRST SC.SNM ;SEND NEXT MESSAGE IF POSSIBLE AND RETURN
;ROUTINE TO FINISH FUNCTION OF SC.DRQ WHEN UNLOCKING A CONNECTION BLOCK.
;CALL:
; P1/ ADDRESS OF CONNECTION BLOCK
; P5/ ADDRESS OF PATH BLOCK
; PUSHJ P,SC.FN3
;RETURN:
; CPOPJ ALWAYS
SC.FN3: CIOFF ;PREVENT RACES
MOVX T1,CB.DRQ ;GET THE BIT
ANDCAM T1,.CBFLG(P1) ;SHOW THIS HAS COMPLETED
MOVEI T1,.STDRQ ;OPCODE IS DISCONNECT_REQUEST
IMULI T1,MXCNST ;COMPUTE OFFSET IN THE TABLE
LOAD T2,CBCNST,(P1) ;GET THE CONNECT STATE
ADDI T1,-1(T2) ;STATES START AT 1
MOVE T2,TABLEK(T1) ;GET THE FLAGS
TXNE T2,K.ERR ;WE CAN'T HANDLE PROTOCOL VIOLATION HERE
BUG. (HLT,SCAFN3,SCASER,SOFT,<Can't complete deferred call to SC.DRQ>,,)
LOAD T1,K.STAT,(T1) ;GET NEW STATE
STOR T1,CBCNST,(P1) ;STORE THE NEW CONNECTION STATE
;IF THE NEW STATE IS DISCONNECT_RECEIVED, PREVIOUS STATE WAS OPEN.
;THIS MEANS THE OTHER SIDE INITIATED THE DISCONNECT.
CAIN T1,.CSDRE ;IS THE STATE DISCONNECT_RECEIVED?
JRST FN3.01 ;YES, GO HANDLE THAT
;HERE WHEN NEW STATE IS NOT DISCONNECT_RECEIVED. IF NEW STATE IS
;CLOSED, PROTOCOL IS COMPLETE. THIS HAPPENS WHEN WE INITIATE THE
;DISCONNECTION, AND THE OTHER SIDE RESPONDS WITH A DISCONNECT_REQUEST.
CAIN T1,.CSCLO ;IS THE NEW STATE CLOSED?
PUSHJ P,SC.PTC ;YES, INDICATE PROTOCOL IS COMPLETE
PJRST CIONPJ ;RESTORE INTERRUPTS AND RETURN
;HERE WHEN NEW STATE IS DISCONNECT_RECEIVED. CORPORATE SCA SPEC SAYS
;THE SYSAP SHOULD BE REQUIRED TO DO A DISCONNECT. WE FAKE IT BY SETTING
;THE STATE AND SENDING THE MESSAGE. SET THE STATE BEFORE CALLING THE
;SYSAP, SO IF THE SYSAP DOES A SC.DIS BEFORE RETURNING WE WON'T SEND
;TWO DISCONNECT_REQUESTS.
FN3.01: MOVEI T1,.CSDMC ;NEW STATE IS DISCONNECT_MATCH
STOR T1,CBCNST,(P1) ;STORE IT
;TELL THE SYSAP THE OTHER SIDE HUNG UP.
MOVX T1,.SSRID ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET SOURCE CONNECT ID
LOAD T3,CBDDRE,(P1) ;RETURN REASON FROM PACKET STATUS FIELD
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
;SET BLOCK STATE TO DISCONNECT_PENDING TO CAUSE DISCONNECT_REQUEST TO BE SENT
MOVEI T1,.BSDPN ;NEW BLOCK STATE
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
MOVX T1,CB.SNM ;INDICATE CALL TO SC.SNM DEFERRED
IORM T1,.CBFLG(P1) ;...
PJRST CIONPJ ;RESTORE INTERRUPTS AND RETURN
SUBTTL MESSAGE HANDLERS - DISCONNECT RESPONSE
SC.DRS: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE AND OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND QUIT
STOR T1,CBCNST,(P1) ;STORE THE NEW CONNECT STATE
;IF NEW STATE IS CLOSED, THIS IS A CONFIRMATION OF OUR DISCONNECT_REQUEST.
;EARLIER WE HAD RECEIVED A DISCONNECT_REQUEST AND SENT A DISCONNECT_RESPONSE.
;IF NOT, THE OTHER SIDE STILL NEEDS TO SEND A DISCONNECT_REQUEST.
CAIN T1,.CSCLO ;IS THE STATE CLOSED?
PUSHJ P,SC.PTC ;YES, DECLARE PROTOCOL COMPLETE
JRST SC.SAR ;GO SEND NEXT SCS CONTROL MESSAGE, RETURN BUFFER
SUBTTL MESSAGE HANDLERS - CREDIT REQUEST
SC.CRQ: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE AND OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND QUIT
MOVE P3,T2 ;SAVE OPCODE OF RESPONSE
LOADE T1,MH$CDT,(P2) ;GET THE CREDIT FIELD FROM THE MESSAGE HEADER
JUMPGE T1,CRQ.01 ;JUMP IF WE ARE GIVING BACK CREDIT
;HERE WHEN THE OTHER SIDE IS WITHDRAWING CREDIT. DON'T ALLOW THIS IF
;SEND CREDIT IS ALREADY BELOW THE MINIMUM, AND DON'T ALLOW IT TO GO
;BELOW THE MINIMUM.
LOAD T2,CBMNSC,(P1) ;GET MINIMUM SEND CREDIT
SUB T2,.CBSCD(P1) ;COMPUTE -(SEND CREDIT - MINIMUM SEND CREDIT)
JUMPLE T2,[SETZ T1, ;IF BELOW MINIMUM, DON'T REDUCE IT
JRST CRQ.01] ;SEND THE RESPONSE
CAMLE T2,T1 ;REQUEST TOO LARGE?
MOVE T1,T2 ;YES, REDUCE ONLY TO MINIMUM SEND CREDIT
;HERE TO SEND THE RESPONSE
CRQ.01: ADDM T1,.CBSCD(P1) ;ADD THIS BACK INTO SEND CREDIT
STOR T1,MH$CDT,(P2) ;PUT THE CREDIT AMOUNT BACK INTO THE HEADER
EXCH T1,P3 ;GET OPCODE, SAVE CREDIT VALUE
PUSHJ P,SC.RS2 ;SEND THE RESPONSE, DON'T ZERO CREDIT
JRST [MOVNS P3 ;GET NEGATIVE OF CREDIT
ADDM P3,.CBSCD(P1) ;RESTORE CREDIT TO PREVIOUS VALUE
JRST SC.RIB] ;RETURN THE BUFFER TO THE FREE QUEUE
;IF THE SYSAP HAS TRIED TO SEND A MESSAGE AND FAILED BECAUSE OF LACK
;OF SEND CREDIT, WE NEED TO NOTIFY IT THAT CREDIT HAS BEEN GIVEN TO
;IT. NOTE WE MUST CLEAR THE BEFORE THE CALL TO THE SYSAP.
JUMPLE P3,CPOPJ## ;IF NOT ADDING CREDIT, WE'RE DONE
LOAD T1,CBCNST,(P1) ;GET THE CONNECTION STATE
MOVX T2,CB.NNC ;NEEDS CREDIT NOTIFY BIT
TDNE T2,.CBFLG(P1) ;DOES SYSAP NEED NOTIFICATION?
CAIE T1,.CSOPN ;YES, IS CONNECTION OPEN?
POPJ P, ;NO, RETURN NOW
ANDCAM T2,.CBFLG(P1) ;CLEAR THE FLAG BEFORE CALLING SYSAP
MOVX T1,.SSCIA ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET SOURCE CONNECT ID
MOVE T3,.CBSCD(P1) ;SHOW THE SEND CREDIT
MOVE T4,.CBRCD(P1) ;SHOW THE RECEIVE CREDIT
PJRST @.CBADR(P1) ;CALL THE SYSAP AND RETURN
SUBTTL MESSAGE HANDLERS - CREDIT RESPONSE
SC.CRS: PUSHJ P,SC.INC ;CHECK VALIDITY, GET STATE AND OPCODE
JRST SC.RIB ;RETURN THE BUFFER AND QUIT
;GET THE CREDIT FROM THE MESSAGE AND FIGURE OUT WHAT IS REQUIRED
LOADE P3,MH$CDT,(P2) ;GET THE CREDIT FIELD FROM THE MESSAGE HEADER
SKIPL .CBRQC(P1) ;WERE WE TRYING TO GET CREDIT BACK?
JRST CRS.01 ;NO
MOVM T2,P3 ;GET THE NUMBER WE WERE ALLOWED
ADDM T2,.CBRTC(P1) ;ADD INTO RETURN CREDIT
JRST CRS.02 ;CONTINUE
CRS.01: CAMN P3,.CBRQC(P1) ;DO WE AGREE WITH THE OTHER END?
JRST CRS.02 ;YES
LOAD T1,PBDPN,(P5) ;GET THE NODE NUMBER
MOVE T2,.CBSCI(P1) ;GET THE CONNECT ID
BUG. (CHK,SCAQQQ,SCASER,SOFT,<Unexpected credit field in credit_request>,<<T1,NODE>,<T2,CID>>,)
CRS.02: ADDM P3,.CBRCD(P1) ;UPDATE THE RECEIVE CREDIT
SETZM .CBRQC(P1) ;IF NEGATIVE, DON'T LET SC.RCB DEQUEUE
; BECAUSE THEY ARE COUNTED IN RETURN_CREDIT
SETZM .CBPND(P1) ;INDICATE NO CREDIT_REQUEST PENDING
PUSHJ P,SC.CD1 ;QUEUE CREDIT REQUEST IF NEEDED
JFCL ;DON'T CARE WHETHER QUEUED OR NOT
PUSHJ P,SC.GCB ;GET CANCELED BUFFERS, IF ANY
PJRST SC.SAR ;GO SEND THE NEXT MESSAGE
SUBTTL COMMON EXIT FOR INCOMING SCS CONTROL MESSAGES
;ROUTINE TO HANDLE A RESPONSE RECEIVED. THIS IS THE PACKET RESERVED
;FOR OUTGOING MESSAGES FOR THE PATH BLOCK OF INTEREST. USE IT TO
;SEND THE NEXT MESSAGE, OR QUEUE IT TO THE PATH BLOCK FOR THE NEXT
;TIME IT WANTS TO SEND A REQUEST.
;CALL:
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.SAR
;RETURN:
; CPOPJ ALWAYS
SC.SAR: MOVEM P2,.PBOBB(P5) ;STORE THE BUFFER ADDRESS
PJRST SC.SNM ;SEND NEXT SCS CONTROL MESSAGE
;ROUTINE TO RETURN BUFFER TO THE PORT. THIS HAPPENS WHEN THE PACKET
;ARRIVES AFTER THE VC HAS ALREADY BEEN CLOSED.
;CALL:
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.RIB
;RETURN:
; CPOPJ ALWAYS
SC.RIB: SETZM (P2) ;CLEAR FLINK OF PACKET
LOAD T1,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDQMB##,<T1,P2>) ;RETURN THE BUFFER TO PORT'S FREE QUEUE
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - PROCESS INCOMING PACKET
;ROUTINE TO PROCESS AN INCOMING PACKET.
;CALL:
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.INC
;RETURN:
; CPOPJ ON ERROR
; CPOPJ1 ON SUCCESS WITH:
; T1/ NEW STATE
; T2/ OPCODE OF RESPONSE
; P1/ CB ADDRESS
SC.INC: SAVEAC <P3> ;SAVE AN AC
LOAD T1,PBVCST,(P5) ;GET THE VC STATE
CAIE T1,VC.OPN ;IS IT OPEN?
POPJ P, ;NO
LOAD P3,MH$MSG,(P2) ;GET THE OPCODE
CAIN P3,.STORQ ;SPECIAL CASE FOR CONNECT_REQ
JRST CPOPJ1## ;SKIP RETURN
;SEE WHETHER WE KNOW ABOUT THE CONNECT ID
MOVE T1,.MHDCI(P2) ;GET DESTINATION CONNECT ID
PUSHJ P,SC.CSC ;CHECK FOR VALIDITY
JRST INC.02 ;NOT VALID, GO HANDLE THE PROBLEM
;SEE WHETHER THIS EVENT IS EXPECTED GIVEN THE CURRENT STATE
IMULI P3,MXCNST ;COMPUTE OFFSET IN THE TABLE BASED
LOAD T1,CBCNST,(P1) ; ON THE CURRENT CONNECT STATE
ADDI P3,-1(T1) ;(STATES START AT 1)
MOVE T1,TABLEK(P3) ;GET THE TABLE ENTRY
TXNE T1,K.ERR ;IF UNEXPECTED, GO HANDLE THE ERROR
JRST INC.04 ;...
TXNN T1,K.CHK ;WANT TO CHECK THIS RESPONSE?
JRST INC.01 ;NO
LOAD T1,MH$MSG,(P2) ;YES, GET OPCODE
LOAD T2,CBEXPR,(P1) ;GET EXPECTED RESPONSE
CAMN T1,T2 ;MATCH?
JRST INC.01 ;YES
LOAD T3,PBDPN,(P5) ;GET DESTINATION NODE
MOVE T4,.CBSCI(P1) ;GET SOURCE CONNECT ID
BUG. (CHK,SCAUXR,SCASER,SOFT,<Unexpected response>,<<T3,NODE>,<T4,CID>,<T1,OPCODE>,<T2,EXPCTD>>,)
JRST INC.07 ;GO CLOSE THE VC
INC.01: LOAD T1,K.STAT,(P3) ;IT'S LEGAL, GET NEW STATE
LOAD T2,K.OP,(P3) ; AND OPCODE TO SEND
JRST CPOPJ1## ;SKIP RETURN
INC.02: LOAD T1,PBDPN,(P5) ;GET THE NODE
MOVE T2,.MHDCI(P2) ;GET DESTINATION CONNECT ID
LOAD T3,MH$MSG,(P2) ;GET THE OPCODE
BUG. (CHK,SCANOC,SCASER,SOFT,<Received packet and connection block doesn't exist>,<<T1,NODE>,<T2,CID>,<T3,OPCODE>>,)
JRST INC.07 ;SKIP THE NEXT ERROR
INC.04: LOAD T1,PBDPN,(P5) ;GET THE DESTINATION NODE
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
LOAD T3,MH$MSG,(P2) ;GET THE OPCODE
LOAD T4,CBCNST,(P1) ;GET THE CONNECT STATE
BUG. (CHK,SCAPER,SCASER,SOFT,<Protocol error>,<<T1,NODE>,<T2,CID>,<T3,OPCODE>,<T4,STATE>>,)
INC.07: PJRST SC.CVC ;CLOSE THE VC AND RETURN
SUBTTL MESSAGE HANDLERS - APPLICATION DATAGRAM/MESSAGE
;CALL:
; T1/ FLAGS
; T2/ LENGTH (BYTES IF INDUSTRY COMPATIBLE, WORDS IF HIGH DENSITY)
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
SC.ADG:
SC.AMG: LOAD T3,PBVCST,(P5) ;GET VC STATE
CAIE T3,VC.OPN ;OPEN?
JRST AMD.07 ;NO, RETURN THE BUFFER AND QUIT
;SAVE FLAGS AND PACKET LENGTH
ANDX T1,C%FLGM ;KEEP JUST THE FLAG BITS
MOVE P3,T1 ;SAVE FLAGS
MOVE P4,T2 ;SAVE LENGTH
;CHECK FOR ERROR CASES - INVALID CID OR INVALID STATE
MOVE T1,.MHDCI(P2) ;GET THE DESTINATION CONNECT ID
PUSHJ P,SC.CSC ;CHECK FOR VALIDITY
JRST AMD.06 ;NO, CLOSE THE VC
LOAD T1,CBCNST,(P1) ;GET THE CONNECT STATE
CAIN T1,.CSOPN ;IS THE CONNECTION OPEN?
JRST AMD.01 ;YES, PROCEED
CAIE T1,.CSDAK ;ARE WE IN THE MIDDLE OF SENDING
CAIN T1,.CSDSE ; OR RECEIVING A DISCONNECT?
JRST AMD.07 ;YES, IT'S OK, RETURN THE BUFFER AND QUIT
JRST AMD.06 ;NO, SHOULDN'T BE GETTING A PACKET NOW
;WE ARE HAPPY TO BE RECEIVING THIS PACKET
AMD.01: MOVEM P4,.MHPKL(P2) ;STORE PACKET LENGTH WHERE SYSAP EXPECTS IT
MOVE T2,.MHDCI(P2) ;GET THE DESTINATION CONNECT ID
MOVE T3,P2 ;SYSAP WANTS ADDRESS OF PACKET
LOAD P4,MH$MSG,(P2) ;GET THE MESSAGE TYPE
CAIE P4,.STAMG ;APPLICATION MESSAGE?
JRST AMD.02 ;NO
SOS .CBRCD(P1) ;YES, DECREMENT RECEIVE CREDIT
LOAD T1,MH$CDT,(P2) ;GET CREDIT FROM PACKET
ADDM T1,.CBSCD(P1) ;UPDATE OUR SEND CREDIT
MOVE P2,T1 ;SAVE THE CREDIT *** P2 NO LONGER POINTS AT PACKET ***
MOVX T1,.SSMGR ;SAY WHY WE ARE CALLING
MOVE T4,[MCSEC1+SC.RBF] ;ADDRESS OF BUFFER-RETURN ROUTINE
JRST AMD.03 ;GO CALL THE SYSAP
AMD.02: SOSGE .CBDGR(P1) ;DATAGRAM, DO WE HAVE A BUFFER QUEUED?
JRST AMD.05 ;NO, HAVE TO DROP THIS ONE ON THE FLOOR
MOVX T1,.SSDGR ;SAY WHY WE ARE CALLING
MOVE T4,[MCSEC1+SC.RLD] ;ADDRESS OF BUFFER-RETURN ROUTINE
AMD.03: IOR T4,P3 ;INCLUDE THE FLAGS
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
CAIE P4,.STAMG ;WAS THIS A MESSAGE?
POPJ P, ;NO, ALL DONE
;THIS WAS A MESSAGE. IF THE REMOTE SYSAP INCREASED OUR SEND CREDIT,
;AND OUR SYSAP NEEDS TO BE TOLD, DO IT NOW.
MOVX T1,CB.NNC ;"WAITING FOR CREDIT NOTIFY" FLAG
TDNE T1,.CBFLG(P1) ;SYSAP WAITING FOR CREDIT?
SKIPN P2 ;YES, DID WE GET ANY?
JRST AMD.04 ;NO, DON'T NOTIFY THEN
ANDCAM T1,.CBFLG(P1) ;CLEAR THE FLAG
MOVX T1,.SSCIA ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET SOURCE CONNECTION ID
MOVE T3,.CBSCD(P1) ;SEND CREDIT
MOVE T4,.CBRCD(P1) ;RECEIVE CREDIT
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
;IF THIS PUSHED OUR RECEIVE CREDIT UNDER THE MINIMUM, NOTIFY THE
;SYSAP THAT LITTLE CREDIT IS LEFT.
AMD.04: MOVE T1,.CBPRC(P1) ;GET PENDING RECEIVE CREDIT
MOVE T2,.CBRCD(P1) ; AND THE RECEIVE CREDIT
ADD T1,T2 ;GET THE TOTAL
LOAD T2,CBMNRC,(P1) ;GET THE MINIMUM RECEIVE CREDIT
SUB T1,T2 ;DIFFERENCE BETWEEN THE TWO
JUMPG T1,CPOPJ## ;RETURN IF CREDIT LEFT
MOVM T3,T1 ;GET THE POSITIVE NUMBER OF BUFFER TO GET
AOS T3 ;PLUS ONE JUST TO HAVE AN EXTRA AROUND
MOVX T1,.SSLCL ;SAY WHY WE ARE CALLING
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
PJRST @.CBADR(P1) ;CALL THE SYSAP AND RETURN
;HAVE TO DROP THIS DATAGRAM AS THERE WAS NO BUFFER QUEUED FOR IT
AMD.05: MOVX T1,.SSDDG ;GET CALLBACK REASON CODE
MOVE T2,.MHDCI(P2) ;GET DESTINATION CONNECT ID
PUSHJ P,@.CBADR(P1) ;CALL THE SYSAP
AOS .CBCDD(P1) ;COUNT ANOTHER ONE DROPPED
AOS .CBDGR(P1) ;RESTORE THE COUNT THAT WE DECREMENTED
JRST AMD.07 ;RETURN THE BUFFER
;THE PACKET SHOULDN'T HAVE COME. CLOSE THE VC.
AMD.06: PUSHJ P,SC.CVC ;CLOSE THE VC
;RETURN THE BUFFER TO THE PORT
AMD.07: SETZM (P2) ;CLEAR FLINK IN PACKET
LOAD T2,MH$MSG,(P2) ;GET OPCODE
LOAD T1,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
CAIE T2,.STAMG ;MESSAGE?
JRST AMD.08 ;NO
BLCAL. (PPDQMB##,<T1,P2>) ;QUEUE A MESSAGE BUFFER
POPJ P, ;RETURN
AMD.08: BLCAL. (PPDQDB##,<T1,P2>) ;QUEUE A DATAGRAM BUFFER
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - ONCE PER TICK/SECOND PROCESSING
;ROUTINE CALLED ONCE PER TICK ON ALL CPUS TO PERFORM PERIODIC
;PROCESSING.
;CALL:
; PUSHJ P,SC.TIC
;RETURN:
; CPOPJ ALWAYS
$XSENT (SC.TIC::) ;EXTENDED ENTRY POINT
SKPCPU (0) ;IS THIS THE BOOT CPU?
JRST TIC.01 ;NO
PUSHJ P,SC.DEF ;HANDLE DEFERRED BUFFER REQUESTS
PUSHJ P,SC.ALM ;HANDLE MEMORY ALLOCATION REQUESTS
TIC.01: SKIPE SCAREP ;DO WE NEED TO REAP CONNECTION BLOCKS?
PUSHJ P,SC.RAP ;YES
POPJ P, ;RETURN
;ROUTINE CALLED ONCE PER SECOND ON ALL CPUS TO PERFORM PERIODIC
;PROCESSING.
;CALL:
; PUSHJ P,SC.SEC
;RETURN:
; CPOPJ ALWAYS
$XSENT (SC.SEC::) ;EXTENDED ENTRY POINT
PUSHJ P,SC.IDL ;DO IDLE CHATTER
POPJ P, ;RETURN
SUBTTL PERIODIC FUNCTIONS - IDLE CHATTER
;ROUTINE TO HANDLE IDLE CHATTER. IF A REMOTE NODE HAS NOT SENT US A
;PACKET LATELY WE WILL SEND IT A CREDIT REQUEST OVER AN OPEN CONNECT.
;(THUS IF THERE ARE NO OPEN CONNECTIONS THEN THERE IS NO IDLE CHATTER.)
;CALL:
; PUSHJ P,SC.IDL
;RETURN:
; CPOPJ ALWAYS
SC.IDL: PUSHJ P,SAVP## ;SAVE THE PRESERVED AC'S
CIOFF ;PREVENT RACES
SKPCPU (0) ;ON THE BOOT CPU?
SKIPA T1,TMGPBI ;NO, DON'T INCREMENT PBI
AOS T1,TMGPBI ;GET THE NEXT PBI WE SHOULD LOOK AT
CAIL T1,C%PBLL ;HAVE WE GONE OFF THE END OF THE WORLD?
SETZB T1,TMGPBI ;YES, RESET TO FIRST ONE
CION ;OK TO INTERRUPT
SKIPN P5,PBLIST(T1) ;IS THERE A PATH BLOCK THERE?
POPJ P, ;NO
IFN FTMP,<
MOVE T1,.PBCPU(P5) ;YES, IS IT ON THIS CPU?
CAME T1,.CPCPN## ;...
POPJ P, ;NO
>; END IFN FTMP
LOAD T1,PBVCST,(P5) ;GET VC STATE
CAIE T1,VC.OPN ;IS IT OPEN?
POPJ P, ;NO
SKIPN .PBFCB(P5) ;ARE THERE ANY CONNECTIONS?
POPJ P, ;NO
SKIPN T1,.PBTIM(P5) ;HAS THIS NODE EVER SPOKEN TO US?
POPJ P, ;NO
SUB T1,DATE## ;YES, HOW LONG AGO DID IT?
CAMLE T1,TMGTIM ;TIME TO POKE IT IN THE SIDE?
POPJ P, ;NO
;IT'S BEEN A WHILE SINCE WE LAST HEARD FROM THIS NODE. IF WE ALREADY
;SENT A TIMED MESSAGE THE LAST TIME WE CAME THROUGH HERE, GIVE UP ON
;IT AND CLOSE THE VC. OTHERWISE, GO SEND A TIMED MESSAGE.
MOVX T1,PB.TMG ;HAS A TIMED MESSAGE BEEN SENT?
TDNN T1,.PBFLG(P5) ;...
JRST IDL.01 ;NO
AOS TMGCNT ;YES, COUNT ANOTHER ONE BITING THE DUST
LOAD T1,PBDPN,(P5) ;GET THE NODE NUMBER
BUG. (INF,SCATMO,SCASER,SOFT,<SCA timed out remote node>,<<T1,NODE>>,)
PJRST SC.CVC ;CLOSE THE VC AND RETURN
;FIND A CONNECTION ON THIS PATH BLOCK WHICH IS FULLY OPEN. IF A NODE
;GOES OFFLINE WHILE WE'RE DOING THIS, ALL ATTEMPTS AT SENDING WILL FAIL
;BECAUSE CONNECTION STATE WILL BE CLOSED FOR EACH CB.
IDL.01: SKIPN P1,.PBFCB(P5) ;GET ADDRESS OF FIRST CONNECTION BLOCK
POPJ P, ;ALL CONNECTIONS ARE GONE, ALL DONE
;TRY THIS CONNECTION BLOCK; IF THE STATE IS OK, SEND A CREDIT_REQUEST
IDL.02: PUSHJ P,SC.LOK ;LOCK THE CONNECTION BLOCK
SETO P3, ;ASSUME WE'LL NEED TO SEND A MESSAGE
PUSHJ P,SC.CD7 ;QUEUE CREDIT REQUEST IF POSSIBLE
SETZ P3, ;DON'T NEED TO SEND A MESSAGE AFTER ALL
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JUMPE P3,IDL.03 ;JUMP IF WE DON'T NEED TO SEND A MESSAGE
PUSHJ P,SC.SNM ;SEND THE NEXT MESSAGE
MOVX T1,PB.TMG ;SET THE TIMED MESSAGE FLAG
IORM T1,.PBFLG(P5) ;...
POPJ P, ;RETURN
IDL.03: SKIPN P1,.CBANB(P1) ;IS THERE ANOTHER CONNECTION BLOCK?
POPJ P, ;NO, RETURN
JRST IDL.02 ;YES, TRY IT
SUBTTL PERIODIC FUNCTIONS - REAP OLD CONNECTIONS
;ROUTINE TO REAP CONNECTION BLOCKS WHICH HAVE THE REAP BIT SET.
;CALL:
; PUSHJ P,SC.RAP
;RETURN:
; CPOPJ ALWAYS
SC.RAP: SAVEAC <Q1,Q2,P1> ;SAVE SOME AC'S
SETZ Q1, ;START WITH FIRST PATH BLOCK
RAP.01: SKIPN Q2,PBLIST(Q1) ;IS THERE A PATH BLOCK THERE?
JRST RAP.04 ;NO, TRY FOR NEXT ONE
IFN FTMP,<
MOVE T1,.PBCPU(Q2) ;GET CPU NUMBER
CAME T1,.CPCPN## ;ON OUR CPU?
JRST RAP.04 ;NO, SKIP THIS
>; END IFN FTMP
MOVE P1,.PBFCB(Q2) ;GET THE POINTER TO THE FIRST CB
JUMPE P1,RAP.04 ;TRY NEXT ONE IF NO CONNECTIONS
RAP.02: MOVE Q2,.CBANB(P1) ;GET ADDRESS OF NEXT CB
MOVX T1,CB.RAP ;GET THE REAP BIT
TDNN T1,.CBFLG(P1) ;SHOULD THIS CONNECTION BE REAPED?
JRST RAP.03 ;NO
; SKIPN .CBNPO(P1) ;ANY PACKETS STILL ON THE COMMAND QUEUE?
PUSHJ P,SC.RCB ;REAP THE CONNECT DATA
RAP.03: SKIPE P1,Q2 ;IS THERE ANOTHER BLOCK?
JRST RAP.02 ;YES, LOOP
RAP.04: CAIGE Q1,C%PBLL-1 ;PAST THE END?
AOJA Q1,RAP.01 ;NO, TRY NEXT
;NOW DO THE DON'T CARE QUEUE
RAP.05: CIOFF ;PREVENT RACES
RAP.06: SKIPN P1,TOPDC ;GET FIRST CONNECTION
JRST CIONPJ ;NONE, RESTORE INTERRUPTS AND RETURN
RAP.07: MOVX T1,CB.RAP ;GET THE REAP BIT
TDNN T1,.CBFLG(P1) ;SHOULD THIS CONNECTION BE REAPED?
JRST RAP.08 ;NO
CION ;ALLOW INTERRUPTS AGAIN
PUSHJ P,SC.RCB ;RETURN THE CONNECTION DATA
JRST RAP.05 ;START OVER
RAP.08: MOVE P1,.CBANB(P1) ;GET THE ADDRESS OF THE NEXT CB
JUMPN P1,RAP.07 ;JUMP IF MORE TO CHECK
PJRST CIONPJ ;DONE, RESTORE INTERRUPTS AND RETURN
SUBTTL SCA SUPPORT ROUTINES - RELEASE A CONNECTION BLOCK
;ROUTINE TO DEALLOCATE A CONNECTION BLOCK.
;CALL:
; P1/ CB ADDRESS
; PUSHJ P,SC.RCB
;RETURN:
; CPOPJ ALWAYS
SC.RCB: SAVEAC <Q1,P2,P5> ;SAVE AN AC OR THREE
CIOFF ;PREVENT RACES
MOVE P5,.CBPBK(P1) ;GET THE PATH BLOCK ADDRESS
JUMPL P5,RCB.04 ;JUMP IF A "DON'T CARE" LISTENER
PUSHJ P,SC.RSQ ;REMOVE THIS CONNECTION BLOCK FROM QUEUE
CION ;OK TO INTERRUPT
;REMOVE CID TABLE ENTRIES FOR THIS CB
MOVE T1,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
LOAD T4,INDEX,T1 ;GET THE INDEX INTO CIDTAB
MOVE T1,T4 ;GET A COPY
ADD T1,CIDTAB ;ADD IN ADDRESS OF CID TABLE
SETZM (T1) ;ZERO THE ADDRESS OF THE CB IN TABLE
;GET BUFFERS BACK FROM THE MESSAGE FREE QUEUE
LOAD P2,PBPBI,(P5) ;GET PATH BLOCK INDEX FOR PPD
MOVE Q1,.CBRCD(P1) ;GET TOTAL RECEIVE CREDIT
ADD Q1,.CBPRC(P1) ;ADD THE PENDING CREDITS
ADD Q1,.CBRQC(P1) ;AND NUMBER OF CREDITS OUTSTANDING IN CDT_REQ
ADD Q1,.CBRTC(P1) ;ADD CANCELED BUFFERS NOT YET DEQUEUED
JUMPE Q1,RCB.02 ;IF NOTHING TO DEQUEUE, TRY FOR DATAGRAMS
RCB.01: BLCAL. (PPDDMB##,<P2>) ;DEQUEUE A MESSAGE BUFFER
JRST RCB.02 ;HMM, NO MESSAGE BUFFERS LEFT
PUSHJ P,SC.RBF ;RETURN THE BUFFER TO SCA
SOJG Q1,RCB.01 ;LOOP FOR ANY REMAINING
;GET BUFFERS BACK FROM THE DATAGRAM FREE QUEUE
RCB.02: MOVE Q1,.CBDGR(P1) ;GET THE NUMBER OF DATAGRAMS QUEUED
JUMPE Q1,RCB.05 ;JUMP IF NOTHING TO DEQUEUE
RCB.03: BLCAL. (PPDDDB##,<P2>) ;DEQUEUE A DATAGRAM BUFFER
JRST RCB.05 ;HMM, NO DATAGRAM BUFFERS LEFT
PUSHJ P,SC.RLD ;RETURN THE BUFFER TO SCA
SOJG Q1,RCB.03 ;LOOP FOR ANY REMAINING
JRST RCB.05 ;GO KILL THE BUFFER
;HERE WHEN DELETING AN ENTRY FROM THE DON'T CARE LISTEN QUEUE
RCB.04: PUSHJ P,SC.RDQ ;REMOVE IT FROM THE DON'T CARE QUEUE
CION ;OK TO INTERRUPT
;GIVE BACK THE CB AND WE'RE DONE
RCB.05: MOVX T1,CB.RAP ;GET THE REAP BIT
TDNN T1,.CBFLG(P1) ;WAS IT SET?
JRST RCB.06 ;NO
SOSGE SCAREP ;YES, COUNT DOWN REAP COUNT
SETZM SCAREP ;WENT TOO FAR, RESET TO ZERO
RCB.06: MOVE T1,P1 ;GET THE CB ADDRESS IN T1
PUSHJ P,SC.RBF ;RETURN THE BUFFER
SETZ P1, ;ERASE ALL KNOWLEDGE OF IT
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - MARK CONNECTION BLOCK REAPABLE
;ROUTINE TO MARK A CONNECTION BLOCK AS REAPABLE.
;CALL:
; P1/ CB ADDRESS
; PUSHJ P,SC.SRB
;RETURN:
; CPOPJ ALWAYS
$XSENT (SC.SRB::)
MOVX T1,CB.RAP ;GET THE REAP BIT
TDNE T1,.CBFLG(P1) ;ALREADY SET?
POPJ P, ;YES
IORM T1,.CBFLG(P1) ;NO, SET IT
AOS SCAREP ;BUMP THE REAP COUNT
POPJ P, ;RETURN
SUBTTL SCA BUFFER MANAGEMENT - ALLOCATE DEFERRED BUFFERS
;ROUTINE CALLED FROM THE CLOCK LEVEL CODE TO ALLOCATE DEFERRED
;BUFFERS IF ANY NEEDED BY CONNECTIONS WAITING FOR BUFFERS BEFORE
;SENDING A CONNECT_REQUEST OR ACCEPT_REQUEST MESSAGE.
;CALL:
; PUSHJ P,SC.DEF
;RETURN:
; CPOPJ ALWAYS
SC.DEF: SKIPE PBSTUK ;ANY NEED TO DO THIS?
SKIPE MDPAGS ;YES, MEMORY ALLOCATOR ALREADY CRANKED UP?
POPJ P, ;RETURN, DON'T NEED (OR WANT) TO
PUSHJ P,SAVP## ;SAVE PRESERVED REGISTERS
DEF.01: SKIPE P1,PBSTUK ;STUCK ON BUFFERS ANYWHERE?
JFFO P1,.+2 ;FIND FIRST PATH BLOCK INDEX WHICH IS STUCK
POPJ P, ;NO
SKIPN P5,PBLIST-1(P2) ;GET PATH BLOCK ADDRESS
XCT SCAFOO ;FOO
MOVE T1,BITTBL##(P2) ;GET THE BIT
ANDCAM T1,PBSTUK ;CLEAR IT
SETZ P3, ;CLEAR RECORD OF FIRST CB FOUND
DEF.02: PUSHJ P,SC.RWQ ;REMOVE NEXT ENTRY FROM WORK QUEUE
JRST DEF.04 ;END OF THE LIST
LOAD T1,CBCNST,(P1) ;GET CONNECTION STATE
CAIN T1,.CSCLO ;IS IT CLOSED?
JRST DEF.03 ;YES, NO NEED TO CREATE BUFFERS
PUSHJ P,SC.BF2 ;TRY TO CREATE SOME BUFFERS
JRST DEF.05 ;STILL SHORT ON MEMORY
MOVX T1,CB.SOB ;GET THE FLAG
ANDCAM T1,.CBFLG(P1) ;CLEAR IT
SKIPN P3 ;HAVE WE RECORDED FIRST MOVED BLOCK?
MOVE P3,P1 ;NO, DO SO NOW
PUSHJ P,SC.AWQ ;PUT IT ON THE END OF THE QUEUE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST DEF.02 ;GET NEXT CONNECTION FOR THIS PATH
DEF.03: SETZRO <CBIMB,CBIDB>,(P1) ;DON'T NEED BUFFERS NOW
MOVX T1,CB.SOB ;CLEAR THE FLAG
ANDCAM T1,.CBFLG(P1) ;...
PUSHJ P,SC.PTC ;FINISHED WITH THIS CB
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST DEF.02 ;GET NEXT CONNECTION FOR THIS PATH
DEF.04: PUSHJ P,SC.SNM ;SEE IF WE CAN SEND ANYTHING NOW
JRST DEF.01 ;SEE IF MORE TO DO
;HERE WHEN WE COULDN'T CREATE BUFFERS - DETERMINE HOW MUCH WE NEED
;FOR THIS CONNECTION AND GET THE MEMORY ALLOCATOR RUNNING.
DEF.05: SKIPN DINITF## ;DON'T TRY THIS TYPE OF ALLOCATION DURING ONCE
SKIPE MDPAGS ;ALREADY DONE THIS FOR SOME CB?
JRST DEF.08 ;YES, WE CAN'T HAVE TWO REQUESTS OUTSTANDING
LOAD T1,CBIMB,(P1) ;GET NUMBER OF MESSAGE BUFFERS
JUMPE T1,DEF.06 ;JUMP IF NONE
IDIVI T1,C%MGPG ;NUMBER PER PAGES
SKIPN T2 ;IF A REMAINDER, ROUND UP
SKIPN T1 ;OR IF LESS THAN A FULL PAGE,
AOS T1 ;ASK FOR AT LEAST ONE PAGE
HRLM T1,MDPAGS ;STORE COUNT OF PAGES REQUIRED
DEF.06: LOAD T1,CBIDB,(P1) ;GET NUMBER OF DATAGRAM BUFFERS
JUMPE T1,DEF.07 ;JUMP IF NONE
IDIVI T1,C%DGPG ;NUMBER PER PAGES
SKIPN T2 ;IF A REMAINDER, ROUND UP
SKIPN T1 ;OR IF LESS THAN A FULL PAGE,
AOS T1 ;ASK FOR AT LEAST ONE PAGE
HRRM T1,MDPAGS ;STORE COUNT OF PAGES REQUIRED
DEF.07: HLRZ T1,MDPAGS ;GET NUMBER OF MESSAGE PAGES
HRRZ T2,MDPAGS ;GET NUMBER OF DATAGRAM PAGES
ADD T1,T2 ;TOTAL NUMBER REQUIRED
HRLI T1,(MS.SCA) ;SECTION TO ALLOCATE FROM
XMOVEI T2,ALM.03 ;WHO TO CALL WHEN ALLOCATION COMPLETES
PUSHJ P,GETCLP## ;QUEUE A REQUEST
DEF.08: SKIPN P3 ;HAVE WE RECORDED FIRST MOVED BLOCK?
MOVE P3,P1 ;NO, DO SO NOW
PUSHJ P,SC.AWQ ;PUT IT ON THE END OF THE QUEUE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
MOVE T1,BITTBL##(P2) ;GET BIT FOR THIS PATH AGAIN
IORM T1,PBSTUK ;SHOW WE'RE STUCK ON BUFFERS (AGAIN)
POPJ P, ;TRY AGAIN NEXT TICK
SUBTTL SCA BUFFER MANAGEMENT - ALLOCATE MEMORY FOR BUFFERS
;ROUTINE CALLED FROM THE CLOCK LEVEL CODE TO ALLOCATE MEMORY IF
;MEMORY IS NEEDED.
;CALL:
; PUSHJ P,SC.ALM
;RETURN:
; CPOPJ ALWAYS
SC.ALM: SKIPE CIBUF ;TIME TO ALLOCATE MEMORY?
SKIPE MDPAGS ;YES, ALREADY REQUESTED IT?
POPJ P, ;RETURN, DON'T NEED (OR WANT) TO
;CHECK FOR MESSAGE BUFFER ALLOCATION
MOVE T1,MINMSG ;GET MINIMUM MESSAGE THRESHOLD
CAMGE T1,MFQCNT ;DO WE HAVE ENOUGH CURRENTLY?
JRST ALM.01 ;YES, CHECK DATAGRAM BUFFERS
SUB T1,MFQCNT ;WE NEED MORE, SEE HOW MANY
IDIVI T1,C%MGPG ;SEE HOW MANY PAGES ARE NEEDED
SKIPN T2 ;IF A REMAINDER, ROUND UP
SKIPN T1 ;OR IF LESS THAN A FULL PAGE,
AOS T1 ;ASK FOR AT LEAST ONE PAGE
HRLM T1,MDPAGS ;STORE COUNT OF PAGES REQUIRED
;CHECK FOR DATAGRAM BUFFER ALLOCATION
ALM.01: MOVE T1,MINDG ;GET MINIMUM DATAGRAM THRESHOLD
CAMGE T1,DFQCNT ;DO WE HAVE ENOUGH CURRENTLY?
JRST ALM.02 ;YES, SEE IF WE HAD ASKED FOR MESSAGE SPACE
SUB T1,DFQCNT ;WE NEED MORE, SEE HOW MANY
IDIVI T1,C%DGPG ;SEE HOW MANY PAGES ARE NEEDED
SKIPN T2 ;IF A REMAINDER, ROUND UP
SKIPN T1 ;OR IF LESS THAN A FULL PAGE,
AOS T1 ;ASK FOR AT LEAST ONE PAGE
HRRM T1,MDPAGS ;STORE COUNT OF PAGES REQUIRED
;NOW SEE IF ANY PAGES ARE REQUIRED, AND FIRE UP THE CLOCK LEVEL
;MEMORY ALLOCATION ROUTINE IF SO
ALM.02: HLRZ T1,MDPAGS ;GET NUMBER OF MESSAGE PAGES
HRRZ T2,MDPAGS ;GET NUMBER OF DATAGRAM PAGES
ADD T1,T2 ;TOTAL NUMBER REQUIRED
JUMPE T1,ALM.06 ;CHECK AGAIN LATER IF NOTHING REQUIRED
SKIPE DINITF## ;INITIALIZATION STILL GOING ON?
JRST ALM.IN ;YES
HRLI T1,(MS.SCA) ;SECTION TO ALLOCATE FROM
XMOVEI T2,ALM.03 ;WHO TO CALL WHEN ALLOCATION COMPLETES
PJRST GETCLP## ;QUEUE UP A REQUEST AND RETURN
;WE PREVIOUSLY ASKED FOR MEMORY ALLOCATION, AND IT HAS NOW COMPLETED
ALM.03: PUSHJ P,SAVE1## ;SAVE P1
MOVE P1,T1 ;ADDRESS OF WHERE PAGES WERE ALLOCATED
;BREAK UP PAGES OBTAINED INTO MESSAGE BUFFERS
HLRZ T2,MDPAGS ;GET NUMBER OF MESSAGE BUFFER PAGES REQUESTED
JUMPE T2,ALM.04 ;JUMP IF NO MESSAGE BUFFER PAGES WERE REQUESTED
MOVE T1,P1 ;GET VIRTUAL ADDRESS OF FIRST PAGE
PUSHJ P,SC.CPC ;CREATE A PAGE CHAIN
MOVE T1,P1 ;GET VIRTUAL ADDRESS OF FIRST PAGE
MOVX T2,C%MGSZ ;GET BUFFER SIZE
PUSHJ P,SC.BBF ;BREAK INTO BUFFERS
CIOFF ;PREVENT RACES
MOVEM T1,@BOTMFQ ;LINK THESE NEW BUFFERS ONTO THE FREE QUEUE
MOVEM T2,BOTMFQ ;...
ADDM T3,MFQCNT ;UPDATE THE FREE COUNT
ADDM T3,TOTMGB ; AND THE TOTAL NUMBER OF BUFFERS CREATED
CION ;OK TO INTERRUPT AGAIN
HLRZ T1,MDPAGS ;GET NUMBER OF MESSAGE BUFFER PAGES
LSH T1,P2WLSH ;CONVERT TO WORDS
ADD P1,T1 ;GET VIRTUAL ADDRESS OF DATAGRAM BUFFER PAGES
;BREAK UP PAGES OBTAINED INTO DATAGRAM BUFFERS
ALM.04: HRRZ T2,MDPAGS ;GET NUMBER OF DATAGRAM BUFFER PAGES REQUESTED
JUMPE T2,ALM.05 ;JUMP IF NO DATAGRAM BUFFER PAGES WERE REQUESTED
MOVE T1,P1 ;GET VIRTUAL ADDRESS OF FIRST PAGE
PUSHJ P,SC.CPC ;CREATE A PAGE CHAIN
MOVE T1,P1 ;GET VIRTUAL ADDRESS OF FIRST PAGE
MOVX T2,C%DGSZ ;GET BUFFER SIZE
PUSHJ P,SC.BBF ;BREAK INTO BUFFERS
CIOFF ;PREVENT RACES
MOVEM T1,@BOTDFQ ;LINK THESE NEW BUFFERS ONTO THE FREE QUEUE
MOVEM T2,BOTDFQ ;...
ADDM T3,DFQCNT ;UPDATE THE FREE COUNT
ADDM T3,TOTDGB ; AND THE TOTAL NUMBER OF BUFFERS CREATED
CION ;OK TO INTERRUPT AGAIN
ALM.05: SETZM MDPAGS ;WE'VE ALLOCATED OUR MEMORY, CLEAR THIS VARIABLE
ALM.06: SETZM CIBUF ;NO LONGER NEED TO ALLOCATE MEMORY
POPJ P, ;RETURN
ALM.IN: PUSHJ P,PGRSKD## ;ASK FOR THE NECESSARY PAGES
PUSHJ P,SCADIE ;CAN'T, DIE
JRST ALM.03 ;CONTINUE
SUBTTL SCA SUPPORT ROUTINES - CREATE A PAGE CHAIN
;ROUTINE TO CREATE A PAGE CHAIN FOR SC.BBF TO TAKE APART.
;CALL:
; T1/ VIRTUAL ADDRESS OF FIRST PAGE
; T2/ NUMBER OF PAGES IN CHAIN
; PUSHJ P,SC.CPC
;RETURN:
; CPOPJ ALWAYS
SC.CPC: SETZM (T1) ;CLEAR LINK TO NEXT PAGE
SOJLE T2,CPOPJ## ;RETURN WHEN DONE
XMOVEI T3,PAGSIZ(T1) ;GET ADDRESS OF NEXT PAGE
MOVEM T3,0(T1) ;LINK THAT PAGE TO THIS PAGE
MOVE T1,T3 ;GET NEXT PAGE ADDRESS
JRST SC.CPC ;LOOP
SUBTTL SCA SUPPORT ROUTINES - SET BLOCK STATE AND QUEUE MESSAGE
;ROUTINE TO SET NEW BLOCK STATE AND QUEUE A MESSAGE TO BE SENT.
;CALL:
; T1/ NEW STATE
; P1/ CB ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.SCA
;RETURN:
; CPOPJ ALWAYS
SC.SCA: LOAD T2,CBBKST,(P1) ;GET THE BLOCK STATE
JUMPE T2,SCA.01 ;JUMP IF ZERO
LOAD T3,PBDPN,(P5) ;GET DESTINATION NODE
BUG. (CHK,SCASBN,SCASER,SOFT,<Block state already non-zero>,<<T3,NODE>,<T2,OLDSTA>,<T1,NEWSTA>>,)
STOR T1,CBBKST,(P1) ;SET STATE AS REQUESTED
POPJ P, ; BUT DON'T TRY TO QUEUE IT AGAIN
SCA.01: STOR T1,CBBKST,(P1) ;SET STATE AS REQUESTED
PUSHJ P,SC.AWQ ;ADD THE CB TO THE WORK QUEUE
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - SEND NEXT SCS CONTROL MESSAGE
;ROUTINE TO SEND THE NEXT SCS CONTROL MESSAGE FOR THIS PATH BLOCK IF
;THE BUFFER IS AVAILABLE AND THERE'S A WAITING CONNECTION BLOCK. IF
;THE CB REQUIRES BUFFERS, CREATES THEM IF POSSIBLE, OTHERWISE MOVES
;THE CB TO THE END OF THE QUEUE AND TRIES THE NEXT ONE.
;CALL:
; P5/ PBK ADDRESS
; PUSHJ P,SC.SNM
;RETURN:
; CPOPJ ALWAYS
SC.SNM: SKIPN .PBTWQ(P5) ;IS THERE A CB THAT NEEDS SOMETHING?
POPJ P, ;NO, NOTHING TO DO
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
SETZ P2, ;PREPARE TO CLEAR THE BUFFER ADDRESS
EXCH P2,.PBOBB(P5) ;GET OUTBOUND BUFFER ADDRESS
JUMPE P2,CPOPJ## ;IF NOT AVAILABLE, RETURN
SETZ P3, ;INITIALIZE ADDRESS OF FIRST CB MOVED
;HERE WHEN BUFFER IS AVAILABLE, AND THERE'S SOMETHING TO BE DONE
;REMOVE FIRST ENTRY FROM WORK QUEUE
SNM.01: PUSHJ P,SC.RWQ ;GET AND LOCK NEXT ENTRY
JRST SNM.06 ;THERE ISN'T ONE
;BLOCK STATE SHOULDN'T BE ZERO - COMPLAIN IF IT IS
LOAD T1,CBBKST,(P1) ;GET THE BLOCK STATE
JUMPN T1,SNM.02 ;OK IF NOT ZERO
LOAD T1,PBDPN,(P5) ;GET NODE NUMBER
MOVE T2,.CBSCI(P1) ;GET CONNECT ID
LOAD T3,CBCNST,(P1) ;GET CONNECT STATE
BUG. (CHK,SCAEEE,SCASER,SOFT,<Block state is zero when trying to send connection management request>,,)
PUSHJ P,SC.PTC ;ALLOW REAPER TO GET THIS BLOCK
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST SNM.01 ;LOOK FOR ANOTHER ENTRY
;THIS PROBABLY ISN'T NECESSARY BUT DO IT ANYWAY.
;IF THE "REAP" BIT IS ON, WE SHOULDN'T BE SENDING ANY REQUESTS.
SNM.02: MOVX T1,CB.RAP ;ARE WE READY TO REAP THIS BLOCK?
TDNN T1,.CBFLG(P1) ;...
JRST SNM.03 ;NO
LOAD T1,PBDPN,(P5) ;GET THE NODE NUMBER
MOVE T2,.CBSCI(P1) ;GET THE CONNECT ID
BUG. (CHK,SCARBS,SCASER,SOFT,<Reap bit is set when block state is non-zero>,,)
PUSHJ P,SC.PTC ;FINISH OFF THIS BLOCK
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
JRST SNM.01 ;DO THE NEXT ENTRY
;IF THIS CONNECTION BLOCK IS ALREADY STUCK ON BUFFERS, MOVE IT TO THE
;END OF THE QUEUE.
SNM.03: MOVX T1,CB.SOB ;GET "STUCK ON BUFFERS" FLAG
TDNE T1,.CBFLG(P1) ;ARE WE STUCK ON BUFFERS?
JRST SNM.05 ;YES, MOVE IT TO THE END OF THE QUEUE
;GET ANY BUFFERS THAT WE WANT, IF POSSIBLE
PUSHJ P,SC.BF1 ;ALLOCATE BUFFERS IF WE NEED THEM
JRST SNM.05 ;COULDN'T GET THEM ALL
;WE'VE GOT THE BUFFERS WE WANTED, OR DIDN'T WANT ANY. CREATE
;THE MESSAGE AND SEND IT.
PUSHJ P,SC.RQS ;BUILD PACKET, SET NEW STATE, AND SEND IT
JRST SNM.04 ;COULDN'T SEND IT
PJRST SC.ULK ;SUCCESS, UNLOCK CONNECTION BLOCK AND RETURN
;SEND FAILED. VC MUST HAVE GONE AWAY, SO GIVE THE BUFFER TO THE PORT
SNM.04: PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
LOAD T1,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
SETZM (P2) ;CLEAR FLINK IN PACKET
BLCAL. (PPDQMB##,<T1,P2>) ;GIVE BUFFER TO PORT
POPJ P, ;RETURN
;HERE WHEN WE COULDN'T GET THE BUFFERS NEEDED OR CONNECTION BLOCK
;WAS ALREADY STUCK. MARK THE CB AS "STUCK ON BUFFERS" SO WE CAN
;FIX THINGS AT CLOCK LEVEL. MARK THE PATH BLOCK TOO.
SNM.05: MOVX T1,CB.SOB ;GET THE FLAG
IORM T1,.CBFLG(P1) ;MARK CB AS STUCK ON BUFFERS
SKIPN P3 ;IS THIS THE FIRST BLOCK MOVED TO END?
MOVE P3,P1 ;YES, RECORD IT
PUSHJ P,SC.AWQ ;ADD THIS CB TO THE WORK QUEUE
PUSHJ P,SC.ULK ;UNLOCK THE CONNECTION BLOCK
LOAD T1,PBPBI,(P5) ;GET PATH BLOCK INDEX
MOVE T1,BITTBL##(T1) ;GET THE BIT
IORM T1,PBSTUK ;MARK PATH BLOCK AS STUCK
JRST SNM.01 ;SEE IF ANYTHING ELSE TO DO
;HERE WHEN ALL THE CONNECTION BLOCKS THAT ARE LEFT REQUIRE BUFFERS
;OR THERE AREN'T ANY BLOCKS. WE HAVE TO KEEP THE BUFFER WE HAD
;PLANNED TO USE FOR THE MESSAGE AND REUSE IT LATER.
SNM.06: CIOFF ;PREVENT RACES
LOAD T1,PBVCST,(P5) ;GET VC STATE
CAIE T1,VC.OPN ;IS VC OPEN?
JRST SNM.07 ;NO
MOVEM P2,.PBOBB(P5) ;YES, RETURN BUFFER TO PATH BLOCK
CION ;OK TO INTERRUPT AGAIN
SKIPE PBSTUK ;IS A PATH BLOCK STUCK?
AOS CIBUF ;ASK SC.DEF TO RUN
POPJ P, ;RETURN
SNM.07: CION ;OK TO INTERRUPT AGAIN
LOAD T1,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
SETZM (P2) ;CLEAR FLINK IN PACKET
BLCAL. (PPDQMB##,<T1,P2>) ;GIVE THE PACKET BACK TO THE PORT
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - ADD AN ENTRY TO THE WORK QUEUE
;ROUTINE TO ADD AN ENTRY TO THE WORK QUEUE.
;CALL:
; P1/ CB ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.AWQ
;RETURN:
; CPOPJ ALWAYS
SC.AWQ: CIOFF ;PREVENT RACES
LOAD T1,PBVCST,(P5) ;GET VC STATE
CAIE T1,VC.OPN ;IS VC OPEN?
PJRST CIONPJ ;NO, DON'T TRY TO SEND
MOVE T1,.PBBWQ(P5) ;GET LAST ENTRY IN WORK QUEUE
XMOVEI T2,.PBTWQ(P5) ;GET HEAD OF QUEUE
CAMN T1,T2 ;EMPTY IF EQUAL
JRST [MOVEM P1,.PBTWQ(P5) ;MAKE THIS BE THE FIRST
JRST .+2] ;CONTINUE
MOVEM P1,.CBNWQ(T1) ;MAKE OLD LAST POINT TO THIS
MOVEM P1,.PBBWQ(P5) ;MAKE THIS BE THE LAST
PJRST CIONPJ ;INTERRUPTS ON AND RETURN
SUBTTL SCA SUPPORT ROUTINES - REMOVE ENTRY FROM WORK QUEUE
;ROUTINE TO REMOVE AN ENTRY FROM A PATH BLOCK WORK QUEUE.
;CALL:
; P3/ ADDRESS OF CONNECTION BLOCK TO STOP AT
; P5/ PATH BLOCK ADDRESS
; PUSHJ P,SC.RWQ
;RETURN:
; CPOPJ IF NO MORE ENTRIES
; CPOPJ1 WITH ENTRY AVAILABLE AND LOCKED WITH:
; P1/ ADDRESS OF CONNECTION BLOCK
; P3/ UPDATED IF NECESSARY
SC.RWQ: CIOFF ;PREVENT RACES
RWQ.01: SKIPN P1,.PBTWQ(P5) ;GET FIRST ENTRY ON QUEUE
JRST RWQ.04 ;QUEUE EMPTY
CAMN P1,P3 ;HAVE WE FOUND THIS BUFFER BEFORE?
JRST RWQ.04 ;YES, WE'RE FINISHED WITH THIS PATH BLOCK
SKIPE T1,.CBNWQ(P1) ;POINT TO THE SECOND ENTRY
JRST RWQ.02 ;THERE IS ANOTHER
XMOVEI T2,.PBTWQ(P5) ;THIS IS THE END, MAKE TAIL
MOVEM T2,.PBBWQ(P5) ; POINT TO HEAD
RWQ.02: MOVEM T1,.PBTWQ(P5) ;MAKE HEAD POINT TO NEXT OR ZERO
SETZM .CBNWQ(P1) ;INDICATE NO LONGER ON QUEUE
MOVX T1,CB.SNM ;SEE IF WE HAVE TO DEFER
PUSHJ P,SC.LAH ;GET THE LOCK IF POSSIBLE
JRST RWQ.03 ;WE HAVE TO DEFER
PJRST CINPJ1 ;INTERRUPTS BACK ON AND SKIP RETURN
;HERE WHEN THE CONNECTION BLOCK WAS LOCKED. MOVE IT TO THE END OF THE
;LIST AND CONTINUE LOOKING FOR A USABLE ENTRY.
RWQ.03: SKIPN P3 ;HAVE WE RECORDED FIRST MOVED BLOCK?
MOVE P3,P1 ;NO, THIS IS IT, THEN
PUSHJ P,SC.AWQ ;MOVE IT TO THE END OF THE QUEUE
JRST RWQ.01 ;TRY FOR THE NEXT ENTRY
;HERE WHEN WE'RE AT THE END OF THE LIST, OR IT'S EMPTY
RWQ.04: SETZ P1, ;BE SAFE
PJRST CIONPJ ;INTERRUPTS BACK ON AND RETURN
SUBTTL SCA SUPPORT ROUTINES - ALLOCATE A CONNECTION BLOCK
;ROUTINE TO ALLOCATE AND INITIALIZE A CONNECTION BLOCK.
;CALL:
; T1/ SYSAP BITS TO BE PLACED IN CI
; PUSHJ P,SC.ACB
;RETURN:
; CPOPJ IF ERROR WITH:
; T1/ ERROR CODE
; CPOPJ1 IF SUCCESS WITH:
; P1/ CONNECTION BLOCK ADDRESS
SC.ACB: STKVAR <SYBITS,IDX,UBTS,CID> ;ALLOCATE SOME STACK STORAGE
MOVEM T1,SYBITS ;SAVE SYSAP CID BITS
;CREATE AND STORE THE CONNECTION-ID
PUSHJ P,SC.FNI ;GET THE NEXT AVAILABLE INDEX
RETBAD (.SCFNE) ;NO MORE, RETURN ERROR
SETZ T4, ;START WITH ZERO
STOR T1,INDEX,T4 ;STORE INDEX
MOVEM T1,IDX ;SAVE THE INDEX
PUSHJ P,SC.FUB ;GET THE UNIQUENESS BITS TO USE FOR CID
STOR T2,UBITS,T4 ;STORE THE UNIQUE BITS
MOVEM T2,UBTS ;SAVE THEM
MOVE T2,SYBITS ;GET SYSAP BITS BACK AGAIN
STOR T2,SID,T4 ;STORE THESE BITS IN THE CID
MOVEM T4,CID ;SAVE THE NEWLY CREATED CONNECT ID
MOVEI T1,1 ;WE ONLY WANT ONE BUFFER
PUSHJ P,SC.ABF ;ALLOCATE IT
RETBAD () ;PASS ERROR ALONG TO CALLER
MOVE P1,T1 ;COPY CONNECTION BLOCK ADDRESS TO STANDARD AC
MOVE T4,CID ;GET THE CREATED CID BACK
MOVEM T4,.CBSCI(P1) ;STORE THE CONNECT ID IN THE CONNECTION BLOCK
MOVE T1,IDX ;GET THE INDEX BACK AGAIN
ADD T1,CIDTAB ;ADD THE BASE ADDRESS OF THE CB ADDRESS TABLE
MOVEM P1,(T1) ;STORE CB ADDRESS IN THE TABLE
MOVE T1,IDX ;GET THE INDEX AGAIN
ADD T1,UBTTAB ;ADD THE BASE ADDRESS OF THE UNIQUESS BITS TABLE
MOVE T2,UBTS ;GET THE BITS
MOVEM T2,(T1) ;STORE THE UNIQUENESS BITS
;INIT JSYS QUEUE POINTERS
SETZM .CBTMQ(P1) ;ZERO FLINK FOR MESSAGE QUEUE
XMOVEI T2,.CBTMQ(P1) ;GET ADDRESS OF HEAD
MOVEM T2,.CBBMQ(P1) ;INIT BLINK TO POINT AT HEAD
SETZM .CBTDQ(P1) ;ZERO FLINK FOR DATAGRAM QUEUE
XMOVEI T2,.CBTDQ(P1) ;GET ADDRESS OF HEAD
MOVEM T2,.CBBDQ(P1) ;INIT BLINK TO POINT AT HEAD
SETZM .CBTXQ(P1) ;ZERO FLINK FOR DATA REQUEST QUEUE
XMOVEI T2,.CBTXQ(P1) ;GET ADDRESS OF HEAD
MOVEM T2,.CBBXQ(P1) ;INIT BLINK TO POINT AT HEAD
SETZM .CBTEQ(P1) ;ZERO FLINK FOR EVENT QUEUE
XMOVEI T2,.CBTEQ(P1) ;GET ADDRESS OF HEAD
MOVEM T2,.CBBEQ(P1) ;INIT BLINK TO POINT AT HEAD
SETZM .CBTBQ(P1) ;ZERO FLINK FOR BUFFER QUEUE
XMOVEI T2,.CBTBQ(P1) ;GET ADDRESS OF HEAD
MOVEM T2,.CBBBQ(P1) ;INIT BLINK TO POINT TO HEAD
MOVEI T2,.CSCLO ;INITIAL STATE IS "CLOSED"
STOR T2,CBCNST,(P1) ;SET THAT IN CONNECTION BLOCK
JRST CPOPJ1## ;SKIP RETURN
ENDSV. ;END OF STACK VARIABLE RANGE
SUBTTL SCA SUPPORT ROUTINES - FIND NEXT INDEX
;ROUTINE TO FIND THE NEXT INDEX INTO THE CID TABLES.
;CALL:
; PUSHJ P,SC.FNI
;RETURN:
; CPOPJ IF NO FREE SLOTS
; CPOPJ1 IF SUCCESS WITH:
; T1/ NEXT AVAILABLE INDEX
SC.FNI: MOVEI T3,C%CIDL ;INIT COUNT OF ENTRIES SEARCHED
FNI.01: SOSL T1,NXTIDX ;TRY FOR THE NEXT INDEX
JRST FNI.02 ;MORE TO GO
MOVEI T1,C%CIDL-1 ;FAILED, TIME TO RECYCLE
MOVEM T1,NXTIDX ;INIT NXTIDX TO HIGHEST CIDTAB ENTRY
AOS CIDRFL ;INDICATE CIDTAB RECYCLING
FNI.02: MOVE T2,T1 ;GET A COPY WE CAN PLAY WITH
ADD T2,CIDTAB ;ADD IN THE OFFSET TO THE CID ADDRESS TABLE
SKIPN (T2) ;IS THERE AN ENTRY THERE?
JRST CPOPJ1## ;NO, SKIP RETURN
SOJN T3,FNI.01 ;IF WE HAVEN'T CHECKED ENTIRE CIDTAB, LOOP
POPJ P, ;TABLE IS FULL, NON-SKIP RETURN
SUBTTL SCA SUPPORT ROUTINES - FIND UNIQUENESS BITS
;ROUTINE TO FIND THE NEXT UNIQUENESS BITS FOR A CID.
;CALL:
; T1/ INDEX INTO CIDTAB OF CID BEING FORMED
; PUSHJ P,SC.FUB
;RETURN:
; CPOPJ ALWAYS WITH:
; T2/ NEXT UNIQUENESS BITS TO USE FOR CID
SC.FUB: SOSLE T2,UNQBTS ;TRY FOR THE NEXT IDENTIFIER
JRST FUB.01 ;MORE TO GO
SETONE UBITS,T2 ;TIME TO RECYCLE, SET ALL BITS IN THE FIELD
LSH T2,-<C%RMBU> ;RIGHT JUSTIFY SAID BITS
MOVEM T2,UNQBTS ;STORE AS THE UNIQUENESS BITS
AOS UNQRFL ;INDICATE RECYCLING
FUB.01: SKIPN UNQRFL ;ARE WE IN RECYCLE MODE FOR THE BITS?
POPJ P, ;NO, RETURN SUCCESS
ADD T1,UBTTAB ;OBTAIN ADDRESS OF OLD ENTRY
CAME T2,(T1) ;ARE THE OLD AND NEW UNIQUENESS BITS EQUAL?
POPJ P, ;NO, SO USE THEM
SOSLE T2 ;YES, MAKE NEW BITS DIFFERENT, STILL VALID?
POPJ P, ;YES, USE THEM
SETONE UBITS,T2 ;SET ALL BITS IN THE FIELD
LSH T2,-<C%RMBU> ;RIGHT JUSTIFY SAID BITS
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - LINK A CONNECTION BLOCK
;ROUTINE TO LINK A NEW CONNECTION BLOCK TO THE LIST OF CONNECTION
;BLOCKS HANGING OFF A PATH BLOCK.
;CALL:
; P1/ CONNECTION BLOCK ADDRESS
; P5/ PATH BLOCK ADDRESS
; PUSHJ P,SC.LCB
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
SC.LCB: CIOFF ;PREVENT RACES
JUMPL P5,LCB.DC ;SPECIAL CASE FOR "DON'T CARE" LISTENERS
LOAD T1,PBVCST,(P5) ;GET STATUS OF THE CONNECTION
CAIE T1,VC.OPN ;IS IT OPEN?
RETBAD (KLPX9,<CION>) ;NO, DON'T TRY TO LINK
SKIPN .CBANB(P1) ;IS THERE A CURRENT FORWARD LINK?
SKIPE .CBAPB(P1) ;OR A CURRENT BACKWARD LINK?
SKIPA ;YES
JRST LCB.01 ;NO
LOAD T1,PBDPN,(P5) ;GET THE DESTINATION NODE NUMBER
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
BUG. (CHK,SCASSS,SCASER,SOFT,<Connect block already linked>,<<T1,NODE>,<T2,CID>>,)
PUSHJ P,SC.RQS ;DEQUEUE CONNECTION BLOCK FROM CURRENT QUEUE
LCB.01: MOVE T2,.PBLCB(P5) ;GET THE POINTER TO CURRENT LAST
XMOVEI T3,.PBFCB(P5) ;GET THE ADDRESS OF THE FLINK
CAME T2,T3 ;IS THERE ANYTHING ON THE LIST?
MOVEM T2,.CBAPB(P1) ;YES, LINK THIS BLOCK TO THAT
MOVEM P1,@.PBLCB(P5) ;LINK THE NEW BLOCK
MOVEM P1,.PBLCB(P5) ;...
PJRST CINPJ1 ;INTERRUPTS BACK ON AND SKIP RETURN
;HERE TO LINK "DON'T CARE" LISTENERS TOGETHER
LCB.DC: MOVE T1,BOTDC ;GET THE LAST BUFFER ON THE QUEUE
MOVEM P1,@BOTDC ;LINK THIS TO THE END OF THE QUEUE
XMOVEI T3,TOPDC ;GET THE ADDRESS OF THE TOP POINTER
CAMN T1,T3 ;IS PREVIOUS CB THE TOP POINTER?
SETZ T1, ;YES, MAKE IT ZERO INSTEAD
MOVEM T1,.CBAPB(P1) ;MAKE THIS CB POINT TO THE PREVIOUS ONE
MOVEM P1,BOTDC ;NOW SHOW IT AS THE END OF THE QUEUE
PJRST CINPJ1 ;INTERRUPTS BACK ON AND SKIP RETURN
SUBTTL SCA SUPPORT ROUTINES - DEQUEUE A CONNECTION BLOCK
;ROUTINE TO DEQUEUE A CONNECTION BLOCK FROM ITS CURRENT QUEUE
;CALL:
; P1/ CB ADDRESS
; PUSHJ P,SC.RSQ
;RETURN:
; CPOPJ ALWAYS
;
;CALLER MUST CIOFF BEFORE SC.RSQ
SC.RSQ: MOVE T1,.CBANB(P1) ;GET FORWARD POINTER
MOVE T2,.CBAPB(P1) ;GET BACKWARD POINTER
MOVE T3,.CBPBK(P1) ;GET THE PATH BLOCK ADDRESS
SKIPN T1 ;IS THERE A NEXT?
SKIPE T2 ;OR A PREVIOUS?
JRST RSQ.01 ;YES, NOT LAST ENTRY
XMOVEI T4,.PBFCB(T3) ;GET POINTER TO HEAD OF CB QUEUE
MOVEM T4,.PBLCB(T3) ;SET BLINK TO POINT AT HEAD
SETZM .PBFCB(T3) ;CLEAR FLINK
POPJ P, ;RETURN
RSQ.01: SKIPE T1 ;IS THERE A NEXT LINK?
MOVEM T2,.CBAPB(T1) ;YES, UPDATE POINTER TO PREVIOUS OF NEXT
SKIPE T2 ;IS THERE A PREVIOUS LINK?
MOVEM T1,.CBANB(T2) ;YES, UPDATE POINTER TO NEXT OF PREVIOUS
SKIPN T1 ;IS THERE A NEXT?
MOVEM T2,.PBLCB(T3) ;NO, DELETED LAST, UPDATE QUEUE BLINK
SKIPN T2 ;IS THERE A PREVIOUS?
MOVEM T1,.PBFCB(T3) ;NO, DELETED FIRST, UPDATE QUEUE FLINK
POPJ P, ;RETURN
;ROUTINE TO DEQUEUE A CONNECTION BLOCK FROM THE "DON'T CARE" QUEUE.
;CALL:
; P1/ CB ADDRESS
; PUSHJ P,SC.RDQ
;RETURN:
; CPOPJ ALWAYS
SC.RDQ: MOVE T1,.CBANB(P1) ;GET THE ADDRESS OF THE NEXT CB
MOVE T2,.CBAPB(P1) ;GET THE ADDRESS OF THE PREVIOUS CB
SKIPN T1 ;IS THERE A NEXT ENTRY?
SKIPE T2 ;OR A PREVIOUS ENTRY?
JRST RDQ.01 ;YES, NOT THE LAST ENTRY
XMOVEI T1,TOPDC ;NO, THIS IS THE LAST CB ON THE QUEUE
MOVEM T1,BOTDC ;INIT TAIL AS POINTER TO HEAD
SETZM TOPDC ;INIT HEAD AS ZERO
POPJ P, ;RETURN
RDQ.01: SKIPE T1 ;IS THERE A NEXT ENTRY?
MOVEM T2,.CBAPB(T1) ;YES, UPDATE PREVIOUS OF NEXT CB
SKIPE T2 ;IS THERE A PREVIOUS ENTRY?
MOVEM T1,.CBANB(T2) ;YES, UPDATE NEXT OF PREVIOUS CB
SKIPN T1 ;WAS THERE A NEXT ENTRY?
MOVEM T2,BOTDC ;NO, UPDATE THE QUEUE BLINK
SKIPN T2 ;WAS THERE A PREVIOUS ENTRY?
MOVEM T1,TOPDC ;NO, UPDATE THE QUEUE FLINK
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - SEARCH FOR CONNECTION MATCH
;ROUTINE TO SEARCH THE CONNECTION BLOCKS FOR A MATCH BETWEEN
;A LOCAL LISTEN AND A DESTINATION CONNECT REQUEST.
;CALL:
; P2/ ADDRESS OF MESSAGE
; P5/ PBK ADDRESS
; PUSHJ P,SC.SCM
;RETURN:
; CPOPJ IF NO MATCH
; CPOPJ1 IF MATCH WITH:
; P1/ CB ADDRESS
SC.SCM: PUSHJ P,SAVQ## ;SAVE Q1-Q3
SETZ Q1, ;START WITH FIRST PATH BLOCK
SCM.01: SKIPN Q2,PBLIST(Q1) ;IS THERE A PATH BLOCK HERE?
JRST SCM.04 ;NO, TRY FOR NEXT ONE
IFN FTMP,<
MOVE T1,.PBCPU(Q2) ;GET CPU NUMBER
CAME T1,.CPCPN## ;ON OUR CPU?
JRST SCM.04 ;NO, SKIP THIS ONE
>; END IFN FTMP
SKIPA P1,.PBFCB(Q2) ;GET THE POINTER TO THE FIRST CB AND SKIP
SCM.02: MOVE P1,.CBANB(P1) ;GET POINTER TO NEXT CB
JUMPE P1,SCM.04 ;JUMP IF AT THE END
LOAD T1,CBCNST,(P1) ;GET THE CONNECTION STATE
CAIE T1,.CSLIS ;IS THE STATE LISTEN?
JRST SCM.02 ;NO, TRY NEXT CB
SKIPGE .CBPBK(P1) ;IS THIS A DON'T CARE LISTENER?
; JRST SCM.03 ;YES, DON'T CHECK NODE NUMBER
BUG. (HLT,SCADLL,SCASER,SOFT,<Dont care listener linked to CB>,,)
CAME Q2,.CBPBK(P1) ;IS THIS THE ASSOCIATED PATH BLOCK?
JRST SCM.02 ;NO, TRY NEXT CB
SCM.03: SKIPN .MGDPN(P2) ;IS THERE A REQUESTED PROCESS NAME?
SKIPE .CBDPN(P1) ;AND DO WE CARE WHO WE TALK TO?
SKIPA ;WE CARE, DO REGULAR NAME CHECKING
JRST CPOPJ1## ;WE DON'T CARE, THEREFORE WE HAVE A MATCH
XMOVEI T1,.CBSPN(P1) ;POINT TO OUR NAME FOR ME
XMOVEI T2,.MGDPN(P2) ;POINT TO THE REMOTE'S NAME FOR ME
PUSHJ P,SC.C4S ;DO THE STRINGS MATCH?
JRST SCM.02 ;NO
XMOVEI T1,.CBDPN(P1) ;POINT TO CB'S DESTINATION PROCESS NAME
XMOVEI T2,.MGSPN(P2) ;AND SOURCE PROCESS NAME FROM CONNECT REQUEST
PUSHJ P,SC.C4S ;DO THE STRINGS MATCH?
JRST SCM.02 ;NO
JRST CPOPJ1## ;WE HAVE A MATCH
SCM.04: CAIGE Q1,C%PBLL-1 ;PAST THE END?
AOJA Q1,SCM.01 ;NO, TRY NEXT
;NO MATCH ON PB LISTS, TRY THE "DON'T CARE" QUEUE
SKIPA P1,TOPDC ;GET ADDRESS OF FIRST CB ON DON'T CARE QUEUE
SCM.05: MOVE P1,.CBANB(P1) ;GET NEXT CB ON THE QUEUE
JUMPE P1,CPOPJ## ;NONE, YOU LOSE
LOAD T1,CBCNST,(P1) ;GET THE CONNECTION STATE
CAIE T1,.CSLIS ;IS THE STATE LISTEN?
JRST SCM.05 ;NO, TRY NEXT CB
SKIPN .MGDPN(P2) ;IS THERE A REQUESTED PROCESS NAME?
SKIPE .CBDPN(P1) ;AND DO WE CARE WHO WE TALK TO?
SKIPA ;WE CARE, DO REGULAR NAME CHECKING
JRST SCM.06 ;WE DON'T CARE, THEREFORE WE HAVE A MATCH
XMOVEI T1,.CBSPN(P1) ;POINT TO OUR NAME FOR ME
XMOVEI T2,.MGDPN(P2) ;POINT TO THE REMOTE'S NAME FOR ME
PUSHJ P,SC.C4S ;DO THE STRINGS MATCH?
JRST SCM.05 ;NO
SKIPN .CBDPN(P1) ;DO WE CARE WHO WE TALK TO?
JRST SCM.06 ;NO, THEN WE HAVE A MATCH
XMOVEI T1,.CBDPN(P1) ;POINT TO CB'S DESTINATION PROCESS NAME
XMOVEI T2,.MGSPN(P2) ;AND SOURCE PROCESS NAME FROM CONNECT REQUEST
PUSHJ P,SC.C4S ;DO THE STRINGS MATCH?
JRST SCM.05 ;NO
;WE FOUND A MATCH, DELINK US FROM THE DON'T CARE QUEUE AND PUT US ON THE
;CB LIST FOR THE PB WE HAVE FOUND A HOME WITH.
SCM.06: MOVEM P5,.CBPBK(P1) ;MAKE SURE WE KNOW WHICH PATH BLOCK
PUSHJ P,SC.RDQ ;REMOVE CB FROM DON'T CARE QUEUE
SETZM .CBANB(P1) ;ZERO LINKS OF CB WE JUST DEQUEUED
SETZM .CBAPB(P1) ;...
PUSHJ P,SC.LCB ;LINK THIS CB ON PB QUEUE
BUG. (HLT,SCACLB,SCASER,SOFT,<Incoming connection request on closed VC>,,)
JRST CPOPJ1## ;SKIP RETURN
SUBTTL SCA SUPPORT ROUTINES - COMPARE FOUR-WORD STRINGS
;ROUTINE TO COMPARE TWO FOUR-WORD STRINGS. THE STRINGS ARE ALWAYS
;PADDED OUT TO THEIR FULL FOUR-WORD SIZE, SO THIS ROUTINE CAN USE
;FULL WORD COMPARES VERSUS ILDBS.
;CALL:
; T1/ ADDRESS OF ONE STRING
; T2/ ADDRESS OF ANOTHER STRING
; PUSHJ P,SC.C4S
;RETURN:
; CPOPJ IF STRINGS DON'T MATCH
; CPOPJ1 IF STRINGS DO MATCH
SC.C4S: MOVE T3,0(T1) ;GET THE FIRST WORD
CAME T3,0(T2) ;DO THEY MATCH?
POPJ P, ;NO, RETURN
MOVE T3,1(T1) ;GET THE SECOND WORD
CAME T3,1(T2) ;DO THEY MATCH?
POPJ P, ;NO, RETURN
MOVE T3,2(T1) ;GET THE THIRD WORD
CAME T3,2(T2) ;DO THEY MATCH?
POPJ P, ;NO, RETURN
MOVE T3,3(T1) ;GET THE FOURTH WORD
CAMN T3,3(T2) ;DO THEY MATCH?
AOS (P) ;YES, SET FOR SKIP RETURN
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - CID SANITY CHECK
;ROUTINE TO CHECK THE VALIDITY OF A CONNECT ID.
;CALL:
; T1/ CONNECT ID TO CHECK
; PUSHJ P,SC.CSC
;RETURN:
; CPOPJ IF NO MATCH FOR CONNECTION ID
; CPOPJ1 IF MATCH WITH:
; T1/ CONNECT ID
; P1/ CONNECTION BLOCK ADDRESS
; P5/ PATH BLOCK ADDRESS
$CSUB ;ENTRY POINT
SC.CSC::TDZA P1,P1 ;FLAG = 0 MEANS WE DON'T WANT TO LOCK CB
SC.CAL: SETO P1, ;FLAG = -1 MEANS WE WANT TO LOCK CB
CIOFF ;PREVENT RACES
LOAD T2,INDEX,T1 ;GET THE INDEX FROM THE CID
MOVE T3,T2 ;SAVE A COPY
CAIL T2,C%CIDL ;IS IT WITHIN RANGE?
JRST CSC.E1 ;NO
ADD T2,CIDTAB ;ADD THE OFFSET TO THE CID TABLE
SKIPN T2,(T2) ;GET THE ENTRY
JRST CSC.E1 ;NONE
LOAD T4,UBITS,T1 ;GET UNIQUENESS BITS
MOVE T2,T3 ;GET A COPY OF THE INDEX
ADD T2,UBTTAB ;ADD THE OFFSET TO THE UNIQUENESS TABLE
MOVE T2,(T2) ;GET THE BITS
CAME T2,T4 ;DO WE HAVE A MATCH?
JRST CSC.E1 ;NO
ADD T3,CIDTAB ;YES, T3 = CID TABLE BASE ADDRESS + INDEX
MOVE T3,(T3) ;GET THE CONNECTION BLOCK ADDRESS
EXCH T3,P1 ;PUT IT IN P1 AND RETRIEVE ENTRY FLAG
SKIPE T3 ;WANT TO LOCK?
PUSHJ P,SC.LOK ;YES, LOCK THE CONNECTION BLOCK
MOVE P5,.CBPBK(P1) ;GET THE PATH BLOCK ADDRESS
JRST CINPJ1 ;INTERRUPTS BACK ON AND SKIP RETURN
CSC.E1: RETBAD (.SCIID,<CION>) ;RETURN AN ERROR
$XHIGH
SUBTTL CONNECTION MANAGEMENT UTILITY ROUTINES - SEND CREDIT_REQUEST
;ROUTINE TO SEND A CREDIT_REQUEST MESSAGE IF NECESSARY.
;CALL:
; P1/ CONNECTION BLOCK ADDRESS
; P5/ PATH BLOCK ADDRESS
; PUSHJ P,SC.CD?
;RETURN:
; CPOPJ IF DIDN'T SEND A MESSAGE
; CPOPJ1 IF SENT A MESSAGE
;
;FOUR ENTRY POINTS:
; SC.CDT - WHEN SYSAP QUEUES BUFFER FOR MESSAGE RECEPTION
; SC.CD1 - WHEN CREDIT_RESPONSE ARRIVES
; SC.CD5 - WHEN SYSAP TAKES A BUFFER BACK
; SC.CD7 - IDLE CHATTER
;
;IF THIS ROUTINE TAKES THE SKIP RETURN THE CALLER MUST CALL SC.SNM AFTER
;UNLOCKING THE CONNECTION BLOCK.
SC.CDT: SKIPG T1,.CBPRC(P1) ;GIVE UP IF PENDING RECEIVE CREDIT
POPJ P, ; IS NOT POSITIVE
JRST SC.CD3 ;GO CHECK ON RECEIVE CREDIT
;HERE WHEN CREDIT_RESPONSE ARRIVES. WE MAY HAVE WANTED TO SEND ANOTHER
;ONE EARLIER, BUT ONLY ONE CAN BE OUTSTANDING AT A TIME. SEND IT IF
;PENDING RECEIVE CREDIT IS NEGATIVE, OR IF PENDING RECEIVE CREDIT IS
;POSITIVE AND RECEIVE CREDIT IS .LT. MINIMUM RECEIVE CREDIT.
SC.CD1: SKIPGE T1,.CBPRC(P1) ;SEND IF PENDING RECEIVE CREDIT IS NEGATIVE
JRST CDT.01 ;...
JUMPE T1,CPOPJ## ;DON'T SEND IF THERE'S NO CHANGE
;SEND IF RECEIVE CREDIT .LT. MINIMUM RECEIVE CREDIT OR IF PENDING
;RECEIVE CREDIT IS GETTING LARGE.
SC.CD3: LOAD T2,CBMNRC,(P1) ;SEND IF RECEIVE CREDIT IS BELOW
CAMLE T2,.CBRCD(P1) ; THE MINIMUM
JRST CDT.01 ;...
CAIGE T1,C%MBCR ;SEND IF PENDING IS GETTING LARGE
POPJ P, ;DON'T SEND
JRST CDT.01 ;SEND
;HERE WHEN SYSAP TAKES A BUFFER BACK. SEND ONLY IF PENDING RECEIVE
;CREDIT IS NEGATIVE.
SC.CD5: SKIPL .CBPRC(P1) ;SEND IF PENDING RECEIVE CREDIT IS NEGATIVE
POPJ P, ;DON'T SEND
JRST CDT.01 ;SEND
;HERE FOR IDLE CHATTER (ALWAYS SEND)
SC.CD7: JRST CDT.01 ;SEND
;HERE BECAUSE CREDIT VALUES SUGGEST SENDING A CREDIT_REQUEST. SEE IF
;THE STATE OF THE CONNECTION WILL ALLOW IT.
CDT.01: LOAD T1,CBCNST,(P1) ;GET THE STATE
CAIE T1,.CSOPN ;CONNECTION OPEN?
POPJ P, ;NO, DON'T SEND A CREDIT REQUEST NOW
SETO T1, ;INDICATE CREDIT REQUEST IS PENDING
EXCH T1,.CBPND(P1) ;GET THE OLD VALUE
JUMPL T1,CPOPJ## ;RETURN IF ONE ALREADY PENDING
LOAD T1,CBBKST,(P1) ;GET THE BLOCK STATE
JUMPE T1,CDT.02 ;GO IF BLOCK STATE IS ZERO
LOAD T1,PBDPN,(P5) ;GET NODE NUMBER
MOVE T2,.CBSCI(P1) ;GET CONNECT ID
LOAD T3,CBBKST,(P1) ;GET BLOCK STATE
BUG. (CHK,SCACSC,SCASER,SOFT,<Can't send credit request>,<<T1,NODE>,<T2,CID>,<T3,STATE>>,)
SETZM .CBPND(P1) ;WE'RE NOT DOING A CREDIT REQUEST AFTER ALL
POPJ P, ;RETURN
CDT.02: MOVEI T1,.BSCRP ;SET BLOCK STATE TO CREDIT PENDING
PUSHJ P,SC.SCA ;SET BLOCK STATE AND QUEUE MESSAGE
JRST CPOPJ1## ;SKIP RETURN
SUBTTL SCA SUPPORT ROUTINES - RECLAIM BUFFERS
;ROUTINE TO RECLAIM BUFFERS ACCORDING TO RETURN_CREDIT FIELD OF
;CONNECT BLOCK.
;CALL:
; P1/ CB ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.GCB
;RETURN:
; CPOPJ ALWAYS
SC.GCB: SAVEAC <P3> ;SAVE AN AC
SETZ P3, ;GET A ZERO
EXCH P3,.CBRTC(P1) ;GET OLD VALUE AND ZERO IT
JUMPE P3,CPOPJ## ;NOTHING TO DO IF ALREADY ZERO
GCB.01: LOAD T1,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDDMB##,<T1>) ;DEQUEUE A MESSAGE BUFFER
JRST GCB.E1 ;ERROR
PUSHJ P,SC.RBF ;RETURN THE BUFFER TO SCA
SOJG P3,GCB.01 ;LOOP FOR ANY MORE
POPJ P, ;RETURN
GCB.E1: LOAD T1,PBDPN,(P5) ;GET THE NODE NUMBER
MOVE T2,.CBSCI(P1) ;GET THE SOURCE CONNECT ID
BUG. (CHK,SCACRB,SCASER,SOFT,<Can't reclaim buffers>,<<T1,NODE>,<T2,CID>>,)
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - CLOSE A VIRTUAL CIRCUIT
;ROUTINE TO CLOSE A VIRTUAL CIRCUIT.
;CALL:
; P5/ PBK ADDRESS
; PUSHJ P,SC.CVC
;RETURN:
; CPOPJ ALWAYS
SC.CVC: LOAD T1,PBDPN,(P5) ;GET THE NODE NUMBER
BUG. (INF,SCACVC,SCASER,SOFT,<Virtual circuit closure requested>,<<T1,NODE>>,)
LOAD T1,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDCVC##,<T1>) ;CALL THE PORT DRIVER
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - MOVE STRINGS AND DATA TO CB
;ROUTINE TO MOVE THE SOURCE PROCESS NAME, THE DESTINATION PROCESS NAME,
;AND THE CONNECTION DATA FROM THE SYSAP'S ARGUMENTS INTO THE CONNECT
;BLOCK. THE ADDRESSES PROVIDED FOR DESTINATION NAME AND CONNECTION
;DATA MAY BE ZERO, BUT THE SOURCE NAME MAY NEVER BE ZERO.
;CALL:
; T1/ ADDRESS OF SOURCE PROCESS NAME
; T2/ ADDRESS OF DESTINATION PROCESS NAME (OR ZERO)
; T3/ ADDRESS OF CONNECTION DATA (OR ZERO)
; P1/ CB ADDRESS
; PUSHJ P,SC.SDM
;RETURN:
; CPOPJ ALWAYS
SC.SDM: STKVAR <DPN,DATA> ;ALLOCATE SOME STACK STORAGE
MOVEM T2,DPN ;SAVE THE ADDRESS OF THE DESTINATION NAME
MOVEM T3,DATA ; AND THE ADDRESS OF THE CONNECTION DATA
;MOVE THE SOURCE PROCESS NAME
MOVE T2,T1 ;ADDRESS OF SOURCE PROCESS NAME
MOVX T1,C%PNLW ;LENGTH OF PROCESS NAME IN WORDS
XMOVEI T3,.CBSPN(P1) ;DESTINATION ADDRESS IN CB
EXTEND T1,[XBLT] ;MOVE THE SOURCE PROCESS NAME
;MOVE THE DESTINATION PROCESS NAME
SKIPN T2,DPN ;IS THERE ONE TO MOVE?
JRST SDM.01 ;NO, CHECK FOR CONNECTION DATA
MOVX T1,C%PNLW ;LENGTH OF PROCESS NAME IN WORDS
XMOVEI T3,.CBDPN(P1) ;DESTINATION ADDRESS IN CB
EXTEND T1,[XBLT] ;MOVE THE SOURCE PROCESS NAME
;MOVE THE CONNECTION DATA
SDM.01: SKIPN T2,DATA ;IS THERE ANY DATA TO MOVE?
POPJ P, ;NO, RETURN
MOVX T1,C%CDLW ;LENGTH OF CONNECTION DATA IN WORDS
XMOVEI T3,.CBDTA(P1) ;DESTINATION ADDRESS IN CB
EXTEND T1,[XBLT] ;MOVE THE CONNECTION DATA
POPJ P, ;RETURN
ENDSV. ;END OF STACK VARIABLE RANGE
SUBTTL SCA SUPPORT ROUTINES - HANDLE CALL FROM SYSAP
;ROUTINE TO HANDLE A CALL FROM THE SYSAP FOR CONNECTION MANAGEMENT
;FUNCTIONS.
;CALL:
; T1/ EVENT CODE
; P1/ CB ADDRESS
; PUSHJ P,SC.OUT
;RETURN:
; CPOPJ ON ERROR WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS WITH:
; T1/ NEW BLOCK STATE (ZERO IF NO CHANGE)
; T2/ NEW CONNECTION STATE (ZERO IF NO CHANGE)
SC.OUT: MOVE T4,T1 ;SAVE THE EVENT
IMULI T4,MXCNST ;COMPUTE TABLE INDEX
LOAD T2,CBCNST,(P1) ;GET THE CONNECT STATE
ADDI T4,-1(T2) ;STATES START AT 1
MOVE T2,TABLEX(T4) ;GET THE FLAGS
TXNE T2,X.ERR ;IS EVENT LEGAL FOR CURRENT STATE?
RETBAD (.SCSWS) ;NO, RETURN "WRONG STATE" ERROR
LOAD T1,X.BSTAT,(T4) ;GET NEW BLOCK STATE
LOAD T2,X.CSTAT,(T4) ;GET NEW CONNECTION STATE
JRST CPOPJ1## ;SKIP RETURN
SUBTTL SCA SUPPORT ROUTINES - SEND RESPONSE
;ROUTINE TO SEND A RESPONSE (IF NEEDED) TO AN INCOMING PACKET.
;CALL:
; T1/ OPCODE
; P1/ CB ADDRESS
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.RSP
;RETURN:
; CPOPJ ON ERROR WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
SC.RSP: SETZRO MH$CDT,(P2) ;CLEAR THE CREDIT FIELD
SC.RS2: STOR T1,MH$MSG,(P2) ;STORE OPCODE
MOVE T2,.MHSCI(P2) ;GET SOURCE CONNECT ID
MOVEM T2,.MHDCI(P2) ;STORE AS THE RECEIVER'S CID
MOVE T2,.CBSCI(P1) ;GET OUR SOURCE CONNECT ID
MOVEM T2,.MHSCI(P2) ;STORE IN PACKET AS SENDING CID
PUSHJ P,@SCMKPK(T1) ;STORE OPCODE-SPECIFIC DATA
PJRST SC.PAK ;SEND THE PACKET AND RETURN
SUBTTL SCA SUPPORT ROUTINES - SEND AN SCS CONTROL MESSAGE
;ROUTINE TO SEND AN SCS CONTROL MESSAGE.
;CALL:
; P1/ CB ADDRESS
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.RQS
;RETURN:
; CPOPJ ON ERROR
; CPOPJ1 ON SUCCESS
SC.RQS: LOAD T1,CBBKST,(P1) ;GET THE BLOCK STATE
LOAD T4,Y.OP,(T1) ;GET OPCODE TO BE SENT
STOR T4,MH$MSG,(P2) ;STORE IT IN THE PACKET
MOVE T1,.CBDCI(P1) ;GET DESTINATION CONNECT ID
MOVEM T1,.MHDCI(P2) ;STORE
MOVE T1,.CBSCI(P1) ;GET SOURCE CONNECT ID
MOVEM T1,.MHSCI(P2) ;STORE
PUSHJ P,@SCMKPK(T4) ;FILL IN OPCODE-SPECIFIC DATA
LOAD T1,CBBKST,(P1) ;GET THE BLOCK STATE BACK
LOAD T1,Y.STAT,(T1) ;GET THE NEW CONNECTION STATE
SKIPE T1 ;UNLESS NO CHANGE DESIRED,
STOR T1,CBCNST,(P1) ; STORE NEW CONNECT STATE
LOAD T1,MH$MSG,(P2) ;GET THE OPCODE
LOAD T1,Z.RSP,(T1) ;GET THE EXPECTED RESPONSE
SKIPE T1 ;IF ONE IS EXPECTED,
STOR T1,CBEXPR,(P1) ; STORE EXPECTED RESPONSE
SETZRO CBBKST,(P1) ;INDICATE NOTHING IS PENDING
PUSHJ P,SC.PAK ;SEND THE PACKET
POPJ P, ;ERROR
SETZRO CBBKST,(P1) ;INDICATE NOTHING IS PENDING
JRST CPOPJ1## ;SKIP RETURN
;DISPATCH TABLE FOR ROUTINE TO FILL IN OPCODE-SPECIFIC DATA
SCMKPK: IFIW SC.MOQ ;CONNECT_REQUEST
IFIW SC.MOS ;CONNECT_RESPONSE
IFIW SC.MAQ ;ACCEPT_REQUEST
IFIW SC.MAS ;ACCEPT_RESPONSE
IFIW SC.MRQ ;REJECT_REQUEST
IFIW SC.MRS ;REJECT_RESPONSE
IFIW SC.MDQ ;DISCONNECT_REQUEST
IFIW SC.MDS ;DISCONNECT_RESPONSE
IFIW SC.MCQ ;CREDIT_REQUEST
IFIW SC.MCS ;CREDIT_RESPONSE
SUBTTL SCA SUPPORT ROUTINES - FILL IN RESPONSE DATA
;ROUTINES CALLED BY SC.RSP TO FILL IN OPCODE-SPECIFIC DATA.
;CALL:
; P1/ CB ADDRESS
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
;RETURN:
; CPOPJ ALWAYS
;CONNECT_RESPONSE
SC.MOS: SETZRO MH$MCR,(P2) ;MINIMUM CREDIT FIELD MUST BE ZERO
POPJ P, ;RETURN
;ACCEPT_RESPONSE
SC.MAS: POPJ P, ;RETURN
;REJECT_RESPONSE
SC.MRS: POPJ P, ;RETURN
;DISCONNECT_RESPONSE
SC.MDS: POPJ P, ;RETURN
;CREDIT_RESPONSE
SC.MCS: POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - FILL IN REQUEST DATA
;ROUTINES CALLED BY SC.RSQ TO FILL IN OPCODE-SPECIFIC DATA.
;CALL:
; P1/ CB ADDRESS
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
;RETURN:
; CPOPJ ALWAYS
;CONNECT_REQUEST
SC.MOQ: PUSHJ P,SC.SCF ;STORE CREDIT FIELD IN PACKET
SETZM .MHDCI(P2) ;WE DON'T KNOW THE DESTINATION'S CID
JRST MAQ.01 ;JOIN WITH ACCEPT_REQUEST CODE
;ACCEPT_REQUEST
SC.MAQ: PUSHJ P,SC.SCF ;STORE CREDIT FIELD IN PACKET
MAQ.01: LOAD T1,CBMNSC,(P1) ;GET THE MINIMUM SEND CREDIT
STOR T1,MH$MCR,(P2) ;STORE
;MOVE THE DESTINATION PROCESS NAME
MOVEI T1,C%PNLW ;NUMBER OF WORDS TO MOVE
XMOVEI T2,.CBDPN(P1) ;SOURCE ADDRESS
XMOVEI T3,.MGDPN(P2) ;DESTINATION ADDRESS
EXTEND T1,[XBLT] ;MOVE THE DESTINATION PROCESS NAME
;MOVE THE SOURCE PROCESS NAME
MOVEI T1,C%PNLW ;NUMBER OF WORDS TO MOVE
XMOVEI T2,.CBSPN(P1) ;SOURCE ADDRESS
XMOVEI T3,.MGSPN(P2) ;DESTINATION ADDRESS
EXTEND T1,[XBLT] ;MOVE THE SOURCE PROCESS NAME
;MOVE THE INITIAL CONNECTION DATA
MOVEI T1,C%CDLW ;NUMBER OF WORDS TO MOVE
XMOVEI T2,.CBDTA(P1) ;SOURCE ADDRESS
XMOVEI T3,.MGSDT(P2) ;DESTINATION ADDRESS
EXTEND T1,[XBLT] ;MOVE THE CONNECTION DATA
POPJ P, ;RETURN
;MAKE A REJECT_REQUEST
SC.MRQ: ;FALL INTO SC.MDQ
;MAKE A DISCONNECT_REQUEST
SC.MDQ: SETZRO MH$CDT,(P2) ;CREDIT FIELD MUST BE ZERO
LOAD T1,CBSDRE,(P1) ;GET THE REASON FOR DISCONNECTING
STOR T1,MH$STS,(P2) ;STORE
SETZRO MH$MCR,(P2) ;MINIMUM CREDIT FIELD MUST BE ZERO
POPJ P, ;RETURN
;MAKE A CREDIT_REQUEST
SC.MCQ: PJRST SC.SCF ;STORE CREDIT FIELD IN PACKET AND RETURN
SUBTTL SCA SUPPORT ROUTINES - SEND A MESSAGE
;ROUTINE TO SEND A MESSAGE.
;CALL:
; P2/ PACKET ADDRESS
; P5/ PBK ADDRESS
; PUSHJ P,SC.PAK
;RETURN:
; CPOPJ ON ERROR WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS
SC.PAK: STKVAR <OPCODE> ;ALLOCATE SOME STACK STORAGE
LOAD T1,MH$MSG,(P2) ;GET THE OPCODE
MOVEM T1,OPCODE ;SAVE IT FOR LATER
LOAD T2,Z.LEN,(T1) ;GET LENGTH OF THIS MESSAGE
PUSHJ P,SC.ROU ;BYTE SWAP THE PACKET HEADER FOR OUTPUT
LOAD T3,Z.PRI,(T1) ;GET PRIORITY FOR THIS OPCODE
LOAD T4,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDSMS##,<T4,P2,T2,[0],T3,[0]>) ;SEND THE PACKET (NO FLAGS)
RETBAD () ;PASS ALONG THE ERROR
MOVE T1,OPCODE ;RESTORE THE OPCODE
AOS SNDTAB(T1) ;INCREMENT SEND COUNT
JRST CPOPJ1## ;SKIP RETURN
ENDSV. ;END OF STACK VARIABLE RANGE
SUBTTL SCA SUPPORT ROUTINES - SET CREDIT FIELD IN PACKET
;ROUTINE TO STORE THE CREDIT FIELD IN THE PACKET AND ADJUST PENDING
;RECEIVE CREDIT.
;CALL:
; P1/ CB ADDRESS
; P2/ PACKET ADDRESS
; PUSHJ P,SC.SCF
;RETURN:
; CPOPJ ALWAYS
SC.SCF: CIOFF ;PREVENT RACES
LOAD T1,MH$MSG,(P2) ;GET THE MESSAGE TYPE
CAIE T1,.STCRQ ;IS IT A CREDIT_REQUEST?
JRST SCF.01 ;NO
MOVE T1,.CBPRC(P1) ;GET PENDING RECEIVE CREDIT
MOVEM T1,.CBRQC(P1) ;STORE AS REQUEST_CREDIT
JRST SCF.02 ;CONTINUE
SCF.01: MOVE T1,.CBPRC(P1) ;GET THE PENDING RECEIVE CREDIT
ADDM T1,.CBRCD(P1) ;UPDATE THE RECEIVE CREDIT
SCF.02: STOR T1,MH$CDT,(P2) ;STORE THE CREDIT FIELD
SETZM .CBPRC(P1) ;ZERO THE PENDING RECEIVE CREDIT
PJRST CIONPJ ;INTERRUPTS BACK ON AND RETURN
SUBTTL SCA SUPPORT ROUTINES - DECLARE PROTOCOL COMPLETE
;ROUTINE TO DECLARE PROTOCOL COMPLETE. CALLED WHEN WE BELIEVE
;THERE SHOULD BE NO MORE OUTPUT SENT TO A NODE AND WE DON'T
;EXPECT ANY INPUT FROM IT.
;CALL:
; P1/ CB ADDRESS
; PUSHJ P,SC.PTC
;RETURN:
; CPOPJ ALWAYS
SC.PTC: MOVX T1,CB.PTC ;GET THE PROTOCOL COMPLETE FLAG
IORM T1,.CBFLG(P1) ;SET IN FLAGS WORD
SETZRO CBBKST,(P1) ;CLEAR THE BLOCK STATE
MOVX T1,CB.JSY ;GET THE JSYS CONNECTION FLAG
TDNE T1,.CBFLG(P1) ;WAS THIS A JSYS CONNECTION?
POPJ P, ;YES, CAN'T REAP NOW
PJRST SC.SRB ;SET REAP BIT AND RETURN
SUBTTL SCA BUFFER MANAGEMENT - QUEUE BUFFERS TO PPD
;ROUTINE TO QUEUE A (CHAIN OF) DATAGRAM BUFFER(S) TO THE PPD.
;CALL:
; T1/ ADDRESS OF FIRST BUFFER
; T2/ NUMBER OF BUFFERS
; P5/ PBK ADDRESS
; PUSHJ P,SC.QDB
;RETURN:
; CPOPJ ALWAYS
SC.QDB: PUSH P,T2 ;SAVE THE COUNT
LOAD T3,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDQDB##,<T3,T1>) ;GIVE THE BUFFERS TO THE PPD
POP P,T1 ;RESTORE COUNT
ADDM T1,.CBDGR(P1) ;UPDATE DATAGRAM CREDIT
POPJ P, ;RETURN
;ROUTINE TO QUEUE A (CHAIN OF) MESSAGE BUFFER(S) TO THE PPD.
;CALL:
; T1/ ADDRESS OF FIRST BUFFER
; T2/ NUMBER OF BUFFERS
; P5/ PBK ADDRESS
; PUSHJ P,SC.QMB
;RETURN:
; CPOPJ ALWAYS
SC.QMB: PUSH P,T2 ;SAVE THE COUNT
LOAD T3,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDQMB##,<T3,T1>) ;GIVE THE BUFFERS TO THE PPD
POP P,T1 ;RESTORE COUNT
ADDM T1,.CBPRC(P1) ;UPDATE PENDING RECEIVE CREDIT
POPJ P, ;RETURN
SUBTTL SCA BUFFER MANAGEMENT - RETURN BUFFERS TO FREE POOL
;ROUTINE TO RETURN A CHAIN OF DATAGRAM BUFFERS TO THE FREE POOL.
;CALL:
; T1/ ADDRESS OF BUFFER LIST
; PUSHJ P,SC.MRD
;RETURN:
; CPOPJ ALWAYS
SC.MRD: SAVEAC <Q1> ;SAVE AN AC
MRD.01: MOVE Q1,(T1) ;GET ADDRESS OF THE NEXT BUFFER
PUSHJ P,SC.RLD ;RETURN A DATAGRAM
SKIPE T1,Q1 ;WAS THERE A NEXT BUFFER?
JRST MRD.01 ;YES, KEEP RETURNING
POPJ P, ;RETURN
;ROUTINE TO RETURN A CHAIN OF MESSAGE BUFFERS TO THE FREE POOL.
;CALL:
; T1/ ADDRESS OF BUFFER LIST
; PUSHJ P,SC.MRM
;RETURN:
; CPOPJ ALWAYS
SC.MRM: SAVEAC <Q1> ;SAVE AN AC
MRM.01: MOVE Q1,(T1) ;GET ADDRESS OF THE NEXT BUFFER
PUSHJ P,SC.RBF ;RETURN A MESSAGE
SKIPE T1,Q1 ;WAS THERE A NEXT BUFFER?
JRST MRM.01 ;YES, KEEP RETURNING
POPJ P, ;RETURN
SUBTTL BUFFER MANAGEMENT ROUTINES - GET BUFFERS FOR SC.SNM OR SC.DEF
;ROUTINES TO GET BUFFERS FOR SC.SNM OR SC.DEF. SINCE TOPS-10 CAN'T
;HANDLE CREATING PAGES BY FAULTING THEM IN SC.BF2 IS ESSENTIALLY AN
;ELABORATE NO-OP. WE MIGHT BE ABLE TO CHECK NUMBER OF FREE PAGES
;IN CORE AND PERHAPS ALLOCATE FROM THAT POOL SOMEDAY.
;CALL:
; P1/ CONNECTION BLOCK ADDRESS
; P5/ PATH BLOCK ADDRESS
; PUSHJ P,SC.BF1 (IF CAN'T CREATE BUFFERS)
; PUSHJ P,SC.BF2 (IF CAN CREATE BUFFERS)
;RETURN:
; CPOPJ IF FAILED TO CREATE BUFFERS
; CPOPJ1 ON SUCCESS
SC.BF1: TDZA T1,T1 ;CAN'T CREATE BUFFERS
SC.BF2: SETO T1, ;CAN CREATE BUFFERS
PUSHJ P,SAVP## ;SAVE THE PRESERVED REGISTERS
MOVE P2,T1 ;SAVE THE FLAG
LOAD T1,CBIMB,(P1) ;GET THE NUMBER OF MESSAGE BUFFERS NEEDED
JUMPE T1,BFX.02 ;NONE, GO CHECK FOR DATAGRAM BUFFERS
PUSHJ P,SC.ABF ;TRY TO GET THEM FROM SCA'S POOL
SKIPA ;FAILED, HAVE TO CREATE THEM
JRST BFX.01 ;SUCCEEDED, GIVE THEM TO THE PORT
;HERE IF WE DIDN'T HAVE ENOUGH BUFFERS IN SCA'S POOL.
JUMPE P2,CPOPJ## ;RETURN IF WE CAN'T CREATE THEM
LOAD T1,CBIMB,(P1) ;GET THE NUMBER OF BUFFERS AGAIN
PUSHJ P,SC.CMG ;CREATE THE MESSAGE BUFFERS
POPJ P, ;FAILED, TRY FOR DATAGRAMS
ADDM T3,TOTMGB ;ADD TO TOTAL NUMBER OF MESSAGE BUFFERS CREATED
;SC.CMG MAY HAVE CREATED MORE THAN WE NEEDED. IF SO, MAKE A CHAIN OF THE
;EXTRA BUFFERS AND RETURN TO SCA'S POOL.
LOAD P4,CBIMB,(P1) ;THE NUMBER WE WANTED
CAMN P4,T3 ;SAME AS THE NUMBER CREATED?
JRST BFX.01 ;YES, QUEUE THE BUFFER CHAIN IMMEDIATELY
;WE GOT MORE THAN WE WANTED. MAKE A CHAIN OF THE DESIRED NUMBER.
MOVE P3,T1 ;SAVE THE ADDRESS OF THE BUFFER CHAIN
MOVE T2,T1 ;INITIALIZE THE LOOP
MOVE T3,T2 ;SAVE THE ADDRESS OF THE PREVIOUS BUFFER
MOVE T2,(T2) ;GET THE ADDRESS OF THE NEXT BUFFER
SOJG P4,.-2 ;LOOP FOR THE NUMBER DESIRED
SETZM (T3) ;ZERO THE FORWARD POINTER OF THE LAST REQ'D BUFFER
;RETURN THE EXCESS BUFFERS CREATED BY SC.CMG TO THE SCA FREE POOL
MOVE T1,T2 ;GET THE ADDRESS OF THE CURRENT BUFFER
PUSHJ P,SC.MRM ;RETURN MESSAGES TO FREE POOL
MOVE T1,P3 ;GET THE ADDRESS OF THE BUFFER CHAIN
;QUEUE THE BUFFERS TO THE PORT QUEUE
BFX.01: LOAD T2,CBIMB,(P1) ;GET THE NUMBER OF BUFFERS IN THE CHAIN
PUSHJ P,SC.QMB ;GIVE THEM TO THE PORT
SETZRO CBIMB,(P1) ;NO LONGER NEED TO ASK FOR THESE BUFFERS
;HANDLE DATAGRAMS
BFX.02: LOAD T1,CBIDB,(P1) ;GET NUMBER OF DATAGRAM BUFFERS TO CREATE
JUMPE T1,CPOPJ1## ;NONE, NOTHING ELSE TO DO
PUSHJ P,SC.ALD ;ALLOCATE THE DATAGRAMS FROM SCA'S POOL
SKIPA ;FAILED, HAVE TO CREATE THEM
JRST BFX.03 ;SUCCEEDED, GIVE THEM TO THE PORT
;DIDN'T HAVE ENOUGH IN SCA'S POOL. CREATE THEM.
JUMPE P2,CPOPJ## ;RETURN IF CAN'T CREATE THEM
LOAD T1,CBIDB,(P1) ;GET THE NUMBER NEEDED
PUSHJ P,SC.CDG ;CREATE THE DATAGRAMS
POPJ P, ;FAILED
ADDM T3,TOTDGB ;ADD TO TOTAL DATAGRAM BUFFERS CREATED
;SC.CDG MAY HAVE CREATED MORE THAN WE NEEDED. IF SO, MAKE A CHAIN OF THE
;EXTRA BUFFERS AND RETURN TO SCA'S POOL.
LOAD P4,CBIDB,(P1) ;NUMBER WE WANTED
CAMN P4,T3 ;SAME AS THE NUMBER CREATED?
JRST BFX.03 ;YES, QUEUE THE BUFFER CHAIN IMMEDIATELY
;WE GOT MORE THAN WE WANTED. MAKE A CHAIN OUT OF THE DESIRED NUMBER.
MOVE P3,T1 ;SAVE THE ADDRESS OF THE BUFFER CHAIN
MOVE T2,T1 ;INITIALIZE FOR LOOP
MOVE T3,T2 ;SAVE THE ADDRESS OF THE PREVIOUS BUFFER
MOVE T2,(T2) ;GET THE ADDRESS OF THE NEXT BUFFER
SOJG P4,.-2 ;LOOP UNTIL WE HAVE THE NUMBER REQUESTED
SETZM (T3) ;ZERO THE FLINK OF THE LAST REQ'D BUFFER
;RETURN THE EXCESS BUFFERS CREATED BY SC.CDG TO THE SCA FREE POOL
MOVE T1,T2 ;GET THE ADDRESS OF THE CURRENT BUFFER
PUSHJ P,SC.MRD ;RETURN DATAGRAMS TO FREE POOL
MOVE T1,P3 ;GET THE ADDRESS OF THE BUFFER CHAIN
;HERE WHEN WE ARE READY TO QUEUE THE BUFFERS TO THE PORT QUEUE
BFX.03: LOAD T2,CBIDB,(P1) ;GET THE NUMBER OF DATAGRAMS REQUESTED
PUSHJ P,SC.QDB ;QUEUE THE DATAGRAM BUFFERS
SETZRO CBIDB,(P1) ;NO LONGER NEED TO ASK FOR THESE BUFFERS
JRST CPOPJ1## ;SKIP RETURN
SUBTTL SCA SUPPORT ROUTINES - SET BUFFER THRESHOLD
;ROUTINE TO SET THE BUFFER THRESHOLDS BASED ON THE NUMBER OF
;PATHS CURRENTLY ONLINE.
;CALL:
; PUSHJ P,SC.SBT
;RETURN:
; CPOPJ ALWAYS
;UPDATES MINMSG WITH NEW MESSAGE BUFFER THRESHOLD
;UPDATES MINDG WITH NEW DATAGRAM BUFFER THRESHOLD
SC.SBT: MOVE T1,PBCNT ;GET CURRENT NUMBER OF ONLINE PATHS
IMUL T1,MBPP ;MULTIPLY BY THRESHOLD PER PATH
ADD T1,MGTRSH ;ADD THE THRESHOLD WE MUST HAVE AROUND
MOVEM T1,MINMSG ;UPDATE THE MINIMUM MESSAGE BUFFER COUNT
MOVE T1,PBCNT ;GET CURRENT NUMBER OF ONLINE PATHS
IMUL T1,DBPP ;MULTIPLY BY THRESHOLD PER PATH
ADD T1,DGTRSH ;ADD THE THRESHOLD WE MUST HAVE AROUND
MOVEM T1,MINDG ;UPDATE THE MINIMUM DATAGRAM BUFFER COUNT
POPJ P, ;RETURN
SUBTTL SCA BUFFER MANAGEMENT - ALLOCATE LONG DATAGRAM BUFFERS
;ROUTINE TO OBTAIN LONG DATAGRAM BUFFERS FROM SCA. WHEN YOU WISH TO
;RECEIVE A LONG DATAGRAM YOU MUST QUEUE A BUFFER OBTAINED FROM HERE.
;CALL:
; T1/ NUMBER OF BUFFERS DESIRED
;RETURN:
; CPOPJ IF COULDN'T ALLOCATE DESIRED NUMBER OF BUFFERS
; CPOPJ1 IF SUCCESS WITH:
; T1/ ADDRESS OF FIRST BUFFER IN THE CHAIN
; T2/ NUMBER OF BUFFERS RETURNED
; T3/ ADDRESS OF ROUTINE TO CALL TO RETURN BUFFERS
;NOTE: IF THE CALLER SETS T1 NEGATIVE (KLPSER) THEY ARE INDICATING THEY
;WISH TO OVER-RIDE THE THRESHOLD CHECK. THIS IS NORMALLY DONE ONLY WHEN
;THE KLIPA IS BEING INITIALIZED.
$XSENT (SC.ALD::) ;EXTENDED ENTRY POINT
MOVM T2,T1 ;GET A (POSITIVE) COPY WE CAN WORK WITH
CIOFF ;PREVENT RACES
SUB T2,DFQCNT ;NUMBER LEFT AFTER SATISFYING THIS REQUEST
JUMPG T2,ALD.04 ;IF MORE THAN WE HAVE AVAILABLE, REFUSE REQUEST
MOVMS T2 ;GET THE MAGNITUDE
SKIPL T1 ;SKIP IF OVER-RIDING THRESHOLD CHECK
CAML T2,DGTRSH ;WILL THERE BE ENOUGH LEFT OVER AFTER REQUEST?
JRST ALD.01 ;YES, DO THE WORK
SKIPE DINITF## ;INITIALIZATION?
JRST ALD.01 ;YES
CAML T1,LRGREQ ;IS THIS A SMALL REQUEST?
JRST ALD.04 ;NO, REFUSE THE LARGE REQUEST
AOS DBUST ;COUNT ANOTHER SMALL REQUEST BUSTING THRESHOLD
;HERE TO HONOR THE REQUEST
ALD.01: STKVAR <NUMBUF> ;ALLOCATE SOME STACK STORAGE
MOVMS T1 ;JUST GET MAGNITUDE
MOVEM T1,NUMBUF ;SAVE THE NUMBER OF BUFFERS REQUESTED
MOVE T4,T1 ;WORKING COPY OF THE REQUEST SIZE
SKIPN T1,TOPDFQ ;IS THERE A FIRST BUFFER?
JRST ALD.05 ;NO, FREE COUNT WAS INCORRECT
MOVE T2,T1 ;START BUFFER LOOP WITH ADDRESS OF FIRST BUFFER
SOJLE T4,ALD.02 ;IF NO MORE BUFFERS, FIX UP COUNT AND POINTERS
SKIPE T2,(T2) ;ON TO THE NEXT BUFFER
JRST .-2 ;LOOP FOR MORE ENTRIES
JRST ALD.05 ;NO ENTRY, FREE COUNT WAS INCORRECT
;HERE WHEN WE KNOW ENOUGH BUFFERS ARE AVAILABLE FOR THE REQUEST.
;T1/ ADDRESS OF FIRST BUFFER T2/ ADDRESS OF LAST BUFFER
ALD.02: SKIPE T3,(T2) ;GET THE ADDRESS OF THE NEW FIRST BUFFER
JRST ALD.03 ;THERE ARE BUFFERS LEFT
XMOVEI T4,TOPDFQ ;NO NEXT BUFFER, GET POINTER TO TOP OF QUEUE
MOVEM T4,BOTDFQ ;INIT THE BLINK AS POINTER TO FLINK
AOS CIBUF ;ASK SC.DEF TO RUN
ALD.03: MOVEM T3,TOPDFQ ;SAVE THE NEW QUEUE FLINK
SETZM (T2) ;CLEAR FLINK IN LAST BUFFER
MOVN T3,NUMBUF ;GET THE NUMBER OF BUFFERS ISSUED
ADDM T3,DFQCNT ;ACCOUNT FOR THESE IN BUFFER COUNTS
MOVE T3,MINDG ;NUMBER OF BUFFERS WE SHOULD HAVE AROUND
CAML T3,DFQCNT ;ARE THERE ENOUGH BUFFERS AROUND?
AOS CIBUF ;ASK SC.DEF TO RUN
CION ;OK TO INTERRUPT AGAIN
MOVE T2,NUMBUF ;RETURN THE NUMBER OF BUFFERS CREATED
MOVE T3,[MCSEC1+SC.RLD] ;TELL CALLER HOW TO RETURN THEM
JRST CPOPJ1## ;SKIP RETURN
;HERE TO REFUSE THE REQUEST. DO SOME BOOKKEEPING FIRST.
ALD.04: MOVMS T1 ;GET THE MAGNITUDE
ADD T1,ASRDR ;ADD CURRENT AVERAGE SIZE TO NEW REQUEST
SKIPE RDRCNT ;DON'T AVERAGE IF THIS IS THE FIRST TIME THROUGH
IDIVI T1,2 ;TAKE THE AVERAGE OF THE TWO
MOVEM T1,ASRDR ;UPDATE THE AVERAGE SIZE OF REFUSED REQUEST
AOS RDRCNT ;INCREMENT THE NUMBER OF REFUSED REQUESTS
RETBAD (.SCNEB,<CION>) ;RETURN AN ERROR
;HERE WHEN THE FREE COUNT WAS INCORRECT (WE HAD LESS BUFFERS THAN
;THE FREE COUNT CLAIMED).
ALD.05: AOS CIBUF ;ASK SC.DEF TO RUN
AOS NDBCNT ;COUNT THIS EVENT
AOS RDRCNT ;INCREMENT THE NUMBER OF REFUSED REQUESTS
MOVE T1,NUMBUF ;GET THE REQUEST SIZE AGAIN
ADD T1,ASRDR ;ADD CURRENT AVERAGE SIZE TO NEW REQUEST
IDIVI T1,2 ;TAKE THE AVERAGE OF THE TWO
MOVEM T1,ASRDR ;UPDATE THE AVERAGE SIZE OF REFUSED REQUEST
;NOW FIX THE BUFFER COUNT
SETZ T2, ;START AT ZERO
SKIPN T1,TOPDFQ ;IS THE QUEUE EMPTY?
JRST ALD.06 ;YES
AOS T2 ;COUNT THE INITIAL BUFFER
SKIPE T1,(T1) ;IS THERE A NEXT BUFFER?
AOJA T2,.-1 ;YES, CONTINUE TO COUNT BUFFERS
MOVEM T2,DFQCNT ;SAVE THE NEW CORRECT COUNT
RETBAD (.SCNEB,<CION>) ;RETURN AN ERROR
;HERE WHEN QUEUE WAS EMPTY
ALD.06: XMOVEI T1,TOPDFQ ;GET A POINTER TO THE QUEUE FLINK
MOVEM T1,BOTDFQ ;INIT THE QUEUE TAIL POINTER
SETZM TOPDFQ ;INIT THE QUEUE HEAD POINTER
SETZM DFQCNT ;MAKE THE COUNT CORRECT
RETBAD (.SCNEB,<CION>) ;RETURN AN ERROR
SUBTTL SCA BUFFER MANAGEMENT - ALLOCATE BUFFERS
;ROUTINE TO OBTAIN MESSAGE BUFFERS FROM SCA. WHEN YOU WISH TO SEND
;OR RECEIVE A MESSAGE YOU MUST OBTAIN THE BUFFER FROM HERE.
;CALL:
; T1/ NUMBER OF BUFFERS DESIRED
; PUSHJ P,SC.ABF
;RETURN:
; CPOPJ IF COULDN'T ALLOCATE DESIRED NUMBER OF BUFFERS
; CPOPJ1 IF SUCCESS WITH:
; T1/ ADDRESS OF FIRST BUFFER IN THE CHAIN
; T2/ NUMBER OF BUFFERS RETURNED
; T3/ ADDRESS OF ROUTINE TO CALL TO RETURN BUFFERS
$XSENT (SC.ABF::) ;EXTENDED ENTRY POINT
MOVE T2,T1 ;GET A COPY WE CAN WORK WITH
CIOFF ;PREVENT RACES
SUB T2,MFQCNT ;NUMBER LEFT AFTER SATISFYING THIS REQUEST
JUMPG T2,ABF.04 ;IF MORE THAN WE HAVE AVAILABLE, REFUSE REQUEST
MOVMS T2 ;GET THE MAGNITUDE
CAML T2,MGTRSH ;WILL THERE BE ENOUGH LEFT OVER AFTER REQUEST?
JRST ABF.01 ;YES, DO THE WORK
SKIPE DINITF## ;INITIALIZATION?
JRST ABF.01 ;YES
CAML T1,LRGREQ ;IS THIS A SMALL REQUEST?
JRST ABF.04 ;NO, REFUSE THE LARGE REQUEST
AOS MBUST ;COUNT ANOTHER SMALL REQUEST BUSTING THRESHOLD
;HERE TO HONOR THE REQUEST
ABF.01: STKVAR <NUMBUF> ;ALLOCATE SOME STACK STORAGE
MOVEM T1,NUMBUF ;SAVE THE NUMBER OF BUFFERS REQUESTED
MOVE T4,T1 ;WORKING COPY OF THE REQUEST SIZE
SKIPN T1,TOPMFQ ;IS THERE A FIRST BUFFER?
JRST ABF.05 ;NO, FREE COUNT WAS INCORRECT
MOVE T2,T1 ;START BUFFER LOOP WITH ADDRESS OF FIRST BUFFER
SOJLE T4,ABF.02 ;IF NO MORE BUFFERS, FIX UP COUNT AND POINTERS
SKIPE T2,(T2) ;ON TO THE NEXT BUFFER
JRST .-2 ;LOOP FOR MORE ENTRIES
JRST ABF.05 ;NO ENTRY, FREE COUNT WAS INCORRECT
;HERE WHEN WE KNOW ENOUGH BUFFERS ARE AVAILABLE FOR THE REQUEST.
;T1/ ADDRESS OF FIRST BUFFER T2/ ADDRESS OF LAST BUFFER
ABF.02: SKIPE T3,(T2) ;GET THE ADDRESS OF THE NEW FIRST BUFFER
JRST ABF.03 ;THERE ARE BUFFERS LEFT
XMOVEI T4,TOPMFQ ;NO NEXT BUFFER, GET POINTER TO TOP OF QUEUE
MOVEM T4,BOTMFQ ;INIT THE BLINK AS POINTER TO FLINK
AOS CIBUF ;ASK SC.DEF TO RUN
ABF.03: MOVEM T3,TOPMFQ ;SAVE THE NEW QUEUE FLINK
SETZM (T2) ;CLEAR FLINK IN LAST BUFFER
MOVN T3,NUMBUF ;GET THE NUMBER OF BUFFERS ISSUED
ADDM T3,MFQCNT ;ACCOUNT FOR THESE IN BUFFER COUNTS
MOVE T3,MINMSG ;NUMBER OF BUFFERS WE SHOULD HAVE AROUND
CAML T3,MFQCNT ;ARE THERE ENOUGH BUFFERS AROUND?
AOS CIBUF ;ASK SC.DEF TO RUN
CION ;OK TO INTERRUPT
MOVE T2,NUMBUF ;RETURN THE NUMBER OF BUFFERS CREATED
MOVE T3,[MCSEC1+SC.RBF] ;TELL CALLER HOW TO RETURN THEM
JRST CPOPJ1## ;SKIP RETURN
;HERE TO REFUSE THE REQUEST. DO SOME BOOKKEEPING FIRST.
ABF.04: ADD T1,ASRMR ;ADD CURRENT AVERAGE SIZE TO NEW REQUEST
SKIPE RMRCNT ;DON'T AVERAGE IF THIS IS THE FIRST TIME THROUGH
IDIVI T1,2 ;TAKE THE AVERAGE OF THE TWO
MOVEM T1,ASRMR ;UPDATE THE AVERAGE SIZE OF REFUSED REQUEST
AOS RMRCNT ;INCREMENT THE NUMBER OF REFUSED REQUESTS
RETBAD (.SCNEB,<CION>) ;RETURN AN ERROR
;HERE WHEN THE FREE COUNT WAS INCORRECT (WE HAD LESS BUFFERS THAN
;THE FREE COUNT CLAIMED).
ABF.05: AOS CIBUF ;ASK SC.DEF TO RUN
AOS NMBCNT ;COUNT THIS EVENT
AOS RMRCNT ;INCREMENT THE NUMBER OF REFUSED REQUESTS
MOVE T1,NUMBUF ;GET THE REQUEST SIZE AGAIN
ADD T1,ASRMR ;ADD CURRENT AVERAGE SIZE OF NEW REQUEST
IDIVI T1,2 ;TAKE THE AVERAGE OF THE TWO
MOVEM T1,ASRMR ;UPDATE THE AVERAGE SIZE OF REFUSED REQUEST
;NOW FIX THE BUFFER COUNT
SETZ T2, ;START AT ZERO
SKIPN T1,TOPMFQ ;IS THE QUEUE EMPTY?
JRST ABF.06 ;YES
AOS T2 ;COUNT THE INITIAL BUFFER
SKIPE T1,(T1) ;IS THERE A NEXT BUFFER?
AOJA T2,.-1 ;YES, CONTINUE TO COUNT BUFFERS
MOVEM T2,MFQCNT ;SAVE THE NEW CORRECT COUNT
RETBAD (.SCNEB,<CION>) ;RETURN AN ERROR
;HERE WHEN QUEUE WAS EMPTY
ABF.06: XMOVEI T1,TOPMFQ ;GET A POINTER TO THE QUEUE FLINK
MOVEM T1,BOTMFQ ;INIT THE QUEUE TAIL POINTER
SETZM TOPMFQ ;INIT THE QUEUE HEAD POINTER
SETZM MFQCNT ;MAKE THE COUNT CORRECT
RETBAD (.SCNEB,<CION>) ;RETURN AN ERROR
SUBTTL BUFFER MANAGEMENT ROUTINES - CREATE MESSAGE/DATAGRAM BUFFERS
;ROUTINE TO CREATE MESSAGE OR DATAGRAM BUFFERS. IT IS INTENDED TO
;BE CALLED DURING "PROCESS CONTEXT" WHICH DOESN'T EXIST IN TOPS-10.
;SOMEDAY THIS ROUTINE MIGHT BE CLEVER ENOUGH TO GRAB FREE PAGES FROM
;PAGTAB BUT FOR NOW JUST GIVE UP UNLESS IN INITIALIZATION.
;CALL:
; T1/ NUMBER OF BUFFERS TO CREATE
; PUSHJ P,SC.CMG/SC.CDG
;RETURN:
; CPOPJ ON ERRORS WITH:
; T1/ ERROR CODE
; CPOPJ1 ON SUCCESS WITH:
; T1/ ADDRESS OF FIRST BUFFER
; T2/ ADDRESS OF LAST BUFFER
; T3/ NUMBER OF BUFFERS RETURNED
;
;NOTE: SINCE THE NUMBER OF BUFFERS IS ROUNDED UP TO AN INTEGRAL
;DIVISOR OF A PAGE WE MAY CREATE MORE BUFFERS THAN REQUESTED. THE
;CALLER SHOULD GIVE BACK THE EXTRA BUFFERS IT DOESN'T WANT.
SC.CMG: TDZA T2,T2 ;CLEAR THE DATAGRAM FLAG
SC.CDG: SETO T2, ;SET THE DATAGRAM FLAG
SAVEAC <Q1,Q2,P4,P5> ;SAVE SOME AC'S
STKVAR <BUFSZ,NUMPPG,NUMBUF> ;ALLOCATE SOME STACK STORAGE
DMOVE T3,[EXP C%MGSZ,C%MGPG] ;ASSUME MESSAGE BUFFERS
SKIPE T2 ;REALLY WANT DATAGRAM BUFFERS?
DMOVE T3,[EXP C%DGSZ,C%DGPG] ;YES, USE DIFFERENT VARIABLES
MOVEM T3,BUFSZ ;SAVE BUFFER SIZE
MOVEM T4,NUMPPG ;SAVE NUMBER OF BUFFERS PER PAGE
MOVE Q1,T1 ;GET THE REQUEST SIZE IN BUFFERS
IDIV Q1,NUMPPG ;NUMBER OF PAGES TO REQUEST
SKIPE Q2 ;ANY REMAINDER?
AOS Q1 ;YES, ROUND UP THE PAGE COUNT
MOVE T1,Q1 ;GET THE NUMBER OF PAGES TO CREATE
IMUL T1,NUMPPG ;FIND THE TOTAL NUMBER OF BUFFERS WE'LL CREATE
MOVEM T1,NUMBUF ;SAVE FOR RETURN TO CALLER
MOVE T1,Q1 ;GET THE NUMBER OF PAGES DESIRED
PUSHJ P,PGRSKD## ;CREATE THE SPACE
POPJ P, ;NICE TRY
MOVE T2,BUFSZ ;GET THE SIZE OF A BUFFER
AOS (P) ;SET FOR SKIP RETURN
PJRST SC.BBF ;BREAK THE PAGES INTO BUFFERS AND RETURN
ENDSV. ;END OF STACK VARIABLE RANGE
SUBTTL SCA BUFFER MANAGEMENT - BREAK MEMORY INTO BUFFERS
;ROUTINE TO BREAK A CHAIN OF PAGES INTO A CHAIN OF MESSAGE BUFFERS.
;CALL:
; T1/ ADDRESS OF FIRST PAGE IN CHAIN
; T2/ BUFFER SIZE
; PUSHJ P,SC.BBF
;RETURN:
; CPOPJ ALWAYS WITH:
; T1/ ADDRESS OF FIRST BUFFER IN CHAIN
; T2/ ADDRESS OF LAST BUFFER IN CHAIN
; T3/ NUMBER OF BUFFERS CREATED
SC.BBF: PUSHJ P,SAVE2## ;SAVE P1 AND P2
TRVAR <BUFSIZ> ;ALLOCATE A WORD OF STACK STORAGE
ADDI T2,C%BINV ;ADD INVISIBLE SPACE SIZE TO BUFFER SIZE
MOVEM T2,BUFSIZ ;SAVE THE ALLEGED BUFFER SIZE
MOVE P1,T1 ;SAVE THE CALLERS LIST POINTER
ADDI T1,C%BINV ;CREATE THE INVISIBLE BUFFER AREA
MOVE T2,T1 ;FOR INIT, TAIL IS SAME AS HEAD POINTER
SETZ P2, ;INIT THE COUNT AT ZERO
MOVEI T3,PAGSIZ ;GET THE SIZE OF A PAGE
MOVE P1,(P1) ;GET THE ADDRESS OF THE NEXT PAGE
MOVE T4,T1 ;INIT NEXT ADDRESS AS FIRST ADDRESS
BBF.01: CAMG T3,BUFSIZ ;HAVE WE RUN OUT OF ROOM IN THIS PAGE?
JRST BBF.02 ;YES, DO THE NEXT PAGE
AOS P2 ;COUNT THIS BUFFER IN THE TOTAL
MOVE T2,T4 ;UPDATE THE TAIL POINTER
MOVE T4,BUFSIZ ;GET THE SIZE OF A BUFFER
ADD T4,T2 ;MAKE IT THE ADDRESS OF THE NEXT BUFFER
MOVEM T4,(T2) ;LINK IT ONTO THE LIST
SUB T3,BUFSIZ ;UPDATE PAGE SPACE COUNTER
JRST BBF.01 ;LOOP OVER THE WHOLE PAGE
BBF.02: SETZM (T2) ;ZERO NEXT POINTER IN CASE WE'RE DONE
JUMPE P1,BBF.03 ;WE'RE DONE IF NO NEXT PAGE TO DO
MOVE T4,P1 ;GET ADDRESS OF NEXT PAGE
ADDI T4,C%BINV ;CREATE THE INVISIBLE SPACE
MOVEM T4,(T2) ;LINK LAST PAGE TO NEW PAGE
MOVE P1,(P1) ;GET THE ADDRESS OF THE NEXT PAGE
MOVEI T3,PAGSIZ ;RESET THE PAGE SPACE COUNTER
JRST BBF.01 ;AND BREAK THIS PAGE INTO BUFFERS
BBF.03: MOVE T3,P2 ;GET THE COUNT OF BUFFERS IN T3
POPJ P, ;RETURN
ENDSV. ;END OF STACK VARIABLE RANGE
SUBTTL SCA BUFFER MANAGEMENT - RETURN A BUFFER
;ROUTINE TO RETURN A BUFFER OBTAINED BY A CALL TO SC.ABF.
;CALL:
; T1/ ADDRESS OF BUFFER
; PUSHJ P,SC.RBF
;RETURN:
; CPOPJ ALWAYS
$XSENT (SC.RBF::) ;EXTENDED ENTRY POINT
MOVE T4,T1 ;SAVE THE ADDRESS OF THE BUFFER
MOVE T2,T1 ;THIS IS THE START ADDRESS
SUBI T2,C%BINV ;MOVE BACK TO THE START OF THE INVISIBLE AREA
MOVE T3,T2 ;DESTINATION ADDRESS TO T3
AOS T3 ;...
MOVX T1,<C%BINV+C%MGSZ>-1 ;NUMBER OF WORDS TO ZERO
SETZM (T2) ;CLEAR THE FIRST WORD
EXTEND T1,[XBLT] ;CLEAR THE REMAINDER
CIOFF ;PREVENT RACES
MOVEM T4,@BOTMFQ ;LINK THIS BUFFER AT THE END OF THE LIST
MOVEM T4,BOTMFQ ;STORE THE NEW FREE QUEUE BOTTOM POINTER
SETZM (T4) ;MAKE SURE THE FLINK OF LAST BUFFER IS ZERO
AOS MFQCNT ;UPDATE THE BUFFER COUNT
PJRST CIONPJ ;INTERRUPTS BACK ON AND RETURN
SUBTTL SCA BUFFER MANAGEMENT - RETURN A LONG DATAGRAM BUFFER
;ROUTINE TO RETURN A LONG DATAGRAM BUFFER OBTAINED BY A CALL TO SC.ALD.
;CALL:
; T1/ ADDRESS OF BUFFER
; PUSHJ P,SC.RLD
;RETURN:
; CPOPJ ALWAYS
$XSENT (SC.RLD::) ;EXTENDED ENTRY POINT
MOVE T4,T1 ;SAVE THE ADDRESS OF THE BUFFER
MOVE T2,T1 ;THIS IS THE START ADDRESS
SUBI T2,C%BINV ;MOVE BACK TO THE START OF THE INVISIBLE AREA
MOVE T3,T2 ;DESTINATION ADDRESS TO T3
AOS T3 ;...
MOVX T1,<C%BINV+C%DGSZ>-1 ;NUMBER OF WORDS TO ZERO
SETZM (T2) ;CLEAR THE FIRST WORD
EXTEND T1,[XBLT] ;CLEAR THE REMAINDER
CIOFF ;PREVENT RACES
MOVEM T4,@BOTDFQ ;LINK THIS BUFFER AT THE END OF THE LIST
MOVEM T4,BOTDFQ ;STORE THE NEW FREE QUEUE BOTTOM POINTER
SETZM (T4) ;MAKE SURE THE FLINK OF LAST BUFFER IS ZERO
AOS DFQCNT ;UPDATE THE BUFFER COUNT
PJRST CIONPJ ;INTERRUPTS BACK ON AND RETURN
SUBTTL SCA SUPPORT ROUTINES - BYTE SWAP HEADERS
;ROUTINE TO PERFORM MAGIC ON THE PACKET HEADER WORDS. SINCE THE
;VAX AND THE 11'S HAVE THEIR NUMBERS BACKWARD WE MUST SWAP THE
;ORDER OF THE BYTES THAT GO OUT AND COME IN FROM THESE SYSTEMS.
;SWAP BYTES IN AN INCOMING MESSAGE.
;CALL:
; P2/ PACKET ADDRESS
;RETURN:
; CPOPJ ALWAYS
SC.RIN: SAVEAC <T1,T2,T3,T4,P1> ;DON'T SMASH ANY AC'S
MOVE T1,.MHTYP(P2) ;GET THE MESSAGE TYPE WORD
LDB P1,[POINT 1,T1,24] ;GET -11 STYLE SIGN BIT
PUSHJ P,SC.ISW ;SWAP THE BYTES INTO -10 FORMAT
SKIPE P1 ;WAS THE NUMBER OF CREDITS NEGATIVE?
TXO T1,3B1 ;YES, LIGHT THE BITS TO MAKE THIS A -10 -VE NUMBER
MOVEM T1,.MHTYP(P2) ;PUT IT BACK
LOAD T1,MH$MSG,(P2) ;GET THE MESSAGE TYPE
CAIE T1,.STADG ;IS THIS AN APPLICATION DATAGRAM
CAIN T1,.STAMG ; OR MESSAGE?
POPJ P, ;YES, SKIP STATUS AND MINIMUM CREDIT WORD
MOVE T1,.MHSTS(P2) ;NO, GET STATUS WORD
PUSHJ P,SC.ISW ;SWAP THE BYTES INTO -10 FORMAT
MOVEM T1,.MHSTS(P2) ;PUT IT BACK
POPJ P, ;RETURN
;SWAP THE BYTES IN AN OUTGOING MESSAGE.
;CALL:
; P2/ PACKET ADDRESS
; PUSHJ P,SC.ROU
;RETURN:
; CPOPJ ALWAYS
SC.ROU: PUSHJ P,SAVT## ;SAVE THE T REGISTERS
LOAD T1,MH$MSG,(P2) ;GET THE MESSAGE TYPE
CAIE T1,.STADG ;IS THIS AN APPLICATION DATAGRAM
CAIN T1,.STAMG ; OR MESSAGE?
JRST ROU.01 ;YES, SKIP STATUS AND MINIMUM CREDIT WORD
MOVE T1,.MHSTS(P2) ;GET THE STATUS WORD
PUSHJ P,SC.OSW ;SWAP THE BYTES INTO -11 FORMAT
MOVEM T1,.MHSTS(P2) ;PUT IT BACK
ROU.01: MOVE T1,.MHTYP(P2) ;GET THE CREDIT AND MESSAGE TYPE WORD
SKIPGE T1 ;IS IT NEGATIVE?
TXZ T1,3B1 ;YES, TURN OFF EXTRANEOUS SIGN BITS
PUSHJ P,SC.OSW ;SWAP THE BYTES INTO -11 FORMAT
MOVEM T1,.MHTYP(P2) ;PUT IT BACK
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - SWAP WORD FROM 11 TO 10 FORMAT
;ROUTINE TO SWAP A WORD FROM 11 TO 10 FORMAT.
;CALL:
; T1/ WORD TO BE SWAPPED
; PUSHJ P,SC.ISW
;RETURN:
; CPOPJ ALWAYS WITH:
; T1/ WORD WITH BYTES SWAPPED
;
;INPUT FORMAT:
; 2 16-BIT HALF WORDS, LEFT JUSTIFIED
;
; !=======================================================!
; ! B (LSB) ! B (MSB) ! A (LSB) ! A (MSB) ! IGN !
; !=======================================================!
; 0 7 8 15 16 23 24 31 32 35
;
;WHERE A AND B ARE THE HALF WORDS, AND LSB ARE THE LEAST SIGNIFICANT
;BITS AND MSB ARE THE MOST SIGNIFICANT BITS.
;
;THE CONTENTS OF BITS 32 THROUGH 35 ARE IGNORED.
;
;OUTPUT FORMAT:
; 2 18-BIT HALF WORDS
;
; !=======================================================!
; !X! BYTE A (MSB+LSB) !X! BYTE B (MSB +LSB) !
; !=======================================================!
; 0 2 17 20 35
;
;X DENOTES THE 2 BIT FIELD WITHIN EACH HALFWORD THAT WILL ALWAYS BE ZERO.
SC.ISW: LDB T2,EA$MSB ;BYTE A, MSB
LDB T3,EA$LSB ;BYTE A, LSB
LDB T4,EB$MSB ;BYTE B, MSB
LSH T1,-^D28 ;MOVE BYTE B, LSB INTO ITS POSITION FOR THE 10
DPB T4,TB$MSB ;NOW REPLACE THE BYTES IN THEIR 10 POSITIONS
DPB T3,TA$LSB ;. . .
DPB T2,TA$MSB ;. . .
POPJ P, ;DONE
SUBTTL SCA SUPPORT ROUTINES - SWAP WORD FROM 10 TO 11 FORMAT
;ROUTINE TO SWAP A WORD FROM 10 TO 11 FORMAT.
;CALL:
; T1/ WORD TO SWAP
; PUSHJ P,SC.OSW
;RETURN:
; CPOPJ ALWAYS WITH:
; T1/ WORD WITH BYTES SWAPPED
;
;INPUT FORMAT:
; 2 18-BIT HALF WORDS
;
; !=======================================================!
; ! BYTE A (MSB+LSB) ! BYTE B (MSB +LSB) !
; !=======================================================!
; 0 17 18 35
;
;OUTPUT FORMAT:
; 2 16-BIT HALF WORDS, LEFT JUSTIFIED
;
; !=======================================================!
; ! B (LSB) ! B (MSB) ! A (LSB) ! A (MSB) ! IGN !
; !=======================================================!
; 0 7 8 15 16 23 24 31 32 35
;
;WHERE A AND B ARE THE HALF WORDS, AND LSB ARE THE LEAST SIGNIFICANT BITS
;AND MSB ARE THE MOST SIGNIFICANT BITS.
SC.OSW: LDB T2,TA$MSB ;GET TEN BYTE A, MSB
LDB T3,TA$LSB ;TEN BYTE A, LSB
LDB T4,TB$MSB ;TEN BYTE B, MSB
LSH T1,^D28 ;MOVE TEN BYTE B, LSB INTO CORRECT POSITION
DPB T4,EB$MSB ;ELEVEN BYTE B, MSB
DPB T3,EA$LSB ;ELEVEN BYTE A, LSB
DPB T2,EA$MSB ;ELEVEN BYTE A, MSB
POPJ P, ;DONE
SUBTTL SCA SUPPORT ROUTINES - BUFFER MANAGEMENT INTERLOCKING
;ROUTINE TO INTERLOCK ACCESS TO SCA BUFFER MANAGEMENT.
;CALLED DIRECTLY OR VIA EXPANSION OF CIOFF MACRO.
$CSUB ;ENTIRE ROUTINE IN HIGH SEG
SC.POF::CONO PI,PI.OFF ;TURN OFF THE PI SYSTEM WHILE TESTING .CPSCA
AOSE .CPSCA## ;BUMP LEVEL OF NESTING
JRST [CONO PI,PI.ON ;JUST NESTING, RETURN, ALREADY HAVE INTERLOCK
POPJ P,] ;...
CONI PI,.CPSCP## ;SAVE CHANNEL ENABLES
CONO PI,PI.ON+DSKPIF## ;TURN PI SYSTEM BACK ON BUT LEAVE DSKCHN OFF
IFN FTMP,<
SKIPGE INTLSC## ;GIVE OTHER CPUS A CHANCE
AOSE INTLSC## ;WAIT FOR THE SYSTEM-WIDE INTERLOCK
JRST .-2 ;WAIT
APRID INTOSC## ;INFORM THE WORLD WHO OWNS THIS
>; END IFN FTMP
POPJ P, ;RETURN
;ROUTINE TO ALLOW ACCESS TO SCA BUFFER MANAGEMENT AFTER
;IT HAS BEEN INTERLOCKED. CALED DIRECTLY OR VIA EXPANSION
;OF CION MACRO
SC.PON::PUSH P,T1 ;SAVE A REGISTER
SOSL T1,.CPSCA## ;DECREMENT LEVEL OF NESTING, SEE IF DONE
PJRST TPOPJ## ;STILL NESTING, JUST RETURN
EXCH T1,.CPSCP## ;GET CHANNEL ENABLE STATES
ANDI T1,177 ;KEEP JUST THE CHANNELS WHICH WERE ON
TRO T1,PI.TNP ;TURN THEM BACK ON
EXCH T1,.CPSCP## ;RESTORE T1 AND SAVE ARGUMENT FOR CONO PI,
IFN FTMP,<
SETOM INTOSC## ;CLEAR INTERLOCK OWNER
EXCH T1,INTLSC## ;RESET THE INTERLOCK
SKIPGE T1 ;MAKE SURE IT WAS OWNED
STOPCD .,CPU,SIU, ;++ SCA INTERLOCK UNOWNED
>; END IFN FTMP
CONO PI,@.CPSCP## ;PUT THE PI SYSTEM BACK THE WAY IT WAS
PJRST TPOPJ## ;RESTORE T1 AND RETURN
;GLOBAL ROUTINES TO RETURN CI INTERLOCK
CINPJ1::AOS (P) ;SET FOR SKIP RETURN
CIONPJ::CION ;GIVE UP INTERLOCK
POPJ P, ;RETURN
$XHIGH ;BACK TO EXTENDED HIGH SEG
SUBTTL CONNECTION BLOCK LOCKING ROUTINES
;ROUTINE TO LOCK A CONNECTION BLOCK.
;CALL:
; P1/ CONNECTION BLOCK ADDRESS
; PUSHJ P,SC.LOK
;RETURN:
; CPOPJ ALWAYS
;
;PRESERVES ALL ACS.
SC.LOK: CONSZ PI,PI.IPA ;ANY PI'S IN PROGRESS?
POPJ P, ;YES, NO NEED TO LOCK?
AOS .CBLCK(P1) ;INCREMENT THE LOCK
POPJ P, ;RETURN
;ROUTINE TO LOCK A CONNECTION BLOCK IF POSSIBLE.
;CALL:
; T1/ BIT TO BE SET IF BLOCK IS LOCKED
; P1/ CONNECTION BLOCK ADDRESS
; PUSHJ P,SC.LAH
;RETURN:
; CPOPJ IF ALREADY LOCKED
; CPOPJ1 IF WE LOCKED THE BLOCK
SC.LAH: CONSZ PI,PI.IPA ;ANY PI'S IN PROGRESS?
JRST SC.HNR ;YES, USE INTERRUPT LEVEL ROUTINE
AOS .CBLCK(P1) ;INCREMENT THE LOCK
JRST CPOPJ1## ;SKIP RETURN
;ROUTINE TO LOCK A CONNECTION BLOCK AT INTERRUPT LEVEL IF POSSIBLE.
;CALL:
; T1/ BIT TO BE SET IF BLOCK IS LOCKED
; P1/ CONNECTION BLOCK ADDRESS
; PUSHJ P,SC.HNR
;RETURN:
; CPOPJ IF ALREADY LOCKED
; CPOPJ1 IF WE LOCKED THE BLOCK
SC.HNR: SKIPN .CBLCK(P1) ;IS IT LOCKED?
JRST CPOPJ1## ;NO, WE CAN PROCEED
IORM T1,.CBFLG(P1) ;YES, LIGHT THE BIT
POPJ P, ;RETURN
SUBTTL CONNECTION BLOCK UNLOCKING ROUTINE
;ROUTINE TO UNLOCK A CONNECTION BLOCK.
;CALL:
; P1/ CONNECTION BLOCK ADDRESS
; PUSHJ P,SC.ULK
;RETURN:
; CPOPJ ALWAYS
;
;PRESERVES T1 BECAUSE ERROR CODES ARE OFTEN PASSED IN T1.
SC.ULK: CONSZ PI,PI.IPA ;ANY PI'S IN PROGRESS?
POPJ P, ;YES, NO NEED TO UNLOCK
SAVEAC <T1,P3,P4,P5> ;SAVE SOME AC'S WE'LL NEED
MOVE T1,.CBLCK(P1) ;WHAT'S THE CURRENT VALUE OF THE LOCK?
CAIG T1,1 ;QUIT IF IT'S NOT 1
JRST ULK.01 ;PROCEED
SOS .CBLCK(P1) ;DECREMENT IT
POPJ P, ;RETURN
ULK.01: SKIPG T1 ;MAKE SURE IT'S NOT NEGATIVE
BUG. (HLT,SCAILC,SCASER,SOFT,<Illegal lock count in connection block>,,)
;CURRENT VALUE IS 1. WE WILL BE THE LAST UNLOCKER. SEE WHAT SORTS
;OF THINGS HAVE BEEN DEFERRED, AND CALL THE APPROPRIATE ROUTINES.
;EACH PROCESSING ROUTINE CLEARS ITS BIT. IF THE BIT GETS SET AGAIN
;WHILE WE'RE IN HERE, WE WILL DETECT THAT.
SETZB P3,P4 ;INITIALIZE FLAGS
MOVE P5,.CBPBK(P1) ;GET ADDRESS OF PATH BLOCK
;SEE IF ANYTHING HAPPENED WHILE WE HAD THIS LOCKED.
ULK.02: CIOFF ;PREVENT RACES
MOVX T1,CB.DEF ;ANYTHING DEFERRED?
TDNN T1,.CBFLG(P1) ;...
JRST ULK.05 ;NO
CION ;OK TO INTERRUPT
;TEST AND HANDLE EACH POSSIBLE EVENT
MOVX T1,CB.ERR ;NODE OFFLINE?
TDNN T1,.CBFLG(P1) ;...
JRST ULK.03 ;NO
SETO P4, ;YES, INDICATE WE HAD DEFERRED NODE OFFLINE
PUSHJ P,SC.FN1 ;DO WHAT'S LEFT TO BE DONE
JRST ULK.04 ;PROCEED
ULK.03: MOVX T1,CB.DIS ;SYSAP WANTED DISCONNECT?
TDNE T1,.CBFLG(P1) ;...
PUSHJ P,SC.FN2 ;YES, FINISH THAT
MOVX T1,CB.DRQ ;DISCONNECT_REQUEST DEFERRED?
TDNE T1,.CBFLG(P1) ;...
PUSHJ P,SC.FN3 ;YES, FINISH THAT
ULK.04: MOVX T1,CB.SNM ;NEED TO SEND A CONNECTION MANAGEMENT REQUEST?
TDNN T1,.CBFLG(P1) ;...
JRST ULK.02 ;NO, SEE IF ANYTHING NEW HAS COME UP
ANDCAM T1,.CBFLG(P1) ;YES, INDICATE NO LONGER DEFERRED
SETO P3, ;REMEMBER THIS
JRST ULK.02 ;SEE IF ANYTHING NEW HAS COME UP
;NOTHING LEFT TO DO, UNLOCK THE BLOCK
ULK.05: SOSE .CBLCK(P1) ;UNLOCK THE CONNECTION BLOCK
BUG. (HLT,SCALCC,SCASER,SOFT,<Connection block lock count has changed>,,)
CION ;OK TO INTERRUPT
;IF WE HAD WANTED TO SEND A CONNECTION MANAGEMENT REQUEST, DO IT
SKIPE P3 ;DID WE WANT TO?
PUSHJ P,SC.SNM ;YES, SEND NEXT MESSAGE IF THERE'S ONE
;IF THIS BLOCK'S NODE HAD GONE OFFLINE, WE HAVE PUT OFF RE-OPENING
;THE VC BECAUSE OF THE LOCKED CB. IF THIS IS THE LAST ONE TO BE
;UNLOCKED, OPEN THE VC NOW.
JUMPE P4,CPOPJ## ;RETURN IF WE DIDN'T HAVE A DEFERRED NODE OFFLINE
SOSE .PBCLC(P5) ;DECREMENT PATH BLOCK COUNT OF LOCKED CB'S
POPJ P, ;STILL HAVE MORE TO GO
MOVX T1,PB.OVC ;NO LONGER WAITING TO OPEN
ANDCAM T1,.PBFLG(P5) ;...
LOAD T1,PBPBI,(P5) ;GET THE PATH BLOCK INDEX
BLCAL. (PPDOVC##,<T1>) ;LET PPD OPEN THE VC
POPJ P, ;RETURN
SUBTTL SCA SUPPORT ROUTINES - OPERATOR NOTIFICATION
;ROUTINES TO NOTIFY THE OPERATOR WHEN A PATH CHANGES STATE.
;CALL:
; P5/ PBK ADDRESS
; PUSHJ P,PTHONL/PTHOFL
;RETURN:
; CPOPJ ALWAYS
IFN FTINFO,<
PTHONL: TDZA T1,T1 ;FLAG ONLINE MESSAGE
PTHOFL: MOVEI T1,400000 ;FLAG OFFLINE
SKIPE DINITF## ;ARE WE OUT OF DISK ONCE-ONLY CODE?
POPJ P, ;NO, DON'T MESS UP THE CTY
LOAD T2,PBDPN,(P5) ;GET DESTINATION PORT (CI NODE) NUMBER
DPB T2,[POINT 8,T1,26] ;STORE NODE NUMBER
IFN FTMP,<
MOVE T2,.CPCPN## ;OUR CPU NUMBER
DPB T2,[POINT 3,T1,35] ;STORE THAT TOO
>; END IFN FTMP
XJRST [MCSEC1+PTHSE0] ;MUST EXECUTE REMAINDER IN SECTION 0/1
$HIGH
PTHSE0: PUSHJ P,SSEC0## ;LEAVE SECTION 1
MOVE T2,[PTHMSG,,1] ;CANT TYPE ON PI LEVEL
SYSPIF ; SO WAIT TILL NEXT TICK
PUSHJ P,SKPCLQ## ;ROOM IN CLOCK QUEUE FOR MESSAGE?
JRST PTHSE1 ;NO, PROBABLY LOTS OF ERRORS, LET IT GO
IDPB T2,CLOCK## ;SET SO WE WILL TELL OPR
IDPB T1,CLOCK## ;SAVE DATA (PATH BLOCK ADDRESS)
SETOM CLKNEW## ;INDICATE NEW ENTRY
PTHSE1: SYSPIN ;ALLOW INTERRUPTS
POPJ P, ;RETURN
;HERE AT CLOCK LEVEL - DATA ITEM (FLAG/NODE NBR/CPU) IS IN T1
PTHMSG: PUSHJ P,SAVE1## ;FREE UP P1
MOVE P1,T1 ;SAVE DATA ITEM
PUSHJ P,TTYERO## ;SET UP TO PRINT ON OPERATOR'S TERMINAL
PUSHJ P,INLMES## ;START THE MESSAGE
ASCIZ /%% CI node / ;START THE MESSAGE
LDB T1,[POINT 8,P1,26] ;FETCH NODE NUMBER
PUSHJ P,RADX10## ;PRINT IT
IFN FTMP,<
PUSHJ P,INLMES## ;IDENTIFY WHICH CPU
ASCIZ / on CPU/ ;...
LDB T3,[POINT 3,P1,35] ;FETCH CPU NUMBER
ADDI T3,"0" ;CONVERT TO ASCII
PUSHJ P,COMTYO## ;...
>; END IFN FTMP
PUSHJ P,INLMES## ;ADD A SPACE, ETC.
ASCIZ /: / ;...
TRNN P1,400000 ;OFFLINE FLAG SET?
SKIPA T1,[[ASCIZ /Online/]] ;NO
MOVEI T1,[ASCIZ /Offline/] ;YES
PUSHJ P,CONMES## ;PRINT IT
PUSHJ P,INLMES## ;MORE NOISE
ASCIZ / at / ;...
PUSHJ P,PRDTIM## ;PRINT DATE/TIME
PJRST CRLF## ;END THE LINE AND RETURN
$XHIGH ;BACK TO EXTENDED HIGH SEGMENT
>; END IFN FTINFO
SUBTTL MISCELLANEOUS BYTE POINTERS
;BYTE POINTERS TO -10 FORMAT 8-BIT BYTES
TA$LSB: POINT 8,T1,17 ;TEN BYTE A, LSB
TA$MSB: POINT 8,T1,9 ;TEN BYTE A, MSB
TB$LSB: POINT 8,T1,35 ;TEN BYTE B, LSB
TB$MSB: POINT 8,T1,27 ;TEN BYTE B, MSB
;BYTE POINTERS TO -11 FORMAT 8-BIT BYTES
EA$LSB: POINT 8,T1,23 ;ELEVEN BYTE A, LSB
EA$MSB: POINT 8,T1,31 ;ELEVEN BYTE A, MSB
EB$LSB: POINT 8,T1,7 ;ELEVEN BYTE B, LSB
EB$MSB: POINT 8,T1,15 ;ELEVEN BYTE B, MSB
SUBTTL IMPURE STORAGE
$LOW
EXP -1 ;FLAG FOR "DON'T CARE" LISTENERS
PBLIST::BLOCK C%PBLL ;PATH BLOCK LIST ARRAY
SBLIST::BLOCK C%SBLL ;SYSTEM BLOCK LIST ARRAY
MFQCNT: BLOCK 1 ;FREE QUEUE BUFFER COUNT
TOPMFQ: BLOCK 1 ;FREE QUEUE FLINK
BOTMFQ: BLOCK 1 ;FREE QUEUE BLINK
DFQCNT: BLOCK 1 ;DATAGRAM FREE QUEUE BUFFER COUNT
TOPDFQ: BLOCK 1 ;DATAGRAM FREE QUEUE FLINK
BOTDFQ: BLOCK 1 ;DATAGRAM FREE QUEUE BLINK
TOPDC: BLOCK 1 ;DON'T CARE QUEUE FLINK
BOTDC: BLOCK 1 ;DON'T CARE QUEUE BLINK
CIDTAB::BLOCK 1 ;ADDRESS OF CONNECT-ID TABLE
CIDRFL: BLOCK 1 ;NUMBER OF TIMES CIDTAB HAS BEEN RECYCLED
UBTTAB: BLOCK 1 ;ADDRESS OF UNIQUENESS TABLE
UNQRFL: BLOCK 1 ;NUMBER OF TIMES CID BITS HAVE BEEN RECYCLED
NXTIDX: BLOCK 1 ;NEXT INDEX INTO UNIQUENESS TABLE
UNQBTS: BLOCK 1 ;UNIQUENESS BITS
SCASIN::BLOCK 1 ;SOFTWARE INCARNATION NUMBER
NOTTAB: BLOCK 1 ;ADDRESS OF NOTIFICATION TABLE
SNDTAB: BLOCK .STLST ;SEND COUNT INDEXED BY MESSAGE TYPE
RECTAB: BLOCK .STLST ;RECEIVE COUNT INDEXED BY MESSAGE TYPE
TMGCNT: BLOCK 1 ;NUMBER OF PATHS KILLED DUE TO IDLE CHATTER
TMGPBI: EXP -1 ;CURRENT PATH BLOCK UNDER CONSIDERATION
TMGTIM: EXP -C%TMGT ;TIMEOUT PERIOD
PBCNT: BLOCK 1 ;NUMBER OF ONLINE PATHS
MBPP: EXP C%MBPP ;MINIMUM MESSAGE BUFFERS PER PATH BLOCK
DBPP: EXP C%DBPP ;NUMBER OF DATAGRAM BUFFERS PER PATH BLOCK
MINMSG: BLOCK 1 ;MINIMUM NUMBER OF MESSAGE BUFFERS WE SHOULD HAVE
MINDG: BLOCK 1 ;MINIMUM NUMBER OF DATAGRAM BUFFERS WE SHOULD HAVE
NMBCNT: BLOCK 1 ;NUMBER OF TIMES WE RAN OUT OF MESSAGE BUFFERS
NDBCNT: BLOCK 1 ;NUMBER OF TIMES WE RAN OUT OF DATAGRAM BUFFERS
TOTMGB: BLOCK 1 ;TOTAL NUMBER OF MESSAGE BUFFERS CREATED
TOTDGB: BLOCK 1 ;TOTAL NUMBER OF DATAGRAM BUFFERS CREATED
MBUST: BLOCK 1 ;NUMBER OF TIMES A SMALL REQUEST WAS HONORED
; EVEN THOUGH WE WERE UNDER MESSAGE THRESHOLD
DBUST: BLOCK 1 ;NUMBER OF TIMES A SMALL REQUEST WAS HONORED
; EVEN THOUGH WE WERE UNDER DATAGRAM THRESHOLD
DMRCNT: BLOCK 1 ;NUMBER OF MESSAGE BUFFER REQUESTS DEFERRED
DDRCNT: BLOCK 1 ;NUMBER OF DATAGRAM BUFFER REQUESTS DEFERRED
RMRCNT: BLOCK 1 ;NUMBER OF MESSAGE BUFFER REQUESTS REFUSED
RDRCNT: BLOCK 1 ;NUMBER OF DATAGRAM BUFFER REQUESTS REFUSED
ASRMR: BLOCK 1 ;AVERAGE SIZE OF REFUSED MESSAGE REQUEST
ASRDR: BLOCK 1 ;AVERAGE SIZE OF REFUSED DATAGRAM REQUEST
LRGREQ: EXP C%LGRQ ;BUFFER REQUESTS OF LESS THAN THIS SIZE ARE
; CONSIDERED SMALL REQUESTS
MGTRSH: EXP C%MGTR ;MINIMUM MESSAGE BUFFER THRESHOLD
DGTRSH: EXP C%DGTR ;MINIMUM DATAGRAM BUFFER THRESHOLD
IFN FTOPS10,< ;THIS IS ELSEWHERE IN TOPS-20
CIBUF: BLOCK 1 ;NON-ZERO IF MEMORY ALLOCATOR SHOULD RUN
SCAREP: BLOCK 1 ;NON-ZERO IF REAPER NEEDS TO RUN
>; END IFN FTOPS10
MDPAGS: BLOCK 1 ;NUMBER OF MESSAGE,,DATAGRAM PAGES REQUESTED OF
; THE MEMORY ALLOCATOR
PBSTUK: BLOCK 2 ;BITS FOR PATHS STUCK ON BUFFERS
SUBTTL THE END
$XHIGH ;BACK TO EXTENDED HIGH SEGMENT
SCAEND::!END