Trailing-Edge
-
PDP-10 Archives
-
BB-F493Z-DD_1986
-
10,7/703mon/sclink.mac
Click 10,7/703mon/sclink.mac to
see without markup as text/plain
There are 9 other files named sclink.mac in the archive. Click here to see a list.
;TITLE SCLINK - Session Control Layer Control for DECnet-36
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1976, 1986.
;ALL RIGHTS RESERVED.
SUBTTL V.Brownell & W.Nichols/Tarl
SEARCH D36PAR,SCPAR,MACSYM
SALL
ENTRY SCTL,SCTINI
IFN FTOPS10,<
.CPYRT<1976,1986>
> ;END IFN FTOPS10
IFN FTOPS20,<
SEARCH PROLOG
TTITLE SCLINK,,< - Session Control Layer for DECnet-36>
>
IFN FTOPS10,<
SEARCH F,S
TITLE SCLINK - Session Control Layer Control for DECnet-36
$RELOC
>
D36SYM ;SET UP D36 SPECIFIC PARAMETERS
XRESCD ;Start in extended resident code
SUBTTL Table of Contents
; Table of Contents for SCLINK
;
;
; Section Page
; 1. Table of Contents. . . . . . . . . . . . . . . . . . . 2
; 2. Definitions
; 2.1. Internal References . . . . . . . . . . . . . 3
; 2.2. External References . . . . . . . . . . . . . 4
; 2.3. Accumulators. . . . . . . . . . . . . . . . . 6
; 2.4. Node name/number database . . . . . . . . . . 7
; 2.5. Loopback node block . . . . . . . . . . . . . 8
; 3. Macros
; 3.1. Code-Generating
; 3.1.1. IFxSTATE . . . . . . . . . . . . . . 9
; 3.1.2. NEWSTATE . . . . . . . . . . . . . . 10
; 4. SCTINI - Session Control Initialization. . . . . . . . 11
; 5. SCTPSQ - Grant a PSI interrupt . . . . . . . . . . . . 12
; 6. SCTSTM - Check Active Connect Timers for Expiration. . 13
; 7. SCTSEC - Once-a-second service for SCLINK. . . . . . . 14
; 8. SCTRFJ - Request Second Service for a Link . . . . . . 15
; 9. SCTL's Interlock
; 9.1. Queuing Version . . . . . . . . . . . . . . . 16
; 9.2. Waiting Version . . . . . . . . . . . . . . . 17
; 9.3. Flag Version. . . . . . . . . . . . . . . . . 18
; 10. SCTULK - SCTL's Interlock
; 10.1. Unlock Checks . . . . . . . . . . . . . . . . 19
; 11. NSP.
; 11.1. Function Dispatch Table . . . . . . . . . . . 20
; 11.2. Wait Check Tables
; 11.2.1. Definitons . . . . . . . . . . . . . 21
; 11.3. Wait check tables
; 11.3.1. "Before" NSP. table. . . . . . . . . 22
; 11.3.2. "After" NSP. table . . . . . . . . . 23
; 11.3.3. Routines . . . . . . . . . . . . . . 24
; 11.4. SCTNSF - The Entry to SCLINK from SCMUUO. . . 25
; 11.5. NSFRE - REset all links . . . . . . . . . . . 31
; 11.6. NSFEA - Enter Active State. . . . . . . . . . 32
; 11.7. NSFEP - Enter Passive State . . . . . . . . . 35
; 11.8. NSFRI - Read Connect Information. . . . . . . 36
; 11.9. NSFAC - Accept the Connect. . . . . . . . . . 37
; 11.10. NSFRJ - Reject the Connect. . . . . . . . . . 39
; 11.11. NSFRC - Read Connect Confirm Information. . . 40
; 11.12. NSFSD - Synchronous Disconnect. . . . . . . . 41
; 11.13. NSFAB - Abort and Release . . . . . . . . . . 43
; 11.14. NSFRD - Read Disconnect Data. . . . . . . . . 44
; 11.15. NSFRL - Release the Channel . . . . . . . . . 45
; 11.16. NSFRS - Read the Channel Status . . . . . . . 46
; 11.17. NSFIS - Send Interrupt Data . . . . . . . . . 47
; 11.18. NSFIR - Receive Interrupt Data. . . . . . . . 49
; 11.19. NSFDS - Send Normal Data. . . . . . . . . . . 51
; 11.20. NSFDR - Receive Normal Data . . . . . . . . . 55
; 11.21. NSFSQ - Set Quotas and Goals. . . . . . . . . 57
; 11.22. NSFRQ - Read Quotas and Goals . . . . . . . . 58
; 11.23. NSFJS - Set Job Quotas and Goals. . . . . . . 59
; 11.24. NSFJR - Read Job Quotas and Goals . . . . . . 60
; 11.25. NSFPI - Set PSI Reason Mask . . . . . . . . . 61
; 12. RETFLW - Return current flow controls. . . . . . . . . 62
; 13. SNDDRQ - Send Data Requests. . . . . . . . . . . . . . 63
; 14. RLSLNK - Release a Link. . . . . . . . . . . . . . . . 64
; 15. LLINKS Calls
; 15.1. Entry Vector Table. . . . . . . . . . . . . . 65
; 15.2. SCTRIB - Reserve Input Buffer . . . . . . . . 66
; 15.3. SCTUCG - Uncongestion Call. . . . . . . . . . 67
; 15.4. SCTLCI - Connect Initiate Call. . . . . . . . 68
; 15.5. The Vectored Call Entry Point SCTL. . . . . . 71
; 15.6. SCCCR - Connect Confirmed call from NSP . . . 72
; 15.7. SCDIR - Disconnect Initiate received call . . 73
; 15.8. SCDCR - Disconnect Confirm received call. . . 74
; 15.9. SCODN - Output done call. . . . . . . . . . . 75
; 15.10. SCSEG - Segment received call . . . . . . . . 76
; 15.11. SCDRQ - Data request received call. . . . . . 77
; 15.12. SCNCF - No confidence in port call. . . . . . 78
; 15.13. SCNRS - No resources call . . . . . . . . . . 79
; 15.14. SCCLS - Close Completed call. . . . . . . . . 80
; 15.15. SCNLK - No link call. . . . . . . . . . . . . 81
; 15.16. SCNCM - No communication call . . . . . . . . 82
; 15.17. SCNRN - Not in Run State call . . . . . . . . 83
; 15.18. SCCAK - Got a Connect ACK . . . . . . . . . . 84
; 16. Subroutines
; 16.1. CHKABO - Check SLABO flag . . . . . . . . . . 85
; 16.2. CHKPPN - Check self PPN for validity. . . . . 86
; 16.3. FREMSG - Free a message block . . . . . . . . 87
; 16.4. CONBUF - Invoke Conservative Buffering. . . . 88
; 16.5. FNDSLB - Find SLB given a channel number. . . 89
; 16.6. FNDSBI - Find SLB from SLBid. . . . . . . . . 90
; 16.7. FRESLB - Deallocate a SLB . . . . . . . . . . 91
; 16.8. FRECBP - Free Connect Block . . . . . . . . . 92
; 16.9. CDMCBP - Copy User Data from Message Block. . 93
; 16.10. CPMSCB - Copy User Data from Message Block. . 94
; 16.11. FRESJB - Deallocate a SJB . . . . . . . . . . 95
; 16.12. MAKSLB - Create a SLB, filling in defaults. . 96
; 16.13. MAKSJB - Create a SJB, filling in defaults. . 98
; 16.14. SCSSTS/CHKSTS - Set Status & Inform PSISER. . 99
; 16.15. SCTWKQ - Queue a Link for later call to SCTPSQ 101
; 16.16. SLBMAT - Pattern match connect to passive SLBs 102
; 16.17. CDBMAT - Match Two Connect Blocks . . . . . . 103
; 16.18. STRMAT - Pattern Matcher. . . . . . . . . . . 106
; 16.19. STPTMR - Stop the Connect Initiate Timer. . . 107
; 16.20. STRTMR - Start the Connect Initiate Timer . . 108
; 16.21. TMRREJ - Send a Reject with Reason RSNNRO . . 109
; 16.22. BLDCTX - Build connect message. . . . . . . . 110
; 16.23. PRSCTX - Parse a connect message. . . . . . . 114
; 16.24. CPYS2M - Copy string block to message segment 118
; 16.25. CPYM2S - Copy message data to string block. . 119
; 16.26. SCTGSS - Get segment size for a destination . 120
; 16.27. SCTCSS - Check segment size for a destination 121
; 17. Node name/number database
; 17.1. Initialize. . . . . . . . . . . . . . . . . . 122
; 17.2. Lock/unlock database. . . . . . . . . . . . . 123
; 17.3. Add a node. . . . . . . . . . . . . . . . . . 124
; 17.4. Address to name . . . . . . . . . . . . . . . 125
; 17.5. Name to address . . . . . . . . . . . . . . . 126
; 17.6. Name to NO block. . . . . . . . . . . . . . . 127
; 17.7. Default area #. . . . . . . . . . . . . . . . 128
; 17.8. Hash routine. . . . . . . . . . . . . . . . . 129
; 17.9. Get a bucket. . . . . . . . . . . . . . . . . 130
; 17.10. SCTANL - Add a loopback node name . . . . . . 131
; 17.11. SCTN2L - Convert name to loop circ. . . . . . 132
; 17.12. SCTL2N - Convert loopback circuit . . . . . . 132
; 17.13. SCTCKL - Check for loopback node. . . . . . . 132
; 18. Network management
; 18.1. Dispatch. . . . . . . . . . . . . . . . . . . 133
; 18.2. SET parameter . . . . . . . . . . . . . . . . 134
; 18.3. CLEAR parameter . . . . . . . . . . . . . . . 134
; 18.4. READ parameter. . . . . . . . . . . . . . . . 134
; 18.5. Return list of entity ids . . . . . . . . . . 135
; 18.6. Map node address to node name . . . . . . . . 136
; 18.7. Map node name to node address . . . . . . . . 136
; 18.8. Check loopback node name. . . . . . . . . . . 136
; 18.9. Event
; 18.9.1. Invalid message. . . . . . . . . . . 137
; 18.9.2. CSSE event . . . . . . . . . . . . . 138
; 19. Local SCTL Storage . . . . . . . . . . . . . . . . . . 139
; 20. End of SCLINK. . . . . . . . . . . . . . . . . . . . . 140
SUBTTL Definitions -- Internal References
;These are the routines and variables in SCLINK that are referenced
; by other modules
;Initialization
INTERN SCTINI ;Initialize SCLINK
;Calls from higher layers
INTERN SCTPSQ ;Grant PSI to user
INTERN SCTWKQ ;Queue a link to SCTPSQ
INTERN SCTSEC ;Once-a-second service
INTERN SCTLCW ;Process level interlock grabber
INTERN SCTNSF ;Session control function entry point
IFN FTOPS20 <
INTERN SCTLOK ;Session control interlock
>
;Calls from LLINKS
INTERN SCTRIB ;Reserve input buffer
INTERN SCTUCG ;Congestion
INTERN SCTLCI ;Connect initiate
INTERN SCTL ;LLINKS entry point in general
;Network management
INTERN SCLNMX ;NTMAN entry point
INTERN SCTLNL ;Loopback node name list
INTERN SCTINT ;Incoming timer
INTERN SCTOTT ;Outgoing timer
INTERN LEVT.0 ;LCG event parameter 0
;SJB routines
INTERN FRESJB ;Free a SJB
INTERN MAKSJB ;Allocate a SJB
INTERN CHKSJB ;Check an SJB for SLBs
;Node name and address mapping
INTERN SCTAND ;Add or delete a node
INTERN SCTA2N ;Map a node address to a name
INTERN SCTN2A ;Map a node name to an address
INTERN SCTNDC ;# of local nodes defined (for JNTMAN)
;Loopback nodes
INTERN SCTN2L ;Map node name to loopback node
INTERN SCTCKL ;Check for existance of loopback node
SUBTTL Definitions -- External References
;These are the external references to the D36COM library of routines.
EXT DNGNBF ;GET TOTAL NUMBER OF BUFFERS IN SYSTEM
EXT DNGINI ;INITIALIZE FOR INPUT (DGXYBY)
EXT DNPINI ;INITIALIZE FOR OUTPUT (DPXYBY)
EXT DNPINR ;REINITIALIZE FOR OUTPUT (DPXYBY)
EXT DNP1BY ;PUT ONE BYTE IN MESSAGE
EXT DNP2BY ;PUT TWO BYTES IN MESSAGE
EXT DNPEBY ;PUT AN EXTENSIBLE BYTE IN MESSAGE
EXT DNG1BY ;GET ONE BYTE FROM MESSAGE
EXT DNG2BY ;GET TWO BYTES FROM MESSAGE
EXT DNGEBY ;GET EXTENSIBLE BYTE FROM MESSAGE
EXT DNGMSG ;GET DECNET-36 MESSAGE BLOCK
EXT DNFMSG ;FREE MESSAGE BLOCK
EXT DNMINI ;REUSE A MESSAGE BLOCK
EXT DNLENG ;GET THE MESSAGE LENGTH
EXT DNSLNG ;FIND THE SEGMENT LENGTH
EXT DNGWDS ;GET SOME WORDS
EXT DNGWDP ;Get some words in process context
EXT DNGWDZ ;GET SOME ZEROED WORDS
EXT DNGWZP ;Get som zeroed words in process context
EXT DNFWDS ;FREE SOME WORDS
EXT DNSWDS ;SMEAR SOME WORDS
EXT DNBKBY ;GO BACKWARDS SOME BYTES
EXT DNSKBY ;SKIP SOME BYTES
EXT DNSMRK ;SET MARK IN MESSAGE
EXT DNGMRK ;POSITION AT MARK IN MESSAGE
EXT DNLMSS ;LINK MESSAGE SEGMENT INTO MESSAGE BLOCK
EXT DNCPYW ;COPY WORDS WITH BLT OR XBLT
EXT DNCM2U ;COPY MESSAGE TO USER BUFFER (TOPS-10)
EXT DNCU2M ;COPY USER BUFFER TO MESSAGE (TOPS-10)
EXT DNCM2B ;COPY MESSAGE TO MONITOR BUFFER
EXT DNCB2M ;COPY MONITOR BUFFER TO MESSAGE
EXT DNGTIM ;GET CURRENT TIME IN MS
EXT DCNTSB ;TOTAL SYSTEM BUFFERS, USED AND UNUSED
EXT DCNCON ;NON-ZERO IF SYSTEM IS CONGESTED
EXT DCNRSB ;RESERVED BUFFERS, MODIFIED UNDER D36OFF
; TO PROTECT AGAINST SCTRIB CALL FROM LLINKS
EXT DCNRHT ;HIGH TIDE FOR DCNRSB
EXT DCNRIF ;INPUT RESERVATION FAILURES
EXT DCNROF ;OUTPUT RESERVATION FAILURES
EXT NTPARM ;Network management parameter processing
EXT EVPBYT ;Network management event parameter output
EXT EVP2BT ; " " " " "
;Entries into NSP.
EXT NSP ;THE MAIN ENTRY TO NSP
EXT NSPINI ;INITIALIZATION ROUTINE FOR NSP
EXT NSPEVT ;SIGNAL AN NSP-LEVEL EVENT, USING EVENT MACRO
; FROM SCPAR.UNV
;Entry into ROUTER.
;Calls to ROUTER violate the layering. However, it is necessary to
; ask ROUTER for the maximum buffer sizes to a given destination node in order
; to implement 'big buffers' on the NI.
EXT RTRGBS ;Get maximum buffer size for a node
EXT RTRCBS ;Check maximum buffer size for a node
;Here are some external references to system things.
EXT RTN ;RETURN
EXT RSKP ;SKIP RETURN
EXT EV96.0 ;Determines whether CSSE event 96.0 is logged
IFN FTOPS10,<
EXT BITTBL ;TABLE OF BIT POSITIONS
BITS==BITTBL ;SCLINK USES BITS TABLE
>; END IFN FTOPS10
IFN FTOPS20,<
EXT ASGVAS ;Assign virtual address space
>
;Externals for TOPS10 interlock management
IFN FTOPS10,< ;EXTERNAL FOR SMP INTERLOCK BREAKER
EXT SCTLOK ;INTERLOCK WORD
EXT SCTLKO ;INTERLOCK OWNER WORD
>
;External data.
EXT %SCHDR ;MAX LENGTH OF HEADERS BELOW SCTL
EXT RTRBSZ ;CELL CONTAINING ROUTER'S BUFFER SIZE
EXT IBBLK ;DECnet initialization block
EXT RTRHOM ;CELL CONTAINING ROUTER'S HOME AREA
EXT RTRMXN ;MAXIMUM NODE ADDRESS IN AREA
EXT %SCP2Q ;"PHASE II" QUOTA
EXT %SCINT ;DEFAULT INCOMING TIMER VALUE
EXT %SCOTT ;DEFAULT OUTGOING TIMER VALUE
EXT %RTMXN ;MAX-NODES
SUBTTL Definitions -- Accumulators
;These are some local AC defintions for Session Control.
SL=FREE1 ;SL POINTS TO THE CURRENT SC LINK BLOCK
SA=FREE2 ;SA POINTS TO THE ARGUMENT BLOCK
PURGE FREE1,FREE2 ;WE DON'T NEED THIS SYMBOL ANYMORE
SUBTTL Definitions -- Node name/number database
;Calculate number of buckets in database.
SCNHSZ==^D223 ;Hash table size
NRNOPB==^D3 ;Nodes per bucket
;The LDAREA macro extracts an area # from a node address
DEFINE LDAREA(DST,SRC) <
LDB DST,[POINTR(SRC,RN%ARE)]
>
;The STAREA macro stores an area # into a node address
DEFINE STAREA(SRC,DST) <
DPB SRC,[POINTR(DST,RN%ARE)]
>
;The LDNOD macro extracts a local node index from a node address
DEFINE LDNODE(DST,SRC) <
LDB DST,[POINTR(SRC,RN%NOD)]
>
;The BEGSTR BU defines a bucket
BEGSTR BU
WORD NXT ;Pointer to next bucket
WORD NO1,<NO.LEN * NRNOPB>
ENDSTR
;The BEGSTR NO defines a single node in a bucket
BEGSTR NO ;Represents a single node
WORD NAM ;Node name
WORD ADR ;Node address
ENDSTR
SUBTTL Definitions -- Loopback node block
BEGSTR LN
WORD NXT ;PTR TO NEXT LOOPBACK NODE BLOCK
WORD NAM ;LOOPBACK NODE NAME
WORD CIR ;LOOPBACK CIRCUIT
ENDSTR
SUBTTL Macros -- Code-Generating -- IFxSTATE
;Use: AC/ One of the .NSSxx state codes
;
;a) IFSTATE AC,<OP,CC,RJ>
; executed if match found
;b) IFSTATE AC,<OP,CC,RJ>,LABEL (Go there if match found)
DEFINE IFSTATE(AC,STATES,GLABEL),<IFST1(AC,<STATES>,<GLABEL>,N,GE,L)>
;Use: AC/ One of the .NSSxx state codes
;
;a) IFNSTATE AC,<OP,CC,RJ>
; executed if match NOT found
;b) IFNSTATE AC,<OP,CC,RJ>,LABEL (Go there if match NOT found)
DEFINE IFNSTATE(AC,STATES,GLABEL),<IFST1(AC,<STATES>,<GLABEL>,E,L,GE)>
DEFINE IFST1(AC,STATES,GLABEL,MOD1,MOD2,MOD3),<
ZZ==0
ZZCNT==0
IRP STATES,<ZZ==ZZ ! 1B<.NSS'STATES>
ZZCNT==ZZCNT+1>
IFE ZZCNT-1,<
CAI'MOD1 AC,.NSS'STATES
IFNB <GLABEL>,<
IFIDN <GLABEL>,<RTN>,<RET>
IFDIF <GLABEL>,<RTN>,<JRST GLABEL>
>>
IFG ZZCNT-1,< ;;IF MORE THAN ONE STATE TESTED
MOVX CX,ZZ
ROT CX,(AC)
IFB <GLABEL>,< SKIP'MOD2 CX >
IFNB <GLABEL>,< JUMP'MOD3 CX,GLABEL >
>
PURGE ZZCNT,ZZ
>
SUBTTL Macros -- Code-Generating -- NEWSTATE
;NEWSTATE will change the state of the link and call SCSSTS to tell
;PSISER to possibly let the user know about the change.
DEFINE NEWSTATE(suffix),<
MOVX T1,.NSS'suffix ;;SET UP STATE
CALL SCSSTS ;;LET PSISER KNOW ABOUT IT
TRACE SC,New State: suffix
>
SUBTTL SCTCCR - Compute Core Requirements
;SCTCCR computes SCLINK's core requirements.
;Call:
; PUSHJ P,SCTCCR
;Returns:
; T1/ Size of SCLINK core
IFN FTOPS10,<
SCTCCR::MOVEI T1,SCNHSZ ;HASH TABLE SIZE
OPSTR <ADD T1,>,IBMXA,+IBBLK ;PLUS NUMBER OF NODES IN AREA
ADDI T1,1 ;AND AN EXTRA WORD FOR NODE 0
RET ;AND RETURN
>; END IFN FTOPS10
SUBTTL SCTINI - Session Control Initialization
;SCTINI - Session Control Initialization
;
; Call:
; IBBLK filled in
;
; Return:
; RET ;COULDN'T INITIALIZE DUE TO RESOURCE FAILURE
; RETSKP ;INITIALIZED
;
; Uses: T1-T4
;
; Context:
; Process
XSWAPCD
SCTINI: TRACE SC,<Initializing Session Control>
;Initialize node name/number database, then call NSP to initialize itself
; and ROUTER
CALL SCTNIN ;Initialize node name/number database
RET ; -failed, return error
CALLRET NSPINI ;NSP, you can fly now!
XRESCD ;Back to resident code
SUBTTL SCTPSQ - Grant a PSI interrupt
;SCTPSQ - Grant a PSI interrupt for user
;
; Call: T1/ SJB Pointer
;
; Return:
; RET ;IF NOTHING IN QUEUE
; RETSKP ;IF FOUND AN SLB QUEUED
; T1+T2/ STRUCTURE PS, SEE SCPAR
;
; Uses:
;Note that this routine is not under the interlock
;Note that if we use T5 or T6 in this routine, we have to save
;them for caller.
XRENT SCTPSQ ;Run in extended resident code
D36OFF ;#AVOID PROBLEMS WITH SLPSI FLAG
DEQUE T4,SJ.PSQ(T1),SL.NXP,SCTPQ1 ;#ANYTHING ON THE PSI Q?
SETZRO SLPSI,(T4) ;#NOT ON THE PSI Q ANY MORE
D36ON
IF1,IFN PS.MOR,<PRINTX SCTPSQ needs PSMOR to be in T1>
MOVE T3,T1 ;GET POINTER TO SJB
LOAD T1,SLSST,(T4) ;NO INTERLOCK, DON'T CALL CHKSTS
STOR T1,PSSTS,+T1 ;STORE FOR CALLER (IN T2)
TMNE QHBEG,+SJ.PSQ(T3) ;MORE SLBS ON PSI Q?
TXO T1,PSMOR ;YES, SET THE MORE FLAG FOR CALLER
LOAD T3,SLCHN,(T4) ;GET CHANNEL NUMBER
STOR T3,PSCHN,+T1
LOAD T3,SLPSM,(T4) ;GET PSI MASK
STOR T3,PSPSM,+T1
RETSKP ;SUCCESS RETURN
;Here if DEQUE found nothing
SCTPQ1: D36ON
RET
SUBTTL SCTSTM - Check Active Connect Timers for Expiration
;SCTSTM - Check active connect timers for expiration
;
; Call:
; With nothing special
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCTSTM: SAVEAC <SA,SL,P1,P2> ;SAVE THE JOB AND LINK BLOCK POINTERS
LOAD SA,QHBEG,+SCTSJQ ;POINT TO THE FIRST SJB
TRNA
SCTST1: LOAD SA,SJNXT,(SA) ;GET THE NEXT SJB IN LIST
JUMPE SA,RTN ;NO MORE, JUST RETURN
JE SJCTA,(SA),SCTST1 ;IF THERE ARE NO TIMERS ACTIVE FOR JOB
; JUST LOOK AT THE NEXT GUY
LOAD P1,SJCHC,(SA) ;GET THE COUNT OF ENTRIES IN SLB TABLE
LOAD P2,SJCHT,(SA) ;POINT TO THE SLB TABLE
SCTST2: SKIPN SL,(P2) ;DO WE HAVE AN SLB?
JRST SCTST3 ;NO, CHECK THE NEXT ONE
JN <SLFSL,SLLBC>,(SL),SCTST3 ;YES, IGNORE IF ALREADY CLOSING
LOAD T1,SLSTA,(SL) ;GET THE STATE
IFSTATE T1,CR,SCTST4 ;CHECK THE INCOMING CONNECT TIMER
IFSTATE T1,CS,SCTST5 ;CHECK THE OUTGOING CONNECT TIMER
SCTST3: ADDI P2,1 ;INCREMENT SLB POINTER
SOJG P1,SCTST2 ;ANY MORE LEFT?
JRST SCTST1 ;NO, CHECK THE NEXT JOB
;Here with a SLB in CR state. Check the incoming timer for expiration.
SCTST4: CALL DNGTIM ;GET THE CURRENT TIME
OPSTR <SUB T1,>,SLCTM,(SL) ;FIND TIME SINCE TIMER STARTED
CAMGE T1,SCTINT ;HAS IT EXPIRED?
JRST SCTST3 ;NO, LOOK AT NEXT SLB
CALL TMRREJ ;YES, SEND REJECT
JRST SCTST3 ;ALLOCATION FAILURE, LEAVE TIMER RUNNING
CALLRET SCTST6 ;REJECT, STOP TIMERS AND CHECK THE NEXT ONE
;Here with a SLB in CS state. Check the outgoing timer for expiration.
SCTST5: CALL DNGTIM ;GET THE CURRENT TIME
OPSTR <SUB T1,>,SLCTM,(SL) ;FIND TIME SINCE TIMER STARTED
CAMGE T1,SCTOTT ;HAS OUTGOING TIMER EXPIRED?
JRST SCTST3 ;NO, LOOK AT NEXT SLB
MOVX T1,RSNNRO ;YES, GET 'NO RESPONSE FROM OBJECT' REASON CODE
STOR T1,SLRSN,(SL) ;STORE REASON FOR INTERESTED CALLER
NEWSTATE RJ ;TELL USER LINK IS REJECTED
SCTST6: CALL STPTMR ;STOP THE TIMERS
JRST SCTST3 ; AND CHECK THE NEXT ONE
SUBTTL SCTSEC - Once-a-second service for SCLINK
;SCTSEC - Once-a-second service for Session Control
;
; Once a second the following things are checked:
; connect timers
; slb's that can be freed
;
; Call:
; with nothing, every second
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
XRESCD
SCTSEC:
IFN FTOPS10 <
SEC1 ;RUN ALL OUR JUNK IN SECTION 1
>
SAVEAC <MB,MS,T5,T6,SL,SA,P1,P2>
SETOM SCTJFF ;TELL SCTULK WE NEED SECOND SERVICE
CALLRET SCTLCF ;GET INTERLOCK, CALL SCTSES
SCTSES: SKIPE SCTCTA ;ARE THERE ANY OUTSTANDING CONNECTS?
CALL SCTSTM ;SCAN FOR RUNNING CONNECT TIMERS
;We must not continue processing after getting a no-resources return
;because the procedure which gave that return put the current port
;back on the second-request queue. If we were to continue along that
;queue, we would visit that port over and over forever.
SCTSS1:!DEQUE SL,SCTJFQ,SL.JFQ,RTN ;RETURN WHEN Q EMPTY
SETZRO SLJFR,(SL) ;NO LONGER ON THE SECOND-REQ Q
TMNN SLFSL,(SL) ;SKIP IF SLB NEEDS TO BE FREED
Repeat 0,< ;See comment below and at SNDDRQ
JRST SCTSS2 ;NO, SEE IF WE NEED DRQ CHECK
>
Repeat 1,<
JRST SCTSS1 ;Should never happen, but if! just loop back
>
CALL SCTSFR ;YES, GET RID OF IT
CALLRET SCTRFJ ;LEAVE, REQUESTING SERVICE AGAIN
JRST SCTSS1 ; AND CHECK THE NEXT CHANNEL
;This code to resend DRQ is commented out since it is never used.
; See comment at SNDDRQ for more information
Repeat 0,<
SCTSS2: OPSTR <SKIPE T1,>,SLDRR,(SL) ;ARE THERE ANY DATA REQUESTS?
CALL SCTJDR ;YES, RESEND THE DATA REQUESTS
CALLRET SCTRFJ ;LEAVE, REQUESTING SERVICE AGAIN
JRST SCTSS1 ;GET NEXT SLB THAT NEEDS SERVICE
>
;Here to free an SLB that we are finished with
SCTSFR: JN SLBSY,(SL),RTN ;CAN'T FREE IT NOW, TRY LATER
CALL FRESLB ;CLEAN UP THAT ONE.
RETSKP ;SUCCESS
Repeat 0,<
;Here with a SLB that needs to have DRQs resent.
SCTJDR: TXZ T2,MBOTH ;ON THE NORMAL SUB-LINK
CALL SNDDRQ ;SEND THOSE DATA REQUESTS
RET ;CAN'T, LET CALLER HANDLE THIS
SETZRO SLDRR,(SL) ;WE SENT THE DATA REQUESTS
RETSKP ; AND RETURN
> ;End repeat 0
SUBTTL SCTRFJ - Request Second Service for a Link
;SCTRFJ - Request Second Service for a Link
;
; Call:
; SL/ The SLB for which service is requested
;
; Return:
; RET ;ALWAYS WITH ALL TEMP ACS SMASHED
;
; Uses: T1
SCTRFJ: MOVX T1,SLJFR ;GET QUEUED-FOR-SERVICE FLAG
TDNE T1,SL.JFR(SL) ;ALREADY QUEUED?
RET ;YES, DON'T Q AGAIN
IORM T1,SL.JFR(SL) ;NO, WILL BE NOW THOUGH
ENDQUE SL,SCTJFQ,SL.JFQ,T1
RET
SUBTTL SCTL's Interlock -- Queuing Version
;SCTLCQ - Interlock routine for interrupt level callers
;
; Call:
; T1/ Address of processor to call with the interlock
; MB/ Pointer to Message Block with arguments stored
; or zero if called from SCTJIF
;
; Return:
; RET ;ALWAYS WITH ALL TEMP ACS SMASHED
;
; Uses: T1
;
;If it could not get the interlock, it queues the message block with its
;arguments. When the interlock is given up, the queue is checked and
;if it has a message on it, it will service it.
SCTLCQ: STOR T1,MBPRC,(MB) ;SAVE THE PROCESSING PROCEDURE
D36OFF ;GET GLOBAL INTERLOCK FOR ENDQUE BELOW
AOSN SCTLOK ;TEST AND SET THE INTERLOCK
JRST SCTLQ1 ;GO PROCESS, NOW THAT WE HAVE THE LOCK
;Here when we have to queue the message and dismiss.
ENDQUE MB,SCTPRQ,MB.NXT,T1 ;QUEUE THE MESSAGE
D36ON ;TURN INTERLOCK OFF
RET
;Here to process the message now.
SCTLQ1: APRID SCTLKO ;SET THE OWNER OF THE INTERLOCK
IFN FTOPS20,<
CONSO PI,1B<DLSCHN+^D20> ;AT DTE PI LEVEL?
CSKED ;NO, ASSURE WE GET THROUGH THIS QUICKLY
>;END IFN FTOPS20 ;MUSTN'T CALL CSKED AT INTERRUPT LEVEL
D36ON ;TURN INTERLOCK OFF
LOAD T1,MBAR1,(MB) ;GET THE FIRST ARGUMENT
LOAD T2,MBAR2,(MB) ; SECOND
LOAD T3,MBAR3,(MB) ; THIRD
OPSTR <CALL @>,MBPRC,(MB) ;GET THE PROCESSOR
CALLRET SCTULK ;DO THE UNLOCK CHECKS
SUBTTL SCTL's Interlock -- Waiting Version
;SCTLCW - Interlock routine for process level callers
;
; Call:
; T1/ Address of processor to call with the interlock
; MB/ Pointer to Message Block with arguments stored
;
; Return:
; RET ;ALWAYS WITH ALL TEMP ACS SMASHED
;
; Uses: T1
;
;This version of the interlock will spin on SCTLOK until it is freed.
;This is to be called only from process level, thus it will only spin
;if another process or interrupt level user has it on another processor.
;It will not fight with any other process level users on this processor
;since only one can be active on any one processor at any one time.
;
;Note that SCTLOK must be uncached if this is a multiprocessor system.
SCTLCW:
SAVEAC <MB,SA> ;TEMPORARY UNTIL AC-TRASHING BUG FOUND.
;Even though we don't really have to store the routine address in
;the message block here, we do because its a convenient debugging tool.
STOR T1,MBPRC,(MB) ;SAVE THE PROCESSING PROCEDURE
IFN FTOPS10,<
SCTLW1: SKIPGE SCTLOK ;TEST INTERLOCK TO SEE IF WE HAVE A CHANGE
AOSE SCTLOK ;TEST AND SET THE INTERLOCK
JRST SCTLW1 ;ITS LOCKED, SPIN UNTIL ITS FREED
APRID SCTLKO ;SET THE OWNER OF THE INTERLOCK
>;END IFN FTOPS10 ; CAN ONLY BE COMPETING WITH ANOTHER
; PROCESSOR ON TOPS10
IFN FTOPS20,<
SCTLW1: CSKED ;ASSURE WE GET THROUGH THIS QUICKLY
AOSN SCTLOK ;TEST AND SET THE INTERLOCK
JRST SCTLW3 ;ITS OK, GO USE IT
ECSKED ;NO, UNDO THE CSKED ABOVE.
SKIPE INSKED ;IN USE, ARE WE AT SCHEDULAR LEVEL?
JRST SCTLW2 ;YES
MOVE T1,[MSEC1,,SCTLWB] ;No, set up scheduler test
MDISMS ;WAIT FOR COMPETING PROCESS TO FINISH
JRST SCTLW1 ;OK, LETS TRY AGAIN
;Must run in section 1 since the data structure used to keep the scheduler
; test routine is currently only 18-bits wide.
RESCD
SCTLWB: SKIPL SCTLOK ;IS SESSION CONTROL LOCK FREE YET?
JRST (T4) ;NO, SLEEP ON
JRST 1(T4) ;YES, WAKE UP FORK
XRESCD
SCTLW2: BUG.(CHK,SCTBWK,SCLINK,SOFT,<SCTNSF call from sched without lock>,,<
Cause: The DECnet entry point SCTNSF has been called from scheduler
level when the Session Control interlock was locked.
Action: All scheduler level routines which call SCTNSF should first
check SCTLOK. If SCTLOK is not -1, then the caller should
wait for the next scheduler cycle before calling SCTNSF.
Inspect the stack to find out who the offender is.
>)
RET ;LET CALLER WORRY ABOUT NO DECNET ACTION
SCTLW3:
>;END IFN FTOPS20
;Here to process the message now.
LOAD T1,MBAR1,(MB) ;GET THE FIRST ARGUMENT
LOAD T2,MBAR2,(MB) ; SECOND
LOAD T3,MBAR3,(MB) ; THIRD
OPSTR <CALL @>,MBPRC,(MB) ;GET THE PROCESSOR
CALLRET SCTULK ;DO THE UNLOCK CHECKS
SUBTTL SCTL's Interlock -- Flag Version
;SCTLCF - Interlock routine for Flagged Routines
;
; Call:
; T1/ Address of processor to call with the interlock
; SCTJFF or SCTUCF set non-zero for SCTULK
;
; Return:
; RET ;ALWAYS WITH ALL TEMP ACS SMASHED
;
; Uses: T1
;
SCTLCF:
;We have no message block here, so we cannot store any processor
;address. Caller has set a SCTxxF flag instead.
;
;All we have to do here is call the unlocker, for it will check
;the Service flags SCTJFF and SCTUCF.
;
IFN FTOPS20,<
CONSO PI,1B<DLSCHN+^D20> ;AT DTE PI LEVEL?
CSKED ;NO, ASSURE WE GET THROUGH THIS QUICKLY
>;END IFN FTOPS20 ;MUSTN'T CALL CSKED AT INTERRUPT LEVEL
AOSE SCTLOK ;TEST AND SET THE INTERLOCK
IFN FTOPS20,<
IFNSK.
CONSO PI,1B<DLSCHN+^D20> ;NOT FREE, LEAVE NOW. AT DTE PI LEVEL?
ECSKED ;NO, UNDO CSKED FROM ABOVE.
RET ;LEAVE.
ENDIF.
>;END IFN FTOPS20
IFN FTOPS10,<
RET ;NOT FREE, LEAVE NOW
>;END IFN FTOPS10
APRID SCTLKO ;SET THE OWNER OF THE INTERLOCK
CALLRET SCTULK ;AND DO THE UNLOCK CHECKS.
SUBTTL SCTULK - SCTL's Interlock -- Unlock Checks
;SCTULK - All interlock routines call SCTULK to unlock
;
; Call:
; No args in registers
; Called with the Session Control Interlock still on
;
; Return:
; RET ;ALWAYS WITH ALL TEMP ACS SMASHED
;
; Uses: T1
;
SCTULK: SAVEAC <MB,MS,SL> ;SAVE SOME ACS
;It is OK to have the window between SKIPE SCTJFF and SETZM SCTJFF
;since the worst that can happen is that we lose a second interrupt.
;If we are so close to the next second when we respond to the last one
;that we fall into the window, its just as well not to introduce more
;overhead by closing the window!
SCTUL1: SETZ T1, ;LOAD UP A ZERO TO TO TURN FLAG OFF
EXCH T1,SCTJFF ;NEED TO DO
SKIPE T1 ; CLOCK LEVEL STUFF?
CALL SCTSES ;YES, GIVE SECOND SERVICE
SETZ T1, ;LOAD UP A ZERO TO TO TURN FLAG OFF
EXCH T1,SCTUCF ;NEED TO DEAL WITH
SKIPE T1 ; CONGESTION RELIEF?
CALL SCIUCG ;YES, DO SO
D36OFF ;TURN OF THE INTERRUPTS
DEQUE MB,SCTPRQ,MB.NXT,SCTUL2 ;DEQUEUE MSG FROM PROCESS Q
D36ON ;UNDO THE D36OFF
LOAD T1,MBAR1,(MB) ;GET THE FIRST ARGUMENT
LOAD T2,MBAR2,(MB) ; SECOND
LOAD T3,MBAR3,(MB) ; THIRD
OPSTR <CALL @>,MBPRC,(MB) ;GET THE PROCESSOR
JRST SCTUL1 ;PROCESS THE NEXT ONE
SCTUL2: SETOM SCTLKO ;CLEAR THE INTERLOCK OWNER
SETOM SCTLOK ;TURN OFF THE INTERLOCK
D36ON ;UNDO THE D36OFF
IFN FTOPS20,<
CONSO PI,1B<DLSCHN+^D20> ;AT DTE PI LEVEL?
ECSKED ;NO, UNDO THE CSKED WE DID BEFORE
>;END IFN FTOPS20 ;MUSTN'T CALL ECSKED AT INTERRUPT LEVEL
RET ; AND RETURN
SUBTTL NSP. -- Function Dispatch Table
;Define some macros to set up the dispatch table for the NSP. UUO functions.
DEFINE INIDSP(PREFIX,LABEL,START<0>,FSTNAM<MN>),<
PREFIX''FSTNAM==START
%%%CTR==START-1
DEFINE DSP(NAME),<
%%%CTR==%%%CTR+1 ;;INCREMENT THE COUNTER
IFN <%%%CTR-PREFIX''NAME>,<
PRINTX ?Function PREFIX''NAME in SCLINK not in
PRINTX ? the same order as in SCPAR.UNV
PASS2
END>
IFIW <LABEL''NAME & 777777>> ;;ENTRY POINT FOR INDIRECT CALL
DEFINE ENDDSP(MAXNAM<MX>),<
PREFIX''MAXNAM==%%%CTR>
>
;This is the table which is used to find the entry vector to for a specific
;NSP. function. Symbols are also defined in the for .NSFxx for each of the
;function types.
NSFNT: ;START OF THE TABLE
INIDSP .NSF,NSF,0
DSP RE ;RESET ALL CHANNELS
DSP EA ;ENTER ACTIVE STATE
DSP EP ;ENTER PASSIVE STATE
DSP RI ;READ CONNECT INFORMATION
DSP AC ;ACCEPT THE CONNECT
DSP RJ ;REJECT THE CONNECT
DSP RC ;READ CONNECT CONFIRM INFORMATION
DSP SD ;SYNCHRONOUS DISCONNECT
DSP AB ;ABORT
DSP RD ;READ DISCONNECT DATA
DSP RL ;RELEASE THE CHANNEL
DSP RS ;READ THE CHANNEL STATUS
DSP IS ;SEND INTERRUPT DATA
DSP IR ;RECEIVE INTERRUPT DATA
DSP DS ;SEND NORMAL DATA
DSP DR ;RECEIVE NORMAL DATA
DSP SQ ;SET QUOTAS
DSP RQ ;READ QUOTAS
DSP JS ;SET JOB QUOTAS
DSP JR ;READ JOB QUOTAS
DSP PI ;SET PSI REASON MASK
ENDDSP
SUBTTL NSP. -- Wait Check Tables -- Definitons
;The following definitions are for the wait check tables. The tables
;are used to find out if session control should wait for a condition
;when the user has set the NS.WAI bit. Each table is indexed by
;function number and returns in T1 a value which means one of:
XP CW.ERR,0 ;GIVE THE USER A UNEXPECTED STATE ERROR
XP CW.NWA,1 ;DON'T BOTHER WAITING
XP CW.WAI,2 ;WAIT FOR SOME MORE TIME
XP CW.SAT,3 ;WAIT FOR SATISFYING COND BEFORE PROCEEDING
XP CW.DAT,4 ;WAIT FOR MORE DATA TO BE SENT
BEGSTR CF ;SEE CHKFOR, BELOW
FIELD IFI,1 ;THE SIGN BIT IS RESERVED FOR IFIW FLG
FILLER 11 ;ROOM FOR SOME FUNCTION FLAGS
FIELD CHN,1 ;SET IF A CHANNEL IS REQ'D FOR THIS FCN
HWORD TST ;LOCAL ADDRESS OF TESTER FUNCTION
ENDSTR
XP CHNREQ,1 ;CHANNEL REQUIRED FOR FUNCTION
XP NOCHAN,0 ;NO CHANNEL REQ'D
;Define some macros to set up the table.
DEFINE INITAB(START<0>),<
%%%CTR==START-1
DEFINE CHKFOR(func,reqchn,tester),<
%%%CTR==%%%CTR+1
IFN <%%%CTR-.NSF'func>,<
PRINTX ?NSP. Function .NSF'func in SCLINK not in
PRINTX ? the same order as in SCPAR.UNV
PASS2
END>
;;The following doubtful format is designed to prevent MACRO from
;;going Polish and thus encountering its bugs.
IFIW reqchn,tester ;SEE BEGSTR CF, ABOVE
>
DEFINE ENDTAB,<
PURGE CHKFOR,...TST
>>
;CHKSTA checks for one of STATES, returning successfully if in WAISTA
;and the wait bit is off.
DEFINE CHKSTA(SUCSTA,WAISTA),<[IFSTATE T2,<SUCSTA>,NOWAIT
IFNB <WAISTA>,< IFSTATE T2,<WAISTA>,WAITMORE >
JRST BLEWIT]
>
;CHKSTE checks for one of STATES, returning an error if in WAISTA
;and the wait bit is off.
DEFINE CHKSTE(SUCSTA,WAISTA),<[ IFSTATE T2,<SUCSTA>,NOWAIT
IFNB <WAISTA>,< JE SAWAI,(SA),BLEWIT
IFSTATE T2,<WAISTA>,WAITMORE >
JRST BLEWIT]
>
;CHKBIT checks for on of the .NSxxx status bits.
;CONDSTATES are conditional states, in which we will allow a data or
;interrupt read only if there is something queued now, else the state
;is illegal. We don't want the poor user who sets the wait bit to hang
;in DR or DC state forever!
DEFINE CHKBIT(BIT,STATES,CONDSTATES),<[
IFB <STATES>,<PRINTX ?No STATE(s) declared for CHKBIT macro>
IFB <CONDSTATES>,IFNSTATE T2,<STATES>,BLEWIT
IFNB <CONDSTATES>,IFNSTATE T2,<STATES,CONDSTATES>,BLEWIT
TXNE T1,NS'BIT
JRST NOWAIT
IFNB <CONDSTATES>,IFNSTATE T2,<STATES>,BLEWIT
JRST WAITMORE]
>
SUBTTL NSP. -- Wait check tables -- "Before" NSP. table
;The following is the wait table which is checked before the NSP.
;function is called. This table is indexed by function type and
;returns CW.xxx as explained above.
;*Note* The macro seems to rely on the address argument not going
; polish. As SCLINK now runs in section 6, this may happen if you
; change anything below, including moving any of the routines (for
; instance NOWAIT) to another psects. Beware!
SCTWTB:
INITAB
CHKFOR RE,NOCHAN,NOWAIT
CHKFOR EA,NOCHAN,NOWAIT
CHKFOR EP,NOCHAN,NOWAIT
IFN FTOPS10,<CHKFOR RI,CHNREQ,CHKSTE(CR,CW)> ;SUCCESS STATE,WAITMORE STATE
IFN FTOPS20,<CHKFOR RI,CHNREQ,NOWAIT>
CHKFOR AC,CHNREQ,CHKSTA(CR) ;SUCCESS STATE,WAITMORE STATE
CHKFOR RJ,CHNREQ,CHKSTA(CR) ;SUCCESS STATE,WAITMORE STATE
IFN FTOPS10,<CHKFOR RC,CHNREQ,CHKSTE(RN,CS)> ;ERROR IF CS STATE AND NS.WAI=0
IFN FTOPS20,<CHKFOR RC,CHNREQ,NOWAIT>
CHKFOR SD,CHNREQ,CHKSTA(RN) ;SUCCESS STATE,WAITMORE STATE
CHKFOR AB,CHNREQ,CHKSTA(RN) ;SUCCESS STATE,WAITMORE STATE
IFN FTOPS10,<CHKFOR RD,CHNREQ,CHKSTA(<DR,RJ>)> ;SUCCESS STATE,WAITMORE STATE
IFN FTOPS20,<CHKFOR RD,CHNREQ,NOWAIT>
CHKFOR RL,CHNREQ,NOWAIT
CHKFOR RS,CHNREQ,NOWAIT
CHKFOR IS,CHNREQ,CHKBIT(IDR,<CS,RN>)
CHKFOR IR,CHNREQ,CHKBIT(IDA,<CS,RN,DS>,<DR,DC>)
CHKFOR DS,CHNREQ,CHKBIT(NDR,<CS,RN>)
CHKFOR DR,CHNREQ,CHKBIT(NDA,<CS,RN,DS>,<DR,DC>)
CHKFOR SQ,CHNREQ,NOWAIT
CHKFOR RQ,CHNREQ,NOWAIT
CHKFOR JS,CHNREQ,NOWAIT
CHKFOR JR,CHNREQ,NOWAIT
CHKFOR PI,CHNREQ,NOWAIT
ENDTAB
SUBTTL NSP. -- Wait check tables -- "After" NSP. table
;The following is the wait table which is checked after the NSP. function
;is called. This table is indexed by function type and returns CW.xxx
;*Note* See comment at SCTWTB about changing the table
SCTWTA:
INITAB
CHKFOR RE,NOCHAN,NOWAIT
CHKFOR EA,CHNREQ,CHKSTA(RN,CS) ;SUCCESS STATE,WAITMORE STATE
CHKFOR EP,CHNREQ,CHKSTA(CR,CW) ;SUCCESS STATE,WAITMORE STATE
CHKFOR RI,CHNREQ,NOWAIT
CHKFOR AC,CHNREQ,CHKSTA(RN) ;SUCCESS STATE,WAITMORE STATE
CHKFOR RJ,CHNREQ,NOWAIT
CHKFOR RC,CHNREQ,CHKSTA(RN,CS) ;SUCCESS STATE,WAITMORE STATE
CHKFOR SD,CHNREQ,CHKSTA(DC,DS) ;SUCCESS STATE,WAITMORE STATE
CHKFOR AB,CHNREQ,CHKSTA(DC,DS) ;SUCCESS STATE,WAITMORE STATE
CHKFOR RD,CHNREQ,NOWAIT
CHKFOR RL,CHNREQ,NOWAIT
CHKFOR RS,CHNREQ,NOWAIT
CHKFOR IS,CHNREQ,NOWAIT
CHKFOR IR,CHNREQ,NOWAIT
CHKFOR DS,CHNREQ,WAITDAT
CHKFOR DR,CHNREQ,WAITSAT
CHKFOR SQ,CHNREQ,NOWAIT
CHKFOR RQ,CHNREQ,NOWAIT
CHKFOR JS,CHNREQ,NOWAIT
CHKFOR JR,CHNREQ,NOWAIT
CHKFOR PI,CHNREQ,NOWAIT
ENDTAB
SUBTTL NSP. -- Wait check tables -- Routines
;The following routines perform the correct action for the function. They
;are dispatched to by the "before" and "after" tables.
;Don't wait any longer.
NOWAIT: MOVX T1,CW.NWA
RET
;Error (possibly expected) occured.
BLEWIT: MOVX T1,CW.ERR
RET
;Wait some more.
WAITMO: MOVX T1,CW.WAI
RET
;Loop to do it again.
WAITSAT:
MOVX T1,CW.SAT
RET
;Wait if we are to get more data.
WAITDAT:
MOVX T1,CW.DAT
RET
SUBTTL NSP. -- SCTNSF - The Entry to SCLINK from SCMUUO
;SCTNSF - Perform a NSP. UUO function
;
; Call:
; T1/ Pointer to Message Block in SA format (See BEGSTR SA in D36PAR)
;
; Return:
; RET ;ALWAYS WITH SJERR CONTAINING A ZERO FOR SUC.
; ; AND A NON-ZERO ERROR CODE FOR FAILURES
;
; Uses: T1-T6
;
;We return the updated user arguments in the SJB (or error code on a
;failure).
;
;Note: It is assumed that SCJSYS, or whatever equivalent, has range
;and privilege checked all of the user arguments. The arguments are
;all in either the SAB portion of the message block or in internal
;blocks pointed to by the SAB (SACBP and SASBP).
XRENT SCTNSF
SAVEAC <MB,MS,SL,SA,T5,T6,P1,P2> ;SAVE ALMOST ALL ACS
SKIPG SA,T1 ;DID HE SUPPLY A MESSAGE BLOCK?
SCERR %NEABE,SCTNIE,<No argument block>
SETZRO SAERR,(SA) ;INITIALIZE THE ERROR LOCATION
LOAD T1,SAAFN,(SA) ;GET THE FUNCTION
CAIL T1,.NSFMN ;RANGE CHECK
CAILE T1,.NSFMX ; THE FUNCTION CODE
SCERR %NEILF,SCTNIE,<Illegal function>
;...
;...
;The code on this page and the following page is a series of coroutines. The
;Session Control interlock will only interlock a whole routine (to reduce the
;possibility of interlock screwups). The routines on this page call
;coroutines on the following page (only) via the Session Control interlock.
;We start on this page, not owning the Session Control interlock. The first
;interlocked coroutine called is SCTNIS (Setup). SCTNIS will do what it can,
;then, when it needs to do something outstide of the Session Control
;interlock, it will put the address of one of the labels on this page into
;MBPRC,(SA) and then RET. The RET takes us back to SCTULK (Session Control
;unlock) where we process any Session Control requests which may have been
;queued. Then control returns to this page after the original coroutine call.
;Each of the coroutines on this page has OPSTR <CALLRET @>,MBPRC,(SA) after
;its call the the Session Control interlock.
;Control leaves this page either via a coroutine call to an interlocked
;routine on the next page or by a RET to SCTNSF's caller.
MOVE MB,SA ;INTERLOCK ROUTINE NEEDS MB SET UP
XMOVEI T1,SCTNIS ;INTERLOCKED SETUP ROUTINE
CALL SCTLCW ;CALL INTERLOCKED SETUP ROUTINE
OPSTR <CALLRET @>,MBPRC,(SA) ;CALL COROUTINE CHOSEN BY SCTNIS
;Here to HIBER without the interlock before calling the BEFORE-function
;coroutine (again).
SCTNS1: LOAD T1,SASJB,(SA) ;PASS PTR TO SJB IN T1 TO @SAHBA(SA)
LOAD T2,SAACH,(SA) ;PASS CHANNEL # IN T2
MOVE T3,SA ;PASS SAB ADDR IN T3 (SIGH)
OPSTR <CALL @>,SAHBA,(SA) ;CALL THE HIBER'ER
MOVE MB,SA ;MB MUST BE SET UP FOR INTERLOCK
XMOVEI T1,SCTNIB ;CALL THE "BEFORE" INTERLOCKED PROCESS
CALL SCTLCW ; AFTER WE GET THE INTERLOCK
OPSTR <CALLRET @>,MBPRC,(SA) ;CALL COROUTINE CHOSEN BY SCTNIB
;Here to HIBER without the interlock before calling the AFTER-function
;coroutine (again).
SCTNS2: LOAD T1,SASJB,(SA) ;PASS PTR TO SJB IN T1 TO @SAHBA(SA)
LOAD T2,SAACH,(SA) ;PASS CHANNEL # IN T2
MOVE T3,SA ;PASS SAB ADDR IN T3 (SIGH)
OPSTR <CALL @>,SAHBA,(SA) ;CALL THE HIBER'ER
MOVE MB,SA ;MB MUST BE SET UP FOR INTERLOCK
XMOVEI T1,SCTNIA ;CALL THE "AFTER" INTERLOCKED PROCESS
CALL SCTLCW ; AFTER WE GET THE INTERLOCK
OPSTR <CALLRET @>,MBPRC,(SA) ;CALL COROUTINE CHOSEN BY SCTNIA
;Here to give up the interlock and call the system schedular to give others
;a chance between segments of a long message.
SCTNS3:
IFN FTOPS10,<
MCALL (RG,MSEC1,INTLVL##) ;ARE WE AT UUO LEVEL?
MCALL (RG,MSEC1,SCDCHK##) ;YES, LET OTHER USERS HAVE A CHANCE
>; END IFN FTOPS10
MOVE MB,SA ;MB MUST BE SET UP FOR INTERLOCK
XMOVEI T1,SCTNIB ;CALL THE "BEFORE" PROCESS AGAIN
CALL SCTLCW ; AFTER WE GET THE INTERLOCK
OPSTR <CALLRET @>,MBPRC,(SA) ;CALL COROUTINE CHOSEN BY SCTNIB
;All of these routines have the interlock. These routines may only go
;back to non-interlocked code by the return address in MBPRC.
;Setup the SLB.
SCTNIS: LOAD T1,SAAFN,(SA) ;GET THE FUNCTION CODE
SETO SL, ;ASSUME WE HAVE NO SLB (-1 IS 'UNASSIGNED')
JE CFCHN,+SCTWTB(T1),SCNIS1 ;IF NO CHANNEL IS REQ'D,
; LEAVE SL AS 'UNASSIGNED' (-1)
LOAD T1,SAACH,(SA) ;GET THE CHANNEL NUMBER
LOAD T2,SASJB,(SA) ;POINT TO THE JOB BLOCK
CALL FNDSLB ;FIND THE CORRESPONDING SLB
SCERR %NEBCN,SCTNIE,<Bad Channel Number>
SETONE SLBSY,(SL) ;NO ONE MAY FREE THIS SLB
LOAD T1,SLUID,(SL) ;GET THE SLB'S SERIAL NUMBER
STOR T1,SAUID,(SA) ; AND STASH IT IN THE SAB
SCNIS1: STOR SL,SASLB,(SA) ;STORE THE SLB POINTER
JRST SCNIB1 ;WE ALREADY HAVE THE INTERLOCK
;Do the BEFORE-function state checking and perform the function.
SCTNIB: LOAD SL,SASLB,(SA) ;GET POINTER TO LINK BLOCK
SCNIB1: JUMPL SL,[SETZB T1,T2 ;NO STATUS IF NO SLB (EA & EP FUNCTS)
JRST SCNIB3] ;GO SEE IF WE CAN MAKE ONE
LOAD T1,SLUID,(SL) ;IS THIS SLB POINTER
OPSTR <CAMN T1,>,SAUID,(SA) ; STALE ?
JRST SCNIB2 ;NO. CONTINUE
SETO SL, ;YES. LOSE THIS POINTER.
SCERR %NEBCN,SCTNIE,<Bad Channel Number> ;FAIL.
SCNIB2: LOAD T1,SLSST,(SL) ;GET CURRENT LINK STATUS
LOAD T2,NSSTA,+T1 ;PUT JUST THE STATE IN T2
SCNIB3: LOAD T3,SAAFN,(SA) ;GET THE FUNCTION BACK
CALL @SCTWTB(T3) ;SEE IF WE SHOULD WAIT A WHILE
CALLRET @.+1(T1) ;BRANCH ON SCTWTB'S RETURN CODE
IFIW <SCTNIU&777777> ;CW.ERR - ERROR RETURN TO MONUSER
IFIW <SCNIB4&777777> ;CW.NWA - NO WAIT, GO DO FUNCTION
IFIW <SCNIB5&777777> ;CW.WAI - WAIT IF MONUSER SO REQUESTED
;Here to call the function processor
SCNIB4: LOAD T1,SAAFN,(SA) ;GET THE FUNCTION TYPE
CALL @NSFNT(T1) ;CALL FUNCTION PROCESSOR
JRST SCTNIE ;REPORT THE ERROR IF NEEDED
STOR SL,SASLB,(SA) ;SAVE THE POSSIBLY NEW SLB FOR AFTER CHECKING
JRST SCNIA1 ;DON'T GET INTERLOCK, WE HAVE IT
;Here when function not yet complete to see if we should wait
SCNIB5: TMNN SAWAI,(SA) ;MONUSER ASK US TO WAIT FOR FCN COMPLETION?
JRST SCTNIX ;NO, RETURN TO MONUSER NOW
XMOVEI T2,SCTNS1 ;YES, DO OUR HIBER
STOR T2,MBPRC,(SA) ;STORE COROUTINE ADDRESS
RET ;BACK TO NON-INTERLOCKED CODE
;Here to do the AFTER-function checking.
SCTNIA: LOAD SL,SASLB,(SA) ;GET POINTER TO LINK BLOCK
SCNIA1: JUMPL SL,SCTNX1 ;IF WE DON'T HAVE A SLB, JUST LEAVE
;Note that none of the NSFxx routines call CHKSTS when they change
;a status other than the link state, because they assume that we will
;call CHKSTS from here.
CALL CHKSTS ;UPDATE SLB'S LINK STATUS WORD
LOAD T1,SLSST,(SL) ;GET CURRENT LINK STATUS
LOAD T2,NSSTA,+T1 ;PUT JUST THE STATE IN T2
LOAD T3,SAAFN,(SA) ;GET THE FUNCTION CODE BACK
CALL @SCTWTA(T3) ;SEE IF WE SHOULD WAIT A WHILE
CALLRET @.+1(T1) ;BRANCH ON ANSWER FROM SCTWTA
IFIW <SCTNIU&777777> ;CW.ERR - ERROR RETURN REQUIRED
IFIW <SCTNIX&777777> ;CW.NWA - FCN COMPLETE, RETURN TO MONUSER
IFIW <SCNIA2&777777> ;CW.WAI - FCN NOT COMPLETE, WAIT
IFIW <SCNIA3&777777> ;CW.SAT - CHECK FOR I/O SATISFIED
IFIW <SCNIA4&777777> ;CW.DAT - BRIEF PAUSE BETWEEN MSG SEGMENTS
;Here if function not yet complete, see if we have to wait
SCNIA2: TMNN SAWAI,(SA) ;DID MONUSER ASK TO WAIT FOR FCN TO COMPLETE?
JRST SCTNIX ;NO, RETURN TO USER NOW
XMOVEI T1,SCTNS2 ;YES, POINT TO HIBER ROUTINE, OUT-OF-INTERLOCK
STOR T1,MBPRC,(SA) ;TELL CO-ROUTINE WHERE TO GO TO HIBER
RET ; AND RETURN TO TO HIBER
;Here to see if .NSFDR function is complete, wait if so requested
SCNIA3: TMNN SAWAI,(SA) ;MONUSER WANT US TO WAIT FOR I/O COMPLETE?
JRST SCTNIX ;NO, RETURN TO MONUSER NOW
TMNN SASAT,(SA) ;YES, IS THE I/O SATISFIED YET?
JRST SCNIB2 ;NO, GO BACK AND TRY AGAIN
JRST SCTNIX ;YES, RETURN TO MONUSER NOW
;Here to free the Session Control interlock briefly between message segments
;so that we don't keep the lock too long when sending long messages.
SCNIA4: TMNE SASAT,(SA) ;I/O SATISFIED YET?
JRST SCTNIX ;YES, RETURN TO CALLER NOW
LOAD T1,SLSST,(SL) ;NO, CAN WE SEND ANOTHER SEGMENT
TXNE T1,NSNDR ; NOW? (ONLY NORMAL DATA CAN HAVE MULT SEGS)
JRST SCNIA5 ;YES
TMNN SAWAI,(SA) ;NO, USER WANT TO BLOCK?
JRST SCTNIX ;NO, RETURN TO USER NOW
JRST SCNIB2 ;YES, GET BEFORE PROCESSOR TO BLOCK
SCNIA5: XMOVEI T1,SCTNS3 ;RELEASE INTERLOCK A BIT
STOR T1,MBPRC,(SA) ; THEN DO THE NEXT SEGMENT
RET ;RETURN FROM THE SCTL INTERLOCK
;Here to exit with the normal return.
SCTNIX: SETZRO SAAST,(SA) ;START WITH NO STATUS SO THAT A RESET
; FUNCTION WILL RETURN A ZERO AS STATUS
JUMPL SL,SCTNX1 ;IF WE DON'T HAVE AN SLB, PUNT
LOAD T1,SLSST,(SL) ;GET CURRENT LINK STATUS
STOR T1,SAAST,(SA) ;STORE STATUS FOR USER AS WE LEAVE
SETZRO SLBSY,(SL) ;WE'RE DONE WITH SLB NOW, IF NEED BE
; IT MAY BE FREED
SCTNX1: XMOVEI T1,RTN ;JUST RETURN WHEN DONE
STOR T1,MBPRC,(SA) ;STORE THAT AS THE PROCEDURE
RET ;RETURN TO OTHER CO-ROUTINE
;Here to report the Unexpected State errors. We will give the error
;based upon the state that was unexpected.
SCTNIU: CALL CHKSTS ;UPDATE SLB'S LINK STATUS WORD
LOAD T1,SLSST,(SL) ;GET CURRENT LINK STATUS
LOAD T2,NSSTA,+T1 ;GET THE STATE
IFSTATE T2,<DR,RJ>,SCTNIR ;IF WE'RE IN DR OR RJ GIVE REASON ERROR
; MESSAGE
ADJBP T2,ERRSBP ;INDEX INTO UNEXPECTED STATE CODE TABLE
LDB T1,T2 ;GET THE VALUE OF THE ERROR MESSAGE
JUMPE T1,SCTNUE ;JUMP IF UNEXPECTED STATE
CALLRET SCTNIE ;REPORT THE ERROR TO USER
SCTNUE: SCERR %NEUXS,SCTNIE,<Unexpected State: Unspecified>
;Here to give the error codes which correspond to the REASON
;codes given by NSP.
SCTNIR: LOAD T3,SLRSN,(SL) ;GET THE REASON CODE NSP GAVE US
JUMPE T3,SCTNR1 ;IF REASON IS ZERO, WE HAVE TO FIGURE
;OUT ERROR BASED ON STATE
CAILE T3,RSNLEN ;IS THE REASON VALUE REASONABLE?
JRST SCTNR2 ;NO, CALL IT UNSPECIFIED
MOVE T1,ERRRBP ;GET THE REASON ERROR TABLE BYTE POINTER
ADJBP T3,T1 ;INDEX TO THE CORRECT MESSAGE
LDB T1,T3 ;GET THE VALUE OF THE ERROR MESSAGE
JUMPE T1,SCTNR2 ;IF TABLE SAYS ZERO, IT UNSPECIFIED
CALLRET SCTNIE ;RETURN THE FAILURE TO THE USER
SCTNR1: IFSTATE T2,RJ
SCERR %NERBO,SCTNIE,<Rejected by Object>
IFSTATE T2,DR
SCERR %NEDBO,SCTNIE,<Disconnected by Object>
SCTNR2: SCERR %NEREJ,SCTNIE,<Unspecified Reject Reason>
;Here with an error code in T1.
SCTNIE: SKIPN T1 ;IS THERE AN ERROR CODE?
BUG.(CHK,SCLNZE,SCLINK,SOFT,<Passing zero error code to SCMUUO>,,<
Cause: The routine that is supposed to store an error code
for the user is zero. This is an illegal value.
Action: Find who called SCTNIE with T1/ 0 and correct the caller's behavior.
>)
STOR T1,SAERR,(SA) ;STORE THE ERROR TYPE
SKIPLE SL ;DON'T UPDATE STATUS IF WE HAVE NO SLB
CALL CHKSTS ;UPDATE SLB'S LINK STATUS WORD
CALLRET SCTNIX ;FREE THE MESSAGE
;The following is the table (indexed by SC state) which contains the
;error code to give (i.e., %NSUDR = Unexpected State: Disconnect
;Received).
ERRSTB: BYTE(6) %NEUXS, %NEUCW, %NEUCR, %NEUCS, %NEURJ, %NEURN
BYTE(6) %NEUDS, %NEUDC, %NEUCF, %NEULK, %NEUCM, %NEUNR
ERRSBP: POINT 6,ERRSTB ;BYTE POINTER TO ERROR MESSAGES
;This table is indexed by reason code, with each cell corresponding to
;the correct error message to give for that reason. A zero in the
;table means "return the Unspecified Reject Reason error code".
;This should only happen when someone gives us a reason that we
;never heard of.
ERRRSB: BYTE(6) %NERES, %NEUNN, %NERNS, %NEURO, %NEIOF, %NEOTB
BYTE(6) 0, %NEABM, %NEABO, %NEINF, %NELNS, 0
BYTE(6) 0, 0, 0, 0, 0, 0
BYTE(6) 0, 0, 0, 0, 0, 0
BYTE(6) 0, 0, 0, 0, 0, 0
BYTE(6) 0, 0, 0, %NEACR, 0, 0
BYTE(6) 0, %NERNO, %NENUR, 0, %NENLK, %NEDSC
BYTE(6) %NEIMG
RSNLEN==<.-ERRRSB>*6
ERRRBP: POINT 6,ERRRSB ;BYTE POINTER TO REASON ERROR MESSAGES
SUBTTL NSP. -- NSFRE - REset all links
;NSFRE - REset all links
;
; Call:
; SA/ Pointer to Session Control Argument Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;This function is only done by the system when the user does a RESET
;UUO. There are no arguments.
NSFRE: SAVEAC SL ;PRESERVE SL FOR SCTNI*
LOAD T1,SASJB,(SA) ;GET POINTER TO SJB
LOAD P1,SJCHT,(T1) ;GET THE POINTER TO SLB TABLE
LOAD P2,SJCHC,(T1) ;GET THE COUNT OF LINKS
NSFRE1: SKIPN SL,(P1) ;IS THERE ANYTHING THERE?
JRST NSFRE2 ;NO, TRY NEXT LINK
SETZRO SLBSY,(SL) ;THIS LINK IS NO LONGER BUSY
SETZ MB, ;RESET PASSES NO MSG BLK, NO Q'D INTERLOCKS
CALL RLSLNK ;(MB)DO A RELEASE ON THIS LINK
NSFRE2: ADDI P1,1 ;POINT TO THE NEXT SLB
SOJG P2,NSFRE1 ;DO THE NEXT ONE, IF THERE ARE ANY LEFT
RETSKP ;RETURN SUCCESS
SUBTTL NSP. -- NSFEA - Enter Active State
;NSFEA - Enter Active State
;
; Call:
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFEA function, the function dependant arguments are:
;
; SAACH/ Returned: zero on failure, channel # on success
; SAAA1/ Ptr to connect-block
; SAAA2/ Segment Size
; SAAA3/ Flow control mode
NSFEA: TRACE SC,<Performing Enter Active (.NSFEA)>
SETZRO SAACH,(SA) ;ASSUME WE CANNOT ASSIGN A CHANNEL
CALL MAKSLB ;MAKE A SLB
SCERR %NEALF,RTN,<Allocation failure>
STOR T1,SAACH,(SA) ;STORE CHANNEL NUMBER FOR MONUSER
NEWSTATE CS ;INITIAL STATE IS CONNECT SENT
; Get the Object type and if format 0, store both the source (SLSOB)
; and destination (SLDOB) object type into the SLB.
LOAD T3,SACBP,(SA) ;GET POINTER TO CONNECT BLOCK
XMOVEI T1,CB.SRC(T3) ;GET THE POINTER TO SOURCE PDB
LOAD T2,PBFOR,(T1) ;GET THE FORMAT TYPE
CAIE T2,FRM.2 ;FORMAT TYPE WITH PPN?
IFSKP.
CALL CHKPPN ;AND VERIFY THE PPN
SCERR %NEPRV,NSFEAC,<No privs to use bad PPN>
ELSE.
IFN FRM.0,<PRINTX ?FRM.0 MUST BE EQUAL TO 0>
ANDE. T2 ;IF OBJECT TYPE, STORE THE NUMBER
LOAD T2,PBOBJ,(T1) ;GET OBJECT TYPE WE CLAIM TO BE
IFN FTOPS10,<
LOAD T3,SLSJB,(SL) ;GET POINTER TO SJB
TMNN SJPRV,(T3) ;ARE WE PRIVED
CAIL T2,^D128 ;IS OBJECT TYPE PRIVED?
TRNA ;WE ARE O.K.
SCERR %NEPRV,NSFEAC,<No privs for this object type>
> ; END FTOPS10
STOR T2,SLSOB,(SL) ;SAVE SOURCE OBJ TYPE FOR SYSDPY AND THE LIKE
ENDIF.
LOAD T3,SACBP,(SA) ;GET POINTER TO CONNECT BLOCK
XMOVEI T1,CB.DST(T3) ;GET THE POINTER TO THE DEST PDB
LOAD T2,PBFOR,(T1) ;GET THE FORMAT TYPE
CAIE T2,FRM.0 ;FORM WITH JUST AN OBJECT TYPE
IFSKP.
LOAD T2,PBOBJ,(T1) ;GET THE OBJECT TYPE FROM PDB
STOR T2,SLDOB,(SL) ;SAVE DEST OBJ TYPE FOR SYSDPY AND THE LIKE
ENDIF.
LOAD T1,SAKCB,(SA) ;GET USER'S 'KEEP CONNECT BLOCK' FLAG
STOR T1,SLKCB,(SL) ;REMEMBER IT
JUMPE T1,NSFEA3 ;JUMP IF WE'RE NOT TO KEEP CONNECT BLOCK
MOVX T1,CB.LEN ;GET 'CONNECT BLOCK LENGTH' WORDS
CALL DNGWDS ;GET NON-ZEROED WORDS
SCERR %NEALF,NSFEAC,<Allocation failure>
STOR T1,SLCBP,(SL) ;SAVE POINTER TO SLB'S NEW CB
; FRESLB WILL FREE THIS CB FROM NOW ON
MOVE T2,T1 ;DESTINATION IS NEW CB
LOAD T1,SACBP,(SA) ;SOURCE IS CONNECT BLOCK FROM SAB
MOVX T3,CB.LEN ;LENGTH IS LENGTH OF A CONNECT BLOCK
CALL DNCPYW ;COPY SAB'S CB TO SLB'S CB
NSFEA3:
LOAD P1,SANAG,(SA) ;GET THE NUMBER OF ARGS USER SPECIFIED
CAIG P1,.NSAA3 ;DID USER SPECIFY THE FLOW CONTROL MODE?
JRST NSFEA4 ;NO
LOAD T1,SAAA3,(SA) ;GET THE FLOW CONTROL MODE
JUMPLE T1,NSFEA4 ;DIDN'T SPECIFY, USE THE DEFAULT
CAIL T1,NSF.C0 ;RANGE CHECK THE
CAILE T1,NSF.MX ; FLOW CONTROL MODE
SCERR %NEIFM,NSFEAC,<Illegal flow control mode>
SUBI T1,1 ;TRANSLATE FLOW CONTROL MODE INTO THE
; FCM.XX FORM THAT NSP USES
STOR T1,SLRFL,(SL) ;STORE THE FLOW CONTROL MODE
NSFEA4: SETZ T1, ;NO USER DATA NEEDED
CALL DNGMSG ;GET MESSAGE BLOCK
SCERR %NEALF,NSFEAC,<Allocation failure>
MOVE MB,T1 ;PUT MESSAGE BLOCK POINTER IN MB
MOVX T1,OA.LEN ;LENGTH OF OPEN ARGS
CALL DNGWDZ ;GET BLOCK FOR OPEN ARGS
SCERR %NEALF,NSFEAD,<Allocation failure>
;Now fill in the Open block with the arguments.
MOVE P1,T1 ;MAKE P1 POINT TO THE ARGUMENT BLOCK
STOR SL,OASCB,(P1) ;PUT ID IN OPEN ARG BLOCK
OPSTR <SKIPN T2,>,SACBP,(SA) ;GET THE CONNECT BLOCK POINTER
SCERR %NENCD,NSFEAE,<No connect block>
OPSTR <SKIPE T1,>,CBNUM,(T2) ;Get node number and check for zero
IFSKP. ;If it is zero, then its a loopback circuit
LOAD T1,CBCIR,(T2) ;Get loopback circuit ID
STOR T1,OACIR,(P1) ; and store it
LOAD T1,IBADR,+IBBLK ;Get local node number
ENDIF.
STOR T1,OANOD,(P1) ;PUT DESTINATION NODE ADDRESS IN ARG BLOCK
STOR T1,SLDNA,(SL) ; AND STORE AS DESTINATION OF THIS LINK
; LOAD T1,SLDNA,(SL)
OPSTR <SKIPN>,OACIR,(P1) ;Loopback?
IFSKP. ; -yes
MOVE T1,RTRBSZ ; Use default buffer size
SUBI T1,%SCHDR ; minus header
ELSE. ; -no,
CALL SCTGSS ; Get segment size for that destination
ENDIF.
LOAD T2,SANAG,(SA) ;Get the number of args user specified
CAIG T2,.NSAA2 ;Did the user specifiy the segment size?
IFSKP. ;Yes, use the supplied value
OPSTR <SKIPLE T2,>,SAAA2,(SA) ;Get the segment size
CAMLE T2,T1 ; is it bigger than the legal max?
IFSKP. <MOVE T1,T2> ; -no smaller, use that value
ENDIF.
STOR T1,SLSIZ,(SL) ;STORE THE SEGMENT SIZE IN SLB
LOAD T1,SLRFL,(SL) ;GET THE FLOW CONTROL MODE BACK
STOR T1,OAFLO,(P1) ;PUT IN OPEN ARG BLOCK
LOAD T2,SLGOL,(SL) ;GET THE DATA REQUEST GOAL
CAIN T1,FCM.MG ;ARE WE IN MESSAGE FLOW CONTROL?
CAIL T2,1 ;YES, IS OUR GOAL SET TO LESS THAN ONE?
TRNA ;NO, DON'T WORRY ABOUT IT
MOVEI T2,1 ;IN MSG FLOW MODE WE GOAL OF AT LEAST 1
STOR T2,SLGOL,(SL) ;REMEMBER THE GOAL WE DECIDED ON
STOR T2,OAGOL,(P1) ;TELL LLINKS ABOUT THE GOAL TOO
LOAD T1,SLSIZ,(SL) ;GET THE MAXIMUM SEGMENT SIZE
STOR T1,OASIZ,(P1) ;THAT TOO
MOVE T1,[XCDSEC,,SCTL] ;HE WANT'S OUR ENTRY VECTOR ADDRESS
STOR T1,OASCV,(P1) ;GIVE IT TO HIM
MOVE T1,P1 ;PASS ARG POINTER IN T1
MOVX T2,OA.LEN ;LENGTH OF THE OPEN ARG BLOCK
MOVX T3,NV.OPN ;FUNCTION IS OPEN A PORT
MOVE T4,MB ;POINT TO THE MESSAGE BLOCK WE ALLOCATED
CALL NSP ;ASK NSP TO OPEN A PORT
SKIPG T1 ;Did we get a port?
SCERR %NERES,NSFEAD,<Resource error>
;Now we have an open port to NSP, let's try to make it active.
STOR T1,SLPID,(SL) ;STORE THE NSPpid
MOVE T1,MB ;LET'S REUSE THE MESSAGE BLOCK
MOVEI T2,^D200 ;GET ENOUGH ROOM FOR THE CONNECT MESSAGE
CALL DNMINI ;MAKE THE MESSAGE BLOCK LIKE NEW
SCERR %NEALF,NSFEAD,<Allocation failure>
XMOVEI T1,UD.MSD(MB) ;POINT TO USER DATA PORTION OF MESSAGE
CALL DNPINI ;INITIALIZE FOR PUTTING BYTES IN MESSAGE
LOAD T1,SACBP,(SA) ;POINT TO THE CONNECT BLOCK
CALL BLDCTX ;BUILD THE CONNECT TEXT IN THE MESSAGE
SCERR %NECFE,NSFEAD,<Connect Block format error>
LOAD T1,SLPID,(SL) ;GET THE NSPpid BACK AGAIN
MOVX T3,NV.ACT ;FUNCTION IS ENTER ACTIVE
MOVE T4,MB ;POINT TO MB WITH CONNECT DATA
CALL NSP ;CALL NSP TO DO THE FUNCTION
CALL STRTMR ;START THE CONNECT TIMERS
RETSKP ;GIVE A GOOD RETURN
;The following are the error returns that free up things that we have
;allocated before we got the error.
;Free an arg block, a message block and a SLB. Report "illegal function".
NSFEAE: MOVE T1,P1 ;POINT TO THE ARGUMENT BLOCK
CALL DNFWDS ; AND GO AND FREE UP THE WORDS
MOVEI T1,%NEILF ;"Illegal function"
JRST NSFEAD ;GO AND FREE MESSAGE BLOCK
;Free a message block and a SLB.
NSFEAD: SAVEAC T1 ;SAVE THE ERROR CODE
CALL FREMSG ;FREE THE MESSAGE BLOCK POINTED TO BY MB
JRST NSFEC1 ;GO AND FREE THE SLB
;Free an SLB.
NSFEAC: SAVEAC T1 ;SAVE THE ERROR CODE
NSFEC1: SETONE SLFSL,(SL) ;FREE THE SLB AFTER THE "AFTER" PROCESSING
SETZRO SAACH,(SA) ;TELL USER THERE'S NO CHANNEL OPEN
CALLRET SCTRFJ ;REQUEST SECOND SERVICE TO FREE SLB
SUBTTL NSP. -- NSFEP - Enter Passive State
;NSFEP - Enter Passive State
;
; Call:
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFEP function, the function dependant arguments are:
;
; .NSAA1/ Ptr to connect-block
NSFEP: TRACE SC,<Performing Enter Passive (.NSFEP)>
CALL MAKSLB ;MAKE A SLB
SCERR %NEALF,RTN,<Allocation failure>
STOR T1,SAACH,(SA) ;STORE THE CHANNEL FOR USER
; Get the Object type and if format 0, store the source (SLSOB) object type
; in the SLB.
LOAD T3,SACBP,(SA) ;GET POINTER TO CONNECT BLOCK
XMOVEI T1,CB.SRC(T3) ;GET THE POINTER TO THE SOURCE PDB
LOAD T2,PBFOR,(T1) ;GET THE FORMAT TYPE
IFE. T2 ;IF FRM.0, IT HAS AN OBJECT TYPE
LOAD T2,PBOBJ,(T1) ;GET THE OBJECT TYPE FROM THE PDB
STOR T2,SLSOB,(SL) ;STORE IT IN THE SLB
ENDIF.
XMOVEI T1,CB.DST(T3) ;GET THE POINTER TO THE DEST PDB
LOAD T2,PBFOR,(T1) ;GET THE FORMAT TYPE
CAIE T2,FRM.2 ;FORMAT TYPE WITH PPN?
IFSKP.
CALL CHKPPN ;AND VERIFY THE PPN
SCERR %NEPRV,NSFEPC,<No privs to use bad PPN>
ELSE.
IFN FRM.0,<PRINTX ?FRM.0 MUST BE EQUAL TO 0>
ANDE. T2 ;IF OBJECT TYPE, STORE THE NUMBER
LOAD T3,SLSJB,(SL) ;GET POINTER TO SJB
LOAD T2,PBOBJ,(T1) ;GET OBJECT TYPE WE CLAIM TO BE
IFN FTOPS20,<
MOVE T1,CAPENB ;ARE WE PRIVED
TXNN T1,SC%WHL!SC%OPR
> ; END FTOPS20
IFN FTOPS10,<
TMNN SJPRV,(T3) ;ARE WE PRIVED
> ; END FTOPS10
CAIL T2,^D128 ;IS OBJECT TYPE PRIVED?
TRNA ;WE ARE O.K.
SCERR %NEPRV,NSFEPC,<No privs for this object type>
STOR T2,SLSOB,(SL) ;SAVE IT FOR SYSDPY AND THE LIKE
ENDIF.
;Now allocate another block for the internal connect block, so that the
;original goes back to SCLINK's caller.
NSFEP2: LOAD T1,SAKCB,(SA) ;GET USER'S 'KEEP CONNECT BLOCK' FLAG
STOR T1,SLKCB,(SL) ;REMEMBER IT
MOVX T1,CB.LEN ;LENGTH OF A INTERNAL CONNECT BLOCK
CALL DNGWDS ;GET THE WORDS
SCERR %NEALF,NSFEPC,<Allocation failure>
STOR T1,SLCBP,(SL) ;STORE THE POINTER IN THE SLB
MOVE T2,T1 ;SET IT UP IN T2 ALSO FOR DNCPYW
LOAD T1,SACBP,(SA) ;POINT TO THE CONNECT BLOCK
MOVX T3,CB.LEN ;LENGTH OF THE CONNECT BLOCK
CALL DNCPYW ;COPY THE WHOLE THING
NEWSTATE CW ;NEW STATE IS CONNECT WAIT
SETONE SLPAS,(SL) ;Flag that this link is passive
RETSKP ;RETURN WITH SUCCESS
;Here to free up the SLB after an error occured.
NSFEPC: SAVEAC T1 ;SAVE THE ERROR CODE
SETONE SLFSL,(SL) ;SAY THAT WE SHOULD FREE THE SLB
CALLRET SCTRFJ ;REQUEST SECOND SERVICE TO FREE SLB
SUBTTL NSP. -- NSFRI - Read Connect Information
;NSFRI - Read Connect Information
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFRI function, the function dependant arguments are:
;
; .NSAA1/ Ptr to connect-block
; .NSAA2/ Maximum segment size
; .NSAA3/ Flow control mode
;
;This function can be called in any state. If we were asked to keep the
;connect in the Enter Active or Enter Passive, then .NSFRI will be able to
;return the connect block at any time, and the user data will have been
;updated with the most recently received user data from CC or DI messages.
NSFRI: TRACE SC,<Performing Read Connect Info (.NSFRI)>
SETZRO SASBP,(SA) ;ZERO THE ARGUMENTS IN
SETZRO SAAA2,(SA) ; CASE WE CAN'T
SETZRO SAAA3,(SA) ; GET THE RIGHT ANSWER
;CDMCBP WILL BUILD A CONNECT BLOCK IF NEEDED
CALL CDMCBP ;COPY ANY MESSAGE DATA TO CONNECT BLOCK
RET ;PROPOGATE ERROR RETURN, CODE IN T1
TMNN SLCBP,(SL) ;ANY DIS/CONNECT DATA TO READ?
SCERR %NENCD,RTN,<No dis/connect data to read>
JE SLKCB,(SL),NSFRI1 ;USER WANT US TO KEEP CONNECT BLOCK
;Here if we are to keep connect block, copy it for user
MOVX T1,CB.LEN ;YES, LENGTH OF AN INTERNAL CONNECT BLOCK
CALL DNGWDS ;GET NON-ZEROED WORDS
SCERR %NEALF,RTN,<Allocation Failure>
STOR T1,SACBP,(SA) ;STORE THE POINTER FOR SCJSYS
MOVE T2,T1 ;SET UP DEST POINTER FOR DNCPYW
LOAD T1,SLCBP,(SL) ;GET THE INTERNAL CB POINTED TO IN THE SLB
MOVX T3,CB.LEN ;COUNT OF WORDS TO COPY
CALL DNCPYW ;COPY CONNECT BLOCK FOR USER
JRST NSFRI2 ;CONTINUE
;Here if we are not to keep the connect block, just hand it over
NSFRI1: LOAD T1,SLCBP,(SL) ;GET THE INTERNAL CB POINTED TO IN THE SLB
SETZRO SLCBP,(SL) ;SCLINK NO LONGER OWNS THE CONNECT BLOCK
SKIPN T1 ;DO WE STILL HAVE A CONNECT BLOCK?
SCERR %NEWRS,RTN,<Function called in wrong state>
STOR T1,SACBP,(SA) ;STORE THE POINTER FOR SCMUUO
NSFRI2: LOAD P1,SANAG,(SA) ;GET THE NUMBER OF ARGUMENTS
CAIG P1,.NSAA2 ;DID HE WANT SOME OTHER ARGUMENTS?
RETSKP ;NO, JUST RETURN
LOAD T1,SLSIZ,(SL) ;YES, GET IT FROM THE SLB
STOR T1,SAAA2,(SA) ;STORE REASON CODE,,SEGMENT SIZE
CAIG P1,.NSAA3 ;HOW ABOUT THE FLOW CONTROL OPTION?
RETSKP ;NO, JUST RETURN
CALL RETFLW ;GET THE RFL,,XFL IN T1
STOR T1,SAAA3,(SA) ; AND STORE IT IN THE ARG BLOCK
RETSKP ;RETURN SUCCESS
SUBTTL NSP. -- NSFAC - Accept the Connect
;NSFAC - Accept the Connect
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFAC function, the function dependant arguments are:
;
; .NSAA1/ Ptr to user-data (which is the DATA-CTL optional response)
; .NSAA2/ Maximum segment size
; .NSAA3/ Flow control mode
NSFAC: TRACE SC,<Performing Accept Connect (.NSFAC)>
CALL STPTMR ;STOP THE CONNECT INITIATE TIMER AND FIX COUNTS
LOAD P1,SANAG,(SA) ;GET THE NUMBER OF ARGS USER SPECIFIED
CAIG P1,.NSAA2 ;DID THE USER SPECIFIY THE SEGMENT SIZE?
JRST NSFAC1 ;NO
LOAD T2,SLSIZ,(SL) ;Get the segment size that we and remote
; decided upon.
OPSTR <SKIPLE T1,>,SAAA2,(SA) ;Get the segment size user wants
CAML T1,T2 ;User's smaller?
IFSKP. <STOR T1,SLSIZ,(SL)> ; -yes, use the user's value
CAIG P1,.NSAA3 ;DID USER SPECIFY THE FLOW CONTROL MODE?
JRST NSFAC1 ;NO
LOAD T1,SAAA3,(SA) ;GET THE FLOW CONTROL MODE
JUMPLE T1,NSFAC1 ;DIDN'T SPECIFY IT, USE THE DEFAULT
CAIL T1,NSF.C0 ;RANGE CHECK THE FLOW
CAILE T1,NSF.MX ; CONTROL MODE
SCERR %NEIFM,RTN,<Illegal flow control mode>
SUBI T1,1 ;TRANSLATE FROM NSP.'S VERSION OF FLOW CONTROL
; VALUE TO NSP'S
STOR T1,SLRFL,(SL) ;STORE THE FLOW CONTROL MODE
;Allocate two message blocks, one for the accept arguments and one to
;send out data requests with.
NSFAC1: MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL
CALL DNGMSG ;GET A MESSAGE BLOCK
SCERR %NEALF,RTN,<Allocation failure>
MOVE MB,T1 ;MAKE MB POINT TO THE MESSAGE BLOCK
SETZ T1, ;DON'T NEED ANY USER DATA FOR DRQ MB
CALL DNGMSG ;GET THE MESSAGE BLOCK
JRST [CALL FREMSG ;FREE THE MESSAGE BLOCK WE JUST ALLOCATED
SCERR %NEALF,RTN,<Allocation failure>] ; AND GIVE A FAILURE TO USER
MOVE P2,T1 ;SAVE THE POINTER TO THE DRQ MB
;Copy the user's DATA-CTL (in the user data area) from the user area to
;the message block.
XMOVEI T1,UD.MSD(MB) ;WE WANT TO WRITE DATA-CTL INTO USER DATA
CALL DNPINI ;INITIALIZE THE MSD
LOAD T1,SASBP,(SA) ;GET THE POINTER TO SBLOCK
CALL CPYS2M ;COPY THE DATA-CTL TO THE MESSAGE
;Now set up the accept argument block for NSP.
MOVX T1,AA.LEN ;LENGTH OF THE ACCEPT ARGUMENT BLOCK
CALL DNGWDZ ;GET THAT MANY WORDS
SCERR %NEALF,NSFACD,<Allocation failure>
LOAD T2,SLSLB,(SL) ;THE SCB ID FOR NEW PORT
STOR T2,AASCB,(T1)
LOAD T2,SLPID,(SL) ;NSP'S PORT IDENTIFIER
STOR T2,AAPID,(T1)
LOAD T3,SLRFL,(SL) ;RECEIVE FLOW CONTROL TYPE
STOR T3,AAFLO,(T1)
LOAD T2,SLGOL,(SL) ;GET THE DATA REQUEST GOAL
CAIN T3,FCM.MG ;ARE WE IN MESSAGE FLOW CONTROL?
CAIL T2,1 ;YES, IS OUR GOAL SET TO LESS THAN ONE?
TRNA ;NO, DON'T WORRY ABOUT IT
MOVEI T2,1 ;IN MSG FLOW MODE WE GOAL OF AT LEAST 1
STOR T2,SLGOL,(SL) ;REMEMBER THE GOAL WE DECIDED ON
STOR T2,AAGOL,(T1) ;TELL LLINKS ABOUT THE GOAL TOO
LOAD T2,SLSIZ,(SL) ;MAX BYTES ALLOWED IN A SEGMENT
STOR T2,AASIZ,(T1)
MOVE T2,[XCDSEC,,SCTL] ;OUT ENTRY VECTOR ADDRESS
STOR T2,AASCV,(T1) ; SO HE KNOWS WHERE TO CALL US
MOVX T2,AA.LEN ;LENGTH OF THE ARG BLOCK
MOVX T3,NV.ACC ;FUNCTION IS ACCEPT THE CONNECT
MOVE T4,MB ;SET UP T4 WITH MB POINTER
;T1 IS SET UP ALREADY WITH ARG BLOCK ADDRESS
CALL NSP ;PERFORM THE FUNCTION
NEWSTATE RN ;NEWSTATE IS CONNECT INITIATE
SETONE SLCCB,(SL) ;HAVE TO CHECK CONNECT BLOCK NOW
;Now let's send the job's input quota worth of DRQs.
MOVE MB,P2 ;POINT TO THE MB WE ALLOCATED BEFORE
TMNE SLPH2,(SL) ;SHOULD WE BE CONSERVATIVE WITH THIS FELLOW?
RETSKP ;YES, WE BETTER LEAVE NICELY
LOAD T1,SLINQ,(SL) ;GET THE INPUT QUOTA
STOR T1,QACNT,+T2 ; USE THAT AS THE DATA REQUEST COUNT
STOR T1,SSRDO,+SL.NSL(SL) ;WE KEEP COUNT OF OUTGOING DATA REQUESTS
TXZ T2,MBOTH ;ON THE NORMAL SUBLINK
CALL SNDDRM ;SEND THE DATA REQUESTS
SCERR %NERES,RTN,<Failed to get memory>
RETSKP ;RETURN SUCCESS
;Here on a error.
NSFACD: SAVEAC T1 ;SAVE THE ERROR CODE
CALLRET FREMSG ;FREE THE MESSAGE BLOCK POINTED TO BY MB
SUBTTL NSP. -- NSFRJ - Reject the Connect
;NSFRJ - Reject the Connect
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFRJ function, the function dependant arguments are:
;
; .NSAA1/ Ptr to user-data (which is the DATA-CTL optional response)
; .NSAA2/ Reason code or zero to take default 'rejected by object'
NSFRJ: TRACE SC,<Performing Reject the Connect (.NSFRJ)>
CALL STPTMR ;STOP THE CONNECT INITIATE TIMER AND FIX COUNTS
MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL
CALL DNGMSG ;GET A MESSAGE BLOCK
SCERR %NEALF,RTN,<Allocation failure>
MOVE MB,T1 ;MAKE MB POINT TO THE MESSAGE BLOCK
XMOVEI T1,UD.MSD(MB) ;WE WANT TO WRITE DATA-CTL INTO USER DATA
CALL DNPINI ;INITIALIZE THE MSD
;Put in the reason code (RSNRBO - Rejected by object).
LOAD T2,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER OFFERED
OPSTR <SKIPLE T1,>,SAAA2,(SA) ;USER SPECIFY A REASON?
CAIGE T2,4 ;YES, SANAG INCLUDE SAAA2?
MOVX T1,RSNRBO ;NO, REJECTED BY THE OBJECT
CALL DNP2BY ;PUT REASON IN THE MESSAGE
;Copy the user's DATA-CTL (in the user data area) from the user area to the
;message block.
LOAD T1,SASBP,(SA) ;GET THE POINTER TO SBLOCK
CALL CPYS2M ;COPY THE DATA-CTL TO THE MESSAGE
LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP
MOVX T3,NV.REJ ;FUNCTION IS REJECT THE CONNECT
MOVE T4,MB ;SET UP T4 WITH MB POINTER
;T1 IS SET UP ALREADY WITH ARG BLOCK ADDRESS
CALL NSP ;PERFORM THE FUNCTION
;There is no need to change the state of the link here, as we are
;about to forget about the link. The user may possibly clean out
;his database about this link and then get the state change interrupt,
;confusing him.
SETONE SLFSL,(SL) ;SAY THAT WE SHOULD FREE THE SLB LATER
CALL SCTRFJ ;REQUEST SECOND SERVICE TO FREE SLB
RETSKP ;RETURN NICELY
SUBTTL NSP. -- NSFRC - Read Connect Confirm Information
;NSFRC - Read Connect Confirm Information
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFRC function, the function dependant arguments are:
;
; .NSAA1/ Ptr to string block to receive data
; .NSAA2/ Segment size
; .NSAA3/ Flow control mode
NSFRC: TRACE SC,<Performing Read Connect Confirm Data (.NSFRC)>
SETZRO SASBP,(SA) ;ZERO THE ARGUMENTS IN
SETZRO SAAA2,(SA) ; CASE WE CAN'T
SETZRO SAAA3,(SA) ; GET THE RIGHT ANSWER
;CDMCBP WILL BUILD A CONNECT BLOCK IF NEEDED
CALL CDMCBP ;COPY ANY MESSAGE DATA TO CONNECT BLOCK
RET ;PROPOGATE ERROR RETURN, CODE IN T1
TMNN SLCBP,(SL) ;DO WE HAVE ANY CONNECT DATA
SCERR %NENCD,RTN,<No dis/connect data to read>
MOVX T1,SB.LEN ;GET SOME WORDS FOR THE DATA-CTL FIELD
CALL DNGWDS ;GET THEM FROM MEMORY MANAGER
SCERR %NEALF,RTN,<Allocation failure>
MOVE P2,T1 ;POINTER TO STRING BLOCK
STOR P2,SASBP,(SA) ;PUT POINTER IN ARG BLOCK FOR SCMUUO
MOVEI T1,SB.LEN ;LENGTH OF STRING BLOCK IN WORDS
STOR T1,SBWDS,(P2) ;STORE LENGTH IN WORDS
LOAD P1,SLCBP,(SL) ;GET PTR TO CONNECT BLOCK
LOAD T3,CBCCT,(P1) ;LENGTH OF USER DATA
STOR T3,SBCNT,(P2) ;STORE IN STRING BLOCK
ADDI T3,3 ;ROUND UP
ASH T3,-2 ;CONVERT BYTES TO WORDS
XMOVEI T1,CB.UDA(P1) ;POINTER TO CONNECT BLOCK'S USER DATA
XMOVEI T2,SB.DAT(P2) ;POINTER TO STRING BLOCK'S DATA SECTION
CALL DNCPYW ;(T1,T2,T3)COPY USER DATA TO STRING BLOCK
JN SLKCB,(SL),NSFRC1 ;JUMP IF WE'RE TO KEEP CONNECT BLOCK
MOVE T1,P1 ;POINTER TO CONNECT BLOCK
CALL DNFWDS ;DEALLOCATE MSG BLK WHICH HAD CONNECT DATA
SETZRO SLCBP,(SL) ; AND REMEMBER WE'VE USED IT
NSFRC1: LOAD T1,SLSIZ,(SL) ;GET THE SEGMENT SIZE
STOR T1,SAAA2,(SA) ;STORE IT IN THE ARGUMENT WORD
CALL RETFLW ;GET THE FLOW CONTROL TYPES
STOR T1,SAAA3,(SA) ;STORE IN THE ARG WORD
RETSKP ;RETURN SUCCESS
SUBTTL NSP. -- NSFSD - Synchronous Disconnect
;NSFSD - Synchronous Disconnect
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFSD function, the function dependant arguments are:
;
; .NSAA1/ Ptr to user-data (which is the optional disconnect data)
; .NSAA2/ Reason code or zero for 'Disconnected by Object'
NSFSD: TRACE SC,<Performing Synchronous Disconnect (.NSFSD)>
TMNE SLOTM,(SL) ;IS THERE A PARTIALLY FILLED OUTPUT MESSAGE?
SCERR %NEWRS,RTN,<Function called in wrong state>
MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL
CALL DNGMSG ;GET A MESSAGE BLOCK
SCERR %NEALF,RTN,<Allocation failure>
MOVE MB,T1 ;MAKE MB POINT TO THE MESSAGE BLOCK
;Copy the user's DATA-CTL (in the user data area) from the user area to the
;message block.
XMOVEI T1,UD.MSD(MB) ;WE WANT TO WRITE DATA-CTL INTO USER DATA
CALL DNPINI ;INITIALIZE THE MSD
LOAD T2,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER OFFERED
OPSTR <SKIPLE T1,>,SAAA2,(SA) ;USER SPECIFY A REASON?
CAIGE T2,4 ;YES, SANAG INCLUDE SAAA2?
MOVX T1,RSNDBO ;NO, REASON IS DISCONNECTED BY OBJECT
CALL DNP2BY ;PUT REASON (2 BYTES) IN MESSAGE
LOAD T1,SASBP,(SA) ;GET THE POINTER TO SBLOCK
CALL CPYS2M ;COPY THE DATA-CTL TO THE MESSAGE
;Now call NSP to do the disconnect.
LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP
MOVX T3,NV.DSC ;FUNCTION IS DISCONNECT
MOVE T4,MB ;SET UP T4 WITH MB POINTER
CALL NSP ;PERFORM THE FUNCTION
NEWSTATE DS ;NEWSTATE IS DISCONNECT SENT
RETSKP ;DID OK
SUBTTL NSP. -- NSFAB - Abort and Release
;NSFAB - Abort and Release
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFAB function, the function dependant arguments are:
;
; .NSAA1/ Ptr to user-data (which is the optional disconnect data)
; .NSAA2/ Reason code or zero for 'Aborted by Object'
NSFAB: TRACE SC,<Performing Abort and Release (.NSFAB)>
MOVX T1,^D20 ;GET ENOUGH ROOM FOR DATA-CTL
CALL DNGMSG ;GET A MESSAGE BLOCK
SCERR %NEALF,RTN,<Allocation failure>
MOVE MB,T1 ;MAKE MB POINT TO THE MESSAGE BLOCK
;Copy the user's DATA-CTL (in the user data area) from the user area to the
;message block.
XMOVEI T1,UD.MSD(MB) ;WE WANT TO WRITE DATA-CTL INTO USER DATA
CALL DNPINI ;INITIALIZE THE MSD
LOAD T2,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER OFFERED
OPSTR <SKIPLE T1,>,SAAA2,(SA) ;USER SPECIFY A REASON?
CAIGE T2,4 ;YES, SANAG INCLUDE SAAA2?
MOVX T1,RSNABO ;NO, REASON IS ABORTED BY OBJECT
CALL DNP2BY ;PUT THE TWO BYTES OF REASON CODE IN MSG
LOAD T1,SASBP,(SA) ;GET THE POINTER TO SBLOCK
CALL CPYS2M ;COPY THE DATA-CTL TO THE MESSAGE
LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP
MOVX T3,NV.ABO ;FUNCTION IS DISCONNECT
MOVE T4,MB ;SET UP T4 WITH MB POINTER
CALL NSP ;PERFORM THE FUNCTION
NEWSTATE DS ;NEWSTATE IS DISCONNECT SENT
CALL STPTMR ;STOP THE CI TIMER IN CASE IT'S GOING
SETONE SLABO,(SL) ;WE HAVE TO CLOSE WHEN LINK IS FINISHED
RETSKP ;RETURN WITH GOODNESS
SUBTTL NSP. -- NSFRD - Read Disconnect Data
;NSFRD - Read Disconnect Data
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFRD function, the function dependant arguments are:
;
; .NSAA1/ Ptr to Connect-Block
; .NSAA2/ The Disconnect Reason
NSFRD: TRACE SC,<Performing Read Disconnect Data (.NSFRD)>
SETZRO SASBP,(SA) ;ZERO THE ARGUMENTS IN
SETZRO SAAA2,(SA) ; CASE WE CAN'T GET THE RIGHT ANSWER
;CDMCBP WILL BUILD A CONNECT BLOCK IF NEEDED
CALL CDMCBP ;COPY ANY MESSAGE DATA TO CONNECT BLOCK
RET ;PROPOGATE ERROR RETURN, CODE IN T1
OPSTR <SKIPN P1,>,SLCBP,(SL) ;GET PTR TO DIS/CONNECT BLOCK
SCERR %NENCD,RTN,<No dis/connect data to read>
MOVX T1,SB.LEN ;GET SOME WORDS FOR THE DATA-CTL FIELD
CALL DNGWDS ;GET THEM FROM MEMORY MANAGER
SCERR %NEALF,RTN,<Allocation failure>
MOVE P2,T1 ;POINTER TO STRING BLOCK
STOR P2,SASBP,(SA) ;PUT POINTER IN ARG BLOCK FOR SCMUUO
MOVEI T1,SB.LEN ;LENGTH OF STRING BLOCK IN WORDS
STOR T1,SBWDS,(P2) ;STORE LENGTH IN WORDS
LOAD T3,CBCCT,(P1) ;LENGTH OF USER DATA IN CONNECT BLOCK
STOR T3,SBCNT,(P2) ;STORE IN STRING BLOCK
ADDI T3,3 ;ROUND UP TO NEAREST WORD
ASH T3,-2 ;CONVERT BYTES TO WORDS
XMOVEI T1,CB.UDA(P1) ;POINTER TO CONNECT BLOCK'S USER DATA
XMOVEI T2,SB.DAT(P2) ;POINTER TO STRING BLOCK'S DATA SECTION
CALL DNCPYW ;(T1,T2,T3)COPY USER DATA TO STRING BLOCK
LOAD T1,SLRSN,(SL) ;GET THE DISCONNECT REASON CODE
STOR T1,SAAA2,(SA) ;RETURN THE REASON CODE
RETSKP ; AND GIVE THE GOOD RETURN
SUBTTL NSP. -- NSFRL - Release the Channel
;NSFRL - Release the Channel
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFRL function, the function dependant arguments are:
;
; .NSAA1/ Ptr to user-data (which is the optional disconnect data)
NSFRL: TRACE SC,<Performing Release (.NSFRL)>
SETZ MB, ;WE HAVE NO MESSAGE BLOCK, NO Q'D INTERLOCKS
CALL RLSLNK ;(MB)RESET THE LINK (DO THE CLOSE)
RETSKP ;RETURN SUCCESS
SUBTTL NSP. -- NSFRS - Read the Channel Status
;NSFRS - Read the Channel Status
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFRS function, the function dependant arguments are:
;
; .NSAA1/ State
; .NSAA2/ Segment Size
; .NSAA3/ Flow control type
NSFRS: TRACE SC,<Performing Read Status (.NSFRS)>
LOAD P1,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER WANTED
CAIG P1,.NSAA1 ;DOES HE WANT TO KNOW SEGMENT SIZE?
RETSKP ;NO, JUST RETURN
LOAD T1,SLSIZ,(SL) ;GET THE MAX SEG SIZE WE'RE USING
STOR T1,SAAA1,(SA) ;STORE IT IN SAB ARGUMENT BLOCK
CAIG P1,.NSAA2 ;DOES HE WANT TO KNOW FLOW CONTROL TYPE?
RETSKP ;NO, JUST RETURN
CALL RETFLW ;RETURN THE FLOW CONTROL TYPES
STOR T1,SAAA2,(SA) ;STORE IT IN THE ARGUEMENT BLOCK
RETSKP ; AND RETURN SUCCESSFULLY
SUBTTL NSP. -- NSFIS - Send Interrupt Data
;NSFIS - Send Interrupt Data
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block with user arguments stored
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
; .NSAA1/ Ptr to user-data (which is the interrupt data to be sent)
NSFIS: TRACE SC,<Sending Interrupt Data (.NSFIS)>
TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK?
CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN
NSFIS1: OPSTR <SKIPN P1,>,SASBP,(SA) ;POINT TO THE SBLOCK POINTER
SCERR %NEABE,RTN,<No Sblock supplied>
LOAD T1,SBCNT,(P1) ;GET THE COUNT OF BYTES
SKIPL T1 ;RANGE CHECK THE LENGTH
CAILE T1,^D16 ;IS IT WITHIN THE SPEC?
SCERR %NEIDL,RTN,<Interrupt data too long>
;...
;...
;Allocate the message block.
MOVX T1,^D16 ;GET 16 BYTES (MIGHT AS WELL GO ALL THE WAY
; SINCE THEY'RE IN THE MB ALREADY)
CALL DNGMSG ;GET THE MESSAGE BLOCK
SCERR %NEALF,NSFIS2,<Allocation failure>
MOVE MB,T1 ;SET UP MB
XMOVEI T1,UD.MSD(MB) ;SET UP TO PUT IN BYTES
CALL DNPINI ; IN THE USER SEGMENT
D36OFF ;INTERLOCK AGAINST SCTRIB CALL FROM LLINKS
JE SLOTU,(SL),NSFISO ;JUMP IF THIS WILL BE ONLY OUTPUT BUFFER NOW
MOVE T1,DCNRSB ;GET # NOW RESERVED
SKIPN DCNCON ;IS SYSTEM CONGESTED?
CAML T1,DCNTSB ;NO, IS THERE ROOM FOR ONE MORE?
JRST NSFISF ;NO, RETURN FAILURE
AOS T1,DCNRSB ;ONE MORE BUFFER RESERVED
CAMLE T1,DCNRHT ;NEW HIGH TIDE?
MOVEM T1,DCNRHT ;YES, RECORD IT
JRST NSFISA ;GOT ROOM, GO ALLOCATE
NSFISF: ;NO ROOM FOR THIS LOGICAL LINK
SETOM DCNCON ;CALL FOR CHKSTS WHEN CONGESTION FREES
D36ON ;END CRITICAL SECTION
AOS DCNROF ;INCREMENT OUTPUT RESERVATION FAILURES
CALL FREMSG ;RETURN THE MESSAGE BLOCK
JRST NSFIS2 ;SUCCEEDED IN SENDING ZERO BYTES (CONGESTION)
NSFISO: JN SLINU,(SL),NSFISA ;JUMP IF INPUT BUFF ALLOC, THAT RESERVES 1 OUT
MOVE T1,DCNRSB ;GET # ALREADY RESERVED
ADDI T1,2 ;WE INTEND TO RESERVE 2 MORE (1 IN + 1 OUT)
CAMLE T1,DCNTSB ;WILL THAT FIT IN TOTAL?
JRST NSFISF ;NO, RETURN FAILURE
MOVEM T1,DCNRSB ;YES, D36OFF MAKES THIS STORE OK
CAMLE T1,DCNRHT ;NEW HIGH TIDE?
MOVEM T1,DCNRHT ;YES, RECORD IT
NSFISA: INCR SLOTU,(SL) ;INCREMENT NUMBER OF OUTPUT BUFFERS IN USE
D36ON ;END OF CRITICAL SECTION
;Here to copy the bytes from the user's buffer into the message.
MOVE T1,P1 ;POINT TO THE SBLOCK
CALL CPYS2I ;(T1)COPY INTERRUPT DATA FROM STRING BLOCK
; TO MESSAGE
SETONE <MBBOM,MBEOM>,(MB) ;INTERRUPT MESSAGES ARE ONE SEGMENT
;Update counts
INCR SLPKS,(SL) ;# of 'packets' sent
LOAD T1,SBCNT,(P1) ;Get # of bytes in string block
OPSTRM <ADDM T1,>,SLBYS,(SL) ; and update count in SLB
;Now send the message to NSP.
LOAD T1,SLPID,(SL) ;GET THE NSPpid
SETZ T2, ;T2 HAS THE DA STRUCTURE
SETONE MBOTH,(MB) ;SEND ON THE OTHER SUB-LINK
MOVX T3,NV.SEG ;FUNCTION IS SEND A SEGMENT
MOVE T4,MB ;POINT TO THE MESSAGE BLOCK
CALL NSP ;SEND INTERRUPT MESSAGE
OPSTRM <SOS>,SSXDO,+SL.OSL(SL) ;DECR COUNT OF XMT DATA REQUESTS
SETZRO SBCNT,(P1) ;TELL ASYNCHRONOUS USER WE SENT THE DATA
RETSKP ; AND RETURN SUCCESSFULLY
;Here when DNGMSG or DCNRSB fails due to congestion.
NSFIS2: LOAD T1,SLSST,(SL) ;GET LINK STATUS HALF-WORD
TXZ T1,NSNDR ! NSIDR ;NEITHER TYPE OF OUTPUT IS OK NOW
STOR T1,SLSST,(SL) ;STORE BACK SO WHEN CONGESTION IS FREED
RET ; CHKSTS WILL WAKE USER
SUBTTL NSP. -- NSFIR - Receive Interrupt Data
;NSFIR - Receive Interrupt Data
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block with user arguments stored
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
; .NSAA1/ Ptr to interrupt data
NSFIR: TRACE SC,<Receiving Interrupt Data (.NSFIR)>
TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK?
CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN
MOVX T1,SB.LEN ;GET SB TO STORE THE INTERRUPT DATA
CALL DNGWDZ ; FROM MEMORY MANAGER
SCERR %NEALF,RTN,<Allocation failure>
STOR T1,SASBP,(SA) ;STORE THE POINTER TO STRING BLOCK
MOVX T2,SB.LEN ;LENGTH OF STRING BLOCK IN WORDS
STOR T2,SBWDS,(T1) ;STORE LENGTH IN WORDS IN STRING BLOCK
XMOVEI T1,SL.OSL(SL) ;POINT TO THE OTHER SUB-LINK'S AREA
DEQUE MB,SS.INQ(T1),MB.NXT,NSFIR2 ;TRY TO DEQUE A MESSAGE ON INPUT Q
MOVE T1,MB ;SET UP FOR DNLENG
CALL DNLENG ;FIGURE OUT LENGTH OF MESSAGE
OPSTRM <ADDM T1,>,SLBYR,(SL) ;Update count of bytes received
CAILE T1,^D16 ;IS IT TOO LONG?
CALLRET SCEIVM ;--INVALID MESSAGE EVENT
MOVE P1,T1 ;SAVE THE LENGTH
;Now copy the data into the intermediate buffer.
MOVE T1,MB ;POINT TO THE MESSAGE BLOCK
CALL DNGINI ;SET UP TO GET IT
LOAD T1,SASBP,(SA) ;POINT TO THE INTERNAL STRING BLOCK
CALL CPYI2S ;COPY INTERRUPT DATA TO INTERNAL SB
CALLRET SCEIVM ;--INVALID MESSAGE EVENT
OPSTRM <SOS T1,>,SSRDO,+SL.OSL(SL) ;DECREMENT DATA REQUEST COUNT
OPSTR <CAML T1,>,SLINQ,(SL) ;IS NEW COUNT WITHIN QUOTA?
JRST [CALL FREMSG ;NO, CAN'T SEND ANOTHER DRQ, FREE THE MB
RETSKP] ;AND RETURN TO SCMUUO
OPSTRM <AOS>,SSRDO,+SL.OSL(SL) ;WE'RE SENDING OUT ONE DATA REQUEST
TXO T2,MBOTH ;PUT IT ON THE OTHER SUB-LINK
MOVX T1,1 ;LET'S SEND OUT ONE DATA REQUEST
CALL SNDDRM ;SEND THE DATA REQUESTS
SCERR %NEALF,RTN,<Allocation Failure>
RETSKP ;RETURN SUCCESSFULLY
;Here when there was nothing on the input queue.
NSFIR2: RETSKP ;SCTNA? WILL CALL CHKSTS FOR US
SUBTTL NSP. -- NSFDS - Send Normal Data
;NSFDS - Send Normal Data
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block with user arguments stored
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For .NSFDS function, the function dependant arguments are:
;
; SAAA1/ Byte count
; SAAA2/ Byte pointer to data
; SAAA3/ Optional second word of byte pointer
NSFDS: TRACE SC,<Sending Normal Data (.NSFDS)>
SETZRO SASAT,(SA) ;NOT YET SATISFIED THIS REQUEST.
TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK?
CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN
;We only check the data requests here, not the quotas as well, because
;we may have a msg blk already allocated on the output queue.
LOAD T1,SLXFL,(SL) ;GET FLOW CONTROL TYPE
TMNN SSXDO,+SL.NSL(SL) ;ARE THERE ANY DRQS LEFT?
JUMPN T1,RSKP ;NO, RETURN NICELY UNLESS NO FLOW CTL
IF1,<IFN FCM.NO,<PRINTX ?NSFDS expects FCM.NO to be zero; it isn't>>
;Fall through to next page
;Fall through from previous page
;Here we get a message block in which to put user's data and calculate
;how much of the user's data will fit.
OPSTR <SKIPGE P1,>,SAAA1,(SA) ;GET USER'S BYTE COUNT
SCERR %NEADE,RTN,<Address Error> ;DON'T ALLOW NEGATIVE COUNT
SETZ T1, ;ASSUME NO BYTES IN SAVED MESSAGE
LOAD MB,SLOTM,(SL) ;ALREADY HAVE A MESSAGE?
JUMPE MB,NSFDS0 ;JUMP IF NOT
SETZRO SLOTM,(SL) ;YES, ITS NOT THERE ANY MORE
XMOVEI T1,UD.MSD(MB) ;REINITIALIZE FOR PUTTING BYTES INTO
CALL DNPINR ; A PARTIALLY FILLED MESSAGE BLOCK
MOVE T1,MB ;SEE HOW MANY ARE BYTES ALREADY
CALL DNLENG ; IN IT BY GETTING LENGTH
ADD P1,T1 ;ADD IN BYTES ALREADY IN MESSAGE
NSFDS0: OPSTR <SUB P1,>,SLSIZ,(SL) ;SUBTRACT SEGMENT SIZE WE'RE USING
;P1 is now:
; Negative if user data fits in segment with room to spare
; Zero if user data fits in segment exactly
; Positive if user data is too big to fit in segment
;This fact is used throughout the rest of this routine.
LOAD P2,SAAA1,(SA) ;ASSUME USER'S BUFFER WILL FIT IN SEGMENT
JUMPLE P1,NSFDS1 ;WILL IT FIT?
LOAD P2,SLSIZ,(SL) ;NO, SEND ONE SEGMENT'S WORTH
SUB P2,T1 ;P2 NOW HAS NUMBER OF BYTES WE'LL COPY
NSFDS1: JUMPN MB,NSFDS2 ;JUMP IF WE JUST DEQUEUED A MESSAGE BLOCK
;Get a message block
MOVE T1,P2 ;NUMBER OF BYTES WE'LL COPY INTO FIRST SEGMENT
TMNN SAEOM,(SA) ;IS THIS SEGMENT AN END OF MESSAGE?
LOAD T1,SLSIZ,(SL) ;NO, ALLOCATE A WHOLE SEGMENT'S WORTH SINCE
; USER WILL BE SENDING MORE IN THIS SEG
CALL DNGMSG ;(T1)GET MESSAGE BLOCK
JRST NSFDS6 ;SUCCEEDED IN SENDING ZERO BYTES (CONGESTION)
MOVE MB,T1 ;SET UP MB WITH MESSAGE BLOCK POINTER
XMOVEI T1,UD.MSD(MB) ;INITIALIZE FOR PUTTING BYTES
CALL DNPINI ; IN USER DATA PART OF MESSAGE BLOCK
D36OFF ;INTERLOCK AGAINST SCTRIB CALL FROM LLINKS
JE SLOTU,(SL),NSFDSO ;JUMP IF THIS WILL BE ONLY OUTPUT BUFFER NOW
MOVE T1,DCNRSB ;GET # NOW RESERVED
SKIPN DCNCON ;IS SYSTEM CONGESTED?
CAML T1,DCNTSB ;NO, IS THERE ROOM FOR ONE MORE?
JRST NSFDSF ;NO, RETURN FAILURE
AOS T1,DCNRSB ;ONE MORE BUFFER RESERVED
CAMLE T1,DCNRHT ;NEW HIGH TIDE?
MOVEM T1,DCNRHT ;YES, RECORD IT
JRST NSFDSA ;GOT ROOM, GO ALLOCATE
NSFDSF: ;NO ROOM FOR THIS LOGICAL LINK
SETOM DCNCON ;CALL FOR CHKSTS WHEN CONGESTION FREES
D36ON ;END CRITICAL SECTION
AOS DCNROF ;INCREMENT OUTPUT RESERVATION FAILURES
CALL FREMSG ;RETURN THE MESSAGE BLOCK
JRST NSFDS6 ;SUCCEEDED IN SENDING ZERO BYTES (CONGESTION)
NSFDSO: JN SLINU,(SL),NSFDSA ;JUMP IF INPUT BUFF ALLOC, THAT RESERVES 1 OUT
MOVE T1,DCNRSB ;GET # ALREADY RESERVED
ADDI T1,2 ;WE INTEND TO RESERVE 2 MORE (1 IN + 1 OUT)
CAMLE T1,DCNTSB ;WILL THAT FIT IN TOTAL?
JRST NSFDSF ;NO, RETURN FAILURE
MOVEM T1,DCNRSB ;YES, D36OFF MAKES THIS STORE OK
CAMLE T1,DCNRHT ;NEW HIGH TIDE?
MOVEM T1,DCNRHT ;YES, RECORD IT
NSFDSA: INCR SLOTU,(SL) ;INCREMENT NUMBER OF OUTPUT BUFFERS IN USE
D36ON ;END OF CRITICAL SECTION
NSFDS2:
;Fall through to next page
;Fall through from previous page
;Message block is now ready to receive data and P2 has the count of
;data to copy into it.
MOVE T1,P2 ;PASS # OF BYTES TO COPY TO COPIER
LOAD T2,SAAA2,(SA) ;GET BYTE POINTER
LOAD T3,SAAA3,(SA) ;GET OPTIONAL SECOND WORD OF BYTE PTR
IFN FTOPS10,<
MOVE T4,[XCDSEC,,DNCU2M] ;Assume buffer in user space
TMNE SAEVA,(SA) ;IS THAT TRUE?
>
;Note: SAEVA must be set on TOPS-20 - user mode buffers are not supported
MOVE T4,[XCDSEC,,DNCB2M] ; -no, copy from monitor buffer
CALL 0(T4) ;COPY BUFFER TO THE MESSAGE BLOCK
STOR T2,SAAA2,(SA) ;STORE UPDATED BYTE POINTER
STOR T3,SAAA3,(SA) ;OPTIONAL SECOND WORD OF BYTE PTR
SUB P2,T1 ;T1 contains count of bytes we didn't copy
SKIPLE T1 ;Any bytes not sent?
MOVE P1,T1 ;Yes, remember that
MOVN T1,P2 ;GET # OF BYTES WE COPIED
OPSTRM <ADDM T1,>,SAAA1,(SA) ;FIX USER'S COUNT OF BYTES TO SEND
TMNN SAEOM,(SA) ;IS THIS END OF MESSAGE
SKIPL P1 ; OR DID WE GET A WHOLE SEGMENTS WORTH?
JRST NSFDS3 ;YES, SEND SEGMENT TO NSP
;Here to save pointer to message so that the user can add data to it
;later. Note that in this case we allocated a whole segment when we
;allocated the message block.
SETONE SASAT,(SA) ;WE HAVE SATISFIED THIS NSFDS REQUEST
STOR MB,SLOTM,(SL) ;SAVE PTR TO PARTIALLY FILLED OUTPUT MSG
RETSKP ;RETURN SUCCESSFULLY
;Send segment to NSP.
;Set the BoM and EoM flags in the message block and remember whether
;or not this segment had EoM for figuring the next segment's BoM.
NSFDS3: MOVE T1,SL.EOM(SL) ;GET "LAST SEGMENT'S EOM" WORD
MOVX T2,MBBOM ;GET MESSAGE BLOCK'S BOM FLAG
TXOE T1,SLEOM ;LAST SEGMENT HAVE EOM? (ASSUME THIS WILL)
IORM T2,MB.BOM(MB) ;YES, THIS MUST BE FIRST SEGMENT OF NEXT MSG
JUMPG P1,NSFDS4 ;NEVER EOM IF WE'RE SEGMENTING
MOVX T2,MBEOM ;GET MESSAGE BLOCK'S EOM FLAG
TMNN SAEOM,(SA) ;IS THIS EOM?
NSFDS4: TXZA T1,SLEOM ;NO, REMEMBER THAT FOR NEXT SEGMENT
IORM T2,MB.EOM(MB) ;YES, MARK MESSAGE BLOCK WITH EOM
MOVEM T1,SL.EOM(SL) ;REMEMBER STATE OF EOM FLAG FOR NEXT TIME
;Update counts
INCR SLPKS,(SL) ;# of 'packets' sent
XMOVEI T1,UD.MSD(MB) ;Point to user MSD
CALL DNSLNG ;Get # of bytes in it
OPSTRM <ADDM T1,>,SLBYS,(SL) ; and update bytes sent
;Send the message
LOAD T1,SLPID,(SL) ;GET NSPpid
SETZ T2, ;DAOTH IS ZERO
MOVX T3,NV.SEG ;FUNCTION IS SEND A SEGMENT
MOVE T4,MB ;POINT TO MESSAGE BLOCK
CALL NSP ;DO SEND
;Determine whether or not to claim that we have satisfied the request
MOVX T1,SASAT ;PICK UP SASAT FLAG
SKIPG P1 ;MORE DATA TO SEND FOR THIS REQUEST?
IORM T1,SA.SAT(SA) ;NO, WE'VE SATISFIED THE REQUEST
;Update DRQs.
LOAD T1,SLXFL,(SL) ;GET FLOW CONTROL TYPE WE ARE USING
CAIN T1,FCM.SG ;IS IT SEGMENT?
JRST NSFDS5 ;YES, DECREMENT DATA REQUEST COUNT
SKIPG P1 ;DO WE HAVE ANY MORE SEGMENTS TO SEND LATER?
CAIE T1,FCM.MG ;NO, SAEOM MUST BE SET IF WE'RE HERE
RETSKP ;MORE SEGS TO GO OR NO FLOW CONTROL
NSFDS5: OPSTRM <SOS>,SSXDO,+SL.NSL(SL) ;DECR COUNT OF XMT DATA REQUESTS
RETSKP ; AND RETURN SUCCESS
;Here when DNGMSG fails due to congestion. We have not yet changed
;SAAA1, so the user will see that we succeeded in sending zero bytes.
NSFDS6: LOAD T1,SLSST,(SL) ;GET LINK STATUS HALF-WORD
TXZ T1,NSNDR ! NSIDR ;NEITHER TYPE OF OUTPUT IS OK NOW
STOR T1,SLSST,(SL) ;STORE BACK SO WHEN CONGESTION IS FREED
RETSKP ; CHKSTS WILL WAKE USER
SUBTTL NSP. -- NSFDR - Receive Normal Data
;NSFDR - Receive Normal Data
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block with user arguments stored
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING THE ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFDR function, the function dependant arguments are:
;
; SAAA1/ Byte count
; SAAA2/ Byte pointer
; SAAA3/ Optional second word of byte pointer
NSFDR: TRACE SC,<Receiving Normal Data (.NSFDR)>
SETZRO SASAT,(SA) ;NOT YET SATISFIED THIS REQUEST.
TMNE SLCCB,(SL) ;SHOULD WE CHECK CONNECT BLOCK?
CALL FRECBP ;YES, GET RID OF CONNECT DATA IF WE CAN
LOAD T1,SAFLG,(SA) ;GET THE FLAGS
TXNN T1,SA%WAI ;IS WAIT OFF
TXNN T1,SA%EOM ; AND EOM ON?
TRNA ;NO, NO DEADLY EMBRACE PROBLEM
SCERR %NEBCF,RTN,<Bad Combination of NS.xxx Flags>
XMOVEI P2,SL.NSL(SL) ;POINT TO NORMAL SUBLINK AREA
NSFDR1: LOAD MB,QHBEG,+SS.INQ(P2) ;GET THE FIRST THING ON THE INPUT QUEUE
JUMPE MB,RSKP ;THERE'S NOTHING THERE,
; SCTNI? WILL CALL CHKSTS
;Here with MB/ The Input Message
; P2/ SL.NSL(SL)
;The SASAT flag is set when a read is satisfied, that is, when we have
;read a message segment containing an End of Message flag. SASAT is
;used to tell whether to wake a user who has requested NS.WAIt. SASAT
;is for internal use only: it has no meaning to the user. We cannot use
;SAEOM for this purpose because SAEOM has meaning when passed from the
;user to us: if it is set, then we must put the next message in one
;buffer, possibly truncating data, if SAEOM is cleared by the user, we
;must keep the overflow and present it to the next read. Also, we
;consider a read satisfied if the user's buffer is filled and the
;user has not asserted SAEOM.
MOVE T1,MB ;SET UP FOR CALL TO DNLENG
CALL DNLENG ;GET THE LENGTH OF THE MESSAGE
MOVE P1,T1 ;P1 HAS LENGTH OF USER'S DATA IN MSG
MOVE T1,MB ;GET READY TO READ REST OF BYTES
CALL DNGINI ; IN THE MESSAGE
;Note that the following code does not depend on SASAT being initialized
MOVE T4,SA.FLG(SA) ;GET USER'S FLAGS BEFORE THEY'RE MODIFIED
LOAD T5,MBEOM,(MB) ;GET EOM FLAG FROM MSG BLK, T5 USED BELOW
STOR T5,SASAT,(SA) ;READ IS SATISFIED IF THIS IS EOM
; IOR IF BUFFER IS FULL, SEE BELOW
LOAD T1,SAAA1,(SA) ;GET THE LENGTH OF THE USER'S BUFFER
;
; SPR 10-34926
; If there's a negative count here, it should be because we're discarding
; DECnet messages for the user until we see EOM in an incoming message.
; This happens if the user sets the EOM bit in his arg block, but
; the incoming message is too big to fit in his buffer, and it doesn't
; have EOM set itself. We should discard bytes until we see an EOM.
; SCMUUO already checked to make sure that the user didn't give us a
; negative count to begin with.
;
SUB T1,P1 ;WILL THIS MESSAGE FIT?
JUMPE T1,NSFDR2 ;MSG FITS IN USER BUFFER EXACTLY
JUMPG T1,NSFDR3 ;MSG FITS IN USER BUFFER WITH ROOM TO SPARE
;Here if message overfills user buffer
LOAD P1,SAAA1,(SA) ;COPY ONLY WHAT FITS IN USER BUFFER
SETZ T5, ;BUFFERFUL HAS NO EOM, SINCE IT OVERFLOWED
TXNN T4,SAEOM ;USER WANT WHOLE MSG IN 1 READ?
SETZB P2,T1 ;NO, LEAVE MSG BLK FOR NEXT READ, COUNT := 0
;YES, TOSS REST OF MSG, P2 STILL PTS TO NSL
;Here if message fills or overfills user buffer
NSFDR2: MOVX T2,SASAT ;SATISFACTION FLAG
TXNN T4,SAEOM ;USER WANT WHOLE MSG IN 1 READ?
IORM T2,SA.SAT(SA) ;NO, READ IS SATISFIED SINCE BUFFER IS FULL
; WHETHER OR NOT MBEOM IS TRUE
;Here for all messages, note that count is negative if we toss overflow
NSFDR3: TXNN T4,SAEOM ;USER WANT WHOLE MSG IN 1 READ?
STOR T5,SAEOM,(SA) ;NO, STORE EOM FLAG WE'VE CALC'D HERE
STOR T1,SAAA1,(SA) ;STORE # BYTES REMAINING IN USER BFR
;We now have: P1/ Length of data to copy
; P2/ Pointer to NSL if we're to free msg blk, else 0
JUMPLE P1,NSFDRA ;IF COUNT IS NEGATIVE, DON'T COPY ANYTHING
;Update byte count in SLB
OPSTRM <ADDM P1,>,SLBYR,(SL) ;# of bytes received
;Copy the message data into the user's buffer.
MOVE T1,P1 ;NUMBER OF BYTES TO COPY FROM MSG TO USER
LOAD T2,SAAA2,(SA) ;GET THE BYTE POINTER
LOAD T3,SAAA3,(SA) ; AND OPTIONAL SECOND WORD OF BPTR
IFN FTOPS10,<
MOVE T4,[XCDSEC,,DNCM2U] ;ASSUME BUFFER IN USER SPACE
TMNE SAEVA,(SA) ;IS THAT TRUE?
>
;Note: SAEVA must be set on TOPS-20 - buffer can never be in user space
MOVE T4,[XCDSEC,,DNCM2B] ;No, copy to monitor buffer
CALL 0(T4) ;COPY MESSAGE BLOCK TO BUFFER
CALLRET SCEIVM ;--INVALID MESSAGE EVENT
STOR T2,SAAA2,(SA) ;STORE THE UPDATED BYTE POINTER
STOR T3,SAAA3,(SA) ; AND OPTIONAL SECOND WORD OF BPTR
NSFDRA: JUMPE P2,RSKP ;IF THERE'S NO PTR, WE HAVE MORE TO READ
; FROM THIS MSG, SO DON'T DEQUE MSG
; OR SEND OUT DATA REQUESTS YET
DEQUE MB,SS.INQ(P2),MB.NXT,NSFDRB ;DEQUE MSG WE WERE PEEKING AT
;Here we unreserve an appropriate number of buffers, but we don't
;reserve any again to correspond to the data requests we send, that is
;done by a call to SCTRIB from LLINKS when a message arrives.
NSFDRB: D36OFF ;PROTECT THIS CODE FROM LLINKS CALL TO SCTRIB
OPSTRM <SOS T1,>,SLINU,(SL) ;ONE LESS INPUT BUFFER USED
MOVX T2,-1 ;ASSUME WE'RE NOT FREEING LAST INPUT BUFFER
JUMPG T1,NSFDR4 ;JUMP IF THAT'S TRUE
MOVX T2,-2 ;WE ARE FREEING LAST INPUT, ASSUME NO OUTPUT
TMNE SLOTU,(SL) ;ANY OUTPUT BUFFERS RESERVED?
MOVX T2,0 ;YES, LEAVE AN INPUT BUFFER RESERVED
NSFDR4: ADDB T2,DCNRSB ;ADJUST THE RESERVED BUFFER COUNT
D36ON ;END OF CRITICAL SECTION
LOAD T1,SLINQ,(SL) ;GET THE INPUT QUOTA
OPSTRM <SOS T2,>,SSRDO,+SL.NSL(SL) ;ONE LESS REC DATA REQUEST
SUB T1,T2 ;HOW MANY REQUESTS SHOULD WE SEND NOW?
JUMPL T1,[CALL FREMSG ;IF WE DON'T HAVE ENOUGH QUOTA, CAN'T SEND
; ANOTHER DRQ, SO FREE MESSAGE BLOCK
RETSKP] ;AND RETURN TO MONITOR USER
OPSTRM <ADDM T1,>,SSRDO,+SL.NSL(SL) ;UPDATE RECEIVE DRQ COUNT
;Send the data requests to NSP.
TXZ T2,MBOTH ;(T1,T2)ON THE NORMAL SUB-LINK
CALL SNDDRM ;SEND DATA REQUESTS USING MESSAGE BLOCK
; WE CURRENTLY HAVE
SCERR %NEALF,RTN,<Allocation Failure>
RETSKP ;RETURN SUCCESSFULLY
SUBTTL NSP. -- NSFSQ - Set Quotas and Goals
;NSFSQ - Set Quotas and Goals
;Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block with user arguments stored
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6, P1 & MB
;
;For the .NSFSQ function, the function dependant arguments are:
; .NSAA1/ Link Quota, input + output
; .NSAA2/ % Input
; .NSAA3/ Input Goal
NSFSQ: TRACE SC,<Performing Set Link Quota (.NSFSQ)>
LOAD T1,SLSTA,(SL) ;GET LINK STATE
IFSTATE T1,<DC,LK,CM,CF,NR>,RSKP ;LEAVE QUIETLY IF IN TERMINAL STATE
LOAD P1,SANAG,(SA) ;GET NUMBER OF ARGUMENTS USER SUPPLIED
CAIG P1,.NSAA1 ;DID HE GIVE THE TOTAL QUOTA?
SCERR %NEWNA,RTN,<Wrong number of arguments>
LOAD T1,SLINQ,(SL) ;GET THE OLD QUOTA
OPSTR <ADD T1,>,SLOTQ,(SL) ;TOTAL OF INPUT + OUTPUT QUOTA
OPSTR <SKIPG>,SAAA1,(SA) ;USER SUPPLY A NEW QUOTA?
STOR T1,SAAA1,(SA) ;NO, STORE OLD QUOTA TOTAL AS DEFAULT
MOVEI T2,0 ;NO VALUE OFFERED YET
CAILE P1,.NSAA2 ;DID HE GIVE THE % INPUT?
LOAD T2,SAAA2,(SA) ;GET HIS VALUE
CAILE T2,^D100 ; AND 100
SCERR %NEPIO,RTN,<Percentage input out of bounds>
JUMPG T2,NSFSQ1 ;USER OFFER A VALUE?
MOVEI T2,^D50 ;NO, ASSUME HALF INPUT & HALF OUTPUT
STOR T2,SAAA2,(SA) ;REMEMBER PERCENTAGE WE DECIDED ON
NSFSQ1:
SETZB T1,MB ;DON'T NEED ANY USER DATA
CAIG P1,.NSAA3 ;USER SPECIFY AN INPUT GOAL?
IFSKP. ;Yes, apply default if necessary
LOAD T2,SASJB,(SA) ;Get pointer to SJB
LOAD T1,SJGOL,(T2) ;Get job goal for default
OPSTR <SKIPGE>,SAAA3,(SA) ;Verify supplied value
STOR T1,SAAA3,(SA) ;Apply default
CALL DNGMSG ;GET MESSAGE BLOCK IN CASE WE NEED IT
SCERR %NEALF,RTN,<Allocation failure>
MOVE MB,T1 ;SAVE POINTER TO MSG BLK
ENDIF.
;No more error returns now
LOAD T1,SAAA1,(SA) ;GET THE LINK QUOTA
LOAD T2,SAAA2,(SA) ;GET PERCENTAGE VERIFIED ABOVE
IMUL T1,T2 ;MULTIPY LINK QUOTA BY % INPUT
IDIVI T1,^D100 ;DIVIDE BY 100. TO FIND INPUT QUOTA
STOR T1,SLINQ,(SL) ;STORE THE INPUT QUOTA IN THE SLB
LOAD T2,SAAA1,(SA) ;GET THE LINK QUOTA BACK
SUB T2,T1 ;SUBTRACT TO FIND THE OUTPUT QUOTA
STOR T2,SLOTQ,(SL) ;STORE THE OUTPUT QUOTA IN THE SLB
CAIG P1,.NSAA3 ;WAS THE GOAL SPECIFIED?
RETSKP ;USE DEFAULT THAT'S THERE ALREADY
;WE ONLY GOT MSG BLK IF WE HAVE A GOAL
LOAD T1,SLRFL,(SL) ;GET THE FLOW CONTROL TYPE
LOAD T2,SAAA3,(SA) ;GET THE INPUT GOAL
CAIN T1,FCM.MG ;ARE WE IN MESSAGE FLOW CONTROL?
CAIL T2,1 ;YES, IS OUR GOAL SET TO LESS THAN ONE?
TRNA ;NO, DON'T WORRY ABOUT IT
MOVEI T2,1 ;IN MSG FLOW MODE WE GOAL OF AT LEAST 1
STOR T2,SLGOL,(SL) ;REMEMBER THE GOAL WE DECIDED ON
;Notify NSP of the change in the goal.
LOAD T1,SLPID,(SL) ;GET THE NSPpid
;T2 CARRIED DOWN FROM ABOVE
IFE. T1 ;IS THERE ONE ?
MOVE T1,MB ;NO. DON'T TELL NSP
CALL DNFMSG ; SINCE THERE IS NO PLACE
RETSKP ; TO PUT IT YET.
ENDIF.
MOVX T3,NV.GOL ;FUNCTION IS SET GOAL
MOVE T4,MB ;NSP TAKES MB POINTER IN T4
CALL NSP ;(T1,T2,T3,T4)PERFORM THE SET GOAL
RETSKP ;RETURN SUCCESS
SUBTTL NSP. -- NSFRQ - Read Quotas and Goals
;NSFRQ - Read Quotas and Goals
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block with user arguments stored
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFRQ function, the function dependant arguments are:
;
; .NSAA1/ Link Quota
; .NSAA2/ % Input
; .NSAA3/ Input Goal
NSFRQ: TRACE SC,<Performing Read Link Quota (.NSFRQ)>
LOAD T1,SLINQ,(SL) ;GET THE INPUT QUOTA
LOAD T2,SLOTQ,(SL) ; AND THE OUTPUT QUOTA
ADD T1,T2 ;TOTAL THEM UP
STOR T1,SAAA1,(SA) ;STORE IN ARG BLOCK WERE THE LINK QUOTA GOES
LOAD P1,SANAG,(SA) ;GET THE NUMBER OF ARGUMENTS USER SUPPLIED
CAIG P1,.NSAA2 ;DOES HE WANT THE %INPUT?
RETSKP ;NO, JUST GIVE GOOD RETURN
LOAD T2,SLINQ,(SL) ;Get the input quota
IMULI T2,^D100 ;Multiply by 100 to get % input
IDIV T2,T1 ; as an integer between 0 and 100.
STOR T2,SAAA2,(SA) ;Store it in argument block
CAIG P1,.NSAA3 ;DOES HE WANT THE INPUT GOAL?
RETSKP ;NO, JUST RETURN
LOAD T1,SLGOL,(SL) ;GET THE GOAL
STOR T1,SAAA3,(SA) ;PUT IT IN THE ARG BLOCK
RETSKP ; AND RETURN
SUBTTL NSP. -- NSFJS - Set Job Quotas and Goals
;NSFJS - Set Job Quotas and Goals
;
; Call:
; Never Happens: serviced in SCMUUO
;
; Return:
;
; Uses: Nothing
;
;This function is performed entirely by SCMUUO or equivalent.
NSFJS: SCERR %NEILF,RTN,<Illegal function - handled in SCMUUO>
SUBTTL NSP. -- NSFJR - Read Job Quotas and Goals
;NSFJR - Read Job Quotas and Goals
;
; Call:
; Never Happens: serviced in SCMUUO
;
; Return:
;
; Uses: Nothing
;
;This function is performed entirely by SCMUUO or equivalent.
NSFJR: SCERR %NEILF,RTN,<Illegal function - handled by SCMUUO>
SUBTTL NSP. -- NSFPI - Set PSI Reason Mask
;NSFPI - Set PSI Reason Mask
;
; Call:
; SL/ Pointer to Session Control Link Block
; SA/ Pointer to Session Control Arg Block with user arguments stored
;
; Return:
; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE
; RETSKP ;ALL IS WELL
;
; Uses: T1-T6
;
;For the .NSFPI function, the function dependent arguments are:
;
; .NSAA1/ XWD 0,reason mask
NSFPI: TRACE SC,<Performing Set PSI Mask (.NSFPI)>
LOAD T1,SAAA1,(SA) ;GET .NSAA1 ARGUMENT
STOR T1,SLPSM,(SL) ;STORE THE PSI MASK FOR SCTPSI
TMNE <SLPSI,SLLBC,SLFSL>,(SL) ;PSI ALREADY PENDING OR LINK CLOSING?
RETSKP ;YES, AVOID RACE
;T1 HOLDS OLD STATUS (0),,NEW MASK
LOAD T2,SLCHN,(SL) ;THE LINK NUMBER
LOAD T5,SLSST,(SL) ;T5 PASSES STATUS CHANGES (CURRENT STATUS)
HRL T2,T5 ;T2 HOLDS NEW STATUS,,CHN NUMBER
LOAD T3,SLSJB,(SL) ;@SLWKA NEEDS T3 SET UP WITH PTR TO SJB
MOVE T4,SL ;'LINK IDENTIFIER' TO PASS TO SCTWKQ
OPSTR <SKIPE T6,>,SLWKA,(SL) ;IS THERE A WAKE ROUTINE?
CALL 0(T6) ;(T1,T2,T3,T4,T5)YES, CALL WAKE ROUTINE
RETSKP ;RETURN SUCCESSFULLY
SUBTTL RETFLW - Return current flow controls
;RETFLW - Return Receive Flow Mode,,Transmit Flow Control
;
; Call:
; SL/ Pointer to Session Control Line Block
;
; Return:
; RET ;ALWAYS, WITH T1 CONTAINING RFL,,XFL
;
; Uses: T1,T2
RETFLW: LOAD T1,SLRFL,(SL) ;GET THE RECEIVE FLOW CONTROL
LOAD T2,SLXFL,(SL) ;GET THE TRANSMIT FLOW CONTROL TYPE
ADDI T1,1 ;TRANSLATE TO USER'S VALUE
HRLI T1,1(T2) ;BUILD RFL,XFL
;TRANSLATE THAT ALSO
RET ; AND RETURN
SUBTTL SNDDRQ - Send Data Requests
;SNDDRQ - Send some data requests to NSP
;
; Call:
; T1/ Number of Data Requests to Send
; T2/ MBOTH set to the correct value
; (for SNDDRM:
; MB/ Pointer to Message Block)
;
; Return:
; RET ;ON ALLOCATION FAILURE
; RETSKP ;ON SUCCESS
;
; Uses: T1-T6
;The SNDDRQ code is commented out since there are no callers of it.
; All callers come in at the SNDDRM entry point
Repeat 0,<
SNDDRQ: SAVEAC <MB,P1,P2> ;GET OUR OWN COPY OF MB AND SAVE SOME PEAS
DMOVE P1,T1 ;PRESERVE THE ARGUMENTS
SETZ T1, ;DON'T NEED ANY USER DATA
CALL DNGMSG ;GET A MESSAGE BLOCK
RET ;COULDN'T ALLOCATE, JUST RETURN
MOVE MB,T1 ;POINT TO THE NEW MESSAGE BLOCK
CALLRET SNDDRX ;JOIN COMMON CODE
>
;This is the alternate entry for those guys which already have a message
;block.
SNDDRM: DMOVE P1,T1 ;SAVE THE COUNT AND MBOTH
MOVE T1,MB ;POINT TO THE MESSAGE BLOCK
MOVEI T2,0 ;NO USER DATA NEEDED
CALL DNMINI ;RE-INITIALIZE THE MESSAGE BLOCK
RET ;COULDN'T DO IT
SNDDRX: SETZ T2, ;BUILD THE DATA REQUEST ARG BLOCK (QA) IN T2
STOR P1,QACNT,+T2 ; USE THAT AS THE DATA REQUEST COUNT
MOVX T1,MBOTH ;GET THE "OTHER" SUBLINK FLAG
TXNE P2,MBOTH ;CALLER WANT IT SET IN MESSAGE BLOCK?
IORM T1,MB.OTH(MB) ;YES, IT WAS CLEARED BY DNMINI
LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP
MOVX T3,NV.DRQ ;FUNCTION IS SEND DATA REQUESTS
MOVE T4,MB ;POINT TO MESSAGE BLOCK
CALL NSP ;CALL NSP AND RETURN EVENTUALLY
RETSKP ;RETURN SUCCESS
SUBTTL RLSLNK - Release a Link
;RLSLNK - Release a Link
;
; Call:
; MB/ Ptr to msg blk or zero if LLINKS will not have to queue NV.CLS call
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6,MB,MS
RLSLNK: JN <SLFSL,SLLBC>,(SL),RLSLN1 ;IGNORE IF LINK ALREADY BEING CLOSED
SKIPN EV96.0 ;Shall we log the CSSE event?
IFSKP. ; -yes, unfortunately
EVENT(LCG,CSE,Link close) ;Log "link close" event for CSSE
ENDIF.
CALL STPTMR ;STOP THE CI TIMER, IF IT'S GOING
JN SLPID,(SL),RLSLN2 ;JUMP IF WE HAVE A PID FROM NSP
SETONE SLFSL,(SL) ;WE HAVEN'T TOLD NSP ABOUT
; THIS LINK YET, DON'T CALL HIM NOW
CALL SCTRFJ ;REQUEST SECOND SERVICE, SLFSL WILL
; TELL IT TO FREE THE SLB
RLSLN1: SKIPN MB ;DID WE HAVE A MSG BLK?
RET ;NO, ONLY RETURN
CALLRET FREMSG ;YES, FREE IT AND RETURN
RLSLN2: LOAD T1,SLPID,(SL) ;GET THE NSPpid FROM SLB
LOAD T2,SLSLB,(SL) ;GET THIS PORT'S SLBid
MOVX T3,NV.CLS ;CLOSE FUNCTION FOR NSP
MOVE T4,MB ;NSP WANTS MSG BLK PTR IN T4 (ZERO IF RESET)
CALL NSP ;CALL NSP TO CLOSE THE PORT
SETONE SLLBC,(SL) ;LINK IS BEING CLOSED
RET ;ONLY RETURN
SUBTTL LLINKS Calls -- Entry Vector Table
;See procedure SCTL for a description of the calling sequence used to
;call SCTL.
;The offsets SV.xxx into this table are defined in D36PAR.
DEFINE SV(NAM),<
IFN .-SCFNT-SV.'NAM,< PRINTX ?SCFNT table (NAM) not in same order
PRINTX ? as SV.'NAM in D36PAR.UNV
PASS2
END>
IFIW <SC'NAM&777777>>
;These are the function codes for the calls to Session Control from
;NSP.
SCFNT: SV CCR ;CONNECT CONFIRMED CALL
SV DIR ;DISCONNECT INITIATE RECEIVED CALL
SV DCR ;DISCONNECT CONFIRM RECEIVED CALL
SV OND ;OUTPUT NOT DONE CALL
SV ODN ;OUTPUT DONE CALL
SV SEG ;SEGMENT RECEIVED CALL
SV DRQ ;DATA REQUEST RECEIVED CALL
SV NCF ;NO CONFIDENCE IN PORT CALL
SV NRS ;NO RESOURCES CALL
SV CLS ;CLOSE COMPLETED CALL
SV NLK ;NO LINK CALL
SV NCM ;NO COMMUNICATION CALL
SV NRN ;NOT IN RUN STATE
SV CAK ;GOT A CONNECT ACK
SV.MAX==.-SCFNT-1 ;THE HIGHEST RECOGNIZED ENTRY OFFSET
;The Connect Initiate call does not go
;through the vectored interface, since
;it must go to a single routine
;capable of sorting out which Session
;Control will handle the incoming
;message. the connect initiate call
;goes to the global label SCTLCI.
PURGE SV
SUBTTL LLINKS Calls -- SCTRIB - Reserve Input Buffer
;SCTRIB - Reserve Input Buffer
;
;Call: T1/ Pointer to SLB
; CALL SCTRIB
; Error Return: no input buffer has been reserved
; Normal Return: one input buffer has been reserved
;Changes T1,T2,T3,T4
;This routine and all others which reference DCNRSB must run under
;D36OFF because this routine is called from LLINKS without the SCLINK
;interlock. This routine is only called from LLINKS. It is here in
;SCLINK so that all references to the reserved buffer counter will be
;together in one module.
;The scheme here is that we want to count the buffers which are
;actually in use, plus those which are required to be reserved in
;order to prevent a deadlock. We must be sure that no logical link is
;put in the position of being having a allowed to read a message while
;being stuck not allowed to send a message. If both ends of a link
;were to be in that state, they would be in a deadly embrace.
;
;So whenever we want to commit a buffer for output (by sending it) or
;for input (by ACKing it), we must check first if we have room in the
;system pool to reserve it. If we reserve a buffer for one direction,
;then we must assure that at least one is reserved for the other
;direction.
;
;The handling of DCNRSB in SCLINK preserves the above guarantees.
;This routine is called from LLINKS when it receives a message and
;there are Session Control data requests for that message. If this
;routine returns failure, LLINKS will keep the message, unACKed, and
;will try to send it to Session Control again when the memory manager
;tells LLINKS that congestion has been relieved.
XRESCD
SCTRIB: OPSTR <CAME T1,>,SLSLB,(T1) ;IS THIS A LEGIT SLB POINTER?
BUG.(CHK,SCLRIB,SCLINK,SOFT,<Bad SCTRIB call from LLINKS>,<<T1,ADDR>>,<
Cause: LLINKS has called SCTRIB for permission to send a message to SCLINK
and has passed an invalid SLB address in T1. The data structures
for this logical link are inconsistent.
Action: Find out what is in LLINK's ELSCB and why its not an SLB pointer.
Data: ADDR - The bad SLB pointer
>,RTN)
D36OFF ;INTERLOCK AGAINST SCTRIB CALL FROM LLINKS
JE SLINU,(T1),SCTRB1 ;JUMP IF THIS WILL BE ONLY INPUT BUFFER NOW
MOVE T2,DCNRSB ;GET # NOW RESERVED
SKIPN DCNCON ;IS THE SYSTEM CONGESTED?
CAML T2,DCNTSB ;NO, CAN WE FIT ONE MORE?
JRST SCTRB3 ;NO ROOM FOR THIS LINK
AOS T2,DCNRSB ;ONE MORE BUFFER RESERVED
JRST SCTRB2 ;SUCCESS
SCTRB1: JN SLOTU,(T1),SCTRB4 ;JUMP IF OUTPUT BUFF ALLOC, THAT RESERVES 1 IN
MOVE T2,DCNRSB ;GET # ALREADY RESERVED
ADDI T2,2 ;WE INTEND TO RESERVE 2 MORE (1 IN + 1 OUT)
CAMLE T2,DCNTSB ;ENOUGH ROOM IN TOTAL SYSTEM BUFFERS?
JRST SCTRB3 ;NO, NO ROOM FOR THIS LINK
MOVEM T2,DCNRSB ;YES, D36OFF MAKES THIS STORE OK
SCTRB2: CAMLE T2,DCNRHT ;NEW HIGH TIDE?
MOVEM T2,DCNRHT ;YES, RECORD IT
SCTRB4: INCR SLINU,(T1) ;UPDATE INPUT_BUFFERS_IN_USE COUNT
D36ON ;END OF CRITICAL SECTION
RETSKP ;GOT ROOM, SUCCESS RETURN
SCTRB3: SETOM DCNCON ;CALL FOR CHKSTS WHEN CONGESTION FREES
D36ON ;END OF CRITICAL SECTION
AOS DCNRIF ;INCREMENT INPUT RESERVATION FAILURES
RET ;FAIL RETURN
SUBTTL LLINKS Calls -- SCTUCG - Uncongestion Call
;SCTUCG - LLINKS calls this routine when memory manager announces
; that congestion is relieved.
;
; Call:
; No arguments
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
XRESCD
SCTUCG: SAVEAC <MB,SL,SA,MS,P1,P2>
TRACE SC,Session Control told of congestion relief
SETOM SCTUCF ;NO MESSAGE BLOCK TO QUEUE HERE
CALLRET SCTLCF ;GET THE INTERLOCK, FLAG IF FAIL
;When NSFDS (data send) and NSFIS (interrupt send) fail to get a
;message block, they will both turn off both NSNDR (normal data
;requests available) and NSIDR (interrupt data requests available).
;Presumably this will only happen if the system is congested. Later,
;when the system congestion is relieved, we must tell the stalled
;links that we again have message blocks available. Since the NSxDR
;flags in the status half-word have been turned off, this call to
;CHKSTS will turn them back on again if appropriate and this will
;trigger CHKSTS to call the wake routine.
SCIUCG: LOAD SL,QHBEG,+SCTASQ ;PTR TO FIRST SLB ON ALL SLBs Q
SCIUC1: JUMPE SL,RTN ;RETURN WHEN NO MORE SLBs TO VISIT
CALL CHKSTS ;SEE IF THIS SLB NEEDS WAKING
LOAD SL,SLASQ,(SL) ;STEP TO NEXT SLB ON ALL SLBs Q
JRST SCIUC1 ;LOOP OVER ALL SLBs IN SYSTEM
SUBTTL LLINKS Calls -- SCTLCI - Connect Initiate Call
;SCTLCI - Connect Initiate Call
;
; Call:
; T1/ NSPpid for port just created
; T2/ Connect Call arguments (see BEGSTR IA in D36PAR)
; T4/ Pointer to Message Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
XRESCD
SCTLCI: SAVEAC <MB,SL,SA,MS,P1,P2>
TRACE SC,Connect Initiate call
MOVE MB,T4 ;SET UP THE MESSAGE BLOCK POINTER
STOR T1,MBAR1,(MB) ;STORE THE FIRST ARGUMENT
STOR T2,MBAR2,(MB) ; AND THE SECOND ONE
XMOVEI T1,SCTLC1 ;PROCESSOR TO CALL WHEN WE
CALLRET SCTLCQ ; GET THE INTERLOCK
;Now try to find a matching SLB for the incoming connect.
SCTLC1: TRACE SC,Processing Connect Initiate
MOVE T1,MB ;POINT TO THE INCOMING MESSAGE BLOCK
CALL DNGINI ;SET UP MS FOR DNGxBY ROUTINES
MOVX T1,CB.LEN ;WE HAVE TO GET A CONNECT BLOCK
CALL DNGWDZ ; TO FILL IN AND COMPARE WITH PASSIVE SLBS
JRST SCTCIR ;RESOURCE FAILURE
MOVE P1,T1 ;SAVE POINTER TO INCOMING CONNECT BLOCK
CALL PRSCTX ;PARSE THE INCOMING CONNECT DATA IN CB
JRST [ MOVE T1,P1 ;PTR TO NEW CONNECT BLK
CALL DNFWDS ;FREE NEW CONNECT BLK
CALLRET SCEIVM] ;--INVALID MESSAGE EVENT
MOVE T1,P1 ;GET THE INCOMING CONNECT BLOCK POINTER BACK
CALL SLBMAT ;FIND PASSIVE SLB TO MATCH NEW SLB
JRST [ EXCH T1,P1 ;Get pointer to new connect block and save
; return code
CALL DNFWDS ;Free the connect blk
JUMPN P1,SCTCIT ;Return 'object too busy'
CALLRET SCTCIN] ; otherwise unrecognized object error
;We have found matching SLB, lets set some parameters in the SLB and
;go into CR state.
LOAD T1,SLCBP,(SL) ;POINT TO PASSIVE CB
CALL DNFWDS ;FREE THAT UP
SETZRO SLCBP,(SL) ;LOSE PTR TO PASSIVE CB WE JUST FREED
LOAD T1,MBSRC,(MB) ;GET SOURCE NODE ADDRESS
STOR T1,SLDNA,(SL) ; AND STORE AS DESTINATION OF THIS LINK
STOR T1,CBNUM,(P1) ; and store in connect block
SCTLC2: STOR P1,SLCBP,(SL) ;PUT PTR TO ACTIVE CONNECT BLK IN SLB
; FOR .NSFRI FUNCTION
XMOVEI T1,CB.SRC(P1) ;Point to source PDB
LOAD T1,PBOBJ,(T1) ;Get remote object type
STOR T1,SLDOB,(SL) ; and store as destination PDB in SLB
LOAD T1,MBAR1,(MB) ;GET THE NSPpid
STOR T1,SLPID,(SL) ;STORE IT IN THE SLB
LOAD T2,MBAR2,(MB) ;GET THE CONNECT CALL ARGUMENTS
LOAD T1,IAFLO,+T2 ;GET FLOW CONTROL TYPE FROM ARGUMENTS
STOR T1,SLXFL,(SL) ; AND STORE IT IN SLB
LOAD T1,SLDNA,(SL) ;Get destination address
LOAD T2,IASIZ,+T2 ;Get segment size specified by remote
CALL SCTCSS ;Check what segment size we should use
STOR T1,SLSIZ,(SL) ; and store the segment size ROUTER calculated
NEWSTATE CR ;CALL SCSSTS TO PUT US IN .NSSCR STATE
; AND WAKE THE USER
TMNE MBPH2,(MB) ;IS THIS CONNECT FROM A PHASE II GUY?
CALL CONBUF ;YES, SET UP FOR CONSERVATIVE BUFFERING
CALL STRTMR ;START CONNECT TIMERS & FIX TIMER COUNTS
CALLRET FREMSG ;DEALLOCATE CI MESSAGE, & RETURN TO NSP
;Here when we could not get enough resources to accept the Connect.
SCTCIR: MOVX P2,RSNRES ;NO RESOURCES ERROR CODE
JRST SCTCFN ;TO COMMON REJECT CODE
SCTCIT: MOVX P2,RSNOTB ;Object too busy code
JRST SCTCFN ; to common rejet code
SCTCIN: MOVX P2,RSNURO ;UNRECOGNIZED OBJECT REASON CODE
SCTCFN: TRACE SC,Rejecting Connect Initiate call
LOAD P1,MBAR1,(MB) ;SAVE THE NSPpid
MOVE T1,MB ;SET UP FOR DNMINI CALL
MOVEI T2,3 ;LENGTH OF USER DATA NEEDED
CALL DNMINI ;RE-INITIALIZE THE MESSAGE BLOCK WE'RE USING
RET ; Will never happen - but if, just return
XMOVEI T1,UD.MSD(MB) ;POINT TO THE USER MSD
CALL DNPINI ;INITIALIZE FOR PUTTING BYTES
MOVE T1,P2 ;GET REASON CODE
CALL DNP2BY ;PLACE IT IN THE MESSAGE
SETZ T1, ;NO DATA-CTL NEEDED
CALL DNP1BY ;PLACE IT IN
MOVE T1,P1 ;SET UP THE NSPpid
MOVX T3,NV.REJ ;REJECT THE CONNECT
MOVE T4,MB ;SET UP POINTER TO MESSAGE BLOCK
CALLRET NSP ;INFORM NSP OF FAILURE
SUBTTL LLINKS Calls -- The Vectored Call Entry Point SCTL
;SCTL - Here for all calls from NSP except Connect Initiate
;
; Call:
; T1/ SLBid
; T2/ Function specific argument
; T3/ Function Code (SV.xxx)
; T4/ Pointer to message block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
XRESCD
SCTL: SAVEAC <MB,MS,SA,SL> ;SAVE SOME ACS
MOVE MB,T4 ;SET UP MESSAGE BLOCK
STOR T1,MBAR1,(MB) ;STORE THE SLBid
STOR T2,MBAR2,(MB) ;STORE THE FUNCTION SPECIFIC ARGUMENT
STOR T3,MBAR3,(MB) ;STORE THE FUNCTION CODE
XMOVEI T1,SCTL1 ;ADDRESS OF PROCESSOR TO CALL AFTER WE
CALLRET SCTLCQ ; GET THE INTERLOCK
SCTL1: CALL FNDSBI ;FIND THE SLB FROM THE SLBid
CALLRET FREMSG ;NO SUCH SLBid, IGNORE THIS MSG
CALLRET @SCFNT(T3) ;DISPATCH BY FUNCTION TYPE
SUBTTL LLINKS Calls -- SCCCR - Connect Confirmed call from NSP
;SCCCR - Connect Confirmed call from NSP
;
; Call:
; T2/ Connect Initiate arguments (see BEGSTR IA in D36PAR)
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCCCR: TRACE SC,Connect confirmed call
SAVEAC P1 ;SAVE A PEA
MOVE P1,T2 ;SAVE ARGUMENT FROM NSP
CALL STPTMR ;STOP CI TIMER & DECREMENT TIMER COUNTS
LOAD T1,IAFLO,+P1 ;GET FLOW CONTROL TYPE
STOR T1,SLXFL,(SL) ;STORE TRANSMIT FLOW TYPE IN SLB
;We have to cater for a VMS crock here. Assuming that the buffer size
; is 576 bytes, VMS announces 561 bytes while TOPS-20 would pick 559 bytes.
; The reason is that VMS never uses the piggy-back field while we do do.
;
;Now, if we are an endnode and we try to connect to a remote node and we run
; with big buffers, we will probably suggest 1450 bytes. If the remote is
; not on the same NI and is a VAX it will return 561 bytes and we will accept
; that.... so we make a special test for if the remote buffer size is equal
; to our executor buffer size - %schdr + 2
LOAD T1,IASIZ,+P1 ;GET MAX BYTES ALLOWED IN MESSAGE SEGMENT
MOVE T2,RTRBSZ ;Get router buffer size
SUBI T2,<%SCHDR-2> ;Get 'VMS size'
CAMN T1,T2 ;Equal?
SUBI T1,2 ; -yes, fudge for VMS
STOR T1,SLSIZ,(SL) ;STORE THAT
TMNE MBPH2,(MB) ;WAS CC FROM A PHASE II NODE?
CALL CONBUF ;YES, USE CONSERVATIVE BUFFERING
STOR MB,SLCDM,(SL) ;SAVE CONNECT MSG FOR "NSFRC"
NEWSTATE RN ;SET NEW STATE TO CONNECT RECEIVED
SETONE SLCCB,(SL) ;HAVE TO CHECK CONNECT BLOCK NOW
;Now let's send the job's input quota worth of DRQs.
TMNE SLPH2,(SL) ;SHOULD WE BE CONSERVATIVE WITH THIS FELLOW?
RET ;LEAVE QUIETLY
MOVEI T1,0 ;DON'T NEED ANY USER DATA
CALL DNGMSG ;GET A NEW MESSAGE BLOCK
RET ; - resource error
MOVE MB,T1 ;POINT TO THE NEW MSG BLK
SETZRO MBOTH,(MB) ;SEND OUT ON THE NORMAL SUBLINK
SETZ T2, ;BUILD THE DATA REQUEST ARG BLOCK (QA) IN T2
LOAD T1,SLINQ,(SL) ;GET THE INPUT QUOTA
STOR T1,QACNT,+T2 ; USE THAT AS THE DATA REQUEST COUNT
STOR T1,SSRDO,+SL.NSL(SL) ;WE KEEP COUNT OF OUTGOING DATA REQUESTS
LOAD T1,SLPID,(SL) ;GET THE NSPpid FOR NSP
MOVX T3,NV.DRQ ;FUNCTION IS SEND DATA REQUESTS
MOVE T4,MB ;POINT TO MESSAGE BLOCK
CALLRET NSP ;CALL NSP AND RETURN EVENTUALLY
SUBTTL LLINKS Calls -- SCDIR - Disconnect Initiate received call
;SCDIR - Disconnect Initiate received call from NSP
;
; Call:
; T2/ Reason Code
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T2
SCDIR: TRACE SC,Disconnect Initiate received call
SAVEAC P1 ;SAVE A PEA
STOR T2,SLRSN,(SL) ;ALSO STORE THE REASON FOR ERROR CODE
; PROCESSING
LOAD P1,SLSTA,(SL) ;GET THE STATE OF LINK
IFSTATE P1,CS ;IF WE WERE IN CONNECT SENT STATE,
CALL STPTMR ; STOP CI TIMERS & ADJUST TIMER CNTRS
OPSTR <SKIPE T1,>,SLCDM,(SL) ;ANY CONNECT DATA STILL THERE?
CALL DNFMSG ;YES, FREE IT NOW
STOR MB,SLCDM,(SL) ;STORE DISCONNECT MESSAGE
SETONE SLCCB,(SL) ;HAVE TO CHECK CONNECT BLOCK NOW
IFNSTATE P1,CS,SCDIR1 ;IF WE WERE IN CONNECT SENT,
NEWSTATE RJ ; SET THE STATE TO RJ
RET ; AND RETURN
;We differentiate between RJ and DR states here so that the user can
;tell from the state whether or not the link has ever been open.
SCDIR1: NEWSTATE DR ;WE GOT INTO RN STATE, SO GO INTO DR STATE
RET ;RETURN
SUBTTL LLINKS Calls -- SCDCR - Disconnect Confirm received call
;SCDCR - Disconnect Confirm received call from NSP
;
; Call:
; T2/ Reason Code
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T2
SCDCR: TRACE SC,Disconnect Confirm received call
SAVEAC P1
;A DC is normally received in response to our sending out a DI. In
;this case, there will be no interesting reason code and the link will
;not be in CS state, etc. Phase II nodes, or those not yet updated to
;Phase III fully, will reject a CI with a DC instead of a DI and in
;this case the only reason code we get is on that DC message.
STOR T2,SLRSN,(SL) ;ALSO STORE THE REASON FOR ERROR CODE
; PROCESSING
OPSTR <SKIPE T1,>,SLCDM,(SL) ;ANY CONNECT DATA STILL THERE?
CALL DNFMSG ;(T1) YES, FREE IT NOW
SETZRO SLCDM,(SL) ;NO DISCONNECT MESSAGE FROM A DC
LOAD P1,SLSTA,(SL) ;GET THE STATE OF LINK
IFNSTATE P1,CS,SCDCR1 ;IF WE WERE IN CONNECT SENT STATE,
CALL STPTMR ; STOP CI TIMERS & ADJUST TIMER CNTRS
NEWSTATE RJ ;GO INTO REJECT STATE
CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY
;Here if link was not in CS state
SCDCR1: NEWSTATE DC ;GO INTO DISCONNECT CONFIRM STATE
CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY
SUBTTL LLINKS Calls -- SCODN - Output done call
;SCODN - Output done call from NSP
;SCOND - Output not done call from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T2
SCOND:!
SCODN: TRACE SC,Output done call
D36OFF ;PROTECT THIS CODE FROM LLINKS CALL TO SCTRIB
OPSTRM <SOS T1,>,SLOTU,(SL) ;DECREMENT OUTPUT BUFFERS IN USE
MOVX T2,-1 ;ASSUME WE'RE NOT FREEING LAST OUTPUT BUFFER
JUMPG T1,SCODN1 ;JUMP IF THAT'S TRUE
MOVX T2,-2 ;WE ARE FREEING LAST OUTPUT, ASSUME NO INPUT
TMNE SLINU,(SL) ;ANY INPUT BUFFERS ALLOCATED?
MOVX T2,0 ;YES, LEAVE AN OUTPUT BUFFER RESERVED
SCODN1: ADDB T2,DCNRSB ;ADJUST THE RESERVED BUFFER COUNT
D36ON ;END OF CRITICAL SECTION
CALL FREMSG ;FREE THE MESSAGE BLOCK
CALLRET CHKSTS ;GENERATE PSI INTERRUPT "OUTPUT-OK"
SUBTTL LLINKS Calls -- SCSEG - Segment received call
;SCSEG - Segment received call from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCSEG: TRACE SC,Segment Received Call
XMOVEI T4,SL.NSL(SL) ;ASSUME IT'S ON THE NORMAL SUBLINK
TMNE MBOTH,(MB) ;IS IT THE OTHER SUBLINK?
XMOVEI T4,SL.OSL(SL) ;YES, POINT TO OTHER AREA
ENDQUE MB,SS.INQ(T4),MB.NXT,T1 ;QUEUE THE MESSAGE
INCR SLPKR,(SL) ;Increment # of packets received
CALLRET CHKSTS ;SEE IF THE USER NEEDS WAKING
;Note: The count of input buffers used is incremented when the data
;requests are sent out in NSFxR, so we don't have to incr now.
SUBTTL LLINKS Calls -- SCDRQ - Data request received call
;SCDRQ - Data request received call from NSP
;
; Call:
; T2/ DATA REQUEST call's arguments (see BEGSTR QA in D36PAR)
; SL/ Pointer to Session Control Link Block
; MB/ Pointer to the Message Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCDRQ: TRACE SC,Data Request Received Call
XMOVEI T4,SL.NSL(SL) ;ASSUME IT CAME FROM NORMAL SUBLINK
TMNE MBOTH,(MB) ;DID IT?
XMOVEI T4,SL.OSL(SL) ;NO, MUST BE FROM INTERRUPT SUBLINK
LOADE T1,QACNT,+T2 ;GET THE DATA REQUEST COUNT
LOADE T3,SSXDO,(T4) ;GET # OF DRQS WE HAVE NOW OUTSTANDING
ADD T3,T1 ;NEW COUNT OF DATA REQUESTS
STOR T3,SSXDO,(T4) ;STORE THE NEW DATA REQUEST COUNT
CALL CHKSTS ;SET THE STATUS, POSSIBLY GENERATING PSI
CALLRET FREMSG ;FREE THE MESSAGE BLOCK
SUBTTL LLINKS Calls -- SCNCF - No confidence in port call
;SCNCF - No confidence in port call from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCNCF: TRACE SC,No confidence in port call
NEWSTATE CF ;NEW STATE IS NO CONFIDENCE
CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY
SUBTTL LLINKS Calls -- SCNRS - No resources call
;SCNRS - No resources call from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCNRS: TRACE SC,No resources call
NEWSTATE NR ;SET THE NEW STATE TO "NO RESOURCES"
CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY
SUBTTL LLINKS Calls -- SCCLS - Close Completed call
;SCCLS - Close Completed call from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCCLS: TRACE SC,Close Completed call
SETONE SLFSL,(SL) ;FREE THE SLB ON NEXT TICK
CALL SCTRFJ ;REQUEST SECOND SERVICE FOR THIS LINK
CALLRET FREMSG ;FREE THE MESSAGE BLOCK
SUBTTL LLINKS Calls -- SCNLK - No link call
;SCNLK - No link call from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCNLK: TRACE SC,No Link call
NEWSTATE LK ;NEW STATE IS NO-LINK
CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY
SUBTTL LLINKS Calls -- SCNCM - No communication call
;SCNCM - No communication call from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCNCM: TRACE SC,No communication call
NEWSTATE CM ;NEW STATE IS NO COMMUNICATION
CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY
SUBTTL LLINKS Calls -- SCNRN - Not in Run State call
;SCNRN - Not in Run State call from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
SCNRN: TRACE SC,Not in Run State call
;NO NEW STATE TO GO INTO HERE
CALLRET CHKABO ;(MB)CLOSE PORT IF NECESSARY
SUBTTL LLINKS Calls -- SCCAK - Got a Connect ACK
;SCCAK - Got a Connect ACK from NSP
;
; Call:
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1
;
;NSP will call us here to report a connect ACK. Using this call, we
;can determine that the CI has made it to the remote, while the remote
;user hasn't yet accepted the connect. Maybe someday we'll figure out
;what to do with this.
SCCAK: TRACE SC,Got a Connect ACK
CALLRET FREMSG
SUBTTL Subroutines -- CHKABO - Check SLABO flag
;CHKABO - Check SLABO flag, close port if need be
;
; Call:
; MB/ Pointer to a message block
; SL/ Pointer to Session Control Link Block
;
; Return:
; RET ;ALWAYS, MESSAGE BLOCK FREED
;
; Uses: T1-T6
;
CHKABO: TMNN SLABO,(SL) ;ARE WE TRYING TO CLOSE AFTER AN ABORT?
CALLRET FREMSG ;NO, FREE MSG BLK AND LEAVE
TMNE <SLFSL,SLLBC>,(SL) ;YES, HAVE WE ALREADY CLOSED LINK?
CALLRET FREMSG ;YES, FREE MSG BLK AND LEAVE
CALLRET RLSLNK ;(MB)RELEASE THE LINK AND RETURN
SUBTTL Subroutines -- CHKPPN - Check self PPN for validity
;CHKPPN - Check PPN in self port block
;
; Call:
; T1/ Pointer to Port Block
; SL/ Pointer to SLB
; Return
; RET ;INVALID PPN AND NO PRIVS TO FAKE IT
; RETSKP ;VALID
CHKPPN:
IFN FTOPS10,<
LOAD T2,SLSJB,(SL) ;GET POINTER TO SJB
JN SJPRV,(T2),RSKP ;IF PRIVED, ALWAYS VALID
IFN <PB.USR-PB.GRP>,<PRINTX PBUSR and PBGRP must be in same word>
MOVE T1,PB.USR(T1) ;GET PPN WE CLAIM TO BE
LOAD T2,SJJOB,(T2) ;GET JOB OUR JOB NUMBER
CAME T1,JBTPPN##(T2) ;COMPARE OUR PPN WITH PPN WE CLAIM TO BE
RET ;THAT'S NOT YOU. FAIL.
RETSKP ;THAT'S YOU ALRIGHT. SUCCEED.
> ;END IFN FTOPS10
IFN FTOPS20,<
RETSKP ;SUCCEED UNTIL WE DECIDE TO CHECK
> ;END IFN FTOPS20
SUBTTL Subroutines -- FREMSG - Free a message block
;FREMSG - Free a message block
;
; Call:
; MB/ Pointer to Message Block
;
; Return:
; RET ;ALWAYS
;
; Uses: T1-T6
FREMSG: MOVE T1,MB ;POINT TO THE MESSAGE BLOCK
TRASH MB, ;CATCH A BUG
CALLRET DNFMSG ;FREE THE MESSAGE BLOCK
SUBTTL Subroutines -- CONBUF - Invoke Conservative Buffering
;CONBUF - Invoke Conservative Buffering
;
; Call:
; SL/ Pointer to SLB
;
; Return:
; RET ;ALWAYS
;
; Uses: T1,T2
;If we do support Phase II, then this routine will have to be updated
;to reserve a small number of buffers (eg, 1 in + 1 out) at open time,
;and then the rest of the 'reserve' routines will have to test for
;Phase II and promise never to release this link's reservations, and
;always to use the existing reservation when reallocating.
CONBUF: BUG.(INF,SCLCBN,SCLINK,SOFT,<Phase-II buffering not implemented>,,<
Cause: Conservative buffering is not yet implemented.
We should never have a logical link open to a phase II node.
>)
SETONE SLPH2,(SL) ;MARK LINK AS A PHASE II LINK
MOVX T1,FCM.SG ;DO SEGMENT FLOW CONTROL ONLY
STOR T1,SLRFL,(SL) ;SET THE RECEIVE FLOW CONTROL TYPE
SETZRO SLGOL,(SL) ;SET THE GOAL TO ZERO
MOVX T1,SCTP2Q ;GET THE PHASE II QUOTA
STOR T1,SLINQ,(SL) ;STORE THAT AS THE INPUT QUOTA
STOR T1,SLOTQ,(SL) ; AND AS THE OUTPUT QUOTA
RET ;ONLY RETURN
SUBTTL Subroutines -- FNDSLB - Find SLB given a channel number
;FNDSLB - Find a SLB from a channel number
;
; Call:
; T1/ Channel #
; T2/ Pointer to Session Control Job Block
;
; Return:
; RET ;COUDLN'T GET IT
; RETSKP ;FOUND IT OK, SL POINTS TO IT
;
; Uses: T1,T2,T4,SL
FNDSLB: JUMPLE T1,RTN ;IF NEGATIVE OR ZERO, RETURN FAILURE
OPSTR <CAMLE T1,>,SJCHC,(T2) ;DO A QUICKIE RANGE CHECK
RET ;OUT OF BOUNDS
SOJ T1, ;OUR OFFSET IS ZERO, WHILE USER'S IS ONE
LOAD T4,SJCHT,(T2) ;GET POINTER TO SLB TABLE
ADD T4,T1 ;FIND ENTRY FOR THIS CHANNEL
SKIPN SL,(T4) ;GET THE POINTER TO IT
RET ;NO THERE, GIVE BAD RETURN
OPSTR <CAME SL,>,SLSLB,(SL) ;MAKE SURE IT POINTS TO AN SLB
BUG.(CHK,SCLSPF,SCLINK,SOFT,<SLB self pointers messed up in FNDSLB>,<<T1,CHAN>,<T2,SJBPTR>>,<
Cause: The DECnet data structures for this link are inconsistent.
If this happens more than once, submit a SPR.
Data: CHAN - The DECnet channel number
SJBPTR - Pointer to the SJB
>,RTN)
TMNE <SLFSL,SLLBC>,(SL) ;IS IT SCHEDULED FOR DESTRUCTION?
RET ;YES, DON'T LET ON T