Google
 

Trailing-Edge - PDP-10 Archives - BB-F493Z-DD_1986 - 10,7/703mon/scaser.mac
There are 3 other files named scaser.mac in the archive. Click here to see a list.
TITLE	SCASER - SYSTEM COMMUNICATIONS ARCHITECTURE SERVICE	V24
SUBTTL	JOSEPH A. DZIEDZIC/JAD	21 JAN 86


	SEARCH	F,S,SCAPRM,MACSYM
	$RELOC
	$HIGH


	PURGEACS		;PURGE DEFAULT (TOPS-10) AC NAMES
	T20SYM			;SWITCH TO TOPS-20 AC NAMES

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
.CPYRT<1984,1986>
;COPYRIGHT (C) 1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.

;BASED ON TOPS-20 "SCAMPI" MODIFIED TO SUPPORT MULTIPLE PATHS


XP	VSCASR,24		;VERSION NUMBER FOR GLOB AND MAP


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

SC.INI::SE1ENT			;RUN IN NON-ZERO SECTION
	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,PGSIZ-1	;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,PGSIZ/2	;POINT TO HALFWAY THROUGH THE TABLE
	MOVEM	T1,UBTTAB	;SAVE AS ADDRESS OF THE UNIQUENESS TABLE
	MOVX	T1,C%CIDL	;INIT NXTIDS AS ONE MORE THAN HIGHEST INDEX
	MOVEM	T1,NXTIDX	;...
	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,CPUN##	;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
;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

SC.SNA::BLSUB.	(<SS.ADR>)
	SAVEAC	<P1,P5>		;FREE UP A PAIR OF AC'S
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.CON::BLSUB.	(<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
	SE1ENT			;ENSURE WE RUN IN NZS
	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.

SC.LIS::BLSUB.	(<SS.SPN,SS.DPN,SS.PBI,SS.ADR,SS.SID,SS.MSC,SS.MRC>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.ACC::BLSUB.	(<SS.CID,SS.DTA,SS.BFR,SS.DGB>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.REJ::BLSUB.	(<SS.CID,SS.RJR>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.DIS::BLSUB.	(<SS.CID,SS.DIR>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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
	MOVX	T1,CB.RAP	;MARK AS REAPABLE
	IORM	T1,.CBFLG(P1)	; (IN CASE JSYS CONNECTION)
	SETOM	SCAREP		;HAVE REAPER RUN NEXT TICK
	POPJ	P,		;NOTHING MORE TO DO

;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

SC.SDG::BLSUB.	(<SS.CID,SS.FLG,SS.LDG,SS.ADG,SS.PRI,SS.PTH>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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	(.SCFWS,<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

SC.SMG::BLSUB.	(<SS.CID,SS.FLG,SS.LMG,SS.AMG,SS.PRI,SS.TSH,SS.PTH>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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	(.SCFWS,<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

SC.RDG::BLSUB.	(<SS.CID,SS.NUM,SS.ADR>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.RMG::BLSUB.	(<SS.CID,SS.NUM,SS.ADR>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.CRD::BLSUB.	(<SS.CID,SS.NUM>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.CRM::BLSUB.	(<SS.CID,SS.NUM>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

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

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

SC.REQ::BLSUB.	(<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

SC.SND::BLSUB.	(<SS.CID,SS.SNM,SS.RNM,SS.SOF,SS.ROF>)
	SETZ	T1,		;INDICATE SEND
SC.SNR:	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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	(.SCFWS,<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

SC.CSP::BLSUB.	(<SS.CID,SS.ADR>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.DCI::BLSUB.	(<SS.CID>)
	SAVEAC	<P1,P5>		;SAVE THE AC'S SC.CAL TROUNCES
	SE1ENT			;ENSURE WE RUN IN NZS
	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).

SC.RSB::BLSUB.	(<SS.SBI>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED AC'S WE USE HERE
	SE1ENT			;ENSURE WE RUN IN NZS
	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).

SC.RPB::BLSUB.	(<SS.PBI>)
	PUSHJ	P,SAVP##	;SAVE THE PRESERVED AC'S WE USE HERE
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.ONL::BLSUB.	(<SS.PBI>)
	PUSHJ	P,SAVP##	;SAVE THE P REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.ERR::BLSUB.	(<SS.PBI>)
	PUSHJ	P,SAVP##	;SAVE THE P REGISTRS
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.DMA::BLSUB.	(<SS.BNM,SS.CID>)
	PUSHJ	P,SAVE1##	;SAVE P1
	SE1ENT			;ENSURE WE RUN IN NZS
	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

SC.INT::BLSUB.	(<SS.PBI,SS.PKT,SS.LEN,SS.FLG>)
	PUSHJ	P,SAVP##	;SAVE THE P REGISTERS
	SE1ENT			;ENSURE WE RUN IN NZS
	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
	XMOVEI	T4,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
	XMOVEI	T4,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

SC.TIC::SE1ENT			;RUN IN NZS
	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

SC.SEC::SE1ENT			;RUN IN NZS
	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
	SETZM	SCAREP		;REMEMBER WE'VE RUN
	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:	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 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##	;ASK FOR THE SPACE 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 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,PGSIZ(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
	SKIPN	CIDRFL		;ARE WE IN RECYCLE MODE?
	JRST	FNI.01		;NO, TRY FOR ANOTHER INDEX
	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

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
	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
	MOVX	T2,CB.RAP	;GET THE REAP BIT
	IORM	T2,.CBFLG(P1)	;WE CAN REAP IT NEXT TICK
	SETOM	SCAREP		;START REAPER NEXT TICK
	POPJ	P,		;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.

SC.ALD::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
	XMOVEI	T3,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

SC.ABF::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
	XMOVEI	T3,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
	SKIPN	CORLOC##	;CAN WE DO IT?
	POPJ	P,		;NO, NICE TRY
	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,PGSIZ	;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,PGSIZ	;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

SC.RBF::SE1ENT			;MAKE SURE WE RUN IN NZS
	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

SC.RLD::SE1ENT			;MAKE SURE WE RUN IN NZS
	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.

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
	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:	SKIPA	T1,[[ASCIZ /Online/]] ;GET TEXT
PTHOFL:	MOVEI	T1,[ASCIZ /Offline/] ;GET TEXT
	LOAD	T2,PBDPN,(P5)	;GET DESTINATION PORT NUMBER
	SKIPE	DINITF##	;ARE WE OUT OF DISK ONCE-ONLY CODE?
	POPJ	P,		;NO, DON'T MESS UP THE CTY
	PUSHJ	P,SAVPQ##	;SAVE ALL THE REGISTERS WE MIGHT STEP ON
	DMOVE	P1,T1		;COPY ARGUMENTS
	PUSHJ	P,SSEC0##	;ENTER SECTION ZERO
	PUSHJ	P,TTYERO##	;SET UP TO PRINT ON OPERATOR'S TERMINAL
	PUSHJ	P,INLMES##	;START THE MESSAGE
	ASCIZ	/%% CI node /	;START THE MESSAGE
	MOVE	T1,P2		;GET NODE NUMBER
	PUSHJ	P,RADX10##	;PRINT IT
IFN FTMP,<
	PUSHJ	P,INLMES##	;IDENTIFY WHICH CPU
	ASCIZ	/ on CPU/	;...
	MOVE	T3,.CPCPN##	;GET CPU NUMBER
	ADDI	T3,"0"		;CONVERT TO ASCII
	PUSHJ	P,COMTYO##	;...
>; END IFN FTMP
	PUSHJ	P,INLMES##	;ADD A SPACE, ETC.
	ASCIZ	/: /		;...
	MOVE	T1,P1		;GET TEXT ADDRESS
	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
>; 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
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
	$HIGH
	SUBTTL	THE END


SCAEND::!END