Google
 

Trailing-Edge - PDP-10 Archives - BB-M780C-SM - monitor-sources/scampi.mac
There are 20 other files named scampi.mac in the archive. Click here to see a list.
; UPD ID= 2178, SNARK:<6.1.MONITOR>SCAMPI.MAC.170,   5-Jun-85 10:58:31 by MCCOLLUM
;TCO 6.1.1406  - Update copyright notice.
; UPD ID= 2105, SNARK:<6.1.MONITOR>SCAMPI.MAC.169,   3-Jun-85 15:58:20 by LOMARTIRE
;TCO 6.1.1374 - Add routine MXCIND to return the max nodes ever on CI
; UPD ID= 1856, SNARK:<6.1.MONITOR>SCAMPI.MAC.168,  30-Apr-85 15:31:22 by MCCOLLUM
;TCO 6.1.1238 - Fix BUG. documentation
; UPD ID= 1718, SNARK:<6.1.MONITOR>SCAMPI.MAC.167,   5-Apr-85 20:17:46 by GRANT
;TCO 6.1.1309 - Make sure SSN.XT always RETs when the virtual circuit is open
; UPD ID= 1675, SNARK:<6.1.MONITOR>SCAMPI.MAC.166,  25-Mar-85 08:26:11 by GRANT
;TCO 6.1.1284 - Use CIBUF instead of DDCFSF.  Set CIREP when reaping is
;needed.  In SC.RAP, remove timing calculations.
; UPD ID= 1251, SNARK:<6.1.MONITOR>SCAMPI.MAC.165,   1-Jan-85 15:21:46 by PAETZOLD
;More TCO 6.1.1097 - Make SC.IDL use SAVEP again.
; UPD ID= 1241, SNARK:<6.1.MONITOR>SCAMPI.MAC.164,  28-Dec-84 09:36:02 by GRANT
;TCO 6.1.1097 - In SC.IDL, add check for CITIMR and change SAVEP to SAVEAC <P4>.
; UPD ID= 1203, SNARK:<6.1.MONITOR>SCAMPI.MAC.163,  13-Dec-84 07:05:35 by GRANT
;TCO - 6.1.1086 - Remove SCACVC BUGINF (PHYKLP now does KLPCVC);  make SCATMO
;an INF rather than CHK.
; UPD ID= 1063, SNARK:<6.1.MONITOR>SCAMPI.MAC.162,  13-Nov-84 09:07:34 by LOMARTIRE
;Replace .MPxxx priority symbols with KLPHI, KLPMED, and KLPDRG
; UPD ID= 951, SNARK:<6.1.MONITOR>SCAMPI.MAC.161,   5-Nov-84 14:48:35 by LOMARTIRE
;New table of contents
; UPD ID= 5046, SNARK:<6.MONITOR>SCAMPI.MAC.160,  31-Oct-84 15:47:06 by LOMARTIRE
;Fix typos in ring buffer usage description
; UPD ID= 4997, SNARK:<6.MONITOR>SCAMPI.MAC.159,  24-Oct-84 20:01:53 by GRANT
;In SC.RCD, return destination node name
; UPD ID= 4890, SNARK:<6.MONITOR>SCAMPI.MAC.158,   1-Oct-84 08:59:03 by HAUDEL
;Add an OKSKED at SCM.ER.
; UPD ID= 4831, SNARK:<6.MONITOR>SCAMPI.MAC.157,  17-Sep-84 11:21:03 by PURRETTA
;Update copyright notice
; UPD ID= 4750, SNARK:<6.MONITOR>SCAMPI.MAC.156,  24-Aug-84 15:50:46 by HALL
;In connect_request and accept_request, force status field to be zero
; UPD ID= 4727, SNARK:<6.MONITOR>SCAMPI.MAC.155,  22-Aug-84 10:47:39 by LOMARTIRE
;Fix bug where FQCNT and DFQCNT can go negative.
;Comment ring buffer usage.
;Fix loop comparison at SBB.CL.
;Rework ring buffer at unlock coroutine SC.FN1.
;
; UPD ID= 4656, SNARK:<6.MONITOR>SCAMPI.MAC.154,   7-Aug-84 16:13:31 by CDUNN
;Remove SC.JSY. Equivalent functionality now in SCSJSY.
;
; UPD ID= 4649, SNARK:<6.MONITOR>SCAMPI.MAC.153,   7-Aug-84 10:24:58 by CDUNN
;Fix .SSPBC callback so that both node number and CID are not returned in T2.
;The CID will be returned in T2 and the node number in T3.
;If there is to be no CID returned, T2 will contain -1.
;
; UPD ID= 4635, SNARK:<6.MONITOR>SCAMPI.MAC.152,  31-Jul-84 08:40:59 by LOMARTIRE
;SC.RRR - don't complain about non-zero requeue credit if v.c. was closed
;CLean up BUGxxxs
;get rid of JSR BUGHLT
; UPD ID= 4603, SNARK:<6.MONITOR>SCAMPI.MAC.151,  27-Jul-84 09:08:50 by LOMARTIRE
;Add buffer manipulation as a default for RNGSW
;
; UPD ID= 4602, SNARK:<6.MONITOR>SCAMPI.MAC.150,  27-Jul-84 08:52:28 by LOMARTIRE
;Replace missing calls to RG.PQM.
;Report SCAMCR BUGCHK sooner and add some additional optional data
;Add SCAOBI BUGCHK to report online interrupt before init done.
;Add routines SC.TMQ and SC.TDQ and calls to detect free queue inconsistency.
;
; UPD ID= 4591, SNARK:<6.MONITOR>SCAMPI.MAC.149,  26-Jul-84 22:25:09 by CDUNN
;Change SC.OFL/SC.ERR to loop over NOTTAB and notify on system offline/error.
;Also fix the use of NOTTAB so filling the last entry does not send monitor 
;into left field.
;
; UPD ID= 4561, SNARK:<6.MONITOR>SCAMPI.MAC.148,  18-Jul-84 18:56:23 by HALL
;Cleanup (no functional change)
;SC.DIS - don't mark listener reapable. The JSYS bit would already have
;been cleared, so SC.PTC will have set the reap bit
; UPD ID= 4499, SNARK:<6.MONITOR>SCAMPI.MAC.147,  12-Jul-84 19:55:04 by LOMARTIRE
;Add .SSDDG callback (dropped datagram).
;Rearrange AC storage for .SSDGR and .SSMGR callbacks.
;Remove all maintenance data code.
;Remove .SSNWO since PHYKLP only calls SC.ERR when node goes away.
;Remove SC.P2S and SC.S2P since they are no longer needed.
;
; UPD ID= 4484, SNARK:<6.MONITOR>SCAMPI.MAC.146,  12-Jul-84 14:52:15 by HALL
;Make it possible to connect to VMS. WHen we initiate a connection, they
;send us a connect_response with zero as the source CID. We don't get the
;real CID until they send the accept_request. We had always copied the
;CID from the connect_response, and it worked with the HSC and other TOPS-20
;systems. For now, at least, we will copy the CID from the accept_request.
;If this creates a problem with the HSC, we'll have to find another
;solution.
; UPD ID= 4451, SNARK:<6.MONITOR>SCAMPI.MAC.145,  12-Jul-84 08:25:53 by HALL
;SC.SNM wasn't clearing the FLINK word when returning buffer to port
; UPD ID= 4450, SNARK:<6.MONITOR>SCAMPI.MAC.144,  11-Jul-84 14:16:47 by HALL
;Table of contents
; UPD ID= 4449, SNARK:<6.MONITOR>SCAMPI.MAC.143,  11-Jul-84 10:46:52 by HALL
;Rearrange the routines. No intended change in code.
; UPD ID= 4438, SNARK:<6.MONITOR>SCAMPI.MAC.142,   5-Jul-84 16:40:23 by HALL
;Start cleaning up BUGxxx's
; UPD ID= 4426, SNARK:<6.MONITOR>SCAMPI.MAC.141,   3-Jul-84 14:27:40 by LOMARTIRE
;Fix all references to removed DEFSTRs and obsolete fields in c.b. and s.b.
;Change SC.RCD to no longer acquire free space but to use address passed.
;Also, make SC.RCD return the intended data correctly.
;Minor changes to SC.SOA alternate code.
;
; UPD ID= 4422, SNARK:<6.MONITOR>SCAMPI.MAC.140,   3-Jul-84 11:34:24 by HALL
;SC.ULK - rearrange a little, shouldn't change action
;SC.INC - close v.c. on unexpected response
;SC.CRS - call SC.GCB
;SIN.ER - comments about lost packet
;Remove SC.MDC
;Fix all callers of OPENVC and CLOSVC to expect +1 return only
;SC.OFL - get rid of unused code, and clean up comments
;SC.NOD - use T2 and avoid saving P4
;SC.CMG - Change HLT to CHK, and return failure
;SC.CRD - if can't get buffer, don't alter count
; UPD ID= 4421, SNARK:<6.MONITOR>SCAMPI.MAC.139,   3-Jul-84 11:22:23 by HALL
;SC.SOA - call the sysap for any nodes that are already online
; UPD ID= 4417, SNARK:<6.MONITOR>SCAMPI.MAC.137,   2-Jul-84 11:37:24 by LOMARTIRE
;Make sure SC.NOD does not destroy T3 and T4 as a result of the CALL SC.CAL
;
; UPD ID= 4414, SNARK:<6.MONITOR>SCAMPI.MAC.136,   2-Jul-84 08:40:57 by HAUDEL
;Change SC.UMP code from BLCAL UMAP to JRST UMAP.
;
; UPD ID= 4412, SNARK:<6.MONITOR>SCAMPI.MAC.135,   2-Jul-84 07:17:07 by GRANT
;Remove special code for OPENVC
;
; UPD ID= 4393, SNARK:<6.MONITOR>SCAMPI.MAC.134,  27-Jun-84 13:48:22 by LOMARTIRE
;Do not destroy temporary ACs when recording interlocks in ring buffer.
;
; UPD ID= 4382, SNARK:<6.MONITOR>SCAMPI.MAC.133,  25-Jun-84 09:20:50 by LOMARTIRE
;Various ring buffer work - 
;  Add feature data to RG.BFM and RG.PQM and place calls to these routines
;  Add a new jacket routine, RG.ITL, to record interlocks
;  
; UPD ID= 4379, SNARK:<6.MONITOR>SCAMPI.MAC.132,  22-Jun-84 17:27:58 by HALL
;SC.FN1 - don't decrement count of locked c.b's for this s.b., because
;	we're doing it in SC.ULK
; UPD ID= 4361, SNARK:<6.MONITOR>SCAMPI.MAC.131,  19-Jun-84 16:06:26 by HALL
;SC.DIS - honor, but don't lock. Use CIOFF for protection against incoming
;	connection management events
;SC.SDG - if don't want response, count buffer as queued for input
;	- if error, put buffer on port's queue
;SC.SMG - move error-handling code inline, handle previously-incremented
;	receive credit if we didn't want the buffer back
;SC.CRD - BUG if UNLKDG fails
;Alternate code for SC.SOA to provide immediate callback - not executed yet
;SC.ALC - check counts racefree
;SC.RAP - protect don't-care list from changes
;SC.CDT - clear .CBPND if decide not to send
;SC.CVC - get rid of old code that tried to open v.c., and prepare for
;	CLOSVC's never failing
;SC.RCB - bitch if can't get buffers
;Get rid of SC.VCM
;SC.ONL - get rid of literal
;Remove repeat 0 around openvc stuff so we can test it, but jump
;around it by default: SC.ERR, SC.FN1, SC.ULK
;
; UPD ID= 4346, SNARK:<6.MONITOR>SCAMPI.MAC.130,  15-Jun-84 13:50:56 by LOMARTIRE
;Record callbacks in ring buffer before callbacks occur
;Convert remaining references to send credit to use .CBSCD
;Lock the c.b. and verify it at SC.NOD and SC.DCI
;Change SC.CSP to use address passed to store data instead of obtaining space.
;
; UPD ID= 4328, SNARK:<6.MONITOR>SCAMPI.MAC.129,  13-Jun-84 12:09:45 by HALL
;SC.RWQ - don't unlock what you haven't locked
;SC.ULK - test for group of bits before testing each individually
;Add (under repeat 0) code for controlling when to open a v.c.
;Complain if SC.LCB finds a c.b.'s FLINK or BLINK non-zero.
;
;Get rid of special entry point in SC.CVC that returns a buffer. Rename
;SC.VC1 to be SC.CVC and fix the callers. Remove NOPs after some calls.
;
;Make changes to count of datagram buffers be race-free. Affected
;routines: SC.CRD, SC.RCB, SC.ADG, SLC.DC
; UPD ID= 4318, SNARK:<6.MONITOR>SCAMPI.MAC.128,  11-Jun-84 10:46:18 by LOMARTIRE
;Fix SC.CSP to not return pointers to the connect block as it may disappear
;
; UPD ID= 4313, SNARK:<6.MONITOR>SCAMPI.MAC.127,   9-Jun-84 15:55:49 by HALL
;Remove old code
; UPD ID= 4312, SNARK:<6.MONITOR>SCAMPI.MAC.126,   9-Jun-84 14:42:01 by HALL
;Make SC.DIS be CIOFF a little longer, to keep out incoming connection
;management requests when sysap does disconnect at odd times
; UPD ID= 4310, SNARK:<6.MONITOR>SCAMPI.MAC.125,   8-Jun-84 13:27:38 by HALL
;Add connection block locks. Create lock, honor, and unlock routines.
;Honor the lock at SC.DRQ (incoming disconnect_request), SC.DIS (sysap
;wants to disconnect), SC.ERR (node offline), SC.SNM (sending connection
;management request). Lock the lock wherever a routine cannot tolerate
;disappearance of the c.b., or change in state.
;
;Most routines lock the c.b. by calling SC.CAL to verify and lock.
;SC.CON and SC.LIS lock the block directly. All unlock by calling SC.ULK.
;
;SC.CDT no longer calls SC.SNM. Its callers do it so that they can
;unlock the c.b. first. Affected routines:
;	SC.RMG, SC.CRM, SC.IDL
;
;Make subroutines to manipulate the queues of c.b.'s -- the system block
;list and the don't-care list.
;	SC.RDQ - remove entry from don't-care queue. Called by SC.RCB and
;		SC.SCM
;	SC.RSQ - remove entry from system block queue. Called by SC.RCB and
;		SC.LCB
;
;Related changes:
;SC.RCB - When can't get a buffer, don't keep trying
;	 - Move JSYS-only code into a subroutine
;SC.RWQ - check and lock c.b., and move entry if it's locked
;SC.ACB - don't initialize the lock word. Let it be 0
;SC.RQS- don't do CIOFF
;Move reap sanity checks into a subroutine, SC.RRR, and complain if lock
;	count isn't zero.
;Make SC.CAL call the lock routine
;SC.DEF - not a bug if JFFO doesn't find bits set
;SC.IDL - use NOSKED to protect list of c.b.'s. Call SC.SNM if needed
;SC.CDT - don't do CIOFF, don't call SC.SNM
;SC.SNd and SC.REQ - combine them; get send credit to be race-free
;Clean up references to SBOBB and .CBSCD
;SC.ERR - clear address of outbound buffer with EXCH
;	- clear requeue credit
;
; UPD ID= 4293, SNARK:<6.MONITOR>SCAMPI.MAC.124,   4-Jun-84 13:46:47 by HAUDEL
;Change SC.MAP - Now only one argument. Code JRSTs to MAPBUF.
; UPD ID= 4285, SNARK:<6.MONITOR>SCAMPI.MAC.123,   1-Jun-84 12:21:57 by LOMARTIRE
;Make the following changes for SBI to node number conversion:
;  Make callers of following routines supply node number instead of SBI:
;	  -  SC.CON, SC.LIS, SC.SMD, SC.RMD, SC.RCD, SC.RST, SC.STA, SC.ONL, 
;         -  SC.ERR, SC.OFL
;  New loop of SBLIST at SSC.SL - use C%SBLL instead of assuming dense
;  Put node number, not SBI in CBDNOD at SSC.LC and SSC.FX
;  LOAD SBDPA not SBSBI at SSN.SB and SBD.DN
;  At SC.ONL, put node number in SBDPA and store SS.NOD in T2 for .SSNCO
;  STOR CBDNOD in SC.CON and SC.LIS
;  LOAD CBDNOD in SC.CSP and store in CDNOD
;  LOAD CDBNOD in SSC.CL
;  Replace all references to SS.SBI with SS.NOD
;  Remove routine SC.SBI
;
; UPD ID= 4260, SNARK:<6.MONITOR>SCAMPI.MAC.122,  30-May-84 16:04:21 by HALL
;Restructure sending of connection management requests to avoid
;races and prepare for c.b. locks. Create SC.RWQ to remove entry from
;system block work queue, and call it from SC.SNM and SC.DEF. Change
;SC.DEF so that it removes an entry from the queue while creating
;its buffers, and then returns it to the queue. Use CIOFF to interlock
;changes to the queue. Do buffer creation for both routines in a new
;routine, SC.BUF.
;
;Add new entry point to SC.CSC, which will lock the c.b. Change
;callers now even though code doesn't exist. Interrupt level routines
;assume that c.b. will remain valid.
;
;Make SC.LCB check for open v.c. and return failure. Fix callers to
;expect that
;
;Miscellaneous changes:
;SC.SNM - bugchk if b.s. is zero
;SC.RQS - assume b.s. of zero is a bug
;SC.SND and SC.REQ - verify connect ID
;SC.CRM - Move CION to precede call to SC.CDT
;SC.ACC - don't return argument to caller
;SC.ERR - don't clear .CBNWQ
;RC.RAP - don't check flink for work queue
; UPD ID= 4247, SNARK:<6.MONITOR>SCAMPI.MAC.121,  25-May-84 14:19:58 by HALL
;Rearrange connection management routines to facilitate c.b. locks.
;Make SC.SCA call SC.AWQ, and change all callers of SC.SBS and SC.SNM.
;Make them call SC.SCA and SC.SNM, and allow them to unlock the c.b.
;between the two. Fix interrupt routines to avoid calling SC.SNM until
;the buffer has been returned.
;Affected routines: SC.CON, SC.LIS, SC.ACC, SC.REJ, SC.DIS, SC.CDT, SC.ARS,
;	SC.DRQ
;
;Fix handling of canceled message buffers to handle interactions with
;other credit functions. It was possible to get confused and leave buffers
;queued to the port in excess of the current receive credit.
;Maintain return_credit, and dequeue one buffer for each time it is incremented.
;New routine, SC.GRB, does the dequeueing
;Affected routines: SC.RMG, SC.CMG, SC.CRS, SC.SMG
;SC.RCB - include return credit in count of buffers to be dequeued
;
;Avoid conflict between 2 contexts that need to send credit_request.
;Maintain interlock word, .CBPND, that indicates when a connection is
;in the process of sending a credit_request. Leave it locked until the
;credit_response is received. If we need to send another credit_request,
;we'll do it then.
;Affected routines: SC.CDT, SC.CRS
;
;Miscellaneous fixes:
;SC.IDL - call into SC.CDT to send credit_request
;SC.SMG - change send credit in one operation
;	- handle receive credit better, including return credit
;SC.SNM - call SC.PTC if block state is zero
;SC.PON - include check for CION before the first CIOFF
;SC.CRD - don't load P4 until we need it
;SC.RQS - Don't clear block state until buffer has been sent
; UPD ID= 4206, SNARK:<6.MONITOR>SCAMPI.MAC.120,  10-May-84 20:33:38 by HALL
;Typo in sanity check in SC.RCB
; UPD ID= 4202, SNARK:<6.MONITOR>SCAMPI.MAC.119,   9-May-84 15:40:53 by LOMARTIRE
;Add temporary check for CBNPO going negative
; UPD ID= 4197, SNARK:<6.MONITOR>SCAMPI.MAC.118,   9-May-84 13:17:52 by LOMARTIRE
;Remove SC.ABT since it is no longer needed - use SC.DIS and give reason code
;Replace all .UCxxx codes with .CMNxx reason codes.
;Remove .RJNOM and use the reason code passed in the packet instead.
;Update table of contents.
;
; UPD ID= 4179, SNARK:<6.MONITOR>SCAMPI.MAC.117,   8-May-84 10:11:20 by HALL
;SC.CRD - return immediately if count is zero
;	- change SOSG to SOSLE so that we continue until count is zero
;SC.CRM - take the buffers if we don't need to send credit_request
;SC.RCB - bitch if requeue credit is non-zero
;	- Remove unnecessary saveac of P3
;SCL.MC and SCL.DC - don't save Q1 since we don't use it
; UPD ID= 4174, SNARK:<6.MONITOR>SCAMPI.MAC.116,   2-May-84 18:33:41 by HALL
;SC.CON and SC.LIS - don't store CBMNRC since it will be overwritten
;SC.CRD and SC.CRM - verify CID
;Convert receive credit away from defstrs
;SC.CRM - don't take buffers right away
;	 - decrement pending receive credit by full amount of request
;	 - send credit_request
;SC.DMA - ignore if v.c. is closed
; UPD ID= 4171, SNARK:<6.MONITOR>SCAMPI.MAC.115,   2-May-84 11:07:50 by LOMARTIRE
;Recycle CIDTAB.  Add routine SC.FUB to return next uniqueness bits.
;Add CIDRFL and UNQRFL to count number of recycles done.
;Remove BDQHD and BDQTL since they are no longer used.
;Rearrange SC.ACB to create CID first then attempt to get CB buffer.
;
; UPD ID= 4168, SNARK:<6.MONITOR>SCAMPI.MAC.114,   1-May-84 19:12:59 by HALL
;Rearrange
; UPD ID= 4164, SNARK:<6.MONITOR>SCAMPI.MAC.113,   1-May-84 13:59:46 by LOMARTIRE
;Make SC.INT return +1 always.
;Add call to SC.SCS to record .SSCIA callback in ring buffer.
;
; UPD ID= 4161, SNARK:<6.MONITOR>SCAMPI.MAC.112,   1-May-84 10:23:57 by HALL
;Replace SC.TC with SC.CDT. Provide three entry points for the three
;	occasions for sending credit_requests.
;SC.CRQ - maintain sign of credit field in incoming packet
;	- compute returned value correctly when incoming value is negative
;	- return 0 if send credit is already below minimum and incoming
;		value is negative
;	- give credit-available callback only if incoming credit is positive
;SC.CRS - maintain sign of credit field in incoming packet
;	- update receive credit, not pending receive credit
;	- send credit_request if needed
;	- remove .SSCIA callback
; UPD ID= 4136, SNARK:<6.MONITOR>SCAMPI.MAC.111,  25-Apr-84 13:03:33 by LOMARTIRE
;Replace all .SCFxx error codes with equilvalent SCSxxx error codes.
;Replace .SCFNE code with SCSTBF at SAC.EH since this is the desired code.
;Make RG.SCS and RG.PKT calling comments accurate.
;
; UPD ID= 4132, SNARK:<6.MONITOR>SCAMPI.MAC.110,  25-Apr-84 11:11:54 by HALL
;SC.ERR - set CBFCVC in connection block for debugging purposes only
;SC.SMG - Check the connect ID
;	- Put credit in packet only if positive
;	- Increment SNDTAB only if we are successful
;	- Increment send credit if we can't send
;SC.SDG - check the connect ID
;	- Increment SNDTAB
; UPD ID= 4117, SNARK:<6.MONITOR>SCAMPI.MAC.109,  24-Apr-84 13:01:52 by HALL
;Handle credit in DMA -
;	SC.SND and SC.REQ - set CBFNNC if fail due to lack of credit
;			- allow sending if credit is 1
;	SC.DMA - give callback if sysap is waiting for credit
;in SC.RIN make comment match code
;Allow sending if credit is 1
; UPD ID= 4102, SNARK:<6.MONITOR>SCAMPI.MAC.108,  18-Apr-84 20:00:33 by HALL
;Don't increment RECTAB at SC.INC. It was already done at SC.INT.
; UPD ID= 4097, SNARK:<6.MONITOR>SCAMPI.MAC.107,  18-Apr-84 17:33:27 by HALL
;Make arrival of credit_request and credit_response go through SC.INC
;Add necessary data to TABLEK
; UPD ID= 4057, SNARK:<6.MONITOR>SCAMPI.MAC.106,  10-Apr-84 13:23:36 by HALL
;New SC.ADG and SC.AMG
;	Common code wherever possible
;	Handle incoming packet when v.c. is closed. Previously, if v.c. was
;		closed while packet was on response queue, receipt of packet
;		would lead to closing the v.c. again
;	Don't return failure to PHYKLP
;	Change SOSG on CBDGR to SOSGE to allow receipt of datagram when
;		one buffer queued
; 	SC.ADG was looking in c.b. for address of system block when c.b.
;		didn't exist (SC.CSC had failed)
;	SC.AMG was returning buffer to SCA but not decrementing receive
;		credit if in middle of disconnect sequence
;	If credit field is non-zero in application message, and sysap failed
;		to send due to lack of credit, give callback
; UPD ID= 4055, SNARK:<6.MONITOR>SCAMPI.MAC.105,   6-Apr-84 11:40:10 by HALL
;SC.CRQ - Clear CBFNNC before calling the sysap
; UPD ID= 4043, SNARK:<6.MONITOR>SCAMPI.MAC.104,   3-Apr-84 14:46:00 by LOMARTIRE
;Test for recording of ring buffer events before SAVETs and STKVARs in
;the ring buffer jacket routines.
;Change the name of a few BUGxxx's to be more descriptive.
;Add SCAPCC BUGCHK for when SC.PTC called and the connect state not closed.
;Clean up labels in SC.SNM and SC.DEF
;
; UPD ID= 4041, SNARK:<6.MONITOR>SCAMPI.MAC.103,   3-Apr-84 10:29:17 by HALL
;SC.CSC - return error code. Change callers not to make up their own.
;SC.RDG and SC.RMG - recode to fix bugs and make routines match
; UPD ID= 4040, SNARK:<6.MONITOR>SCAMPI.MAC.102,   3-Apr-84 09:06:56 by HALL
;Remove all references to ALMTIM. Instead, AOS DDCFSF to get DDMP fork running
;	Affected routines: SC.ONL, SC.ALD, SC.ABF
; UPD ID= 4039, SNARK:<6.MONITOR>SCAMPI.MAC.101,   3-Apr-84 07:20:13 by HALL
;In SC.DIS, if closing a listener, force connection state to closed. SC.PTC's
;	sanity check was objecting.
; UPD ID= 4035, SNARK:<6.MONITOR>SCAMPI.MAC.100,   1-Apr-84 17:58:47 by GLINDELL
;Add ENDBS. to SC.S2P and SC.P2S
;
; UPD ID= 4034, SNARK:<6.MONITOR>SCAMPI.MAC.99,   1-Apr-84 14:22:28 by HALL
;SC.INC - call SC.VC1 instead of SC.CVC. Buffer was being returned to
;port twice
;
; UPD ID= 4026, SNARK:<6.MONITOR>SCAMPI.MAC.98,  31-Mar-84 17:37:13 by GLINDELL
;Add SC.S2P and SC.P2S to translate between system block index and port number
;
; UPD ID= 3985, SNARK:<6.MONITOR>SCAMPI.MAC.97,  27-Mar-84 14:14:46 by LOMARTIRE
;Make the default for RNGSW record all packet transactions
;
; UPD ID= 3973, SNARK:<6.MONITOR>SCAMPI.MAC.96,  25-Mar-84 10:39:42 by HALL
;Major changes to the way connections are terminated.
;	1. SC.DIS succeeds in any state. If the state is other than "open",
;the connection is marked "closed" but protocol continues until both sides
;agree.
;	2. SC.ABT will soon go away. At the moment, it calls SC.DIS
;	3. The "abort" bit no longer exists.
;	4. A sysap is called only when a connection terminates. If the
;other side initiates a disconnection on an open connection, the sysap
;is called when the disconnect_req arrives, not when the disconnect_rsp
;arrives.
;	5. In general, bits are no longer used to indicate the state of a
;connection. If the state is "closed", the sysap isn't interested in it
;any more.
;	6. A new bit, CBFPTC, indicates that the protocol is complete; that
;is, we don't expect to exchange any more messages with the other node.
;
;Specific changes:
;
;ModifY table K to allow any incoming packet when the connection
;	state is closed. 
;Modify table Y to leave state unchanged when connect_req is sent
;New routine, SC.PTC to declare protocol complete. Called as follows:
;	SC.DIS - disconnect on listener
;	SC.ERR - node went offline
;	SC.ORS - connect_rsp no match
;	SC.ARQ - accept_req when our side has disconnected
;	SC.ARS - accept_rsp no match
;	SC.RRQ - reject_req
;	SC.RRS - reject_rsp
;	SC.DRQ - disconnect_req when new state is closed
;	SC.DRS - disconnect_rsp when new state is closed
;Don't set abort bit. Affected routines: SC.ABT,SC.ERR,SC.ORS,SC.DRQ, SC.DRS
;Don't test abort bit. Affected routines: SC.RAP, SC.SCM,SC.IDL, SC.ERR,
;	SC.DMA, SC.ORS, SC.ARQ, SC.ARS, SC.RRQ, SC.RRS, SC.INC,SC.SNM, SC.DEF
;SC.DIS - set reap bit if connection state was listen
;SC.ABT - always call SC.DIS, don't do ring buffer
;SC.RAP - no longer check abort bit; do check for work queue FLINk and
;queued buffers, and postpone reaping if non-zero. If this happens repeatedly
;complain.
;SC.ACB - initialize connection state to closed
;SC.SCM - don't check abort and reap bits. Do check for listen state
;	(don't care code wasn't doing that. WHY???).
;SC.ERR - notify sysap only if state is not closed. Don't check abort or
;	reap bits. Don't set CBFCVC. Do call SC.PTC.
;	 - clear .CBNWQ when closing connection
;SC.IDL - get rid of check on abort and reap bits, combine other checks
;	Send only if state is open
;SC.ORS - handle no-match when already closed
;SC.ARQ - set block state to send disconnect_req rather than calling SC.DIS
;	- when sending no match, use standard routine.
;	- store reason code in accept_response if no match
;SC.ARS - handle no match when already closed
;SC.RRQ - don't call sysap if already closed
;SC.DRQ - Notify sysap when remote side requests disconnect first, not at the
;	end of the sequence.
;	 - put reason in Ac 3 before .SSRID callback
;SC.DRS - never call sysap. Declare protocol complete if new state is closed
;SC.SNM - If block state is 0 or reap bit is on, don't send request
;SC.INC - don't check CBFCVC. It no longer exists.
;SC.RQS - if block state is zero, assume v.c. is closed, and return+1
;Table X - new state for SC.CON is .CSCSE. This disagrees with corporate
;spec, which says to set the state only after the message is sent. It allows
;us to use a connection state of "closed" to mean that the sysap is not
;expecting to hear about this connection again.
;
;Implementation of state machine for requesting connection management
;functions. Routines call SC.OUT, which references table X, to check
;legality and get new connection and block states.
;Affected routines:
;	SC.CON,SC.LIS,SC.ACC,SC.REJ,SC.DIS
;
;New approach to handling incoming packets if v.c. is already closed.
;We assume that the packet that caused the closure was important, and therefore
;we can't trust anything that comes after it. For now, only SC.INC implements
;this change, but all incoming packets should eventually be thrown away without
;interpretation.
;SC.INC - if v.c. state is closed, return +1.
;
;Miscellaneous fixes not directly related to the major edit:
;Call SC.CSC in SC.ACC, SC.REJ, SC.DIS
;SC.SMG and SC.SDG -Don't try to skip over INCR or DECR of CBNPO
;SC.ERR - add missing CION after SCAOF2
;SC.DMA - check for open connection and valid CID
;SC.ORQ - call SC.INC
;SC.ORQ,SC.ARQ - reorder events to avoid changing state without notifying sysap
;SC.CRS - bitch if can't get buffers, and go to SC.SAR. Don't fall through to 
;	this code
;SC.AWQ - don't queue if already on queue
;
; UPD ID= 3951, SNARK:<6.MONITOR>SCAMPI.MAC.95,  21-Mar-84 12:43:23 by LOMARTIRE
;Add calls to RG.SCS for callbacks
;Add feature specific data to RG.SCS - the following is placed in the entry:
;	node number, CBA, callback reason code
;Add calls to RG.PKT for packet transmission/reception
;Add feature specific data to RG.PKT - the following is placed in the entry:
;  node number, CBA, buffer addr, flags, prio,,length, MH$TYP, MH$SCI, MH$DCI
;Remove the old SCA ring buffer which was under the SCADBG conditional
;Remove the old PI ring buffer which was under the PIDBG conditional
;Also remove the PIDBG conditional
;Update table of contents
;
; UPD ID= 3950, SNARK:<6.MONITOR>SCAMPI.MAC.94,  20-Mar-84 21:33:49 by MCLEAN
;ADD REASON FOR DISCONNECT TO SC.DRQ
; UPD ID= 3942, SNARK:<6.MONITOR>SCAMPI.MAC.93,  19-Mar-84 09:55:00 by HAUDEL
;Put call to CLOSVC in SC.RST
; UPD ID= 3931, SNARK:<6.MONITOR>SCAMPI.MAC.92,  14-Mar-84 16:30:47 by LOMARTIRE
;Add calls to RG.SSC for connection management routines
;Add feature specific data to RG.SSC - the following is placed in the entry:
;	node number, connect block address, .CBSTS, .CBFLG, .CBSCI, .CBDCI
;Add calls to RG.PIT in routines SC.PON and SC.POF
;Add feature specific data to RG.PIT - the following is placed in the entry:
;	CHNCTL, PIFLAG
;
; UPD ID= 3917, SNARK:<6.MONITOR>SCAMPI.MAC.91,  13-Mar-84 12:17:14 by HAUDEL
;Add documentation for UPD ID 3906
; UPD ID= 3910, SNARK:<6.MONITOR>SCAMPI.MAC.90,  12-Mar-84 17:27:17 by HALL
;Work on BUGxxx's
; UPD ID= 3908, SNARK:<6.MONITOR>SCAMPI.MAC.89,  12-Mar-84 16:25:50 by LOMARTIRE
;Rework ring buffer - allow for selectivity of event recording
;Add ring buffer routines SC.RGI, SC.RHD, SC.RTE, and SC.RWR
;Also add ring buffer jackets for events to be recorded.
;
; UPD ID= 3906, SNARK:<6.MONITOR>SCAMPI.MAC.88,  12-Mar-84 15:49:05 by HAUDEL
;Change SC.STA and SC.RST. Move RMTSTA and RMTRST to PHYKLP.
; UPD ID= 3883, SNARK:<6.MONITOR>SCAMPI.MAC.87,   9-Mar-84 11:28:53 by HALL
;Changes in sending of connection management requests:
;
;For sending connection management requests, packet is no longer acquired,
;filled in, and queued. Instead, connection block's block state indicates type
;of message to be sent, and the connection block is queued. Packet is filled
;in only when it can be sent. Thus there is no failure return for sending
;requests, and connection management routines no longer try to build packets,
;acquire buffers, or send packets. Affected routines:
;	SC.CON,SC.ACC,SC.REJ,SC.DIS,SC.TC,SC.IDL,SC.DRQ
;
;Handling of block state has changed significantly. Block state is non-zero
;only while a connection block is waiting to send a request. The sending
;routine zeroes it. Other routines that previously set or zeroed or tested
;it no longer do. Affected routines:
;	SC.CON, SC.LIS, SC.ACC, SC.REJ, SC.DIS, SC.ERR,SC.ORS,SC.ARQ,SC.ARS,
;	SC.RRQ, SC.RRS,SC.CRS
;
;New SC.SCA queues connection block to system block and calls SC.SNM.
;New SC.SNM uses block state to determine type of packet to send. If
;unable to allocate buffers requested by the sysap, it moves a connection
;block to the end of the queue and flags it for job 0. It returns when it
;sends one packet, is unable to proceed, or has no pending requests.
;SC.RQS generates the packet based on block state, sets new connection state,
;clears block state, and sends packet. It uses new table Y.
;
;New SC.DEF (replacing SC.ALM) finds queued connection blocks and allocates
;buffers. It tries to get them from SCA's pool in case some have been returned.
;
;In general, sending of connection management requests now conforms to corporate
;spec. However, SC.CON sets the connection state to connect_sent rather than
;waiting until the connect_req is sent.
;
;Additional changes related to this:
;
;SC.CON, SC.LIS - moved linking of connection block to system block to occur
;	after connection block is initialized
;SC.ACC - store caller's connection data in the connection block. Previously,
;	the remote node's data remained there forever. This change was necessary
;	in order to have this data available when the accept_req is sent. If
;	necessary, both sets of connection data could be stored in the
;	connection block.
;SC.TC - return +1 always
;SC.ALM is replaced by cals to SC.DEF and SC.ALC. The latter is ALMCHK turned
;into a routine
;SC.RAP - if connection block is queued to system block's work queue, skip
;	  reaping it. SC.SNM or SC.ERR will dequeue it eventually.
;SC.ONL - add some sanity checks related to outgoing requests.
;	- when node comes online, allocate 2 buffers for SCS control messages.
;	  Put one on port's message free queue, and make system block point
;	  to the other.
;SC.ERR - Clean work queue by resetting head and tail. No longer have buffers
;	  to return.
;	- Clear system block's bit in SBSTUK
;	- Return SCS control message buffers to SCA free pool.
;SC.SAR - Give incoming buffer to system block. Don't return to port's
;	  queue as before.
;SCACDT - Get op code from packet, not from caller
;Add K.CHK to TABLEK
;SC.INC	- If no protocol error, and K.CHK is set, check op code against
;	  expected response
;
;Other changes not directly related to the above:
;
;SC.ALC - change queue count while CIOFF to update queue
;SC.ERR - set flag in system block when node goes offline. If flag is set
;	  when this routine is called, don't do anything
;Callers of SC.INC were handling +1 return incorrectly, losing the buffer.
;Now they go to SC.RIB. Affected routines:
;	SC.ORS,SC.ARQ,SC.ARS,SC.RRQ,SC.RRS,SC.DRQ,SC.DRS
;SC.PAK - increment count only if send succeeds
;SC.INC - return +1 if protocol error when v.c. is closed. Check this before
;	  checking the abort bit.
;	- If protocol error and incoming op code is disc_req or disc_rsp,
;	   close v.c. This may not be correct, but it more nearly matches the
;	   old code.
;
; UPD ID= 3839, SNARK:<6.MONITOR>SCAMPI.MAC.86,   2-Mar-84 15:52:08 by HALL
;SC.INC - if protocol error and v.c has been closed, return +1
;	- if protocol error, aborted, and received disc_req, close the v.c.
; UPD ID= 3780, SNARK:<6.MONITOR>SCAMPI.MAC.85,  28-Feb-84 13:12:28 by LOMARTIRE
;Add SC.NOD to return node number given connect ID
;Modify some BUGxxx to include node number and CID when appropriate
;
; UPD ID= 3755, SNARK:<6.MONITOR>SCAMPI.MAC.84,  25-Feb-84 16:50:50 by HALL
;SC.REJ - don't put listener back on "don't care" queue
; UPD ID= 3754, SNARK:<6.MONITOR>SCAMPI.MAC.83,  25-Feb-84 07:59:33 by HALL
;Introduction of state machine for processing incoming SCS control packets --
;Includes changes to match corporate SCA spec version 6, as follows:
;	Add states accept_sent and reject_sent
;	Remove sub-states of closed
;	After sending accept_request, state is accept_sent. Old code left it
;		as connect_received
;	When we receive an accept_req, and state is closed, send an accept_rsp
;		with no match. Old code treated as error and closed the v.c.
;		unless the "aborted" bit was on
;	When we receive accept_rsp, expect state to be accept_sent. Old
;		code expected connect_received
;	After sending reject_request, state is reject_sent. Old code left
;		is as listen
;	When we receive reject_response, expect state to be reject_sent.
;		Old code expected listen
;	After receiving reject_response, state is closed. Old code left is
;		as listen
;New routine, SC.INC, is called for incoming packets to determine validity
;	for current state, and return new state and op code of response
;	Called by SC.ORS,SC.ARQ,SC.ARS,SC.RRQ,SC.RRS,SC.DRQ,SC.DRS
;SC.CON - store minimum send credit in minimum_credit field
;SC.ACC - deferred new state is accept_sent
;SC.REJ - don't set state to listen
;SC.REJ - deferred new state is reject_sent
;SC.RNG - get destination CID rather than credit field
;SC.OFL - set new state to closed instead of closed_v.c. failure
;SC.ORQ - rearrange copying of input, move SOR.NM to end of routine,
;	store minimum_Credit from packet into mininum receive credit
;SC.ORS - store other CID in connection block only if there's a match
;	- New state is closed instead of closed_no_match if no match
;SC.ARQ - If current state is closed, go send accept_response with "no
;	match"
;	- At SAR.NG, assume op code was set up by SC.INC
;SC.RRQ - new state is closed instead of closed_rejected
;SC.RRS - check on "aborted" was reversed
;	store new connection state as closed instead of leaving as listen
;
;SC.IDL - SCATMO BUGCHK when timed out a connection
;SC.CVC - Changed SCACVC to a BUGCHK (may be temporary), added node number
;	to optional data
;SC.OFL - set CBFCVC flag in connection block when v.c. is closed. Test
;	it in SC.INC. At the moment, this an CBFABT will be set when a v.c.
;	is closed. This may change over time.
;
;Changes to routines that send responses. SC.RSP now fills in common data
;	and then calls a specific routine according to op code for filling in 
;	the rest. Callers were changed to expect this: SC.ORQ, SC.ARQ, 
;	SC.RRQ, SC.DRQ,SC.CRQ.
;Name changes: SC.RS1 to SC.PAK, SC.MDS to SC.SMD, SC.MDR to SC.RMD
;
; UPD ID= 3717, SNARK:<6.MONITOR>SCAMPI.MAC.82,  21-Feb-84 13:22:13 by LOMARTIRE
;Remove name WQANB for location .WQANB since entire word is needed
;Fix manipulations of WQFLG to work with the correct half word
;Add name WQLFW to refer to the entire .WQLEN word
;Use names WQDG and WQMSG instead of .WQNBF
;
; UPD ID= 3714, SNARK:<6.MONITOR>SCAMPI.MAC.81,  21-Feb-84 13:01:09 by CDUNN
;More TCO 6.1127 - Change SC.CON and SC.LIS to use an address instead of
;a byte pointer to the process strings.
;
; UPD ID= 3689, SNARK:<6.MONITOR>SCAMPI.MAC.80,  15-Feb-84 11:05:35 by LOMARTIRE
;Add extra needed field to SCAMCR BUGCHK to insure correct assembly
;
; UPD ID= 3688, SNARK:<6.MONITOR>SCAMPI.MAC.79,  15-Feb-84 08:54:31 by LOMARTIRE
;Fix routines in which LNKMFQ/LNKDFQ used to fail to return +1 always
;Remove unneeded error routines and SC.P2Q and SC.P2M
;Fix SCAMCR BUGCHK so that it assembles correctly and fix some typos
;
; UPD ID= 3686, SNARK:<6.MONITOR>SCAMPI.MAC.78,  12-Feb-84 13:30:46 by HALL
;SC.SCA was loading connection state when it wanted block state
; UPD ID= 3681, SNARK:<6.MONITOR>SCAMPI.MAC.77,  10-Feb-84 14:37:47 by LOMARTIRE
;Change all system block references to use defined structure if one available.
;All values which are not word location independent will not use the structure.
;These include FLINKs and BLINKs and other values with must be a full word.
;
; UPD ID= 3680, SNARK:<6.MONITOR>SCAMPI.MAC.76,   9-Feb-84 10:43:10 by HALL
;Fix bug in SC.RSP, in which SC.RS1 was being called without doing
;a STKVAR
;In SC.SCA, zero FLINK when adding buffer to end of work queue
; UPD ID= 3676, SNARK:<6.MONITOR>SCAMPI.MAC.75,   8-Feb-84 17:43:35 by HALL
;General cleanup of interrupt-level code that handles incoming SCS control
;messages. Includes creation of common exits, SC.SAR and SC.RIB.
;The functions performed there will probably change over time. All
;incoming responses lead to SC.SAR, where we attempt to send the next
;queued SCS message, and fall through to SC.RIB.
;All incoming requests cause a response to be sent if possible, and go
;to SC.RIB on failure. SC.RIB returns the buffer to the free queue.
;
;New routine, SC.RSP, stores common data into a packet and sends it
;Routines that receive requests and send responses now call this instead of
;calling SNDMSG directly.
;
;The following functional changes were made as well:
;SC.DRQ - If call to SC.SCA fails, go to usual code for notifying sysap
;	of disconnect
;SC.RRQ - Don't assume T3 preserved over call to SC.RSP. Get reason for
;	rejection from c.b. when calling sysap
;SC.ORQ - Zero minimum_credit field in CONNECT_RSP
;SC.ARQ - store minimum_credit field of packet into connect block's
;	minimum receive credit field
;Set CBDSBI in SC.SCM rather than SC.ORQ. Don't set CBDSBI in SC.ORS because
;	SC.CON did it
;
; UPD ID= 3673, SNARK:<6.MONITOR>SCAMPI.MAC.74,   8-Feb-84 12:18:40 by LOMARTIRE
;Use defined structures for all message header references
;
; UPD ID= 3666, SNARK:<6.MONITOR>SCAMPI.MAC.73,   8-Feb-84 08:38:31 by LOMARTIRE
;Account for the fact that LNKDFQ and LNKMFQ now return +1 always
;
; UPD ID= 3654, SNARK:<6.MONITOR>SCAMPI.MAC.72,   3-Feb-84 19:36:51 by HALL
;In SC.ORS, add P4 to reference to SBSBI
;Add SC.RSP
; UPD ID= 3598, SNARK:<6.MONITOR>SCAMPI.MAC.71,  31-Jan-84 11:38:41 by LOMARTIRE
;Change OPSTRs to OPSTRMs for operations to memory
; Fix a few credit update manipulations
;
; UPD ID= 3593, SNARK:<6.MONITOR>SCAMPI.MAC.70,  30-Jan-84 17:06:36 by CDUNN
;More TCO 6.1127 - Add missing SETZM in SC.RLD to zeor the forward link of the
;new buffer.
;
; UPD ID= 3592, SNARK:<6.MONITOR>SCAMPI.MAC.69,  30-Jan-84 16:11:36 by MOSER
;Fix SC.RLD and SC.RBF to do BLT correctly.
;
; UPD ID= 3582, SNARK:<6.MONITOR>SCAMPI.MAC.68,  28-Jan-84 18:29:55 by MCLEAN
;ADD OPSTR'S TO .CBXXX
;
; UPD ID= 3574, SNARK:<6.MONITOR>SCAMPI.MAC.67,  28-Jan-84 01:41:51 by MCLEAN
;MASSIVE EDITS TO CONFORM TO STANDARDS
;
; UPD ID= 3570, SNARK:<6.MONITOR>SCAMPI.MAC.66,  27-Jan-84 22:04:45 by MCLEAN
;REDIT MISSED CHANGE OF ENDTV TO ENDSV OR SOMETHING....
;REMOVE IMPLIED (P1) REFERENCES
;
; UPD ID= 3569, SNARK:<6.MONITOR>SCAMPI.MAC.65,  27-Jan-84 17:53:30 by MCLEAN
;Make a few subroutines and fix up credit stuff
;
; UPD ID= 3563, SNARK:<6.MONITOR>SCAMPI.MAC.64,  26-Jan-84 22:27:01 by MCLEAN
;FIX TYPO.
;
; UPD ID= 3562, SNARK:<6.MONITOR>SCAMPI.MAC.63,  26-Jan-84 22:10:59 by MCLEAN
;FIX SC.SNM CAUSE IT DOESN'T GIVE CREDIT.....
;
; UPD ID= 3561, SNARK:<6.MONITOR>SCAMPI.MAC.62,  26-Jan-84 14:38:57 by MCLEAN
;ADD NEW PARAMETER FOR SC.MAP
;
; UPD ID= 3547, SNARK:<6.MONITOR>SCAMPI.MAC.61,  25-Jan-84 22:01:46 by MCLEAN
;FIX SCL.TC THE LABEL IS OFF BY 1
;
; UPD ID= 3546, SNARK:<6.MONITOR>SCAMPI.MAC.60,  25-Jan-84 21:22:29 by MCLEAN
;PUT ENDTV.'S IN ALL THE NECESSARY PLACES.
;
; UPD ID= 3545, SNARK:<6.MONITOR>SCAMPI.MAC.59,  25-Jan-84 21:09:30 by MCLEAN
;MISSING ENDTV. AT SC.BBF AND MISPELLING IN SC.CMG
;
; UPD ID= 3533, SNARK:<6.MONITOR>SCAMPI.MAC.58,  24-Jan-84 22:33:03 by MCLEAN
;SC.ADG SHOULD NOT CLOSE SC.CSC
;
; UPD ID= 3530, SNARK:<6.MONITOR>SCAMPI.MAC.57,  24-Jan-84 20:51:12 by MCLEAN
;ADD EXTRA ARGUMENT TO MAPBUF AND THIS WILL BE CHANGED SOON TO SS.RDW
;
; UPD ID= 3528, SNARK:<6.MONITOR>SCAMPI.MAC.56,  24-Jan-84 16:56:58 by MOSER
;FIX SC.CSP
;
; UPD ID= 3504, SNARK:<6.MONITOR>SCAMPI.MAC.55,  22-Jan-84 13:19:14 by MCLEAN
;BUFFER FIXES AND MISSING SETZM DFQCNT
;
; UPD ID= 3492, SNARK:<6.MONITOR>SCAMPI.MAC.54,  20-Jan-84 11:10:45 by CDUNN
;More TCO 6.1127 - Add buffer deferral support. Also a few random fixes
;
; UPD ID= 3412, SNARK:<6.MONITOR>SCAMPI.MAC.53,   6-Jan-84 05:42:48 by GRANT
;MAPBUF is now a BLCAL.
;
; UPD ID= 3394, SNARK:<6.MONITOR>SCAMPI.MAC.52,   3-Jan-84 07:17:09 by HALL
;In SC.RRS, fix SETZRO of CBBKST so that it works
;In SAR.AB, remove the comma after SETZM P5
;
; UPD ID= 3363, SNARK:<6.MONITOR>SCAMPI.MAC.51,  22-Dec-83 21:17:08 by GRANT
;Use BLCAL. for LNKDFQ and LNKMFQ
;
; UPD ID= 3355, SNARK:<6.MONITOR>SCAMPI.MAC.50,  22-Dec-83 09:18:46 by HALL
;Fix SC.PON and SC.POF: test for being at interrupt level was backwards.
;	Channel 7 (instead of 5) was being turned on and off
;
; UPD ID= 3348, SNARK:<6.MONITOR>SCAMPI.MAC.49,  20-Dec-83 08:15:53 by GRANT
;Use BLCAL. for ULNKDG and ULNKMG
;
; UPD ID= 3333, SNARK:<6.MONITOR>SCAMPI.MAC.48,  16-Dec-83 15:50:35 by HALL
;Change calls to SNDDG and SNDMSG to get arguments right
;Call CLOSVC with BLCAL
;
; UPD ID= 3301, SNARK:<6.MONITOR>SCAMPI.MAC.47,  13-Dec-83 13:15:53 by CDUNN
;More TCO 6.1127 - Random fixes to online/offline stuff for handling VCs that
;come back. Also random DMA help...
;
; UPD ID= 3287, SNARK:<6.MONITOR>SCAMPI.MAC.46,  11-Dec-83 20:19:51 by GRANT
;In SSC.LP and SC.CLK, use new symbol VC.OPN.
;Change calling convention comments for SC.DMA - it accepts T1,T2 not T1,P4.
;
; UPD ID= 3255, SNARK:<6.MONITOR>SCAMPI.MAC.45,   5-Dec-83 19:22:37 by CDUNN
;More TCO 6.1127 - Add support for maintenance data send from JSYS level.
;Also some random fixes.
;
; UPD ID= 3185, SNARK:<6.MONITOR>SCAMPI.MAC.44,  17-Nov-83 16:18:38 by CDUNN
;More TCO 6.1127 - Remove support for mapping user buffers to monitor space
;on packet send. Handle monitor buffer being used for copy of user packet send 
;data.
;
; UPD ID= 3137, SNARK:<6.MONITOR>SCAMPI.MAC.43,  11-Nov-83 10:46:56 by CDUNN
;More TCO 6.1127 - Make SC.CVC and its callers agree on how its returns
;
; UPD ID= 3118, SNARK:<6.MONITOR>SCAMPI.MAC.42,   8-Nov-83 11:47:23 by CDUNN
;More TCO 6.1127 - Move SAVEAC to top of SC.RCB so AC is always saved. Also
;add lost SETZM of first word in buffer handed to LNKMFQ by SC.P2Q
;
; UPD ID= 2874, SNARK:<6.MONITOR>SCAMPI.MAC.41,   2-Sep-83 11:27:29 by CDUNN
;More TCO 6.1127 - Add DBIU (cousin of MBIU) to add scratch datagram buffers
;
; UPD ID= 2824, SNARK:<6.MONITOR>SCAMPI.MAC.40,  11-Aug-83 15:32:59 by CDUNN
; More TCO 6.1127 - Fix SC.ALM to correctly create and lock pages. A number
;of random fixes as well.
;
; UPD ID= 2761, SNARK:<6.MONITOR>SCAMPI.MAC.39,  24-Jul-83 02:01:20 by CDUNN
; More TCO 6.1127 - Fix SC.ABF to give the return address for the buffer as 
;promised.
;
; UPD ID= 2741, SNARK:<6.MONITOR>SCAMPI.MAC.38,  22-Jul-83 15:19:49 by CDUNN
;More TCO 6.1127 - General code cleanup. Removal of memory managment routines
;that try to do partial request returns. They now return all or nothing...
;
; UPD ID= 2606, SNARK:<6.MONITOR>SCAMPI.MAC.37,  20-Jun-83 16:12:30 by HALL
;TCO 6.1689 - Move fork tables to extended section
;Reference FKPGS via DEFSTR
;
; UPD ID= 2555, SNARK:<6.MONITOR>SCAMPI.MAC.36,   3-Jun-83 17:13:23 by CDUNN
;More TCO 6.1127 - Fix SC.ONL not to do anything with memory managment routines
;(Fixes ILMNRF at startup after crash). Make SC.SNM not loop to bad places on
;finding a stale message on work queue.
;
; UPD ID= 2531, SNARK:<6.MONITOR>SCAMPI.MAC.35,  26-May-83 18:07:16 by CDUNN
;More TCO 6.1127 - Fix SC.DRQ and SC.DRS to not light the abort bit on
;JSYS connections. Also make 10/11 word format byte pointers global
;
; UPD ID= 2493, SNARK:<6.MONITOR>SCAMPI.MAC.34,  19-May-83 11:14:48 by MURPHY
;Put EPGMAP in another section.
;
; UPD ID= 2461, SNARK:<6.MONITOR>SCAMPI.MAC.33,  12-May-83 17:14:28 by CDUNN
;More TCO 6.1127 - Add code to SC.RAP to observe the CBFKIL bit when
;deleting CB's
;
; UPD ID= 2420, SNARK:<6.MONITOR>SCAMPI.MAC.32,   4-May-83 13:49:30 by CDUNN
;More TCO 6.1127 - Change SC.INT and related code to return message length
;in the packet her rather than in another AC (I.E. Q1)
;
; UPD ID= 2366, SNARK:<6.MONITOR>SCAMPI.MAC.31,  27-Apr-83 23:45:11 by CDUNN
;More TCO 6.1127 - Make SC.CLK check port VC state before any other processing.
;Add code to SC.OFL/SC.ERR to mark all connections as closed by VC error.
;
; UPD ID= 2351, SNARK:<6.MONITOR>SCAMPI.MAC.30,  26-Apr-83 21:52:13 by CDUNN
;More TCO 6.1127 - Fix sense of F.RTB test in SC.SMG. Increment outstanding
;packet on correct send type. Fixes for idle chatter in SC.CLK and SC.INT
;
; UPD ID= 2326, SNARK:<6.MONITOR>SCAMPI.MAC.29,  22-Apr-83 01:41:13 by CDUNN
;More TCO 6.1127 - Change SC.SMG and SC.SMG to no do conversion from word
;count to byte count. Allow PHYKLP to do that. Also modify SC.INT to hand
;the SYSAP the length of the packet received since we now get it from PHYKLP.
;
; UPD ID= 2307, SNARK:<6.MONITOR>SCAMPI.MAC.28,  19-Apr-83 16:25:34 by CDUNN
;More TCO 6.1127
;1. Fix calling sequences for SNDMSG, flags and priority sometimes reversed
;2. Fix SC.DRQ to use a different buffer for the request sent after the
;response.
;3. Fix SC.SCA to not smash T3 on entry.
;
; UPD ID= 2251, SNARK:<6.MONITOR>SCAMPI.MAC.27,  12-Apr-83 20:06:48 by CDUNN
;More TCO 6.1127
;1. Fix SC.SCM to correctly dequeue entries from the dont care listener queue.
;2. Fix SC.ALM to use MLKMA instead of FMLKPG.
;3. Fix SC.REQ to do correct check for sufficient credits and do SOS to credit.
;
; UPD ID= 2231, SNARK:<6.MONITOR>SCAMPI.MAC.26,  10-Apr-83 18:17:14 by CDUNN
;More TCO 6.1127 - Fix sense of test for credit in SC.SND
;
; UPD ID= 2211, SNARK:<6.MONITOR>SCAMPI.MAC.25,   8-Apr-83 06:59:01 by GRANT
;TCO 6.1127 - In SC.ALD, zero the SYSAP's header area when assigning a buffer
;
; UPD ID= 2198, SNARK:<6.MONITOR>SCAMPI.MAC.24,   8-Apr-83 04:41:35 by CDUNN
;More TCO 6.1127 
;1. Add address of system block to the SCA ring buffer entry. Also add
;buffer address and PC of caller to the ring buffer entry. Fix init of the end
;of the SCA ring buffer.
;2. Fix SC.ALD to zero T2 when taking an error return.
;3. Fix SC.SCM to dequeue dont care listeners only once, not twice.
;4. Add SC.CLK to do idle chatter.
;
; UPD ID= 2161, SNARK:<6.MONITOR>SCAMPI.MAC.23,   4-Apr-83 20:51:03 by CDUNN
;More TCO 6.1127 - Change default for PIDBG to be off...
;
; UPD ID= 2136, SNARK:<6.MONITOR>SCAMPI.MAC.22,   3-Apr-83 20:35:55 by CDUNN
;More TCO 6.1127 - 
;1. Fix SC.ALM to use the number of buffers per page, not buffer size when 
;determining page count to obtain.
;2. Fix SCA protocol violation in disconnect. Send a response to a DISC_REQ
;in ALL cases, not just some. Then do other checking...
;3. Fix AC typos in SC.DIS.
;4. Add routine SC.PRT to return the local port number on a KL with a single
;CI port.
;5. Make rejecting a connect to a listener put you back in listen, not dumping
;the connection.
;6. Support SC.REJ going to listen again by makeing SC.LCB dequeue buffer
;from current queue before putting on a new one...
;7. Add code to support the SCA ring buffer. Routine SC.RNG is the collector
;8. SC.OFL/SC.ERR remove STKVAR and use P5 instead.
;9. Fix SC.ONL to correctly calculate new buffer minimums based on system count
;10. Replace PION and PIOFF with CION and CIOFF which go NOSKED and turn off 
;the channel, rather than all of PI.
;11. Add missing CION to SC.ALD exit routine
;
; UPD ID= 2066, SNARK:<6.MONITOR>SCAMPI.MAC.20,  23-Mar-83 01:21:40 by CDUNN
;More TCO 6.1127 - Add SCA overhead byte count to send message and datagrams
;
; UPD ID= 2064, SNARK:<6.MONITOR>SCAMPI.MAC.19,  23-Mar-83 00:39:26 by CDUNN
;More TCO 6.1127 - Remove referances to .CBDGB, replace with .CBDGR. Also
;fix SC.ADG to check the number of datagrams buffers queued for a connect and
;drop datagrasm if there are none. Also install .CBCDD (count of dropped
;datagrams) in the CB.
;
; UPD ID= 2061, SNARK:<6.MONITOR>SCAMPI.MAC.18,  22-Mar-83 10:12:43 by GRANT
;TCO 6.1127 - In SC.REJ, make proper test for connection state.  In SC.RRQ, put
;correct destination CID in the packet being assembled.
;
; UPD ID= 2055, SNARK:<6.MONITOR>SCAMPI.MAC.17,  22-Mar-83 00:49:38 by CDUNN
;More TCO 6.1127 - Fix SC.ALD to setup T2 as promised for +1 return. Also
;add counter to SC.RCB for number of CB's killed. Teach SC.SCM to watch the
;abort and reap bits in "don't care" listeners.
;
; UPD ID= 2022, SNARK:<6.MONITOR>SCAMPI.MAC.16,  19-Mar-83 00:21:09 by CDUNN
;More TCO 6.1127 - Fix SC.SCM to check name local SYSAP wishes to talk to 
;versus source name of remote on don't care listeners.
;More TCO 6.1127 - Dont be PIOFF in certain places where it turns out page
;faults are possible. Also fix sense of check for last buffer in SC.RCB when
;doing "dont care listeners".
;
; UPD ID= 2013, SNARK:<6.MONITOR>SCAMPI.MAC.14,  17-Mar-83 03:07:54 by CDUNN
;More TCO 6.1127 - 1. Fix SC.LCB to correctly link dont care listeners onto
;fork CB queue
;2. Fix SC.RCB to correctly handle deletion of dont care listeners
;3. In init, add general pool buffer to minimum count.
;4. Force SC.ALM to not run if we have not inited yet. (Prevents crash when
;no nodes are up at init and one shows up later)
;
; UPD ID= 2012, SNARK:<6.MONITOR>SCAMPI.MAC.13,  16-Mar-83 18:19:14 by CDUNN
;More TCO 6.1127 - Fix error in last edit.
;
; UPD ID= 1989, SNARK:<6.MONITOR>SCAMPI.MAC.12,  15-Mar-83 02:00:26 by CDUNN
;More TCO 6.1127 - Init tail queue to correct address when not current fork and
;deleteing last entry on a fork connect block queue.
;Also, TEMPORARILY! turn on RS%SE0 in calls to ASGRES until extended free
;space code is done...
;
; UPD ID= 1954, SNARK:<6.MONITOR>SCAMPI.MAC.11,  10-Mar-83 00:30:54 by CDUNN
;More TCO 6.1127 - Code DMA routines so rest of the world can properly
;access DMA code in port driver.

;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, 1985.
;ALL RIGHTS RESERVED.


	SEARCH SCAPAR,PROLOG

	TTITLE (SCAMPI,,<- Systems Communications Architecture service>)


;SCAMPI - Systems Communications Architecture for Multi Processor Interconnects
;	       Not to be confused with an Italian shrimp dish.
;
;
; Note:
; Some abbreviations appear EVERYWHERE in this module. They are:
;
; CB - Connection block
; SB - System block
; SBI - System block index - same as node number
; CID - Source connect ID
; PPD - Physical port driver
; MBZ - Must be zero
; BDT - Buffer descriptor table (xlation for JSYS buffers to monitor buffers)
;

	EXTERN SCSINI,SCSTCQ,SCSBCQ
	EXTERN MSG,DG,XFER,EVT,SCSDEQ
	EXTERN MAPBUF,UMAP,SNDDAT,REQDAT,OPENVC
	EXTERN LOCPRT
;		DESIGN NOTES:

;If a connection's state is closed, either the sysap disconnected, or it's
;been notified that the connection is closed. If CBFPTC is on, no more
;protocol is necessary (we won't send anything else over the wire, or
;receive anything).

;When CBFPTC is set, we also set CBFRAP unless it's a JSYS connection. SCSJSY
;sets reap if it is. We still can't get rid of the c.b. until the block
;has been dequeued from the work queue, and all its outstanding packets
;have been returned. The first case probably doesn't happen, but it's
;conceivable that we were about to send a credit request when the connection
;was closed. SC.SNM will dequeue the block eventually and find its block
;state set to zero. This avoids trying to dequeue it at the time that
;CBFPTC is set.

;A connection may be closed but not PTC. The opposite is not true.

;		FUNCTIONAL NOTES:

;SC.ACC no longer returns the address of the other side's connect data.
;That was risky anyway because it points at a connection block that could
;conceivably go away.

;.SSRID callback occurs when the other side initiates a disconnect, rather
;than when it confirms one. It provides a reason code in T3.

;The TOPS-20 spec said that the sysap could provide a "minimum receive
;credit" value, which controlled when the sysap received a "little credit
;left" callback. That is no longer true. The code now implements the
;corporate spec, which says that the other side will set this value in
;the minimum_credit field of the connect_request or accept_request

;After receiving a connection request, a listening sysap must open another
;listener. THis is true for both accepting and rejecting.
	COMMENT |

                       Comments on Ring Buffer Usage

     The  ring  buffer  will record various events which occur. Currently,
the following can be recorded: SYSAP to SCA calls, SCA  callbacks,  buffer
manipulation,    packet   transactions,   PI   transitions,   port   queue
manipulation, and interlocks. The recording of events is dictated  by  the
setting  of  RNGSW. If the appropriate bit is set, then that event will be
recorded when it occurs. These bit definitions are defined in  SCAPAR  and
are  as follows for the corresponding events listed above: RSYSCA, RSCASY,
RBUFMG, RPACKT, RPITRN, RPRTQU, RINTLK.

     The format of a ring buffer entry is described in SCAPAR. Briefly, an
entry  starts with the entry header word (currently -77,,-77). The rest of
the entry header follows as described in  SCAPAR.  Every  entry  has  this
common  header.  Following  the header is the feature event specific data.
Each feature event has its own feature specific data which  is  placed  in
the  buffer  entry.  For  this reason, ring buffer entries are of variable
size depending upon feature type being recorded (which  depends  upon  the
setting  of RNGSW). [The length of the buffer entry for each event is kept
in the table ENTLTB which is indexed by event code. These event codes  are
defined  in  SCAPAR.]  Following  the  feature specific data is the buffer
entry tail. Currently, this is one word which points to the start  of  the
buffer  entry.  This word can be used to easily step back through the ring
buffer.

     RNGSIZ  is the size in words of the ring buffer. At startup, SCA will
get the number of pages defined by symbol  RBFLEN  (in  SCAPAR)  for  ring
buffer usage. Currently, this is 5 pages.

     RNGTOP  is a pointer to the top of the ring buffer pages. RNGBOT is a
pointer to the bottom of the ring buffer pages and will  be  RBFLEN  pages
greater  than  the  value  in RNGTOP since the ring buffer is allocated in
contiguous pages.

     RNGNUM  is the total number of ring buffer entries written. RNGCUR is
the pointer to the top of the most recent entry completed. Use this  value
as  the  first entry to investigate and work backwards through less recent
entries. RNGADR is used by the various ring buffer routines as  a  pointer
into the ring buffer.

|
	SUBTTL	Table of Contents


;		Table of Contents for SCAMPI
;
;
;			   Section			      Page
;   1. Local variable storage for SCS . . . . . . . . . . . .    6
;   2. State Tables . . . . . . . . . . . . . . . . . . . . .    7
;   3. Initialization code. . . . . . . . . . . . . . . . . .   16
;   4. Calls from sysap
;        4.1.   SC.SOA (Set ONLINE address) . . . . . . . . .   17
;        4.2.   Connection management . . . . . . . . . . . .   18
;             4.2.1.     SC.CON (Connect) . . . . . . . . . .   20
;             4.2.2.     SC.LIS (Listen). . . . . . . . . . .   23
;             4.2.3.     SC.ACC (Accept). . . . . . . . . . .   26
;             4.2.4.     SC.REJ (Reject). . . . . . . . . . .   28
;             4.2.5.     SC.DIS (Disconnect). . . . . . . . .   29
;        4.3.   Messages and datagrams. . . . . . . . . . . .   32
;             4.3.1.     SC.SDG (Send a datagram) . . . . . .   32
;             4.3.2.     SC.SMG (Send a message). . . . . . .   35
;             4.3.3.     SC.RDG (Receive a datagram). . . . .   39
;             4.3.4.     SC.RMG (Receive a message) . . . . .   40
;             4.3.5.     SC.CRD (Cancel Receive datagram) . .   42
;             4.3.6.     SC.CRM (Cancel receive message). . .   43
;        4.4.   Named buffers . . . . . . . . . . . . . . . .   44
;             4.4.1.     SC.MAP (Map a buffer). . . . . . . .   44
;             4.4.2.     SC.UMP (Unmap a mapped buffer) . . .   45
;             4.4.3.     SC.SND (Send DMA data) . . . . . . .   46
;        4.5.   State polling . . . . . . . . . . . . . . . .   48
;             4.5.1.     SC.CSP (Connect state poll). . . . .   48
;             4.5.2.     SC.DCI (Return destination connect ID)   49
;             4.5.3.     SC.RCD (Return configuration data) .   50
;             4.5.4.     SC.NOD (Return node number given CID)  51
;             4.5.5.     SC.RAC (Return available credit) . .   52
;             4.5.6.     SC.PRT (Return local port number). .   53
;        4.6.   Maintenance . . . . . . . . . . . . . . . . .   54
;             4.6.1.     SC.RST (Reset remote system) . . . .   54
;             4.6.2.     SC.STA (Start remote node) . . . . .   55
;   5. Call from port driver. . . . . . . . . . . . . . . . .   56
;        5.1.   SC.ONL (Node has come online) . . . . . . . .   56
;        5.2.   SC.ERR (Node(s) have gone away) . . . . . . .   60
;        5.3.   SC.DMA (DMA operation complete) . . . . . . .   64
;        5.4.   Incoming buffer
;             5.4.1.     SC.INT (Buffer arrival). . . . . . .   65
;             5.4.2.     SC.ORQ (Connect request) . . . . . .   68
;             5.4.3.     SC.ORS (Connect response). . . . . .   70
;             5.4.4.     SC.ARQ (Accept request). . . . . . .   71
;             5.4.5.     SC.ARS (Accept response) . . . . . .   73
;             5.4.6.     SC.RRQ (Reject request). . . . . . .   74
;             5.4.7.     SC.RRS (Reject response) . . . . . .   75
;             5.4.8.     SC.DRQ (Disconnect request). . . . .   76
;             5.4.9.     SC.DRS (Disconnect response) . . . .   79
;             5.4.10.    SC.CRQ (Credit request). . . . . . .   80
;             5.4.11.    SC.CRS (Credit response) . . . . . .   82
;             5.4.12.    SC.INC (Connection management) . . .   84
;             5.4.13.    SC.ADG/SC.AMG (application datagram/message)   88
;   6. Periodic functions . . . . . . . . . . . . . . . . . .   91
;        6.1.   SC.CLK (Dispatch) . . . . . . . . . . . . . .   91
;        6.2.   SC.IDL (Idle chatter) . . . . . . . . . . . .   92
;        6.3.   SC.RAP (Reap old connections) . . . . . . . .   94
;        6.4.   SC.ALM (Allocate buffers) . . . . . . . . . .  100
;        6.5.   SC.ALC (Allocate buffers for pool). . . . . .  101
;        6.6.   SC.DEF (Allocate deferred buffers for sysap).  103
;   7. Connection management utility routines . . . . . . . .  106
;        7.1.   SC.SCA (Send connection management message) .  106
;        7.2.   SC.SNM (Send next connection management message) 107
;        7.3.   SC.AWQ (Add entry to work queue). . . . . . .  110
;        7.4.   SC.RWQ (Remove entry from work queue) . . . .  111
;        7.5.   SC.ACB (Allocate a connection block). . . . .  112
;        7.6.   SC.LCB (Link a new CB). . . . . . . . . . . .  115
;        7.7.   SC.SCM (Search for connection match). . . . .  118
;        7.8.   SC.CSC (CID sanity check) . . . . . . . . . .  122
;        7.9.   SC.CDT (Send credit_request). . . . . . . . .  123
;        7.10.  SC.CVC (Close a virtual connection) . . . . .  126
;        7.11.  SC.SDM (String and data move to CB) . . . . .  127
;        7.12.  SC.OUT (Check sysap call) . . . . . . . . . .  128
;        7.13.  SC.RSP (Send a response). . . . . . . . . . .  129
;        7.14.  SC.RQS (Send a request) . . . . . . . . . . .  130
;        7.15.  SC.PAK (Send a packet). . . . . . . . . . . .  133
;   8. Buffer management routines . . . . . . . . . . . . . .  135
;        8.1.   SC.SBT (Set buffer thresholds). . . . . . . .  135
;        8.2.   SC.BUF. . . . . . . . . . . . . . . . . . . .  140
;        8.3.   SC.ALD (Allocate long datagram buffers) . . .  142
;        8.4.   SC.ABF (Allocate a buffer/buffers). . . . . .  143
;        8.5.   SC.CMG/SC.CDG (Create MSG/DG buffers) . . . .  144
;        8.6.   SC.BBF (Break memory into buffers). . . . . .  145
;        8.7.   SC.RBF (Return a message buffer). . . . . . .  146
;        8.8.   SC.RLD (Return a datagram buffer) . . . . . .  147
;        8.9.   SC.TMQ/SC.TDQ (Trace free queue). . . . . . .  148
;   9. Byte-swapping routines . . . . . . . . . . . . . . . .  149
;        9.1.   SC.RIN (Byte swap incoming packet). . . . . .  149
;        9.2.   SC.ISW (Swap bytes from 11 to 10 format). . .  150
;        9.3.   SC.ROU (Byte swap outgoing packet). . . . . .  151
;        9.4.   SC.OSW (Swap word from 10 to 11 format) . . .  152
;  10. Locking/unlocking routines . . . . . . . . . . . . . .  153
;       10.1.   SC.POF (Turn KLIPA channel off) . . . . . . .  153
;       10.2.   SC.PON (Turn KLIPA channel on). . . . . . . .  154
;       10.3.   SC.LOK (Lock connection block). . . . . . . .  155
;       10.4.   SC.ULK (Unlock connection block). . . . . . .  156
;  11. Ring Buffer routines . . . . . . . . . . . . . . . . .  157
;       11.1.   SC.RGI (Initialize ring buffer variables) . .  157
;       11.2.   SC.RHD (Write ring buffer entry header) . . .  158
;       11.3.   SC.RTE (Write ring buffer entry tail) . . . .  159
;       11.4.   SC.RWR (Write ring buffer entry). . . . . . .  160
;       11.5.   RG.SSC (SYSAP to SCA calls) . . . . . . . . .  161
;       11.6.   RG.SCS (SCA to SYSAP calls) . . . . . . . . .  162
;       11.7.   RG.BFM (Buffer manipulation). . . . . . . . .  163
;       11.8.   RG.PKT (Packet movement). . . . . . . . . . .  164
;       11.9.   RG.PIT (PI transitions) . . . . . . . . . . .  165
;       11.10.  RG.PQM (Port queue manipulation). . . . . . .  166
;       11.11.  RG.ITL (Interlocks) . . . . . . . . . . . . .  167
;  12. Dummy routines until the port driver supports them . .  169
;  13. End of SCS . . . . . . . . . . . . . . . . . . . . . .  170
	SUBTTL Local variable storage for SCS

	RS (SCAINI)		;Flag set when we run through SCA init code

	RS (TOPFQ)		;Pointer to top of free queue
	RS (BOTFQ)		;Pointer to bottom of free queue
	RS (FQCNT)		;Count of the number of buffer on free queue

	RS (TOPDC)		;Top of the dont care queue
	RS (BOTDC)		;Bottom of the dont care queue

	RS (TOPDFQ)		;Pointer to first buffer on long DG Q
	RS (BOTDFQ)		;Pointer to last buffer on long DG Q
	RS (DFQCNT)		;Count of buffers on long DG queue

	RS (SBCNT)		;Save the number of SB's we have
	RS (MXSBCT)		;The max SBCNT has ever been
	RS (NOTTAB)		;Address of notification table
	RS (NOTEND)		;Address of the end of the notification table
	RS (UNQBTS)		;Storage for the next CID bits to be assigned
	RS (UNQRFL)		;Number of times CID bits have been recycled
	RS (NXTIDX)		;Next free index into the list of CID's
	RS (CIDRFL)		;Number of times CIDTAB has been recycled
	RS (CIDTAB)		;Base address of the CID address table
	RS (UBTTAB)		;Base address of the CID unique bits table
	RS SBSTUK,1
	RPMAX==:5		;Don't postpone reaping more than this
	RSI (RAPTIM,<C%RAPT>,1)	;Timer for SCA connection reaper
	RSI (RAPINC,<C%RAPT>,1)	;Min time increment (millisec)between reap runs

;SCA ring buffer storage
;
	RSI (RNGSW,<RPACKT+RBUFMG>,1)  ;Ring buffer switch - default is RPACKT

;Note:	RNGSW is not under the SCARNG conditional because it must always 
;	be present since SCAPAR uses it to create structure names for the 
;	various switch settings.

   IFN SCARNG,<
	RS (RNGSIZ)		;Actual length of ring buffer
	RS (RNGTOP)		;Start of ring buffer
	RS (RNGBOT)		;End of ring buffer
	RS (RNGNUM)		;Number of entries written to ring buffer
	RS (RNGCUR)		;Top of the most recent complete entry
	RS (RNGADR)		;Current position in ring buffer

;Below is the ring buffer entry length table.  This table contains the
;entry length for each of the events.  It is indexed by event code.

ENTLTB:	-1			;Illegal event code
	15			;Code 1 - SYSAP to SCA
	12			;Code 2 - SCA to SYSAP
	17			;Code 3 - Buffer manipulation
	17			;Code 4 - Packet transaction
	11			;Code 5 - PI transition
	12			;Code 6 - Port queue manipulation
	13			;Code 7 - Interlocks
	0			;Reserved for future expansion
	0			;Reserved for future expansion
	0			;Reserved for future expansion
>				;End of IFN SCARNG

;Channel control word. When we reach zero here, really turn on the CI channel
;on a CION.
	RSI (CHNCTL,<0>,1)	;CI channel control word...

; Performance and analysis counter tables
	RS (SNDTAB,.STLST)	;Table for packets sent
	RS (RECTAB,.STLST)	;Table for packets received
	RS (LISTEN)		;A place to count listens
	RS (RCBCNT)		;Count of CB killed by SC.RCB

; Idle chatter support locations.
	RS (TMGCNT)		;Count of systems nailed by idle chatter
	RSI (TMGSBI,<-1>,1)	;Current system under consideration
	RSI (TMGTIM,<-C%TMGT>,1);Timeout perioud

; Message and datagram buffer managment parameter locations. Diddle at your
;own risk. See SCAPAR for definitions of initial values.

	RSI (MBPS,<C%MBPS>,1)	;Min message buffers per SB

	RSI (MBCR,<C%MBCR>,1)	;Number of msg buffers to queue before sending
				;  a credit request for them

	RSI (DBPS,<C%DBPS>,1)	;Min datagram buffers per SB

	RS (MINMSG)		;Min number of messages we should have
	RS (MINDG)		;Min number of datagrams we should have

	RS (NMBCNT)		;Count of times we ran out of message buffers
	RS (NDBCNT)		;Count of time we ran out of datagram buffers

	RS (TOTMGB)		;Total number of message buffers ever created
	RS (TOTDGB)		;Total number of datagram buffers ever created

	RS (MBUST)		;Number of times a small request was honored
				; even though we were under message threshold
	RS (DBUST)		;Number of times a small request was honored
				; even though wer were under datagram threshold

	RS (DMRCNT)		;Number of message buffer requests deferred
	RS (DDRCNT)		;Number of datagram buffer requests deferred
	RS (RMRCNT)		;Number of message buffer requests refused
	RS (RDRCNT)		;Number of datagram buffer requests refused
	RS (ASRMR)		;Average size of refused message request
	RS (ASRDR)		;Average szie of refused datagram request

	RSI (LRGREQ,<C%LGRQ>,1)	;Buffer requests of less than this size are 
				; small requests

	RSI (MGTRSH,<C%MGTR>,1)	;MSG threshold. SC.ABF will not allocate a 
				; large request that would take us below this
	RSI (DGTRSH,<C%DGTR>,1)	;DG threshold. SC.ALD will not allocate a 
				; large request that would take us below this
				;A large request is any request larger than 2

	RSI (LSTEPG,<777>,1)	;Last page used in EPGSEC,starts at section end

	.PSECT RSDAT		;Put this in PSECT which is not zeroed

; PRESBL and SBLIST must stay together in this order!!!
;
PRESBL::-1			;Flag for dont care for remote
SBLIST::BLOCK C%SBLL		;Keep storage for a list of system block addr's

; Byte pointers to ten format 8 bit bytes...
;
TA$LSB::POINT ^D8,T1,17		;Ten byte A, least significant bits
TA$MSB::POINT ^D8,T1,9		;Ten byte A, Most significant
TB$LSB::POINT ^D8,T1,35		;Ten byte B, Least significant
TB$MSB::POINT ^D8,T1,27		;Ten byte B, most significant

; Byte pointers to eleven format 8 bit bytes...
;
EA$LSB::POINT ^D8,T1,23		;Eleven, byte A, least sig
EA$MSB::POINT ^D8,T1,31		;Eleven, byte A, most sig
EB$LSB::POINT ^D8,T1,7		;Eleven, byte B, least sig
EB$MSB::POINT ^D8,T1,15		;Eleven, byte B, most sig


DSPTAB:	$DISPA			;Generate addr table for message handlers

INITAB:	$SYSAP			;Generate the SYSAP init address list
	C%SYTL==<.-INITAB>-1	;The length of INITAB

	.ENDPS RSDAT		;End this part of the PSECT

;Routines to build packets

SCMKPK:	MSEC1,,SC.MOQ		;Connect_request
	MSEC1,,SC.MOS		;Connect_response
	MSEC1,,SC.MAQ		;Accept_request
	MSEC1,,SC.MAS		;Accept_response
	MSEC1,,SC.MRQ		;Reject_request
	MSEC1,,SC.MRS		;reject_response
	MSEC1,,SC.MDQ		;Disconnect_request
	MSEC1,,SC.MDS		;Disconnect_response
	MSEC1,,SC.MCQ		;Credit_request
	MSEC1,,SC.MCS		;Credit_response
	SUBTTL State Tables

;TABLE X

;Table X - used when sysap calls SCA. For each event, provides new connection
;and block state. Also allows checking for invalid state

TABLEX:

;Connect

FLD(.BSCNP,X.BSTAT)+FLD(.CSCSE,X.CSTAT) ;Closed
X.ERR				;Listening
X.ERR				;Connect_sent
X.ERR				;Connect_received
X.ERR				;Connect_ACK
X.ERR				;Accept_sent
X.ERR				;Reject_sent
X.ERR				;Open
X.ERR				;Disconnect_sent
X.ERR				;Disconnect_rec
X.ERR				;Disconnect_ACK
X.ERR				;disconnect_match

;Listen

FLD(.CSLIS,X.CSTAT)		;Closed
0				;Listening
X.ERR				;Connect_sent
X.ERR				;Connect_received
X.ERR				;Connect_ACK
X.ERR				;Accept_sent
X.ERR				;Reject_sent
X.ERR				;Open
X.ERR				;Disconnect_sent
X.ERR				;Disconnect_rec
X.ERR				;Disconnect_ACK
X.ERR				;disconnect_match

;Accept

X.ERR				;Closed
X.ERR				;Listening
X.ERR				;Connect_sent
FLD(.BSACP,X.BSTAT)		;Connect_received
				;New state is set when request is sent
X.ERR				;Connect_ACK
X.ERR				;Accept_sent
X.ERR				;Reject_sent
X.ERR				;Open
X.ERR				;Disconnect_sent
X.ERR				;Disconnect_rec
X.ERR				;Disconnect_ACK
X.ERR				;disconnect_match
;Reject

X.ERR				;Closed
X.ERR				;Listening
X.ERR				;Connect_sent
FLD(.BSRPN,X.BSTAT)		;Connect_received
				;New state is set when request is sent
X.ERR				;Connect_ACK
X.ERR				;Accept_sent
X.ERR				;Reject_sent
X.ERR				;Open
X.ERR				;Disconnect_sent
X.ERR				;Disconnect_rec
X.ERR				;Disconnect_ACK
X.ERR				;disconnect_match

;Disconnect

0					;Closed (no change)
FLD(.CSCLO,X.CSTAT)			;Listening
FLD(.CSCLO,X.CSTAT)			;Connect_sent
FLD(.BSRPN,X.BSTAT)+FLD(.CSRJS,X.CSTAT) ;Connect_received
FLD(.CSCLO,X.CSTAT)			;Connect_ACK
FLD(.CSCLO,X.CSTAT)			;Accept_sent
FLD(.CSCLO,X.CSTAT)			;Reject_sent
FLD(.BSDPN,X.BSTAT)+FLD(.CSDSE,X.CSTAT) ;Open
0					;Disconnect_sent (no change)
FLD(.BSDPN,X.BSTAT)+FLD(.CSDMC,X.CSTAT) ;Disconnect_rec
0					;Disconnect_ACK (no change)
0					;Disconnect_match (no change)
;Table Y

;For each block state, this table provides the op code to send and the
;new connection state

; * * * *
;Disagrees with corporate spec when block state is connect_pending. We
;have already set the connection state to .CSCSE in order to ensure that
;if a connection's state is "closed", the sysap never expects to hear
;about it again. If this is not changed, there is potential for the sysap
;to call SC.DIS between the time that the connection state is set and
;the message is actually sent. That sets the state to closed. We can't
;change it to connect_sent when the message is finally sent, because
;we'd lose track of the fact that the sysap had closed it.
; * * * *

TABLEY:	0			;Not used
	0			;Free (1)
	0			;Allocate (2)
;	FLD(.STORQ,Y.OP)+FLD(.CSCSE,Y.STAT) ;Connect_pending (3)
	FLD(.STORQ,Y.OP)	;Connect_pending (3)
	FLD(.STARQ,Y.OP)+FLD(.CSACS,Y.STAT) ;Accept_pending (4)
	FLD(.STRRQ,Y.OP)+FLD(.CSRJS,Y.STAT) ;Reject_pending (5)
	FLD(.STCRQ,Y.OP)	;Credit_pending (state doesn't change) (6)
	FLD(.STDRQ,Y.OP)	;Disconnect_pending (state already set) (7)
YSIZE==:.-TABLEY
;Table Z

;This table indicates, for a given op code, the length of its message,
;the priority for sending it, and the expected response.

TABLEZ:
	FLD(.LNORQ,Z.LEN)+FLD(KLPMED,Z.PRI)+FLD(.STORS,Z.RSP)	;Connect_req
	FLD(.LNORS,Z.LEN)+FLD(KLPMED,Z.PRI)			;CONNECT_RSP
	FLD(.LNARQ,Z.LEN)+FLD(KLPMED,Z.PRI)+FLD(.STARS,Z.RSP)	;ACCEPT_REQ
	FLD(.LNARS,Z.LEN)+FLD(KLPMED,Z.PRI)			;ACCEPT_RSP
	FLD(.LNRRQ,Z.LEN)+FLD(KLPMED,Z.PRI)+FLD(.STRRS,Z.RSP)	;REJECT_REQ
	FLD(.LNRRS,Z.LEN)+FLD(KLPMED,Z.PRI)			;REJECT_RSP
	FLD(.LNDRQ,Z.LEN)+FLD(KLPDRG,Z.PRI)+FLD(.STDRS,Z.RSP)	;DISCONNECT_REQ
	FLD(.LNDRS,Z.LEN)+FLD(KLPMED,Z.PRI)			;DISCONNECT_RSP
	FLD(.LNCRQ,Z.LEN)+FLD(KLPHI,Z.PRI)+FLD(.STCRS,Z.RSP)	;CREDIT_REQ
	FLD(.LNCRS,Z.LEN)+FLD(KLPMED,Z.PRI)			;CREDIT_RSP
;Table K

;This table indicates, for a given incoming op code and current state
;of a connection, whether the event is legal, and if it is, what the new
;state and returned op code should be

TABLEK:

;Received Connect_req

FLD(.STORS,K.OP)		;Closed
FLD(.STORS,K.OP)+FLD(.CSCRE,K.STAT) ;Listening
K.ERR				;Connect request was sent (CONNECT_SENT)
K.ERR				;Connect request was received (CONNECT_REC)
K.ERR				;Connect response was received (CONNECT_ACK)
K.ERR				;Accept request was sent (ACCEPT_SENT)	
K.ERR				;Reject request was sent (REJECT_SENT)
K.ERR				;Connection is open (OPEN)
K.ERR				;Disconnect request was sent (DISCONNECT_SENT)
K.ERR				;Disconnect request received (DISCONNECT_REC)
K.ERR				;Disconnect response received (DISCONNECT_ACK)	
K.ERR				;Waiting for disconnect response (DISCONNECT_MATCH)

;Received connect_response
;"No match" is handled specially.

FLD(.CSCLO,K.STAT)		;Closed
K.ERR				;Listening
FLD(.CSCAK,K.STAT)+K.CHK	;Connect_sent
K.ERR				;Connect_received
K.ERR				;Connect response was received (CONNECT_ACK)
K.ERR				;Accept request was sent (ACCEPT_SENT)	
K.ERR				;Reject request was sent (REJECT_SENT)
K.ERR				;Connection is open (OPEN)
K.ERR				;Disconnect request was sent (DISCONNECT_SENT)
K.ERR				;Disconnect request received (DISCONNECT_REC)
K.ERR				;Disconnect response received (DISCONNECT_ACK)	
K.ERR				;Waiting for disconnect response (DISCONNECT_MATCH)

;Received accept-request

FLD(.STARS,K.OP)+FLD(.CSCLO,K.STAT) ;Closed. Send "no match"
K.ERR				;Listening
K.ERR				;Connect_sent
K.ERR				;Connect_received
FLD(.STARS,K.OP)+FLD(.CSOPN,K.STAT) ;Connect_ACK
K.ERR				;Accept_sent
K.ERR				;Reject_sent
K.ERR				;Open
K.ERR				;Disconnect_sent
K.ERR				;Disconnect_rec
K.ERR				;Disconnect_ACK
K.ERR				;disconnect_match
;Received accept_response
;"No match" is handled specially.
;If state is "closed", we must send disconnect_request. This is handled specially.

FLD(.STDRQ,K.OP)+FLD(.CSCLO,K.STAT) ;CLosed
K.ERR				;Listening
K.ERR				;Connect_sent
K.ERR				;Connect_received
K.ERR				;Connect_ACK
FLD(.CSOPN,K.STAT)+K.CHK	;Accept_sent
K.ERR				;Reject_sent
K.ERR				;Open
K.ERR				;Disconnect_sent
K.ERR				;Disconnect_rec
K.ERR				;Disconnect_ACK
K.ERR				;disconnect_match


;Received reject_request

FLD(.STRRS,K.OP)+FLD(.CSCLO,K.STAT) ;Closed
K.ERR				;Listening
K.ERR				;Connect_sent
K.ERR				;Connect_received
FLD(.STRRS,K.OP)+FLD(.CSCLO,K.STAT) ;Connect_ACK
K.ERR				;Accept_sent
K.ERR				;Reject_sent
K.ERR				;Open
K.ERR				;Disconnect_sent
K.ERR				;Disconnect_rec
K.ERR				;Disconnect_ACK
K.ERR				;disconnect_match

;Received reject_response

FLD(.CSCLO,K.STAT)		;Closed
K.ERR				;Listening
K.ERR				;Connect_sent
K.ERR				;Connect_received
K.ERR				;Connect_ACK
K.ERR				;Accept_sent
FLD(.CSCLO,K.STAT)+K.CHK	;Reject_sent
K.ERR				;Open
K.ERR				;Disconnect_sent
K.ERR				;Disconnect_rec
K.ERR				;Disconnect_ACK
K.ERR				;disconnect_match
;Received disconnect_request

FLD(.STDRS,K.OP)+FLD(.CSCLO,K.STAT) ;Closed
K.ERR				;Listening
K.ERR				;Connect_sent
K.ERR				;Connect_received
K.ERR				;Connect_ACK
K.ERR				;Accept_sent
K.ERR				;Reject_sent
FLD(.STDRS,K.OP)+FLD(.CSDRE,K.STAT) ;Open
FLD(.STDRS,K.OP)+FLD(.CSDMC,K.STAT) ;Disconnect_sent
K.ERR				;Disconnect_rec
FLD(.STDRS,K.OP)+FLD(.CSCLO,K.STAT) ;Disconnect_ACK
K.ERR				;disconnect_match


;received disconnect_response

FLD(.CSCLO,K.STAT)		;Closed
K.ERR				;Listening
K.ERR				;Connect_sent
K.ERR				;Connect_received
K.ERR				;Connect_ACK
K.ERR				;Accept_sent
K.ERR				;Reject_sent
K.ERR				;Open
FLD(.CSDAK,K.STAT)+K.CHK	;Disconnect_sent
K.ERR				;Disconnect_rec
K.ERR				;Disconnect_ACK
FLD(.CSCLO,K.STAT)+K.CHK	;disconnect_match


;Received credit_request

FLD(.STCRS,K.OP)		;Closed
K.ERR				;Listening
K.ERR				;Connect_sent
K.ERR				;Connect_received
K.ERR				;Connect_ACK
K.ERR				;Accept_sent
K.ERR				;Reject_sent
FLD(.STCRS,K.OP)		;Open
FLD(.STCRS,K.OP)		;Disconnect_sent
K.ERR				;Disconnect_rec
FLD(.STCRS,K.OP)		;Disconnect_ACK
K.ERR				;disconnect_match
;Received credit_response

0				;Closed
K.ERR				;Listening
K.ERR				;Connect_sent
K.ERR				;Connect_received
K.ERR				;Connect_ACK
K.ERR				;Accept_sent
K.ERR				;Reject_sent
K.CHK				;Open
0				;Disconnect_sent
K.CHK				;Disconnect_rec
0				;Disconnect_ACK
0				;disconnect_match

;Table X - used when sysap calls SCA. For each event, provides new connection
;and block state. Also allows checking for invalid state

	DEFSTR X.ERR,TABLEX,0,1		;Error flag
	DEFSTR X.BSTAT,TABLEX,17,17	;New block state
	DEFSTR X.CSTAT,TABLEX,35,18	;New connection state

;In some cases, the connection state is set when the request is sent,
;rather than when the sysap calls SCA.

	EV.CON==:0		;SC.CON
	EV.LIS==:1		;SC.LIS
	EV.ACC==:2		;SC.ACC
	EV.REJ==:3		;SC.REJ
	EV.DIS==:4		;SC.DIS

;DEFSTRs for table Y. For each block state, provides op code to
;send and new connection state

	DEFSTR (Y.OP,TABLEY,17,18)
	DEFSTR (Y.STAT,TABLEY,35,18)

;Defstrs for table Z. For each op code to be sent, provides length, priority,
;and expected response

	DEFSTR Z.LEN,TABLEZ,17,18
	DEFSTR Z.PRI,TABLEZ,20,3
	DEFSTR Z.RSP,TABLEZ,35,15

;Defstrs for table K. For each incoming packet, provides op code of response
;and new connection state. Also allows checking for protocol violations

	DEFSTR (K.ERR,TABLEK,0,1)
	DEFSTR (K.CHK,TABLEK,1,1)
	DEFSTR (K.OP,TABLEK,17,16)
	DEFSTR (K.STAT,TABLEK,35,18)
	SUBTTL	Initialization code

	RESCD

; Here we start the world of SCA. One of the assumptions that we make here is 
;that the port driver has already run and hence there are system blocks already
;in existance. What we must do here is queue a message receive buffer for each
;of these system blocks. In addition we must init the buffer chain that we will
;use as space for the SCA flow control messages. One buffer per system block
;is allocated at init time. So, what we do here is as follows:
;
; 1. Count how many system blocks there are.
;
; 2. Build a chain of buffers to be queued by the port driver as flow message 
;receive buffers.
;
; 3. Build the chain of send buffer which SCA maintains. (Head pointer: TOPFQ)
;
SCA::	EA.ENT			;Insure we run in non-zero section
	SAVEPQ

   IFN SCARNG,<
	CALL SC.RGI		;Initialize ring buffer
	 CALL SCADIE		;No space, so die
>				;End of IFN SCARNG

	MOVX T1,<1B1>		;Get a very large positive number
	MOVEM T1,SCSTIM		;Init SCS% clock as never going off

	SETZM FQCNT		;Be sure the buffer count is accurate
	SETZM TOPFQ		;Zero the FLINK for the free queue
	XMOVEI T1,TOPFQ		;Get a pointer to the free queue FLINK
	MOVEM T1,BOTFQ		;Init BLINK as pointer to FLINK

	SETZM DFQCNT		;Init datagram buffer count
	SETZM TOPDFQ		;Zero long datagram queue FLINK
	XMOVEI T1,TOPDFQ	;Get a pointer to the top of this queue
	MOVEM T1,BOTDFQ		;Init the BLINK as pointer to FLINK

	SETZM TOPDC		;Zero the dont care queue FLINK
	XMOVEI T1,TOPDC		;Get the address of top of dont care queue
	MOVEM T1,BOTDC		;Save as the bottom of the queue

	MOVX T1,1		;We desire only one page
	CALL PGRSKD		;Get a page of resident memory for us pls..
	 BUG. (HLT,SCANPT,SCAMPI,SOFT,<SCA - No page for CID table>,,<

Cause:	SCA called PGRSKD for a page to put its data tables in.
	The call failed. Nothing can be done without these tables.
>)
	PUSH P,T1		;Save this page addr for a short while
	MOVEM T1,T2		;Set up source addr for BLT
	MOVEM T1,T3		;  and destination addr
	AOS T3			;Make the destination addr source addr+1
	MOVX T1,PGSIZ-1		;Number of words to move
	SETZM (T2)		;Be sure we BLT zeros
	EXTEND T1,[XBLT]	;Zero the table space
	POP P,T1		;Get the table addr again
	MOVEM T1,CIDTAB		;Save the address of the CID table
	ADDI T1,<PGSIZ/2>	;Point to halfway through the page
	MOVEM T1,UBTTAB		;Save this as address of uniqueness table
	MOVX T1,C%CIDL		;Init NXTIDX as one more than highest index
	MOVEM T1,NXTIDX		;.	.	.
	SETZM CIDRFL		;Not doing CIDTAB recycling yet

	SETONE UBITS,T1		;Set all bits in the unique bits field
	LSH T1,-<C%RMBU>	;Right justify said bits
	MOVEM T1,UNQBTS		;Store as the uniquness bits
	AOS UNQBTS		;Init as one more than the first unique bits
	SETZM UNQRFL		;Not doing CID bits recycling yet

; Set buffer thresholds.
;
	SETZM SBCNT		;Init the count of remotes online
	SETZM MXSBCT		;Init the max value of SBCNT
	CALL SC.SBT		;Set msg and dg buffer thresholds

; Set initial levels for both message and datagram buffers.
;
SSC.NX:	MOVE T1,MINMSG		;Get the number of messages to start with
	IDIVI T1,C%MGPG		;(T1) = (number of buffer) / (buffers per page)
	SKIPE T2		;Any remainder???
	AOS T1			;Yes, round up to the next page
	CALL PGRSKD		;Get buffer space from the monitor
	 CALL SCADIE		;If we cannot init, die here pls...
	IMULI T2,C%MGPG		;(T2) = (Number of pages) * (buffers per page)
	ADDM T2,FQCNT		;Update buffer count
	ADDM T2,TOTMGB		;  and count of total buffers created
	MOVX T2,C%MGSZ		;Get the buffer size we desire
	CALL SC.BBF		;Turn it all into quanta sized pieces
	MOVEM T1,TOPFQ		;Set up the pointer to the top of the free q
	MOVEM T2,BOTFQ		;And the pointer to the bottom of the free q
   IFN SCADBG,<
	CALL SC.TMQ		;Trace the message free queue
>				;End of IFN SCADBG

	MOVE T1,MINDG		;Get the number of datagrams to have onhand
	CALL PGRSKD		;Get buffer space from the monitor
	 CALL SCADIE		;If we cannot init, die here pls...
	IMULI T2,C%DGPG		;(T2) = (Number of pages) * (buffers per page)
	ADDM T2,DFQCNT		;Update the buffer count
	ADDM T2,TOTDGB		;  and the count of datagram buffers created
	MOVX T2,C%DGSZ		;Get the buffer size we desire
	CALL SC.BBF		;Turn it all into quanta sized pieces
	MOVEM T1,TOPDFQ		;Set up the pointer to the top of the free q
	MOVEM T2,BOTDFQ		;And the pointer to the bottom of the free q
   IFN SCADBG,<
	CALL SC.TDQ		;Trace the datagram free queue
>				;End of IFN SCADBG

; Allocate the notification table
;
SSC.NN:	MOVEI T1,1		;We only wish one buffer
	CALL SC.ABF		;Get a single buffer
	 BUG. (HLT,SCANBL,SCAMPI,SOFT,<SCA - No buffer for online list>,,<

Cause:	SC.ABF was called to get a buffer for the address list to be used
	to call SYSAPs when a node comes online. Without this list no one will
	ever be told when a node comes online and hence we cannot run.
>)
	MOVEM T1,NOTTAB		;Save the address of the list
	ADDI T1,C%MGSZ		;Add the size of the table
	MOVEM T1,NOTEND		;  and save the end address of the table

; Here to init the various SYSAPs...
;
	MOVEI P5,C%SYTL		;Get the length of the SYSAP table
SSC.SI:	SKIPE INITAB(P5)	;Is there an entry for this index???
	CALL @INITAB(P5)	;Yes, call the SYSAP init routine pls...
	SOJGE P5,SSC.SI		;Loop for all SYSAPs pls...
	SETOM SCAINI		;Indicate completion of init code
	RET			;And return...

; Here when we find an unrecoverable error in SCA init.
;
SCADIE:	BUG. (HLT,SCACCI,SCAMPI,SOFT,<SCA - Cannot complete initialization>,,<

Cause:	During the init SCA detected an error it could not recover from. 
	SCADIE is called by the location and the stack points out the 
	faultly phase of init.
>)
	JRST SCADIE		;Just in case we try something silly, like
				;  continue...
	SUBTTL Calls from sysap -- SC.SOA (Set ONLINE address)

; This routine sets the online address. A SYSAP calls
;this routine to tell SCA what address to use, to notify the SYSAP of a node
;coming online.
;
;	Call
;	BLCAL. (SC.SOA,<SS.ADR>)
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	No data, address saved for SCA
;
SC.SOA::BLSUB. (<SS.ADR>)
	SAVEAC <Q1>

;Find a free slot in the table.

	MOVE T1,NOTTAB		;Get the address of the notice table
	MOVX T2,C%MGSZ-1	;Get its size
	MOVE T3,SS.ADR		;Get the user provided address
SSO.EL:	SKIPN (T1)		;Is there an entry here?
	JRST SSO.CO		;No.Go store this address
	AOS T1			;Yes. Try for the next entry.
	SOJGE T2,SSO.EL
	BUG. (CHK,SCANLF,SCAMPI,SOFT,<SCA - Notice table full>,,<

Cause:	So many SYSAPs have requested notification of nodes that come on
	and go off line that the table of notification addresses overflowed.
>)
	RETBAD (SCSNRT)		;Return error code

;Store the address. 

SSO.CO:	CIOFF			;DOn't let 2 callbacks happen for one online
	MOVEM T3,(T1)		;Store the address
	SETZM Q1		;Start with node zero

;If a system is already online, tell the sysap. If its system block
;exists, but its v.c. is closed, we will be notified when it is
;reopened.

SSO.LP:	SKIPN T2,SBLIST(Q1)	;Is there a system block
	JRST SSO.YY		;No.
	LOAD T3,SBVCST,(T2)	;Yes. is v.c. open?
	CAIE T3,VC.OPN
	JRST SSO.YY		;No. Don't call the sysap, then.
	MOVEI T1,.SSNCO		;Say why we are calling the SYSAP
	MOVE T2,Q1		;Get node number
	CALL @SS.ADR		;(T1,T2/) Give online notification
	 NOP
SSO.YY:	CAIGE Q1,C%SBLL-1	;Step to next node
	AOJA Q1,SSO.LP
	CION			;Finished with all nodes
	RETSKP
	ENDBS.
	SUBTTL Calls from sysap -- Connection management

; Functions performed within the realm of these routines:
; 1. Connect
; 2. Listen
; 3. Accept
; 4. Reject
; 5. Disconnect
;
; These routines may be called either by SYSAPs within the monitor or by the
;JSYS code 
;These routines implement the SCS connection management protocol. The
;following pictures describes the normal sequence.

COMMENT #

	NODE A				NODE B


call	state		message		state		call
----	-----		-------		-----		----

	closed				listen


SC.CON	conn_sent	conn_req
			------->

			conn_rsp M	conn_rec	.SSCTL
			<-------

	conn_ack


			accept_req	acc_sent	SC.ACC
			<---------

.SSCRA	open		accept_rsp M
			--------->

					open		.SSOSD



SC.DIS	disc_sent	disc_req
			------->

			disc_rsp	disc_rec	.SSRID
			<-------

	disc_ACK



			disc_req	disc_match	SC.DIS
			<-------

	closed *	disc_rsp
			------->

					closed *


* indicates ready to reap

#
	SUBTTL Calls from sysap -- Connection management -- SC.CON (Connect)

;     This routine allocates a connection block and requests a connection.
;
;Usage:
;	Call
;BLCAL. (SC.CON,<SS.SPN,SS.DPN,SS.NOD,SS.MSC,SS.MRC,SS.ADR,SS.SID,SS.DTA,SS.BFR,SS.DGB>)
;
; Where:
;	SS.SPN -- Address of source process name
;	SS.DPN -- Address of destination process name
;	SS.NOD -- System block index of destination system
;	SS.MSC -- Minimum send credit (Level to not allow return of credits)
;	SS.MRC -- Minimum receive credit (Point at which LCL callbacks start)
;	SS.ADR -- Address to call on condition changes for this connection
;	SS.SID -- Six bits of connect ID set by the SYSAP
;	SS.DTA -- Address of SYSAP connection data or zero
;	SS.BFR -- Number of buffers to queue for message reception
;	SS.DGB -- Number of datagram buffers to queue
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	T1/	Connect ID
;

SC.CON::BLSUB. (<SS.SPN,SS.DPN,SS.NOD,SS.MSC,SS.MRC,SS.ADR,SS.SID,SS.DTA,SS.BFR,SS.DGB>)
	SAVEP			;Save the preserved ACs

;Don't do this if the node has never been seen

	MOVE T1,SS.NOD		;Get the SBI 
	SKIPN P4,SBLIST(T1)	;Get the system block address
	RETBAD (SCSISB)		;Doesn't exist. Fail.

;Allocate a connection block and initialize with common data

	MOVE T1,SS.SID		;Get the SYSAP CID bits
	CALL SC.ACB		;Allocate and initialize a connection block
	 RETBAD ()		;Return with the error in T1

;See if the current state is correct (It should be in this case!), and
;get new connection and block states.

	MOVEI T1,EV.CON		;Event is connect call
	CALL SC.OUT		;(T1,P1/T1,T2)
	 BUG. (HLT,SCACFO,SCAMPI,SOFT,<SCA - SC.CON received failure from SC.OUT>,,<

Cause:	SC.CON created a new connection block and then called SC.OUT to
	check its state. The call should never fail.
>)
	DMOVEM T1,P2		;Save new states
	;..
;Store address for calling the sysap into the connection block

	;..
	MOVE T1,SS.ADR		;Get the addr to call SYSAP at
	MOVEM T1,.CBADR(P1)	;Store it in the connection block

; The minimum send credit is the lower boundary allowed for credit cancelation.
;I.E. never sink below this level when canceling credits for the remote.

	MOVE T1,SS.MSC		;Get the minimum send credit
	STOR T1,CBMNSC,(P1)	;Pack it away in the CB pls...

;Store source and destination process names and connection data

	MOVE T1,SS.SPN		;Get a pointer to the source process name
	MOVE T2,SS.DPN		;  and the destination name
	MOVE T3,SS.DTA		;  and a pointer to the connection data
	CALL SC.SDM		;Move the strings and data to the connect block

;Store in the connection block the number of buffers to be queued

	MOVE T1,SS.BFR		;Number of message buffers the user wants
	STOR T1,CBIMB,(P1)	;SC.SNM will look at this later
	MOVE T1,SS.DGB		;Number of datagram buffers the user wants
	STOR T1,CBIDB,(P1)

;Store connection state.

	SKIPE P3		;If we need to change it
	STOR P3,CBCNST,(P1)	;  Store connection state

;Lock the connection block before we link it to the system block. That way,
;if the node goes offline after we link it, processing will be deferred until
;we have finished changing the state.

	CALL SC.LOK		;(P1/) Lock the connection block

;Make the connection block point to the system block, and vice versa

	MOVE T1,SS.NOD		;Get the node number for dest system
	STOR T1,CBDNOD,(P1)	;Store in the CB
	MOVEM P4,.CBSBA(P1)	;Store it in the connection block
	CALL SC.LCB		;Link this connection block into list
	 JRST SCO.FL
	;..
;Record this event in the ring buffer if requested

	;..
   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-1(P6)		;Get caller to feature routine
	MOVE T3,P1		;Get CB address
	CALL RG.SSC		;(T1,T2,T3) Record SYSAP to SCA event
>				;End of IFN SCARNG

	LOAD P5,CBSCID,(P1)	;Get the connect ID while block is locked

;Send the request now, or queue it for later

	SKIPN T1,P2		;Get the new block state
	IFSKP.
	  CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  CALL SC.SNM		;(P4/) Send the message if possible
	ELSE.
	  CALL SC.ULK		;(P1/) Unlock the connection block
	ENDIF.

; Here to set up the returned arg, and return.

	MOVE T1,P5		;Return the connect ID
	RETSKP			;Return success

;V.C. is closed. Don't open the connection

SCO.FL:	MOVEM T1,P3		;Save error code
	CALL SC.ULK		;(P1/) Unlock the connection block (does OKSKED)
	CALL SC.RCB		;(P1/) Release the connection block
	MOVE T1,P3		;Recover error code
	RETBAD ()
	ENDBS.
	SUBTTL Calls from sysap -- Connection management -- SC.LIS (Listen)

; Here when we wish to listen for a connection, any connection.
;
; Usage:
;	Call
;	BLCAL. (SC.LIS,<SS.SPN,SS.DPN,SS.NOD,SS.ADR,SS.SID,SS.MSC,SS.MRC>)
;
; Where:
;	SS.SPN -- Address of source process name
;	SS.DPN -- Address of destination process name or 0
;	SS.NOD -- System block index or -1
;	SS.ADR -- Address to call on connection condition changes
;	SS.SID -- Six bits of Connect ID setable by the SYSAP
;	SS.MSC -- Minimum send credit 
;			(See SS.CON code comments for more detailed info)
;	SS.MRC -- Minimum receive credit (Ditto)
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	T1/	Connect ID
;
; Where a zero in SS.DPN and -1 in SS.NOD indicates a connect from anyone is
;acceptable. A byte pointer and a system block index indicate a
;listen for a particular node.
;
SC.LIS::BLSUB. (<SS.SPN,SS.DPN,SS.NOD,SS.ADR,SS.SID,SS.MSC,SS.MRC>)
	SAVEP			;Save the preserved ACs

	AOS LISTEN		;Count the call to LISTEN

;Don't do this if the node has never been seen

	MOVE T1,SS.NOD		;Get the SBI 
	SKIPN P4,SBLIST(T1)	;Get the system block address
	RETBAD (SCSISB)		;Doesn't exist. Fail.

;Allocate a connection block and initialize with common data

	MOVE T1,SS.SID		;Get the SYSAP CID bits
	CALL SC.ACB		;Allocate and initialize a connection block
	 RETBAD ()		;Return with the error in T1
	;..
;See if the current state is correct (It should be in this case!), and
;get new connection and block states.

	;..
	MOVEI T1,EV.LIS		;Event is listen call
	CALL SC.OUT		;(T1,P1/T1,T2)
	 BUG. (HLT,SCALFO,SCAMPI,SOFT,<SCA - SC.LIS received failure from SC.OUT>,,<

Cause:	SC.LIS created a new connection block and then called SC.OUT to
	check its state. The call should never fail.
>)
	DMOVEM T1,P2		;Save new states

;Store address for calling the sysap into the connection block

	MOVE T1,SS.ADR		;Get the addr to call SYSAP at
	MOVEM T1,.CBADR(P1)	;Store it in the connection block

; The minimum send credit is the lower boundary allowed for credit cancelation.
;I.E. never sink below this level when canceling credits for the remote.

	MOVE T1,SS.MSC		;Get the minimum send credit
	STOR T1,CBMNSC,(P1)	;Pack it away in the CB pls...

; Move the source and destination process names. There is no connection
;data allowed on a LISTEN.

	MOVE T1,SS.SPN		;Get address of source process name
	MOVE T2,SS.DPN		;Get address of destination process name
	SETZ T3,		;There is no connect data
	CALL SC.SDM		;Move the process names please

;Store the connection state

	SKIPE P3
	STOR P3,CBCNST,(P1)	;Store new connection state

;Lock the connection block before we link it to the system block. That way,
;if the node goes offline after we link it, processing will be deferred until
;we have finished changing the state.

	CALL SC.LOK		;(P1/) Lock the connection block

;Make the connection block point to the system block, and vice versa

	MOVE T1,SS.NOD		;Get the node number for dest system
	STOR T1,CBDNOD,(P1)	;Store in the CB
	MOVEM P4,.CBSBA(P1)	;Store it in the connection block
	CALL SC.LCB		;Link this connection block into list
	 JRST SLI.FL		;Failed. Return error

;This connection is now ready to accept a connect_request.
;Record this event in the ring buffer.

   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-1(P6)		;Get caller to feature routine
	MOVE T3,P1		;Get CB address
	CALL RG.SSC		;(T1,T2,T3) Record SYSAP to SCA event
>				;End of IFN SCARNG
	LOAD P5,CBSCID,(P1)	;Get connect ID while block is locked
	;..
; Set the new block state. For now, this routine never
;sends a request. The code is identical to the other routines to allow for
;possible changes in the future.

	;..
	JUMPL P4,SCL.CO		;If don't care listener, don't do this
	SKIPN T1,P2		;Get the new block state
	IFSKP.
	  CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  CALL SC.SNM		;(P4/) Send the message if possible
	ELSE.
SCL.CO:	  CALL SC.ULK		;(P1/) Unlock the connection block
	ENDIF.

;Return success, providing connect ID

	MOVE T1,P5		;Get connect ID saved earlier
	RETSKP			;Tell the caller we made out OK

SLI.FL:	MOVEM T1,P3		;Save error code
	CALL SC.ULK		;(P1/) Unlock the connection block (does OKSKED)
	CALL SC.RCB		;(P1/) Release the connection block
	MOVE T1,P3		;Recover error code
	RETBAD ()

	ENDBS.
	SUBTTL Calls from sysap -- Connection management -- SC.ACC (Accept)

; Here when we are accepting a request from the outside for a connection.
;I.E. Allow a connect...
;
; Usage:
;	Call
;	BLCAL.	(SC.ACC,<SS.CID,SS.DTA,SS.BFR,SS.DGB>)
;
; Where:
;	SS.CID -- Connect ID
;	SS.DTA -- Address of initial connection data or zero
;	SS.BFR -- Number of buffers to be queued for message reception
;	SS.DGB -- Number of buffers to queue for datagram reception
;
;	Return (+1)
;	T1/	Failure code
;
;	Return (+2)
;	T1/	Address of initial connect data
;
SC.ACC::BLSUB. (<SS.CID,SS.DTA,SS.BFR,SS.DGB>)
	SAVEP			;Save the preserved ACs

	MOVE T1,SS.CID		;Get connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD()		;Return failure

   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-1(P6)		;Get caller to feature routine
	MOVE T3,P1		;Get CB address
	CALL RG.SSC		;(T1,T2,T3) Record SYSAP to SCA event
>				;End of IFN SCARNG

;See if the current state is correct, and get new connection and block states.

	MOVEI T1,EV.ACC		;Event is accept call
	CALL SC.OUT		;(T1,P1/T1,T2)
	 RETBAD (,<CALL SC.ULK>) ;Illegal. Return failure
	DMOVEM T1,P2		;Save new states

;Store in the connection block the optional data to be sent to the
;other end.

	SKIPN T2,SS.DTA		;Is there any data to move???
	JRST SCA.OK		;No. Continue
	MOVEI T1,C%DTLW		;Yes, get its length in words
	XMOVEI T3,.CBDTA(P1)	;Destination addr in CB for connect data
	XBLT. T1		;Copy the data
	;..
;Store in the connection block the number of buffers to be queued

	;..
SCA.OK:	MOVE T1,SS.BFR		;Number of message buffers the user wants
	STOR T1,CBIMB,(P1)	;SC.SNM will look at this later
	MOVE T1,SS.DGB		;Number of datagram buffers the user wants
	STOR T1,CBIDB,(P1)

; Set the new connection and block states

	SKIPE P3
	STOR P3,CBCNST,(P1)	;Store new connection state
	SKIPN T1,P2		;Get new block state
	IFSKP.
	  MOVE P4,.CBSBA(P1)	;Get the address of the system block
	  CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  CALL SC.SNM		;(P4/) Send the message if possible
	ELSE.
	  CALL SC.ULK		;(P1/) Unlock the connection block
	ENDIF.
	RETSKP

	ENDBS.
	SUBTTL Calls from sysap -- Connection management -- SC.REJ (Reject)

; Here to reject a connect request.
;
; Usage:
;	Call
;	BLCAL. (SC.REJ,<SS.CID>,<SS.RJR>)
;
; Where:
;	SS.CID -- Connect ID
;	SS.RJR -- Reject reason code
;
;	Return (+1)
;	T1/	Failure code
;
;	Return (+2)
;	No data is returned by this routine
;
SC.REJ::BLSUB. (<SS.CID,SS.RJR>)
	SAVEAC <P1,P2,P4>

	MOVE T1,SS.CID		;Get connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD()		;Return failure

   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-1(P6)		;Get caller to feature routine
	MOVE T3,P1		;Get CB address
	CALL RG.SSC		;(T1,T2,T3) Record SYSAP to SCA event
>				;End of IFN SCARNG

;See if the current state is correct, and get new connection and block states.

	MOVEI T1,EV.REJ		;Event is reject call
	CALL SC.OUT		;(T1,P1/T1,T2)
	 RETBAD (,<CALL SC.ULK>) ;Illegal. Return failure

	MOVE T3,SS.RJR		;Obtain the disconnect reason
	STOR T3,CBSDRE,(P1)	;Place reject reason into CB

;Store connection and block states and send message, if any

	SKIPE T2
	STOR T2,CBCNST,(P1)	;Store connection state
	SKIPN T1
	IFSKP.
	  MOVE P4,.CBSBA(P1)	;Get the address of the system block
	  CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  CALL SC.SNM		;(P4/) Send the message if possible
	ELSE.
	  CALL SC.ULK		;(P1/) Unlock the connection block
	ENDIF.
	RETSKP			;All done, return.

	ENDBS.
	SUBTTL Calls from sysap -- Connection management -- SC.DIS (Disconnect)

; Here to close a connection.
;
; Usage:
;	Call
;	BLCAL.	(SC.DIS,<SS.CID,SS.DIR>)
;
; Where:
;	SS.CID -- Connect ID
;	SS.DIR -- Disconnect reason
;
;	Return (+1)
;	T1/	Failure code
;
;	Return (+2)
;	No data is returned by this routine
;

;This routine may be called in any context. If at interrupt level, it
;honors the connection block lock after verifying that the current
;state allows disconnection, and saving the reason code. If at non-
;interrupt level, it uses CIOFF while changing the state. This locks
;out interruption from SC.DRQ, SC.ARQ, SC.ARS, SC.ORQ.

SC.DIS::BLSUB.	(<SS.CID,SS.DIR>)
	SAVEP

	CIOFF			;Don't let state change
	MOVE T1,SS.CID		;Get connect ID
	CALL SC.CSC		;(T1/T1,P1) Check validity
	 RETBAD(,<CION>)	;Return failure

   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-1(P6)		;Get caller to feature routine
	MOVE T3,P1		;Get CB address
	CALL RG.SSC		;(T1,T2,T3) Record SYSAP to SCA event
>				;End of IFN SCARNG

;See if the current state is correct, and get new connection and block states.

	MOVEI T1,EV.DIS		;Event is disconnect call
	CALL SC.OUT		;(T1,P1/T1,T2)
	 RETBAD (,<CION>)	;Illegal. Return failure
	DMOVEM T1,P2		;Save new states

;Copy caller's reason into the connection block

	MOVE T3,SS.DIR		;Get the disconnect reason
	STOR T3,CBSDRE,(P1)	;Store it in the connect block
	;..
;We've done all we can if someone has the c.b. locked. So check that,
;and quit if it's true. (We must be at interrupt level, then.) Otherwise,
;lock it and continue. If we can't continue, the unlock routine will
;complete this function.

	;..
	MOVX T1,CBFDIS		;Set this bit if we have to wait
	CALL SC.HNR		;(T1,P1/) See if lock is locked
	IFNSK.
	  CION			;We're at interrupt level, and
	  RETSKP		; someone beat us to it.
	ENDIF.

;We got the lock.
;If old state was "listen", indicate protocol is complete.

	LOAD T3,CBCNST,(P1)	;Get old state
	CAIE T3,.CSLIS		;Listening?
	IFSKP.
	  MOVEI T3,.CSCLO	;Force its state to "closed"
	  STOR T3,CBCNST,(P1)
	  CALL SC.PTC		;(P1/) declare protocol complete
	  CION
	  RETSKP		;Finished. Return success
	ENDIF.

;Store connection and block states and send message, if any

	SKIPE P3
	STOR P3,CBCNST,(P1)	;Store new connection state
	SKIPN T1,P2		;Get new block state
	IFSKP.
	  MOVE P4,.CBSBA(P1)	;Get the address of the system block
	  CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	  CION			;Changes in state are OK now
	  CALL SC.SNM		;(P4/) Send the message if possible
	ELSE.
	  CION			;Allow changes in state now
	ENDIF.
	RETSKP			;Return all OK
	ENDBS.
;SC.FN2 - Finish function of SC.DIS when unlocking a c.b.

;Accepts:
;	P1/ address of c.b.
;	P4/ address of system block

;	CALL SC.FN2

;Returns +1: always

;This is called when the owner of a c.b. is about to unlock it.
;The c.b. is still locked, and we return with it in that condition.
;Since it is locked, we don't call SC.SNM, but set a bit so that the
;unlocker will do so.

SC.FN2:
	SETZRO CBFDIS,(P1)	;Clear indication that this was deferred

;If old state was "listen", indicate protocol is complete

	LOAD T3,CBCNST,(P1)	;Get old state
	CAIE T3,.CSLIS		;Listening?
	IFSKP.
	  MOVEI T3,.CSCLO	;Force its state to "closed"
	  STOR T3,CBCNST,(P1)
	  CALL SC.PTC		;(P1/) declare protocol complete
	  SETONE CBFRAP,(P1)	;Mark as reapable (in case JSYS connection)
	  SETONE CIREP		;TELL CIFORK TO RUN
	  RET			;Nothing more to do
	ENDIF.

;Connection state may have changed since SC.DIS was first called. Make
;sure a disconnect is still legal, and get new states.

	MOVEI T1,EV.DIS		;Event is disconnect call
	CALL SC.OUT		;(T1,P1/T1,T2) Get new states
	 BUG. (HLT,SCAFN2,SCAMPI,SOFT,<SCA - Can't complete deferred call to SC.DIS>,,<

Cause:	A sysap called SCAMPI at SC.DIS when the connection block was locked.
	The connection block is being unlocked, and the	request is being 
	processed. SC.OUT has returned failure, indicating that this
	function can't be performed for the current state. There is no way
	to return that failure to the sysap, which believes that the
	disconnect has proceeded normally. The system will crash to determine 
	the cause.

Action:	It may be impossible to analyze this from the current data.
	If the ring buffer was enabled, try to determine the sequence of
	events. Look at the current state of the connection block, and try
	to see why SC.OUT failed.

>)

;Store connection and block states. If new block state is non-zero,
;we want to send a disconnect_request. Queue the block, and flag the
;unlock code to call SC.SNM

	SKIPE T2		;Zero means no change
	STOR T2,CBCNST,(P1)	;Store new connection state
	IFN. T1			;Get new block state
	  CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	  SETONE CBFSNM,(P1)	;Indicate call to SC.SNM was deferred
	ENDIF.
	RET
	SUBTTL Calls from sysap -- Messages and datagrams

	SUBTTL Calls from sysap -- Messages and datagrams -- SC.SDG (Send a datagram)

; Usage:
;	Call
;	BLCAL.	(SC.SDG,<SS.CID,SS.FLG,SS.LDG,SS.ADG>)
;
; Where:
;	SS.CID -- Connect ID
;	SS.FLG -- Flag word (See SCAPAR.MAC)
;	SS.LDG -- Len of datagram (in bytes)
;	SS.ADG -- Address of datagram buffer
;	SS.PRI -- Priority for packet send
;	SS.PTH -- Path to send the packet on
;			0 -- Auto path select
;			1 -- Use path A
;			2 -- Use path B
;
;	Return (+1)
;	T1/	Failure code
;
;	Return (+2)
;	No data is returned by this routine,datagram sent
;
; ** Note **
;	The address of the datagram buffer points to the bottom of the
;header area. The offset to where user data begins is (.MHUDA) 
;
SC.SDG::BLSUB.	(<SS.CID,SS.FLG,SS.LDG,SS.ADG,SS.PRI,SS.PTH>)
	SAVEAC <P1,P2,P3,P4>

;Validate the arguments and check the state of the connection.

	MOVE T1,SS.CID		;Get connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD ()		;Return failure
	LOAD T1,CBCNST,(P1)	;Get the connection state
	CAIE T1,.CSOPN		;Is the connection open?
	RETBAD (SCSCWS,<CALL SC.ULK>) ;No. Return failure

	;..
;Check the length, and add SCA overhead

	;..
	MOVE T1,SS.LDG		;Get the length of the datagram
	MOVX T2,F.SPM		;Get the mode flag bit
	TDNE T2,SS.FLG		;Are we doing high density mode???
	IFNSK.
	  ADDI T1,C%OVHW	;Yes, add overhead in words, not bytes
	  CAILE T1,C%WORD	;Is datagram longer than we should be sending??
	  RETBAD (SCAPTL,<CALL SC.ULK>) ;Yes, complain
	ELSE.
	  ADDI T1,C%OVHD	;No, add overhead size in bytes
	  CAILE T1,C%BYTD	;Is the datagram larger than I can send???
	  RETBAD (SCAPTL,<CALL SC.ULK>) ;Message is too long. Fail
	ENDIF.
	MOVEM T1,SS.LDG		;Store for later port call

;Add the SCA header to the packet we have been passed.

	MOVE P2,SS.ADG		;Get address of packet
	SETZRO MH$CDT,(P2)	;Zero the credit field
	MOVEI P3,.STADG		;Get the packet type (Application datagram)
	STOR P3,MH$MSG,(P2)	;Place the packet type in the datagram header
	LOAD T2,CBDCID,(P1)	;Get the destination connect ID
	STOR T2,MH$DCI,(P2)	;Put it in the message header
	LOAD T2,CBSCID,(P1)	;Get the source connect ID now
	STOR T2,MH$SCI,(P2)	;This also goes into the message header

;If sysap wants the buffer back, count this among its queued buffers.

	MOVX T1,F.RTB		;Packet return status flag
	TDNN T1,SS.FLG		;Is sysap getting this packet back?
	IFSKP.
	  INCR CBNPO,(P1)	;Yes, increment count of outstanding packets
	ELSE.
	  AOS .CBDGR(P1)	;No. Count this as queued for incoming datagram
	ENDIF.

;Record the sending of a packet in the ring buffer

	MOVE P4,.CBSBA(P1)	;Get a pointer to the system block 
   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-1(P6)		;Get caller to feature routine
	MOVE T3,SS.FLG		;Get flags
	HRLZ T4,SS.PRI		;Position priority correctly
	HRR T4,SS.LDG		; and get packet length
	CALL RG.PKT		;(T1,T2,T3,T4,P2,P4) Record packet transmission
>				;End of IFN SCARNG
	;..
;Pass the buffer off to the port driver, which will send it to the node

	;..
	CALL SC.ROU		;Byte swap the header for output
	BLCAL. (SNDDG,<SS.LDG,SS.FLG,P4,P2,SS.PRI>)
	 JRST SSD.ER		;Handle the error
	AOS SNDTAB(P3)		;Increment send count for this type of packet
	CALL SC.ULK		;(P1/) Unlock the connection block
	RETSKP			;Return OK.

; Here on an error. Undo the counting that we did, and return failure.
;If we had counted up this buffer as being on the free queue, put one
;there. It's possible that we've already dequeued one while the count was
;incremented, so we can't just decrement it.

SSD.ER:	MOVX T2,F.RTB		;The packet return status flag again
	TDNN T2,SS.FLG		;Did we bump the pending packet count?
	IFSKP.
   IFN SCADBG,<
	  LOAD T2,CBNPO,(P1)	;Get outstanding packet count
	  SKIPG T2		;Is it greater than zero?
	  BUG. (HLT,SCANP1,SCAMPI,SOFT,<SCA - CBNPO about to go negative>,,<

Cause:	The count is already zero or less when the count of queued buffers 
	for a connection block is to be decremented. 
>)
   >				;END OF IFN SCADBG
	  DECR CBNPO,(P1)	;Yes, packet send failed, fix count
	ELSE.
	  MOVEI T1,1		;No. We counted this as queued for input
	  CALL SC.ALD		;(T1/T1,T2,T3) Get a buffer from SCA
	   JRST SSD.EX		;Couldn't get one
   IFN SCARNG,<
	  BLOCK.
	    SAVEAC <T1>		;Save smashed AC
	    MOVE T4,T1		;Get buffer address
	    XMOVEI T1,.		;Get feature routine address
	    MOVE T2,-1(P6)	;Get PC of caller to feature routine
	    MOVEI T3,1		;Set buffer count
	    TXO T3,RPQFLK   	;Set port link flag
	    TXZ T3,RPQFMG   	;Clear message free queue flag since datagram
	    CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	  ENDBK.
>				;End of IFN SCARNG
	  BLCAL. (LNKDFQ,<P4,T1>) ;Link buffer chain onto Datagram Free queue
	ENDIF.
SSD.EX:	CALL SC.ULK		;(P1/) Unlock the connection block
	RETBAD ()		;Return with error code in T1
	ENDBS.
	SUBTTL Calls from sysap -- Messages and datagrams -- SC.SMG (Send a message)

; Here to send a sequenced data message.
;
; Usage:
;	Call
;	BLCAL.	(SC.SMG,<SS.CID,SS.FLG,SS.LMG,SS.AMG,SS.PRI,SS.TSH,SS.PTH>)
;
; Where:
;	SS.CID -- Connect ID
;	SS.FLG -- Flag word (See SCAPAR.MAC)
;	SS.LMG -- Length of message in bytes
;	SS.AMG -- Address of message buffer
;	SS.PRI -- Priority to give message
;	SS.TSH -- Allow send only if more than this many send credits exist
;	SS.PTH -- Path to send packet on
;			0 -- Auto path select
;			1 -- Use path A
;			2 -- Use path B
;
;	Return (+1)
;	T1/	Failure code
;
;	Return (+2)
;	No data returned
;
SC.SMG::BLSUB.	(<SS.CID,SS.FLG,SS.LMG,SS.AMG,SS.PRI,SS.TSH,SS.PTH>)
	SAVEP			;Save the quasi preserved ACs

;Validate the arguments and check the state of the connection.

	MOVE T1,SS.CID		;Get connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD ()		;Return failure
	LOAD T1,CBCNST,(P1)	;Get the connection state
	CAIE T1,.CSOPN		;Is the connection open?
	RETBAD (SCSCWS,<CALL SC.ULK>) ;No. Return failure

	;..
;Check the length, and add SCA overhead

	;..
	MOVE T1,SS.LMG		;Get the length of the message
	MOVX T2,F.SPM		;Get the mode flag bit
	TDNE T2,SS.FLG		;Are we doing high density mode???
	IFNSK.
	  ADDI T1,C%OVHW	;Yes, add overhead in words, not bytes
	  CAILE T1,C%WORM	;Is message longer than we should be sending???
	  RETBAD (SCAPTL,<CALL SC.ULK>) ;Yes, complain
	ELSE.
	  ADDI T1,C%OVHD	;No, add overhead size in bytes
	  CAILE T1,C%BYTM	;Is the message larger than I can send???
	  RETBAD (SCAPTL,<CALL SC.ULK>) ;Message is to long, fail the send attempt
	 ENDIF.
	MOVEM T1,SS.LMG		;Store for later port call

;Don't send if we don't have enough send credit. We must have more than the
;threshold provided by the caller.

	SOS T1,.CBSCD(P1)	;Decrement send credit
	CAML T1,SS.TSH		;Do we have more than the threshold?
	IFSKP.
	  AOS .CBSCD(P1)	;No. Put it back where we found it, then
	  SETONE CBFNNC,(P1)	;Set the flag to notify on credit gain
	  RETBAD (SCSNEC,<CALL SC.ULK>) ;Return to caller with error code
	ENDIF.

;If pending receive credit is positive, we need to tell the other side
;that it can have more credit, so put that value into the packet.
;And because it's no longer pending, add it into receive credit.
;If the sysap doesn't want the buffer back, that's one more receive credit.
;If we increment pending receive credit, and it was negative, count
;this as a successful cancel.

	CIOFF			;Turn off interrupts for the moment
	MOVX T1,F.RTB		;Get the response bit
	TDNE T1,SS.FLG		;Does sysap want this buffer back?
	IFSKP.
	  AOS T2,.CBPRC(P1)	;No. Increment pending receive credit
	  SKIPG T2		;Had we been waiting to cancel some?
	  AOS .CBRTC(P1)	;Yes. Count this as return credit.
	ENDIF.
	SKIPG T2,.CBPRC(P1)	;Is pending receive credit now positive?
	IFSKP.
	  ADDM T2,.CBRCD(P1)	;Yes. Add this into receive credit
	  SETZM .CBPRC(P1)	;It's no longer pending
	ELSE.
	  SETZM T2		;Negative. No credit in the packet
	ENDIF.
	CION			;Turn CI interrupts on again
	;..
;Add the SCA header to the packet we have been passed.

	;..
	MOVE P2,SS.AMG		;Get address of packet
	STOR T2,MH$CDT,(P2)	;Store the credit field into the header
	MOVEI P3,.STAMG		;Get the message type
	STOR P3,MH$MSG,(P2)	;Put the message type into the message header
	LOAD T2,CBDCID,(P1)	;Get the detination connect ID
	STOR T2,MH$DCI,(P2)	;Put it up in the message header
	LOAD T2,CBSCID,(P1)	;Get the source connect ID now
	STOR T2,MH$SCI,(P2)	;This also goes into the message header

;If sysap wants the buffer back, count this among its queued buffers.

	MOVX T1,F.RTB		;Get the buffer return status flag
	TDNN T1,SS.FLG		;Does sysap get this buffer back?
	IFSKP.
	  INCR CBNPO,(P1)	;Yes, bump count of outstanding packets
	ENDIF.

;Record the sending of a packet

	MOVE P4,.CBSBA(P1)	;Get the address of the system block
   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-1(P6)		;Get caller to feature routine
	MOVE T3,SS.FLG		;Get flags
	HRLZ T4,SS.PRI		;Position priority correctly
	HRR T4,SS.LMG		; and get packet length
	CALL RG.PKT		;(T1,T2,T3,T4,P2,P4) Record packet transmission
>				;End of IFN SCARNG

;Pass the buffer off to the port driver, which will send it to the node

	CALL SC.ROU		;Revert certain words in outgoing message
	BLCAL. (SNDMSG,<SS.LMG,SS.FLG,P4,P2,SS.PRI>) ;Call the port driver
	 JRST SSM.ER		;Handle the error
	AOS SNDTAB(P3)		;Bump the sent message count

;We may have incremented return_credit. If so, reclaim a buffer.

	CALL SC.GCB		;(P1,P4/)Get a canceled buffer, if any
	CALL SC.ULK		;(P1/) Unlock the connection block
	RETSKP			;All ok.
; Here on an error from the port driver.
;If we had incremented credit because of this buffer, we may have
;taken the buffer off the port's free queue by now. We can't just decrement
;the count, so we give the port a buffer.

SSM.ER:
	AOS .CBSCD(P1)		;We didn't use the send credit after all
	CIOFF			;Interlock credit database
	LOAD T2,MH$CDT,(P2)	;Get the credit field back from the packet
	ADDM T2,.CBPRC(P1)	;Turn it back into pending credit
	MOVNS T2		;Get negative count
	ADDM T2,.CBRCD(P1)	;Update the credit count in the CB
	CION			;Release the interlock
	MOVX T2,F.RTB		;Packet return status flag
	TDNN T2,SS.FLG		;Did we bump the pending packet count
	IFSKP.
   IFN SCADBG,<
	  LOAD T2,CBNPO,(P1)	;Get outstanding packet count
	  SKIPG T2		;Is it greater than zero?
	  BUG. (HLT,SCANP2,SCAMPI,SOFT,<SCA - CBNPO about to go negative>,,<

Cause:	We are about to decrement the count of queued buffers for a
	particular connection block, but the count is already zero or less.
>)
   >				;END OF IFN SCADBG
	  DECR CBNPO,(P1)	;Yes, packet didn't go, correct count
	ELSE.
	  MOVEI T1,1		;No. We counted this as queued for input
	  CALL SC.ABF		;(T1/T1,T2,T3) Get a buffer from SCA
	   JRST SSM.EX
   IFN SCARNG,<
	  BLOCK.
	    SAVEAC <T1>		;Saved smashed AC
	    MOVE T4,T1		;Get buffer address
	    XMOVEI T1,.		;Get feature routine address
	    MOVE T2,-1(P6)	;Get PC of caller to feature routine
	    MOVEI T3,1 		;Get buffer count
	    TXO T3,RPQFLK	;Set port link flag
	    TXO T3,RPQFMG	;Set message free queue flag
	    CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	  ENDBK.
>				;End of IFN SCARNG
	  BLCAL. (LNKMFQ,<P4,T1>) ;Link buffer onto message free queue
	ENDIF.
SSM.EX:	CALL SC.ULK		;(P1/) Unlock the connection block
	RETBAD ()		;Return with PPD error code
	ENDBS.
	SUBTTL Calls from sysap -- Messages and datagrams -- SC.RDG (Receive a datagram)

; This routine queues buffers for reception of datagrams.
;
; Usage:
;	Call
;	BLCAL.	(SC.RDG,<SS.CID,SS.NUM,SS.ADR>)
;
; Where:
;	SS.CID -- Connect ID
;
;	If SS.ADR is zero then:
;	SS.NUM -- Number of buffers to queue
;
;	If SS.ADR is non-zero, then:
;	SS.NUM is ignored, and
;	SS.ADR -- Address of the buffer to queue. Note that this
;		buffer must be a buffer procured from SCA. This means it has
;		been used as a datagram buffer before. This is handy for those
;		time you are done with an SCA datagram buffer and wish to
;		requeue it. It eliminated the need for two calls to SCA...
;
;	Return (+1)
;	T1/	Number of buffers actually queued
;
;	Return (+2)
;	Buffer(s) have been queued to receive datagrams.
;

;NOTE: SC.RDG and SC.RMG are almost identical. If you need to change one,
;you'll probably need to change the other.

SC.RDG::BLSUB.	(<SS.CID,SS.NUM,SS.ADR>)
	SAVEAC <P1,P4>
	MOVE T1,SS.CID		;Get user's connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD ()		;No. return failure
	MOVE P4,.CBSBA(P1)	;Get the address of the system block
	SKIPN T1,SS.ADR		;Did user provide address of buffer?
	IFSKP.
	  SETZM (T1)		;Yes. Clear its FLINK
	  MOVEI T2,1		;Number of buffers is 1
	ELSE.
	  MOVE T1,SS.NUM	;Get number of buffers desired
	  CALL SC.ALD		;(T1/T1,T2,T3) Create the buffers
	   RETBAD (,<CALL SC.ULK>) ;Can't get them. Return failure
	ENDIF.
	CALL SCL.DC		;(T1,T2,P1,P4/) Queue the buffers to the port
	CALL SC.ULK		;(P1/) Unlock the connection block
	RETSKP			;And return all OK
	ENDBS.
	SUBTTL Calls from sysap -- Messages and datagrams -- SC.RMG (Receive a message)

; Here to queue a buffer to receive a sequenced message.
;
; Usage:
;	Call
;	BLCAL.	(SC.RMG,<SS.CID,SS.NRB,SS.ADR>)
;
; Where:
;	SS.CID -- Connect ID
;
;	SS.NUM -- If SS.ADR is zero then this is the number of buffers 
;			to be queued for message reception.
;		  If SS.ADR is non-zero, then this is the number of buffers
;			in the chain pointed to by SS.ADR.
;
;	SS.ADR -- Address of message buffer (Optional)
;		  If SS.ADR is zero then a buffer is taken from the SCA
;		message buffer free queue. If it is non-zero, then it
;		is assumed that no problems will arise if the buffer
;		is returned to the SCA pool. Since it may end up in
;		the SCA pool it must be the length of all other buffers
;		in the pool, must have come from the general free
;		pool,and must be resident.
;
;	Return (+1)
;	T1/	Failure code
;
;	Return (+2)
;	Buffer has been queued.
;

;NOTE: SC.RDG and SC.RMG are almost identical. If you need to change one,
;you'll probably need to change the other.

SC.RMG::BLSUB.	(<SS.CID,SS.NUM,SS.ADR>)
	SAVEAC <P1,P3,P4>
	MOVE T1,SS.CID		;Get user's connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD ()		;No. return failure
	MOVE P4,.CBSBA(P1)	;Get the address of the system block
	SKIPN T1,SS.ADR		;Did user provide address of buffer?
	IFSKP.
	  SETZM (T1)		;Yes. Clear its FLINK
	  MOVEI T2,1		;Number of buffers is 1
	ELSE.
	  MOVE T1,SS.NUM	;Get number of buffers desired
	  CALL SC.ABF		;(T1/T1,T2,T3) Create the buffers
	   RETBAD (,<CALL SC.ULK>) ;Can't get them. Return failure
	ENDIF.
	;..
	;..

;If we had been waiting to cancel some buffers, increment return
;credit for as many buffers as possible

	MOVE P3,T2		;Save buffer count
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Saved smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-1(P6)	;Get PC of caller to feature routine
	  MOVE T3,P3		;Get buffer count
	  TXO T3,RPQFLK		;Set port link flag
	  TXO T3,RPQFMG		;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	BLCAL. (LNKMFQ,<P4,T1>)	;Link buffer chain onto Message Free queue
	CIOFF
	MOVE T2,.CBPRC(P1)	;Save current pending receive count
	ADDM P3,.CBPRC(P1)	;Update to include new buffers
	JUMPGE T2,SCR.EX	;If always positive, nothing more to do
	SKIPLE .CBPRC(P1)	;Previously negative. Is it still?
	IFSKP.
	  ADDM P3,.CBRTC(P1)	;Yes. Reclaim all the buffers, then
	ELSE.
	  MOVMS T2		;No. Take only the number we wanted
	  ADDM T2,.CBRTC(P1)
	ENDIF.

;We may want to send a credit_request. SC.CDT will queue the connection
;block to the system block work queue if we need to send the request.
;If so, we must call SC.SNM to do the sending after we unlock the
;connection block.

SCR.EX:	CION
	CALL SC.GCB		;(P1,P4/) Get canceled buffer, if any
	SETOM P3		;Assume we'll need to send something
	CALL SC.CDT		;(P1,P4/) Queue credit request if needed
	 SETZM P3		;Don't need to send a message
	CALL SC.ULK		;(P1/) Unlock the connection block
	SKIPE P3		;Need to send the request?
	CALL SC.SNM		;(P4/) Yes. Send next message
	RETSKP			;And return all OK
	ENDBS.
	SUBTTL Calls from sysap -- Messages and datagrams -- SC.CRD (Cancel Receive datagram)

; Here to dequeue a datagram buffer.
;
; Usage:
;	Call
;	BLCAL.	(SC.CRD,<SS.CID,SS.NBF>)
;
; Where:
;	SS.CID -- Connect ID
;	SS.NUM -- Number of buffers to dequeue
;
;	Return (+1)
;	T1/	Failure code
;
;	Return (+2)
;	No data returned, buffers dequeued.
;
SC.CRD::BLSUB.	(<SS.CID,SS.NUM>)
	SAVEAC <P1,P4>
	MOVE T1,SS.CID		;Get user's connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD ()		;No. return failure
	SKIPE T1,SS.NUM		;Get the number of buffers desired
	IFSKP.
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  RETSKP		;Nothing to do (but why?)
	ENDIF.
	MOVE P4,.CBSBA(P1)	;Get the system block address
SCR.BL:	SOSL .CBDGR(P1)		;Reduce number of queued buffers
	IFSKP.
	  AOS .CBDGR(P1)	;Didn't have that many. Restore count
	  RETBAD (SCSNEB,<CALL SC.ULK>) ;Return failure
	ENDIF.
	BLCAL. (ULNKDG,<P4>)	;(/T1) Unlink a datagram buffer
	IFNSK.
	  EXCH T1,P4		;Save error code, get system block address
	  LOAD T1,SBDPA,(T1)	;Get node number
	  LOAD T2,CBSCID,(P1)	;Get connect ID
	  MOVE T3,SS.NUM	;Number we still need
	  BUG. (CHK,SCACCD,SCAMPI,SOFT,<SCA - Can't cancel datagram buffer>,<<T1,NODE>,<T2,CID>,<T3,COUNT>>,<

Cause:	A sysap has done the "cancel receive datagram" function of SCA, and
	the port's queue did not contain as many buffers as the system believes
	it should contain.

Data:	NODE  - Node number
	CID   - Connect ID
	COUNT - Number of buffers we couldn't get
>)
	  AOS .CBDGR(P1)	;Shouldn't have decremented count in this case
   IFN SCARNG,<
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-1(P6)	;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  SETOM T4		;Set buffer address to -1 due to failure
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXZ T3,RPQFMG   	;Clear message free queue flag since datagram
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>	         		;End of IFN SCARNG
	  MOVE T1,P4		;Restore error code
	  RETBAD (,<CALL SC.ULK>) ;Return PPD failure with error code
	ENDIF.
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Save smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-1(P6)	;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXZ T3,RPQFMG   	;Clear message free queue flag since datagram
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	CALL SC.RLD		;(T1/) Return the buffer to the SCA pool
	SOSLE SS.NUM		;Decrement count to dequeue
	JRST SCR.BL		;More to do, loop to dequeue
	CALL SC.ULK		;(P1/) Unlock the connection block
	RETSKP			;All done, return happy
	ENDBS.
	SUBTTL Calls from sysap -- Messages and datagrams -- SC.CRM (Cancel receive message)

; This routine allows a SYSAP to cancel a buffer or set of buffers that were
;queued for message reception for a particular connection.
;
; Usage:
;	BLCAL. (SC.CRM,<SS.CID,SS.NUM>)
;
;	Where:
;	SS.CID - The connection ID 
;	SS.NUM - The number of buffers to dequeue
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	Operation is legal. Buffers have been returned to SCA's pool,
;	or credit_request will be sent.

SC.CRM::BLSUB.	(<SS.CID,SS.NUM>)
	SAVEAC <P1,P3,P4>
	MOVE T1,SS.CID		;Get user's connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD ()		;No. return failure
	MOVN T1,SS.NUM
	SKIPE T1
	IFSKP.
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  RETSKP
	ENDIF.

;Decrease pending receive credit by the number the sysap wants back.
;If we had a positive count, we can claim some (maybe all) of the buffers
;without asking permission.

	CIOFF
	MOVE T2,.CBPRC(P1)	;Save current pending receive count
	ADDM T1,.CBPRC(P1)	;decrease it by number desired
	JUMPLE T2,SCC.FF	;If already negative, can't reclaim any
	SKIPGE .CBPRC(P1)	;Did we have enough already pending?
	IFSKP.
	  MOVE T1,SS.NUM	;Yes. Get number we wanted
	  ADDM T1,.CBRTC(P1)	; and count all as return credit
	ELSE.
	  ADDM T2,.CBRTC(P1)	;No. Claim the ones we had pending
	ENDIF.

;We may need to send a credit_request. If so, SC.CD5 will queue the
;packet. We must cause it to be sent after unlocking the connection
;block

SCC.FF:	CION
	MOVE P4,.CBSBA(P1)	;Get the system block address
	CALL SC.GCB		;(P1,P4/) Get canceled buffer, if any
	SETOM P3		;Assume we'll need to send something
	CALL SC.CD5		;(P1,P4/) Queue credit request if needed
	 SETZM P3		;Don't need to send a message
	CALL SC.ULK		;(P1/) Unlock the connection block
	SKIPE P3		;Need to send the request?
	CALL SC.SNM		;(P4/) Yes. Send next message
	RETSKP
	ENDBS.
	SUBTTL Calls from sysap -- Named buffers

	SUBTTL Calls from sysap -- Named buffers -- SC.MAP (Map a buffer)

; This routine defines a buffer for the port...
;
;	Call
;	BLCAL. (SC.MAP,<SS.BLK,SS.RWF>)
;
; Where:
;	SS.BLK -- Address of the first entry in a chain of buffer
;			descriptor blocks.
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	T1/	32 bit buffer name
;
;	Buffer descriptor blocks ahve the following format:
;
;	 !=======================================================!
; .MDNXT !    Address of next buffer in chain or zero if none    !
;	 !-------------------------------------------------------!
; .MDFLG !               Flags                                   !
;	 !-------------------------------------------------------!
; .MDLEN !               Length of buffer segment                !
;	 !-------------------------------------------------------!
; .MDADR !            Physical address of the segment            !
;	 !-------------------------------------------------------!
; 	 \                                                       \
;	 \                                                       \
;	 \              N segment descriptor pairs               \
;	 \                                                       \
;	 \                                                       \
;	 !-------------------------------------------------------!
;	 !    A zero length to terminate the descriptor list     !
;	 !=======================================================!
;
; Note that .MDNXT is an offset from the start of the block to the address of
;the next entry in the chain, but .MDLEN and .MDADR are offsets within 
;the words describing a single buffer segment.
;

SC.MAP::JRST MAPBUF		;THIS JUST PASSES THROUGH TO MAPBUF.
				;THE ARGUMENTS AND CALLING CONVENTIONS
				;FOR SC.MAP AND MAPBUF ARE THE SAME.
	SUBTTL Calls from sysap -- Named buffers -- SC.UMP (Unmap a mapped buffer)

; This routine is called when the SYSAP has completed all operations with a
;named (mapped) buffer. Note that doing data transfers does not unmap the 
;buffer. The buffer will remain mapped until the user has done this unmap
;call.
;
;	Call
;	BLCAL. (SS.UMP,<SS.NAM>)
;
; Where:
;	SS.NAM -- 32 bit name of buffer to be unmapped
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	No data, buffer name is no longer valid
;
SC.UMP::JRST UMAP		;JUST PASS THROUGH TO UMAP. THE
				;ARGUMENTS AND CALLING CONVENTIONS
				;FOR SC.UMP AND UMAP ARE THE SAME.
	SUBTTL Calls from sysap -- Named buffers -- SC.SND (Send DMA data)

; This routine sends block data from a named buffer.
;
;	Call
;	BLCAL. (SC.SND,<SS.CID,SS.SNM,SS.RNM,SS.SOF,SS.ROF>)
;
; Where:
;	SS.CID -- Connection on which this transfer is being done
;	SS.SNM -- 32 bit name of the buffer to get data from
;	SS.RNM -- 32 bit name of buffer to put data into
;	SS.SOF -- Byte offset into transmision buffer
;	SS.ROF -- Byte offset into reception buffer
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	No data returned.
;
;Note:
;The corporate spec provides for the sysap's selecting
;the threshold value; we have chosen to make it 1 always.

SC.SND::BLSUB. (<SS.CID,SS.SNM,SS.RNM,SS.SOF,SS.ROF>)
	SETZM T1		;Indicate send
	JRST SC.SN2
SC.REQ::BLSUB. (<SS.CID,SS.SNM,SS.RNM,SS.SOF,SS.ROF>)
	SETOM T1		;indicate request

SC.SN2:	SAVEAC <P1,P3,P4>
	MOVEM T1,P3		;Save flag
	MOVE T1,SS.CID		;Get connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD ()

;Don't send if the connection isn't open

	LOAD T1,CBCNST,(P1)	;Get the current connection state
	CAIE T1,.CSOPN		;Is this connection open???
	RETBAD (SCSCWS,<CALL SC.ULK>) ;No, return "connection in wrong state"

;Don't send if we don't have enough send credit. Must have at least 1
;This code is race-free. Comparing and then decrementing is not.

	SOS T1,.CBSCD(P1)	;Decrement send credit
	CAIL T1,1		;Do we have more than the threshold?
	IFSKP.
	  AOS .CBSCD(P1)	;No. Put it back
  	  SETONE CBFNNC,(P1)	;No. Indicate waiting for credit callback
	  RETBAD (SCSNEC,<CALL SC.ULK>) ;Return "not enough credit"
	ENDIF.
	;..
	;..
	MOVE P4,.CBSBA(P1)	;Get a pointer to the system block
	IFE. P3			;Want to send?
	  BLCAL. (SNDDAT,<SS.SNM,SS.RNM,SS.SOF,SS.ROF,SS.CID>)
	   JRST SC.SN5		;Failed
	ELSE.
	  BLCAL. (REQDAT,<SS.SNM,SS.RNM,SS.SOF,SS.ROF,SS.CID>)
	   JRST SC.SN5		;Failed
	ENDIF.
	CALL SC.ULK		;(P1/) Unlock the connection block
	RETSKP			;Return OK

;Here when we failed. This happens only if the v.c. is closed.

SC.SN5:	AOS .CBSCD(P1)		;We didn't use the send credit after all
	CALL SC.ULK		;(P1/) Unlock the connection block
	RETBAD ()		;Return with failure
	ENDBS.
	SUBTTL Calls from sysap -- State polling

	SUBTTL Calls from sysap -- State polling -- SC.CSP (Connect state poll)

; Here to update the state of a connection.
;
; Usage:
;
;	Call
;	BLCAL.	(SC.CSP,<SS.CID,SS.ADR>)
;
; Where:
;	SS.CID -- Connect ID
;	SS.ADR -- Address of block in which to place data
;
;	Return (+1)  Failure, with:
;	T1/	Failure code
;	T2/	Pointer to data block
;
;	Return (+2)  Success, with:
;	T1/	Connect ID
;	T2/	Pointer to data block
;
;
SC.CSP::BLSUB.	(<SS.CID,SS.ADR>)
	SAVEP			;Save the quasi ACs
	MOVE T1,SS.CID		;Get user's connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity and lock CB
	 RETBAD (,<MOVE T2,SS.ADR>)  ;Invalid connect ID, return failure
	MOVE T1,SS.ADR		;Get address of where to place data

; Now that we have the space, fill it with what we promised it would contain.
;
	LOAD T2,CBCNST,(P1)	;Get the connection state
	STOR T2,CDCST,(T1)	;Store in the allocated block
	LOAD T2,CBDCID,(P1)	;Get the destination connect ID
	STOR T2,CDDCI,(T1)	;Store this in the returned data
	DMOVE T2,.CBDPN(P1)	;Get first and second word of destination name
	DMOVEM T2,.CDDPN(T1)	;Put it up in the returned data
	DMOVE T2,.CBDPN+2(P1)	;Get third and fourth word of destination name
	DMOVEM T2,.CDDPN+2(T1)	;Put it up in the returned data
	LOAD T2,CBDNOD,(P1)	;Get the node number
	STOR T2,CDNOD,(T1)	;Put it up in the returned data
	LOAD T2,CBDDRE,(P1)	;Destination disconnect reasons
	STOR T2,CDDREA,(T1)	;Put this up in the returned data too...
	LOAD T2,CBSDRE,(P1)	;Once more kids, get the source disconn reasons
	STOR T2,CDSREA,(T1)	;One last time... Put it in the returned data
	CALL SC.ULK		;(P1/) Unlock connect block
	MOVE T2,T1		;Move block address
	MOVE T1,SS.CID		;Get connect ID
	RETSKP			;Return success
	ENDBS.
	SUBTTL Calls from sysap -- State polling -- SC.DCI (Return destination connect ID)

; This routine returns the destination connect ID for a connection.
;
; Usage:
;	Call
;	BLCAL. (SC.DCI,<SS.CID>)
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	T1/	Destination connect ID for given connection
;
SC.DCI::BLSUB. (<SS.CID>)
	SAVEAC <P1>		;Save the preserved AC we are about to kill
	MOVE T1,SS.CID		;Get connect ID
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD()		;Return failure
	LOAD T1,CBDCID,(P1)	;Get the destination connect ID
	CALL SC.ULK		;(P1/) Unlock the connection block
	RETSKP			;All done...
	ENDBS.
	SUBTTL Calls from sysap -- State polling -- SC.RCD (Return configuration data)

; Here to get configuration data on a system.
;
; Usage:
;
;	Call
;	BLCAL.	(SC.RCD,<SS.NOD,SS.ADR>)
;
; Where:
;	SS.NOD -- System block index
;	SS.ADR -- Address of block in which to place data
;
;	Return (+1)  Failure, with:
;	T1/	Failure code
;	T2/	Address of data block
;
;	Return (+2)  Success, with:
;	T1/	Node number
;	T2/	Address of data block
;
SC.RCD::BLSUB.	(<SS.NOD,SS.ADR>)
	SAVEP			;Save the preserved ACs we use here
	MOVE T2,SS.NOD		;Get the callers SBI
	CAIG T2,C%SBLL-1	;Are we over the SBLIST size???
	SKIPGE T2		;Or maybe a negative number???
	RETBAD (SCSBAS,<MOVE T2,SS.ADR>)  ;Bad arguments, tell the caller
	SKIPN P4,SBLIST(T2)	;See if (and get) if there is an SB addr here
	RETBAD (SCSBAS,<MOVE T2,SS.ADR>)  ;No entry for this SBI

	MOVE T2,SS.ADR		;Get address of data block
	LOAD T3,SBVCST,(P4)	;Get the virtual circuit state from the SB
	STOR T3,RDVCST,(T2)	;Put it up in the returned data
	LOAD T3,SBDPA,(P4)	;Get the destination port number
	STOR T3,RDPORT,(T2)	;And this also goes in the returned data

	MOVE T3,.SBDSS(P4)	;Get the first word of the system address
	MOVEM T3,.RDSYS(T2)	;Put it in the returned data
	MOVE T3,.SBDSS+1(P4)	;Now the second word of the system address
	MOVEM T3,.RDSYS+1(T2)	;Put it with its friend...

	LOAD T3,SBMXDG,(P4)	;Get the max datagram system will allow
	STOR T3,RDMDG,(T2)	;Put it up in the returned data
	LOAD T3,SBMXMG,(P4)	;Now the max message allowed
	STOR T3,RDMMS,(T2)	;Store in data
	LOAD T3,SBDTSW,(P4)	;Dest software type
	STOR T3,RDDST,(T2)	;.	.	.
	LOAD T3,SBDVSW,(P4)	;Dest software version
	STOR T3,RDDSV,(T2)	;.	.	.
	MOVE T3,.SBDSE(P4)	;Destination software incarnation (first word)
	MOVEM T3,.RDDSI(T2)	;.	.	.
	MOVE T3,.SBDSE+1(P4)	;Destination software incarnation (second word)
	MOVEM T3,.RDDSI+1(T2)	;.	.	.
	LOAD T3,SBDTHW,(P4)	;Destination hardware type
	STOR T3,RDDHT,(T2)	;.	.	.
	LOAD T3,SBDVHW,(P4)	;Destination hardware version
	STOR T3,RDDHV,(T2)	;.	.	.

	DMOVE T3,.SBNNM(P4)	;Get destination node name
	DMOVEM T3,.RDNNM(T2)	;Store it in returned data
	MOVE T3,.SBDPC(P4)	;Get destination port characteristics
	MOVEM T3,.RDPCH(T2)	;Store it in returned data
	MOVE T3,.SBDCR(P4)	;Get destination port revision level
	MOVEM T3,.RDPRL(T2)	;Store it in returned data
	MOVE T3,.SBDPF(P4)	;Get destination port functionality
	MOVEM T3,.RDPFC(T2)	;Store it in returned data
	MOVE T3,.SBDPS(P4)	;Get destination port state
	MOVEM T3,.RDPST(T2)	;Store it in returned data

	MOVE T1,SS.NOD		;Get node number back
	RETSKP			;Return success
	ENDBS.
	SUBTTL Calls from sysap -- State polling -- SC.NOD (Return node number given CID)

;This routine returns the node number associated with a CID...
;
; Usage:
;	CALL SC.NOD
;	T1/	Local connect ID
;
;	Return (+1) Always
;	T1/	Local connect ID  (or SCSIID error code if CID invalid)
;	T2/	Node number of the remote end of the connection specified
;		(or -1 if the CID is invalid)
;
SC.NOD::SAVEAC <T3,T4,P1>	;Save the ACs we kill here
	CALL SC.CAL		;(T1/T1,P1) Check validity, and lock
	 RETBAD (,<SETOM T2>)	;Return failure
	MOVE T2,.CBSBA(P1)	;Get the system block address
	LOAD T2,SBDPA,(T2)	;Get the node number
	CALL SC.ULK		;(P1/) Unlock the connection block
	RET
	SUBTTL Calls from sysap -- State polling -- SC.RAC (Return available credit)

; This routine returns the number of credits available to a particular connect.
;
; Usage:
;	Call
;	BLCAL. (SC.RAC,<SS.CID>)
;
; Where:
;	SS.CID -- Connect ID of connection whose credits we desire
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	T1/	Send credit
;	T2/	Receive credit
;	T3/	Number of datagram buffers queued
;


REPEAT 0,<
SC.RAC:	BLSUB. (<SS.CID>)
	SAVEAC <P1>		;Save the CB addr AC
	MOVE T1,SS.CID		;Get the callers connect ID
	CALL SC.CSC		;Is it valid???
	 RETBAD (SCSIID)	;Nope, yell at the caller
	MOVX T1,CBFABT		;Get the CB aborted bit
	TDNE T1,.CBFLG(P1) 	;Is the abort bit lit???
	RETBAD (SCSIID)		;Yes, return bad CID
	MOVE T1,.CBSCD(P1)	;Get the send credit
	MOVE T2,.CBRCD(P1)	;  the receive credit
	MOVE T3,.CBDGR(P1)	;  and the number of datagrams queued
	RETSKP			;Return all OK
	ENDBS.
>
				;END REPEAT 0
	SUBTTL Calls from sysap -- State polling -- SC.PRT (Return local port number)

; This routine returns the local port number, but only on a KL with a single
;CI port!.
;
; Usage:
;	Call
;	No arguments
;
;	Return (+1)
;	No known KLIPA port
;
;	Return (+2)
;	T1/	Local port number
;
SC.PRT::CALLRET LOCPRT		;Get requested info from the port driver
	SUBTTL Calls from sysap -- Maintenance

	SUBTTL Calls from sysap -- Maintenance -- SC.RST (Reset remote system)

; This routine will call the port driver to send a remote node reset message.
;No checks are done for remote node type since this message type is ignored
;by KL's and "other" reasonable machines.
;
; Usage:
;	Call
;	BLCAL. (SC.RST,<SS.NOD,SS.FRB>)
;
; Where:
;	SS.NOD -- SBI or remote system to be reset
;	SS.FRB -- Force reset bit, if one, reset is forced, if zero,
;		     reset will only be done if we are the last node to do
;		     a reset for this remote
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	No data returned, reset packet sent
;
SC.RST::BLSUB. (<SS.NOD,SS.FRB>)
	SAVEAC <P4>
	MOVE P4,SS.NOD		;Get the SBI of the doomed remote
	SKIPN P4,SBLIST(P4)	;Now the address of the system block
	RETBAD (SCSISB)	;No such system, return failure
	BLCAL. (CLOSVC,<P4>)	;CLOSE THE VC
	HRRZ T1,.SBDSP(P4)	;Get the node number.
	BLCAL. (RMTRST,<T1,SS.FRB>);Have te port reset the remote please
	 RETBAD ()		;Return with error code in T1
	RETSKP			;Return ok
	ENDBS.
	SUBTTL Calls from sysap -- Maintenance -- SC.STA (Start remote node)

; This routine will call the port driver to start a remote node. Note that
;no check of system type is done since KL's and other important machines will
;ignore this packet type...
;
; Usage:
;	Call
;	BLCAL. (SC.STA,<SS.NOD,SS.DSA,SS.STA>)
;
; Where:
;	SS.NOD -- SBI of ill fated remote
;	SS.DSA -- Flag for use of SS.STA, if zero, SS.STA is ignored and
;			the default start address is used. If non-zero, SS.STA
;			is used as the start address of the remote.
;	SS.STA -- Start address for the remote node. Only used if SS.DSA is
;			non-zero.
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	No data returned
;
SC.STA::BLSUB. (<SS.NOD,SS.DSA,SS.STA>)
	SAVEAC <P4>
	MOVE P4,SS.NOD		;Get the desired system block index
	SKIPN P4,SBLIST(P4)	;Get the system block address for given SBI
	RETBAD (SCSISB)	;No such system, return badness
	HRRZ T1,.SBDSP(P4)	;Get the node number.
	BLCAL. (RMTSTA,<T1,SS.DSA,SS.STA>)	;Do the packet send
	 RETBAD ()		;Fail with code from the port driver
	RETSKP			;All ok

	ENDBS.
	SUBTTL Call from port driver

	SUBTTL Call from port driver -- SC.ONL (Node has come online)

; This routine handles the appearance of a node.
;
SC.ONL::BLSUB. (<SS.NOD>)
	SAVEAC <Q1,Q2,P1,P3,P4>
	SKIPN SCAINI		;Has SCA been initialized???
	IFNSK.
	  BUG.(CHK,SCAOBI,SCAMPI,SOFT,<SCA - Online before initialization done>,,<

Cause:	A node came online before the initialization of SCA was completed.
>)
	  CALL SCA		;It has now...
	ENDIF.
	MOVE T2,SS.NOD		;Get the node number
	MOVE P4,SBLIST(T2)	;Now for the system block address

;By now, we shouldn't still be stuck on buffers

  IFN SCADBG,<
	MOVE T3,SS.NOD		;Get node number for bugs below
	MOVE T1,BITS(T2)
	TDNN T1,SBSTUK		;Is this system block stuck on buffers?
	IFSKP.
	  BUG.(CHK,SCAONS,SCAMPI,SOFT,<SCA - Online when stuck on buffers>,<<T3,NODE>>,<

Cause:	A node came online while stuck on buffers. This should have been cleared
	when the node went offline.

Action:	Determine whether PHYKLP is calling twice with the same node.
	If not, something has probably clobbered the flags word for this
	system block.

Data:	NODE - Node number
>)
	  ANDCAM T1,SBSTUK
	ENDIF.

;The system block's work queue should have been cleared before.

	SKIPN .SBTWQ(P4)	;Does work queue still exist?
	IFSKP.
	  BUG.(CHK,SCAOWJ,SCAMPI,SOFT,<SCA - Online when work queue exists>,<<T3,NODE>>,<

Cause:	A node came online while its work queue still contained entries. 
	The work queue should have been cleaned up when the node went offline.

Data:	NODE - Node number
>)
	  XMOVEI T1,.SBTWQ(P4)
	  MOVEM T1,.SBBWQ(P4)
	  SETZM .SBTWQ(P4)
	ENDIF.
	;..
;No connection blocks should be locked now. We get here only after the
;v.c. has been closed, at which point the c.b.'s should have been unlocked.

	;..
	SKIPN T1,.SBCLC(P4)	;Is a connection block still locked?
	IFSKP.
	  BUG.(CHK,SCAOWL,SCAMPI,SOFT,<SCA - Online when connection block still locked>,<<T3,NODE>,<T1,COUNT>>,<

Cause:	A node came online while a connection block was still locked.  The 
	v.c. should not have been closed until this count was zero.

Data:	NODE  - Node number
	COUNT - Lock count for connection block
>)
	  SETZM .SBCLC(P4)	;Clear it and hope for the best
	ENDIF.
   >				;END IFN SCADBG

	SETZRO SBFLG,(P4)	;Clear any residual flags
	SETZM .SBTIM(P4)	;Indicate we have not spoken to the SB yet

; See if there are enough buffers around or do we need more. Also update the
;minimum number of buffers we should have onhand.

	AOS SBCNT		;Account for the new system
	MOVE T1,SBCNT		;Get number of systems we know about now
	CAMLE T1,MXSBCT		;Is it greater than the max we keep?
	MOVEM T1,MXSBCT		;Yes, save it
	CALL SC.SBT		;Set new buffer thresholds

	MOVE T1,MINMSG		;Number of message buffers we should have
	MOVE T2,MINDG		;Number of datagram buffers we should have
	CAMLE T1,FQCNT		;Do we have enough message buffers?
	JRST SC.ON1		;NO
	CAMG T2,DFQCNT		;Yes. Do we have enough datagram buffers?
	IFSKP.
SC.ON1:	   SETONE CIBUF		;NO, SAY WE NEED TO CREATE BUFFERS
	ENDIF.
	;..
;Get two buffers -- one for incoming (give that to the port), and one for
;outgoing (queue that to the system block)

	;..
   IFN SCADBG,<
	SKIPN T2,.SBOBB(P4)	;Already have a buffer?
	IFSKP.
	  LOAD T3,SS.NOD	;Get node number
	  BUG.(CHK,SCAOBB,SCAMPI,SOFT,<SCA - Buffer already exists>,<<T3,NODE>,<T2,BUFFER>>,<

Cause:	A node that already had an outbound buffer came online.  This field 
	should have been zeroed when the node went offline. SCAMPI may have 
	been called twice for node online. The buffer will be lost after
	this.

Data:	NODE   - Node number
	BUFFER - Address of connection management buffer
>)
	ENDIF.
   >				;END IFN SCADBG
	MOVEI T1,1		;Need one buffer
	CALL SC.ABF		;(T1/T1) Get buffer from SCA pool
	 JRST SON.ME
	MOVEM T1,.SBOBB(P4)	;Make this the outbound buffer
	MOVEI T1,1		;Need another one
	CALL SC.ABF		;(T1/T1,T2,T3) Get buffer from SCA pool
	 JRST SON.ME
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Saved smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-1(P6)	;Get PC of caller to feature routine
	  MOVEI T3,1		;Get buffer count
	  TXO T3,RPQFLK   	;Set port link flag
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	BLCAL. (LNKMFQ,<P4,T1>)	;Give it to port for incoming messages
	;..
;Notify each sysap that's asked to be notified when nodes come online

	;..
	MOVE Q1,NOTTAB		;Get the address of the notification list
SON.SL:	SKIPN (Q1)		;Is there an entry
; * * * Should return +1
	RETSKP			;Nope, we are all done here
; * * * *

	MOVX T1,.SSNCO		;Say why we are calling the SYSAP
	MOVE T2,SS.NOD		;Indicate which node
	CALL @(Q1)		;Call the SYSAP about this new node
	 NOP			;Handle any silly SYSAP's
	AOS Q1			;Point to the next entry
	CAMG Q1,NOTEND		;Are we going off the end of the table???
	JRST SON.SL		;No, loop for another entry
	RETSKP			;Off the end of the table, all done

;Here when we failed to allocate the two buffers required for connection
;management. In theory, we should be able to tolerate this failure, and
;wait until job 0 creates more buffers. If we start to see this problem,
;it seems reasonable to try to do that. For now, we'll crash.

SON.ME:	BUG. (HLT,SCASCQ,SCAMPI,SOFT,<SCA - Can't get connection management buffers>,<<T1,ERROR>>,<

Cause:	SCA has been notified of a new system coming online. It tried
	to allocate two buffers to be used for connection management, and
	failed. This indicates that a large number of buffers have been
	allocated at interrupt level, and the process that creates more 
	hasn't run recently.

Action:	It is possible to recover from this by deferring buffer allocation 
	to process context. Meanwhile, try to find out why buffers are being 
	used so rapidly, or why job 0 is not running.

Data:	ERROR - error code from allocation routine

>)
	ENDBS.
	SUBTTL Call from port driver -- SC.ERR (Node(s) have gone away)

; This routine handles a node going offline. Note that all SYSAP connections
;on this system must be closed and the SYSAP notified...
;
;	Call
;
;	BLCAL. (SC.ERR,<SS.NOD>)
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	No data returned...
;
SC.ERR::BLSUB. (<SS.NOD>)
       	CIOFF			;Dont do CI work until CB's are marked closed
	SAVEP			;Save the preserved regs we kill

;See if we already counted this system as going offline. If not, set the
;flag saying we did, and decrement the count of systems online.

	MOVE P4,SS.NOD		;Get the SBI of the system that went offline
	MOVE P4,SBLIST(P4)	;Get the address of the system block
	TMNN SBFOFL,(P4)	;Have we seen this as offline already?
	IFSKP.
	  LOAD T1,SBDPA,(P4)	;Yes. get node number
	  BUG. (CHK,SCAOF2,SCAMPI,SOFT,<SCA - Offline twice for a node>,<<T1,NODE>>,<

Cause:	SC.ERR was called when a system block was already flagged as offline.
	While this won't cause an immediate problem, it does indicate 
	internal confusion and should be investigated.

Data:	NODE - Node number
>)
	  CION
	  JRST SOF.NT
	ENDIF.
	SETONE SBFOFL,(P4)	;No. Mark it
	SOSL SBCNT		;Decrement the system count
	IFSKP.
	  BUG. (CHK,SCANSC,SCAMPI,SOFT,<SCA - Negative system count>,,<

Cause:	SCA was notified of a system going offline and decremented the count
	of systems currently online. In doing so, the count went negative. 
>)

	  SETZM SBCNT		;Make the count zero, rather than -1
	 ENDIF.			;  and continue normally
	;..
;Loop over all connections on the SB and mark them as closed. If they were
;already closed, the sysap isn't interested in them any more. If not, tell
;the sysap that the connection has been closed.
;If not CIOFF, need NOSKED to keep reaper from changing the list
;Sysaps expect this callback not to be interrupted

	;..
	SKIPN P1,.SBFCB(P4)	;Get the addr of the first connection block
	JRST SOF.NT		;No connects to mark, go on
SOF.CL:	
	SETONE CBFCVC,(P1)	;Indicate v.c. was closed
	MOVX T1,CBFERR		;Set this flag if it's locked
	CALL SC.HNR		;(T1,P1/) Is the c.b. locked?
	IFNSK.
	  AOS .SBCLC(P4)
	  JRST SOF.NX		;Yes. Go to the next one
	ENDIF.
	LOAD T2,CBCNST,(P1)	;Get current state
	MOVEI T1,.CSCLO		;New state will be "closed"
	STOR T1,CBCNST,(P1)	;Store as new connect state
	CAIN T2,.CSCLO		;Was it already closed?
	IFSKP.			;No.
   IFN SCARNG,<
      	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-1(P6)	;Get PC of caller to feature routine
	  MOVEI T3,.SSPBC	;Get callback notification code
	  CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	  MOVEI T1,.SSPBC	;Get the notification code back
	  LOAD T2,CBSCID,(P1)	;Get the local connect ID
	  MOVE T3,SS.NOD	;Get node number
	  SETZM T4		;Clear unused AC
	  CALL @.CBADR(P1)	;Notify the SYSAP of the disaster
	ENDIF.
	SETZM .CBRQC(P1)	;We'll never get credit_response now
				; so clear this so we can reap
	CALL SC.PTC		;(P1/) Indicate protocol is complete

SOF.NX:	SKIPE P1,.CBANB(P1)	;Is there a next connect block???
	JRST SOF.CL		;Yes, loop for its new state

SOF.NT:
	CALL SC.SBT		;Set new buffer thresholds based on SBCNT

;If there were pending connect_req or accept_req messages that required
;buffers, this system may have been marked as stuck. These messages will
;no longer be sent. Clear the "stuck" bit, and get rid of the queue of
;connection blocks needed to send requests.

	MOVE T1,SS.NOD		;Get system block index
	MOVE T1,BITS(T1)	;Mark this block as no longer
	ANDCAM T1,SBSTUK	; stuck on buffers

	XMOVEI T1,.SBTWQ(P4)	;Else, we have exhauted the q, init list ptrs
	MOVEM T1,.SBBWQ(P4)	;Init tail as pointer to head
	SETZM .SBTWQ(P4)	;Init head as zero
	CION
	;..
;When system came online, we got 2 buffers from the SCA pool for sending
;and receiving SCS control messages. Give them back to SCA now

	;..
	SETZM P2		;Prepare to clear the address of the buffer
	EXCH P2,.SBOBB(P4)	;Grab outbound buffer if it's there
	SKIPN P2		;Was it there?
	IFSKP.
	  MOVE T1,P2		;Yes. Give it back to SCA
	  CALL SC.RBF		;(T1/)
	ENDIF.
	BLCAL. (ULNKMG,<P4>)	;(/T1) Get a buffer from the port
	 JRST SOF.NG		;Couldn't get it.
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Save smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-1(P6)	;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	CALL SC.RBF		;(T1/) This was inbound buffer. Give it to SCA
	JUMPN P2,SOF.NZ		;Did we have an outbound buffer?
	BLCAL. (ULNKMG,<P4>)	;(/T1) No. get another from the port
	 JRST SOF.NG		;Couldn't get it
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Save smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-1(P6)	;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	CALL SC.RBF		;(T1/) Give it to SCA
	JRST SOF.NZ		;Skip past the error code

;The port ran out of buffers. In theory, we put two buffers on the queue when
;this node came online, so we ought to be able to take two off.

SOF.NG:	LOAD T1,SBDPA,(P4)
	BUG. (CHK,SCANMB,SCAMPI,SOFT,<SCA - Can't return SCS control message buffer>,<<T1,NODE>>,<

Cause:	A node went offline, The local node tried to retrieve two message 
	buffers from the port's queue but found the queue empty.

Action:	Depending on timing this may happen legitimately. If it persists, 
	stock the port's message free queue more generously at system startup.

Data:	NODE - Node number
>)
   IFN SCARNG,<
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-1(P6)	;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  SETOM T4		;Set buffer address to -1 due to failure
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>	         		;End of IFN SCARNG


; Here to notify ALL sysaps that a node has gone offline. Note that this means
;any sysap with connections open to the node that went offline will get one
;extranious notification.
;
; NOTE:  For this callback the connect ID returned in T2 is -1.

SOF.NZ:	MOVE P5,NOTTAB		;Start with first word in notification table

SOF.VL:	SKIPN (P5)		;Is there an entry
	JRST SOF.VC		;Nope, go do VC opening checks
	MOVX T1,.SSPBC		;Say why we are calling the SYSAP
	SETOM T2		;There is no CID returned for this callback
	MOVE T3,SS.NOD		;Indicate which node
	SETZM T4		;Insure the rest of the calling ACs are zero
	CALL @(P5)		;Call the SYSAP about this new node
	AOS P5			;Point to the next entry
	CAMG P5,NOTEND		;Have we gone off the end of the table???
	JRST SOF.VL		;No. Loop for more entries

;Tell PHYKLP it can reopen the v.c. unless we have locked connection
;blocks. If we do, SC.ULK will eventually call OPENVC.

SOF.VC:	SKIPN .SBCLC(P4)	;Any locked connection blocks?
	IFSKP.
	  SETONE SBFOVC,(P4)	;Yes. Indicate waiting to open
	ELSE.
	  BLCAL. (OPENVC,<P4>)	;No. Open it now
	ENDIF.
	RETSKP

	ENDBS.
;SC.FN1 - finish work of SC.ERR when c.b. is unlocked

;Accepts:
;	P1/ address of connection block

;	CALL SC.FN1

;Returns +1: always

SC.FN1:
	SETZRO CBFERR,(P1)	;Clear indication that this was deferred
	LOAD T2,CBCNST,(P1)	;Get current state
	MOVEI T1,.CSCLO		;New state will be "closed"
	STOR T1,CBCNST,(P1)	;Store as new connect state
	CAIN T2,.CSCLO		;Was it already closed?
	IFSKP.
   IFN SCARNG,<
      	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,(P)		;Get PC of caller to feature routine
	  MOVEI T3,.SSPBC	;Get callback notification code
	  CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	  LOAD T1,CBSCID,(P1)	;Get the local connect ID
	  CALL SC.NOD		;(T1/T1,T2) Get node number
	  MOVEM T2,T3		;Reposition node number for callback
	  MOVEM T1,T2		;Reposition CID for callback
	  MOVEI T1,.SSPBC	;Port broke connection
	  CIOFF			;Sysap wants no interrupts
	  CALL @.CBADR(P1)	;Notify the SYSAP of the disaster
	  CION
	ENDIF.
	CALL SC.PTC		;(P1/) Indicate protocol is complete
	RET
	SUBTTL Call from port driver -- SC.DMA (DMA operation complete)

; Here when the port noticed that a DMA operation has completed and we
;need to notify the guilty party...
;
;	Call
;	T1/	32 bit buffer name of completed transfer
;	T2/	CID
;	P4/ address of system block
;
;	Return (+1)
;	No data returned, no failure return...
;
SC.DMA::SAVEAC <P1,P2,P3>
	DMOVEM T1,P2
	LOAD T3,SBVCST,(P4)	;Don't do anything if the v.c.
	CAIE T3,VC.OPN		; is already closed
	RET
	MOVE T1,T2		;Get CID
	CALL SC.CSC		;(T1/T1,P1) Is it valid?
	 RET
	LOAD T3,CBCNST,(P1)	;See if connection is open
	CAIE T3,.CSOPN
	RET			;No. Ignore it
	AOS .CBSCD(P1)		;Give back the credit we took at the start
   IFN SCARNG,<
        XMOVEI T1,.		;Get feature routine address
        MOVE T2,-4(P)		;Get PC of caller to feature routine
        MOVEI T3,.SSDMA		;Get callback notification code
        CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVE T3,P2		;Put the name where promised
	MOVX T1,.SSDMA		;Say why we care calling
	MOVE T2,P3		;Get CID
	CALL @.CBADR(P1)	;Notify SYSAP of his DMA complete

;We've just incremented send credit. If the sysap had been told "not
;enough credit" on a previous attempt at sending, we need to tell it to
;try again.

	TMNN CBFNNC,(P1)	;Does sysap need notification?
	RET			;Nope, return now
	SETZRO CBFNNC,(P1)	;Show notification complete, zero flag in CB
   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-4(P)		;Get PC of caller to feature routine
	MOVEI T3,.SSCIA		;Get callback notification code
	CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVX T1,.SSCIA		;Say why we are calling, we have credit for you
	LOAD T2,CBSCID,(P1)	;Indicate which connection this for
	MOVE T3,.CBSCD(P1)	;Show the send credit 
	MOVE T4,.CBRCD(P1)	;Receive credit
	CALL @.CBADR(P1)	;Leap into the SYSAP
	RET			;All done
	SUBTTL Call from port driver -- Incoming buffer -- SC.INT (Buffer arrival)

; We get here when the port driver has a message the it has deceided SCA needs
;to see. The various types that make their way thourgh here are:
;	1. Application datagrams (Get passed to SYSAP)
;	2. Application messages  (Get passed to SYSAP)
;	3. SCA control messages  (Get eaten by SCA routines)
;
; First things the we have to do is figure out which message type we have.
;Having divined this we can do what each type requires. A datagram or message
;get passed on to the SYSAP that gets it. I.E. set up the ACs as they were
;promised (See SCAPAR) and call the address in the CB. If the message
;is an SCA control message, then dispatch to the correct routine based on
;message type. A dispatch table is provided that one merely indexes into
;by message type.
;
; Usage:
;	Call
;	P2/	Address of message/datagram/SCA buffer
;	P4/	Address of system block
;
;
;	Return +1:	Always
;
SC.INT::BLSUB.	(<SS.FLG,SS.LEN>)
	SAVEP			;Save the ACs we kill here...
	CALL SC.RIN		;Byte swap the SCA header of the packet
   IFN SCARNG,<
SCINT:	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-1(P6)		;Get caller to feature routine
	MOVE T3,SS.FLG		;Get flags
	HRRZ T4,SS.LEN		; and get packet length (no priority)
	CALL RG.PKT		;(T1,T2,T3,T4,P2,P4) Record packet transmission
>				;End of IFN SCARNG
	MOVE T2,SS.FLG		;Get the arg flags
	TXNN T2,F.RSP		;Is this a local or remote packet
	 JRST SIN.RP		;A remote packet, dispatch to a handler

;Buffer is being returned after a send. Return it to the pool or give it
;to the sysap.

	LOAD T3,MH$MSG,(P2)	;Get the packet type
	CAIE T3,.STADG		;Is this a datagram??
	CAIN T3,.STAMG		;  or an application message
	JRST SIN.MS		;Handle the return of a SYSAP buffer

;Buffer had been sent by SCA. This should happen only on error.
; * * * *
;This shouldn't happen at all. We need a BUGCHK here
; * * * *

	MOVE T1,P2		;Get the buffer address
	CALL SC.RBF		;Return the buffer to the SCA free pool
	RET			;Return...
; Here to return a locally generated SYSAP message buffer to its owner.

;NOTE: SC.RAP won't reap a connection until CBNPO is zero. If this is ever
;changed, the following code could cause a problem. The LDCID might produce
;a zero because the connection block may have gone away.

SIN.MS:	LOAD T3,MH$SCI,(P2)	;Get the source connect ID from the packet
	$LDCID P1,T3		;Get the CB address from the CID
   IFN SCADBG,<
	LOAD T1,CBNPO,(P1)	;Get outstanding packet count
	SKIPG T1		;Is it greater than zero?
	  BUG. (HLT,SCANP3,SCAMPI,SOFT,<SCA - CBNPO about to go negative>,,<

Cause:	When the count of queued buffers is about to be decremented, the
	count is found to be already zero or less.
>)
   >				;END OF IFN SCADBG
	DECR CBNPO,(P1)		;Decrement the count of outstanding packets
   IFN SCARNG,<
    	XMOVEI T1,.		;Get feature routine address
        MOVE T2,-1(P6)		;Get PC of caller to feature routine
        MOVEI T3,.SSMSC		;Get callback notification code
        CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVEI T1,.SSMSC		;Tell the SYSAP why we are calling
	LOAD T2,MH$SCI,(P2)	;Indicate which connection
	MOVE T3,P2		;Setup the address of the buffer
	CALL @.CBADR(P1)	;Call the SYSAP about his buffer
	RET			;And return to the port driver

; Here to dispatch to a routine that will handle a remotely generated packet.
;
SIN.RP:	MOVE T1,TODCLK		;Get current time of day
	MOVEM T1,.SBTIM(P4)	;Store time we got this message
	SETZRO SBFTMG,(P4)	;Zero the flag in the system block
	MOVE T1,SS.FLG		;Make the flags available to handler routines
	MOVE T2,SS.LEN		;Get the length from the PPD args
	LOAD T3,MH$MSG,(P2)	;Get the message type
	CAILE T3,.STLST		;Is the packet type within range???
	JRST SIN.ER		;NO!! Handle remote SCA brain damage
	AOS RECTAB(T3)		;Count the message we just received
	JRST @DSPTAB(T3)	;Yes it is, goto the handling routine

; Here when we have a bad message type from the remote SCA. Since this could
;very well have been a message we must close the VC.
;Note that we don't know what kind of buffer we have, so we just throw
;it away.

SIN.ER:	LOAD T1,SBDPA,(P4)	;Get node number
	LOAD T2,CBSCID,(P1)	;Get connect ID
	BUG. (CHK,SCABMT,SCAMPI,SOFT,<SCA - Bad message type from remote node>,<<T1,NODE>,<T2,CID>,<T3,OPCODE>>,<

Cause:	A bad message type was found on range checking. This shouldn't
	happen if the port and port driver are working correctly. The 
	message is thrown away.

Data:	NODE   - node number
	CID    - Connect ID
	OPCODE - SCS op code received

>)
	CALL SC.CVC		;(P4/) Close the v.c.
	RET			;All done here for now, return
	ENDBS.
; Note: All message handlers assume that they have been called by SC.INT.
;Hence they assume that a SAVEP was done at that level and another is not
;necessary.

;They also assume they're at interrupt level (i.e., not interruptible),
;that v.c. is open (SC.INC checks it), that SC.RSP will fail only if the v.c.
;is closed. Note that this means there's currently no way for SC.RSP to fail,
;since we never try to send a response if the v.c. was found to be closed
;at SC.INC. In the future, we might try for some reason. If so, we may want
;to have PHYKLP check for closed v.c.

;THe order of events in these routines is deliberately as follows:
;	Copy input from packet
;	Send response
;	Update the state
;	Tell the sysap

;This allows us to be sure that the state won't be updated if sending the
;response mysteriously fails.
	SUBTTL Call from port driver -- Incoming buffer -- SC.ORQ (Connect request)

; This routine handle the reception of connection requests.
;
;	Call
;	P2/	Addr of datagram
;
;	Return +1:	Always
;
SC.ORQ:	CALL SC.INC		;(P2/T1,T2,P1) Just do check on v.c. closed
	 JRST SC.RIB		;Ignore this packet
	CALL SC.SCM		;(P2/P1,P4) Search for a connection match
	 JRST SOR.NM		;No match, say so...

;Copy data from the packet into the connect block

	LOAD T2,MH$CDT,(P2)	;Get the credit from the message header
	MOVEM T2,.CBSCD(P1)	;Store it as the credit (since previous MBZ)
	LOAD T2,MH$SCI,(P2)	;Get the remotes connect ID
	STOR T2,CBDCID,(P1)	;Store in the CB 
	LOAD T2,MH$MCR,(P2)	;Get the minimum credit from mess header
	STOR T2,CBMNRC,(P1)	;Store it as the minimum receive credit
	MOVEI T2,<C%PNMN+3>/4	;Number of words to move
	XMOVEI T3,.MGSPN(P2)	;Source address
	XMOVEI T4,.CBDPN(P1)	;Destination address
	EXTEND T2,[XBLT]	;Move the destination process name
	MOVEI T2,<C%SDTL+3>/4	;Number of words to move
	XMOVEI T3,.MGSDT(P2)	;Source address for connection data
	XMOVEI T4,.CBDTA(P1)	;Destination address
	EXTEND T2,[XBLT]	;Move the connection data

;Build and send a match CONNECT_RESPONSE.

	MOVEI T4,.CMCMT		;Get the "match" status
	STOR T4,MH$STS,(P2)	;Put the status info into the message header
	MOVEI T1,.STORS		;Get the CONNECT_RESPONSE message type code
	CALL SC.RSP		;(T1,P1,P2,P4/)Send the response
	 JRST SC.RIB		;Failed. Return the buffer to the free queue
	;..
;Update connection state to connect_received

	;..
	MOVEI T2,.CSCRE		;Get the CONNECT_RECEIVED circuit state
	STOR T2,CBCNST,(P1)	;Put it up in the connection block

;Notify the SYSAP that someone has connected to its listener.

   IFN SCARNG,<
        XMOVEI T1,.		;Get feature routine address
        MOVE T2,(P)		;Get PC of caller to feature routine
        MOVEI T3,.SSCTL		;Get callback notification code
        CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVEI T1,.SSCTL		;Tell the reason for the SYSAP call
	LOAD T2,CBSCID,(P1)	;Tell who was connected to
	XMOVEI T3,.CBDTA(P1)	;Point to the remote connection data
	CALL @.CBADR(P1)	;Make the trusting leap into oblivion
	RET			;Return to the port driver, all went well

;Build and send a no match CONNECT_RESPONSE. Can't use standard routines
;because we want to zero the source connect ID

SOR.NM:	SETZRO MH$CDT,(P2)	;Zero the credit field of the message header
	MOVEI T1,.STORS		;Get op code for CONNECT_RSP
	STOR T1,MH$MSG,(P2)	;Store op code
	LOAD T2,MH$SCI,(P2)	;Get the sending CID
	STOR T2,MH$DCI,(P2)	;Store as the receiving CID
	SETZRO MH$SCI,(P2)	;Send our ID as zero since we have no connect
	MOVEI T4,.CMCNM		;Say we found no connection match
	STOR T4,MH$STS,(P2)	;Put the status info into the message header
	SETZRO MH$MCR,(P2)	;Zero minimum_credit field for safety
	CALL SC.PAK		;(P2,P4/)Send the response
	 JRST SC.RIB		;Failed. Return the buffer to the free queue
	RET			;Else return now, no one to notify
	SUBTTL Call from port driver -- Incoming buffer -- SC.ORS (Connect response)

; Here we handle connect responses. 
;
;	Call
;	P2/	Addr of message
;	P4/	Addr of system block
;
;	Return +1:	Always
;
SC.ORS:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit
	MOVEM T1,P3		;Save new state

;If state was closed, our end disconnected after requesting connection
;Don't need to update state. If other side said "match", wait for the
;accept or reject to come in. If it said "no match", we're finished.

	LOAD T2,CBCNST,(P1)	;Get old state
	LOAD T3,MH$STS,(P2)	;Get match/no match code
	CAIE T2,.CSCLO		;Was it closed already?
	IFSKP.
	  CAIE T3,.CMCMT	;It was closed. Is this a match?
	  CALL SC.PTC		;No. End of protocol, then

;Here when state wasn't closed. This is the normal case. If the other
;side said "no match", tell the sysap that the connection failed, and
;mark protocol complete. Otherwise, update the state and wait for
;the accept or reject.

	ELSE.
	  CAIE T3,.CMCMT	;Not closed. Is this a match?
	  IFSKP.
	    LOAD T2,MH$SCI,(P2)	;Get source connect ID from packet
	    STOR T2,CBDCID,(P1)	;Store as destination ID
	    STOR T1,CBCNST,(P1)	;Store the new connection state
	  ELSE.
	    MOVEI T1,.CSCLO	;No match, new connect state is closed
	    STOR T1,CBCNST,(P1)	;Store the new connect state
   IFN SCARNG,<
      	    XMOVEI T1,.		;Get feature routine address
	    MOVE T2,(P)		;Get PC of caller to feature routine
	    MOVEI T3,.SSCRA	;Get callback notification code
	    CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	    MOVEI T1,.SSCRA	;Say why we are calling the SYSAP
	    LOAD T2,CBSCID,(P1)	;Get the connect ID
	    SETZ T3,		;Say we were rejected
	    LOAD T4,MH$STS,(P2)	;Get reason code for rejection
	    CALL @.CBADR(P1)	;Call the SYSAP
	    CALL SC.PTC		;(P1/) Declare protocol complete
	  ENDIF.
	ENDIF.
	JRST SC.SAR		;Go send next SCS control message, return buffer
	SUBTTL Call from port driver -- Incoming buffer -- SC.ARQ (Accept request)

; Here to handle an ACCEPT_REQUEST.
;
;	Call
;	P2/	Address of message buffer
;	P4/	Address of system block
;
;	Return +1:	Always
;
SC.ARQ:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit
	MOVEM T1,P5		;Save new state
	MOVEM T2,P3		;Save op code of response

;If the connection is currently closed, then the sysap changed its mind after
;sending a connect_request.

	LOAD T3,CBCNST,(P1)	;If current state is closed, we want
	CAIN T3,.CSCLO		; to send an accept-response with
	JRST SAR.NG		; "no match"

;Copy data from the packet into the connect block
;* * * *
;NOTE: We've added the next two lines in order to talk to VMS.
;The connect ID that they send us with the connect_response isn't useful.
;For now, the copy remains in SC.ORS in case there's something wrong with
;this approach.

	LOAD T2,MH$SCI,(P2)	;Get source connect ID from packet
	STOR T2,CBDCID,(P1)	;Store as destination ID
; * * * *
	LOAD T2,MH$CDT,(P2)	;Get the credit field from the message header
	ADDM T2,.CBSCD(P1) 	;Calculate and store the new send credit
	LOAD T2,MH$MCR,(P2)	;Get the min credit out of the message header
	STOR T2,CBMNRC,(P1)	;Store it in the CB as the min send credit
	MOVEI T2,<C%SDTL+3>/4	;Number of words to move
	XMOVEI T3,.MGSDT(P2)	;Source address of connection data
	XMOVEI T4,.CBDTA(P1)	;Destination address for connect data
	EXTEND T2,[XBLT]	;Move the connection data

;Build and send the ACCEPT_RESPONSE message.

	MOVX T4,.CMCMT		;Get the universal MATCH code
	STOR T4,MH$STS,(P2)	;Put the status info into the message header
	MOVE T1,P3		;Get the op code
	CALL SC.RSP		;(T1,P1,P2,P4/)Send the response
	 JRST SC.RIB		;Failed. Return the buffer to the free queue

;Set new state

	STOR P5,CBCNST,(P1)	;Store connection state returned above
	
	;..
;Notify the SYSAP about what has happened.

	;..
   IFN SCARNG,<
        XMOVEI T1,.		;Get feature routine address
        MOVE T2,(P)		;Get PC of caller to feature routine
        MOVEI T3,.SSCRA		;Get callback notification code
        CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVEI T1,.SSCRA		;Say why we are calling
	LOAD T2,CBSCID,(P1)	;Say for whom we are calling
	SETO T3,		;Indicate accepted connection request
	XMOVEI T4,.CBDTA(P1)	;Build a pointer to the connection data
	CALL @.CBADR(P1)	;L E A P  . . . . .
	RET			;And return...

;Send accept_response "no match" because our side disconnected.
;State is already closed; no need to change it.

SAR.NG:	MOVE T1,P3		;Get op code for ACCEPT_RSP
	LOAD T2,CBSDRE,(P1)	;Get sysap's reason for disconnecting
	STOR T2,MH$STS,(P2)	;Store as the status
	CALL SC.RSP		;(T1,P1,P2,P4/)Send the response
	 JRST SC.RIB		;Failed. Return the buffer to the free queue
	CALL SC.PTC		;(P1/) Declare protocol complete
	RET
	SUBTTL Call from port driver -- Incoming buffer -- SC.ARS (Accept response)

; Here to handle an ACCEPT_RESPONSE.
;
;	Call
;	P2/	Address of message buffer
;	P4/	Address of system block
;
;	Return +1:	Always
;
SC.ARS:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit

	LOAD T2,CBCNST,(P1)	;Get old state
	LOAD T3,MH$STS,(P2)	;Get the status word from the message
	CAIE T2,.CSCLO		;Was it closed?
	IFSKP.
	  CAIE T3,.CMCMT	;Is the status MATCH?
	  IFSKP.
	    MOVEI T1,.BSDPN	;New block state is disconnect_pending
	    CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	  ELSE.
	    CALL SC.PTC		;No match. We've finished with this c.b.
	  ENDIF.

;Here when state was not closed. This is the normal case
;If match, tell sysap it's OK to send data. if no match, the other side
;changed its mind. Tell the sysap and declare protocol complete.

	ELSE.
	  CAIE T3,.CMCMT	;Match?
	  IFSKP.
	    STOR T1,CBCNST,(P1) ;Store the new connection state
   IFN SCARNG,<
      	    XMOVEI T1,.		;Get feature routine address
	    MOVE T2,(P)		;Get PC of caller to feature routine
	    MOVEI T3,.SSOSD	;Get callback notification code
	    CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	    MOVEI T1,.SSOSD	;Say why we are calling
	    LOAD T2,CBSCID,(P1)	;Provide local CID
	    CALL @.CBADR(P1)	;Make the leap of faith into the SYSAP
	  ELSE.
	    MOVEI T1,.CSCLO	;Get the closed state
	    STOR T1,CBCNST,(P1)	;Store as the new connection state
   IFN SCARNG,<
      	    XMOVEI T1,.		;Get feature routine address
	    MOVE T2,(P)		;Get PC of caller to feature routine
	    MOVEI T3,.SSRID	;Get callback notification code
	    CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	    MOVEI T1,.SSRID	;Say the remote has changed its mind
	    LOAD T2,CBSCID,(P1)	;Show who locally
	    CALL @.CBADR(P1)	;Tell the SYSAP about the change of mind
	    CALL SC.PTC		;(P1/) Declare protocol complete
	  ENDIF.
	ENDIF.
	JRST SC.SAR		;Go send next SCS control message, return buffer
	SUBTTL Call from port driver -- Incoming buffer -- SC.RRQ (Reject request)

; Here for REJECT_REQUEST received.
;
;	Call
;	P2/	Address of message buffer
;	P4/	Address of system block
;
;	Return +1:	Always
;
SC.RRQ:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit
	MOVEM T1,P5		;Save new state

;Get reason for rejection from the packet, and store it in the connect block

	LOAD T3,MH$STS,(P2)	;Find out why we were rejected
	STOR T3,CBDDRE,(P1)	;Store as his reason for saying "NO."

;Now build the response in the buffer we have from the REJECT_REQUEST.

	MOVE T1,T2		;Get op code returned above
	CALL SC.RSP		;(T1,P1,P2,P4/)Send the response
	 JRST SC.RIB		;Failed. Return the buffer to the free queue

;Now poke the SYSAP with its response to our connect.
;If state was already closed, don't change it. Sysap isn't interested
;in hearing about this.

	LOAD T1,CBCNST,(P1)	;Get old connection state
	CAIN T1,.CSCLO		;If closed, sysap isn't interested.
	IFSKP.
	  STOR P5,CBCNST,(P1)	;Store the new connection state
   IFN SCARNG,<
      	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,(P)		;Get PC of caller to feature routine
	  MOVEI T3,.SSCRA	;Get callback notification code
	  CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	  MOVEI T1,.SSCRA	;Tell the SYSAP why we are calling
	  LOAD T2,CBSCID,(P1)	;Get the connect ID
	  SETZ T3,		;Indicate that the connection was rejected
	  LOAD T4,CBDDRE,(P1)	;T4/ reason for rejection
	  CALL @.CBADR(P1)	;Call the SYSAP
	ENDIF.
	CALL SC.PTC		;(P1/) Declare protocol complete
	RET
	SUBTTL Call from port driver -- Incoming buffer -- SC.RRS (Reject response)

; Here to handle REJECT_RESPONSE messages.
;
;	Call
;	P2/	Address of message buffer
;	P4/	Address of system block
;
;	Return +1:	Always
;
SC.RRS:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit

;Set new state

	STOR T1,CBCNST,(P1)	;Set connection block state as returned above
	CALL SC.PTC		;Declare protocol complete
	JRST SC.SAR		;Go send next SCS control message, return buffer
	SUBTTL Call from port driver -- Incoming buffer -- SC.DRQ (Disconnect request)

; Here for DISCONNECT_REQUESTs.
;
;	Call
;	P2/	Address of message buffer
;	P4/	Address of system block
;
;	Return +1:	Always
;

;NOTE: This code assumes it's running at interrupt level. If it
;isn't, it must lock the c.b.

SC.DRQ:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit
	MOVEM T1,P3		;Save new state

;Copy reason for disconnect from packet to connect block

	LOAD T3,MH$STS,(P2)	;Get the disconnect reason
	STOR T3,CBDDRE,(P1)	;Stash the remote discconect reason in CB

;send a DISC_RSP

	MOVE T1,T2		;Get op code as returned above
	CALL SC.RSP		;(T1,P1,P2,P4/)Send the response
	 JRST SC.RIB		;Failed. Return the buffer to the free queue

;Honor the c.b. lock. If it's locked, set a flag. When the locker unlocks
;the block, this function will be completed.

	MOVX T1,CBFDRQ
	CALL SC.HNR		;(T1,P1/) See if the c.b. is locked
	 RET			;Yes. Can't finish this now

;Now store new state as returned above

	STOR P3,CBCNST,(P1)	;Store the new connection state

;If the new state is disconnect_received, previous state was open.
;This means the other side initiated the disconnect.

	CAIN P3,.CSDRE		;Is the state disconnect received???
	JRST SDR.CO		;Yes. Go handle that

;Here when new state is not disconnect_received. If new state is closed,
;protocol is complete. This happens when we initiate the disconnection, and
;the other side responds with a disconnect_request.

	CAIN P3,.CSCLO		;Is the new state closed?
	CALL SC.PTC		;(P1/) Yes. Indicate protocol is complete
	RET
	;..
;Here when new state is disconnect_received.
;Corporate spec says the sysap should be required to do a disconnect.
;We fake it by setting the state and sending the message.
;Set the state before calling the sysap. If it does an SC.DIS before returning
;we won't send two disconnect_requests.

SDR.CO:	MOVEI T1,.CSDMC		;New connection state is disconnect_match
	STOR T1,CBCNST,(P1)

;Tell the sysap that the other side hung up.

   IFN SCARNG,<
        XMOVEI T1,.		;Get feature routine address
        MOVE T2,(P)		;Get PC of caller to feature routine
        MOVEI T3,.SSRID		;Get callback notification code
        CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVX T1,.SSRID		;Get SYSAP notify code for remote disconnect
	LOAD T2,CBSCID,(P1)	;Tell the SYSAP which connection went away
	LOAD T3,CBDDRE,(P1)	;Return reason from packet status field
	CALL @.CBADR(P1)	;Notify sysap of disconnection

;Set block state to disconnect_pend to cause disconnect_request to be
;sent.

	MOVEI T1,.BSDPN		;New block state is disconnect_pend
	CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	CALL SC.SNM		;(P4/) Send the message if possible
	RET
;SC.FN3 - finish work of SC.DRQ when c.b. is unlocked

;Accepts:
;	P1/ address of c.b.
;	P4/ address of system block

;	CALL SC.FN3

;Returns +1: always

;CIOFF protects from incoming disconnect_response. Ordinarily, it can't
;interfere with incoming disc_req because both are at interrupt level.
;We must be CIOFF for the callback anyway.

SC.FN3:
	CIOFF
	SETZRO CBFDRQ,(P1)	;Clear indication that this was deferred
	MOVEI T1,.STDRQ		;Op code is disconnect_request
	IMULI T1,MXCNST		;Compute offset in the table based
	OPSTR <ADD T1,>,CBCNST,(P1) ; on op code and current state
	SOS T1			;States start at 1
	TMNE K.ERR,(T1)		;We can't handle protocol violation here
	BUG. (HLT,SCAFN3,SCAMPI,SOFT,<SCA - Can't complete deferred call to SC.DRQ>,,<

Cause:	PHYKLP called SCAMPI at SC.DRQ when the connection block was locked.
	At the time, the incoming packet was legal for the current state of
	the connection. Now it is not legal. This shouldn't happen, and it 
	is uncertain how to proceed. It is possible to close the v.c. and 
	continue, but there is a halt in order to analyze the protocol 
	confusion and fix the bug.
>)
	LOAD T1,K.STAT,(T1)	;Get new state
	STOR T1,CBCNST,(P1)	;Store the new connection state

;If the new state is disconnect_received, previous state was open.
;This means the other side initiated the disconnect.

	CAIN T1,.CSDRE		;Is the state disconnect received?
	JRST FN3.CO		;Yes. Go handle that

;Here when new state is not disconnect_received. If new state is closed,
;protocol is complete. This happens when we initiate the disconnection, and
;the other side responds with a disconnect_request.

	CAIN T1,.CSCLO		;Is the new state closed?
	CALL SC.PTC		;(P1/) Yes. Indicate protocol is complete
	CION
	RET

;Here when new state is disconnect_received.
;Corporate spec says the sysap should be required to do a disconnect.
;We fake it by setting the state and sending the message.
;Set the state before calling the sysap. If it does an SC.DIS before returning
;we won't send two disconnect_requests.

FN3.CO:	MOVEI T1,.CSDMC		;New connection state is disconnect_match
	STOR T1,CBCNST,(P1)

;Tell the sysap that the other side hung up.

;	CIOFF			;Sysap wants us to prevent interrupts
   IFN SCARNG,<
      	XMOVEI T1,.		;Get feature routine address
	MOVE T2,(P)		;Get PC of caller to feature routine
	MOVEI T3,.SSRID		;Get callback notification code
	CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVEI T1,.SSRID		;Get SYSAP notify code for remote disconnect
	LOAD T2,CBSCID,(P1)	;Tell the SYSAP which connection went away
	LOAD T3,CBDDRE,(P1)	;Return reason from packet status field
	CALL @.CBADR(P1)	;Notify sysap of disconnection
;	CION

;Set block state to disconnect_pend to cause disconnect_request to be
;sent.

	MOVEI T1,.BSDPN		;New block state is disconnect_pend
	CALL SC.SCA		;(T1,P1,P4/) Set block state and queue message
	SETONE CBFSNM,(P1)	;Indicate call to SC.SNM was deferred.
	CION
	RET
	SUBTTL Call from port driver -- Incoming buffer -- SC.DRS (Disconnect response)

; Here for DISCONNECT_RESPONSE
;
;	Call
;	P2/	Address of message buffer
;	P4/	Address of system block
;
;	Return +1:	Always
;
SC.DRS:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit

	STOR T1,CBCNST,(P1)	;Store the new connect state

;If new state is closed, this is confirmation of our disconnect_request.
;earlier we had received a disconnect_request and sent a disconnect_response
;If not, the other side still needs to send a disconnect_request

	CAIN T1,.CSCLO		;Is the next state CLOSED???
	CALL SC.PTC		;(P1/) Yes. Declare protocol complete
	JRST SC.SAR		;Go send next SCS control message, return buffer
	SUBTTL Call from port driver -- Incoming buffer -- SC.CRQ (Credit request)

; Here to receive CREDIT_REQUEST messages...
;
;	Call
;	P2/	Address of message buffer
;	P4/	Address of system block
;
;	Return +1:	Always
;
SC.CRQ:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit
	MOVEM T2,P5		;Save op code of response

	LOADE T1,MH$CDT,(P2)	;Get the credit field from the message header
	JUMPGE T1,SCR.RS	;Taking credit back?

;Here when the other side is withdrawing credit
;Don't allow this if send credit is already below the minimum, and don't
;allow it to go below the minimum

;Spec says

;if PTR^.CREDIT < 0 
;   then PTR^.CREDIT:=
;        -MIN(MAX(0,CB$SEND_CREDIT-CB$MIN_SEND_CREDIT),-PTR^.CREDIT)

;In our terms,
;	if .CBSCD < CBMNSC, use 0
;	if .CBSCD - CBMNSC .LT. T1, use -(.CBSCD-CBMNSC)
;	if .CBSCD - CBMNSC .GE. T1, use T1 as it is

;Implemented in the opposite sense:
;	Compute CBMNSC-.CBSCD
;	If positive, use 0
;	If .GT. T1, use the difference as computed
;	If .LE. T1, use T1 as it is

	LOAD T2,CBMNSC,(P1)	;Get minimum_send_credit
	SUB T2,.CBSCD(P1)	;Compute -(send_credit - minimum_send_credit)
	SKIPG T2		;Already below minimum?
	IFSKP.
	  SETZM T1		;Yes. Don't reduce at all
	ELSE.
	  CAMLE T2,T1		;Request too large?
	  MOVE T1,T2		;Yes. Reduce only to minimum_send_credit
	ENDIF.
	;..
;Send the response.

;	T1/ credit we decided to accept or give up

	;..
SCR.RS:	ADDM T1,.CBSCD(P1)	;Add this back into send credit
	STOR T1,MH$CDT,(P2)	;Put the credit amount back into the header
	EXCH T1,P5		;Get op code, save credit value
	CALL SC.RS2		;(T1,P1,P2,P4/)Send the response, don't zero credit
	IFNSK.
	  MOVNS P5		;Get negative of credit
	  ADDM P5,.CBSCD(P1)	;Restore credit to previous value
	  JRST SC.RIB		;Return the buffer to the free queue
	ENDIF.

;If the sysap has tried to send a message and failed because of lack of
;send credit, we need to notify it that credit has been given to it.
;Note that we must clear the flag BEFORE the call to the sysap, because
;it may try to send more messages, and run the credit down again, before
;returning control. In that case, SC.SMG could set the flag, and then this
;code would clear it.

	JUMPLE P5,R		;If not adding to credit, we've finished
	LOAD T1,CBCNST,(P1)	;Get current state of the connection.
	TMNE CBFNNC,(P1)	;Does sysap need notification?
	CAIE T1,.CSOPN		;Yes. Is connection open?
	RET			;Nope, return now
	SETZRO CBFNNC,(P1)	;Show notification complete, zero flag in CB
   IFN SCARNG,<
        XMOVEI T1,.		;Get feature routine address
        MOVE T2,(P)		;Get PC of caller to feature routine
        MOVEI T3,.SSCIA		;Get callback notification code
        CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVX T1,.SSCIA		;Say why we are calling, we have credit for you
	LOAD T2,CBSCID,(P1)	;Indicate which connection this for
	MOVE T3,.CBSCD(P1)	;Show the send credit 
	MOVE T4,.CBRCD(P1)	;Receive credit
	CALL @.CBADR(P1)	;Leap into the SYSAP
	RET
	SUBTTL Call from port driver -- Incoming buffer -- SC.CRS (Credit response)

; Here to receive a CREDIT_RESPONSE.
;
;	Call
;	P2/	Address of message buffer
;	P4/	Address of system block
;
;	Return +1:	Always
;

;NOTE:
;If credit field is negative, we can take buffers back from the port. If
;that fails, we have a problem. There will be disagreement among 1) our
;receive credit, 2) the other side's send credit, and 3) the number of
;buffers actually queued for this connection. This code attempts to
;keep 1 and 2 in agreement.

SC.CRS:	CALL SC.INC		;(P2/T1,T2,P1) Check validity, get state & op code
	 JRST SC.RIB		;Return the buffer and quit

;Get credit from message, and figure out what is required

	LOADE P3,MH$CDT,(P2)	;Get the credit field from the message header
	SKIPL .CBRQC(P1)	;Were we trying to get credit back?
	IFSKP.
	  MOVM T2,P3		;Get the number we were allowed
	  ADDM T2,.CBRTC(P1)	;Add into return credit.
   IFN SCADBG,<
	ELSE.
	  CAMN P3,.CBRQC(P1)	;Do we agree with the other end?
	  JRST SCC.YY		;Yes. Proceed
	  LOAD T1,SBDPA,(P4)	;Get node number
	  LOAD T2,CBSCID,(P1)	;Get connect ID
	  BUG. (CHK,SCAUCF,SCAMPI,SOFT,<SCA - Unexpected credit field in credit_request>,<<T1,NODE>,<T2,CID>>,<

Cause:	The response to a positive credit_request contains a credit value that
	is different from what is believed to have been sent.

Data:	NODE - Node number
	CID  - Connect ID
>)
   >				;End of IFN SCADBG
	ENDIF.
SCC.YY:	ADDM P3,.CBRCD(P1)	;Update the receive credit
SCC.XX:	SETZM .CBRQC(P1)	;If negative, don't let SC.RCB dequeue
				; because they are counted in return_credit
	SETZM .CBPND(P1)	;Indicate no credit_request pending
	CALL SC.CD1		;(P1,P4/) Queue credit_request if needed
	 NOP			;Don't care whether queued or not
	CALL SC.GCB		;(P1/) Get canceled buffers, if any
	JRST SC.SAR		;Go send the next message

;Common exit for incoming SCS control messages.

;Here when response arrived. This is the packet that is reserved for outgoing
;messages for the system block of interest. Use it to send the next message,
;or queue it to the system block for the next time it wants to send a request.

SC.SAR:	MOVEM P2,.SBOBB(P4)	;Queue buffer to system block
	CALL SC.SNM		;(P4/)Send next SCS control message
	RET

;Here to return buffer to the port. THis happens when the packet arrives
;after the v.c. has already been closed. If it was a request, we can't queue
;it to the system block, because SC.ERR has already run. If we queued it
;now, it would cause a problem when the node came online again, or stay there
;forever if the node never came back.

;Any failing attempt to send a response to a connection management request
;will come here. However, this shouldn't happen because of other checks that
;were made earlier.

;Failure to send a packet will occur only if the v.c. is closed. No attempt
;is made to handle the state of the connection or to notify the sysap when
;this happens, on the assumption that closing the v.c. took care of these things

SC.RIB:	SETZM (P2)		;Clear forward pointer in buffer
   IFN SCARNG,<
	XMOVEI T1,.		;Get feature routine address
	MOVE T2,(P)		;Get PC of caller to feature routine
	MOVEI T3,1		;Set buffer count
	MOVE T4,P2		;Get buffer address
	TXO T3,RPQFLK   	;Set port link flag
	TXO T3,RPQFMG    	;Set message free queue flag
	CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>				;End of IFN SCARNG
	BLCAL. (LNKMFQ,<P4,P2>)	;Return buffer to port's free queue
	RET
	SUBTTL Call from port driver -- Incoming buffer -- SC.INC (Connection management)

;SC.INC - process incoming packet

;Accepts:
;	P2/ address of buffer
;	P4/ address of system block

;	CALL SC.INC

;Returns +1: failure
;	 +2: success,

;		T1/ new state
;		T2/ op code of response
;		P1/ address of connection block

;Determines new state for connection, and appropriate response, for
;incoming SCS control message

;NOTE: callers to this routine give the buffer back to the port if this
;returns +1, on the assumption that the v.c. has been closed. If this
;routine is changed to handle failure in some other way, changes may be
;necessary in the callers.

SC.INC:	SAVEAC <P3>
	LOAD T1,SBVCST,(P4)	;If the v.c. is already closed, we aren't
	CAIE T1,VC.OPN		; interested in this packet
	RET
	LOAD P3,MH$MSG,(P2)	;Get the op code
	CAIN P3,.STORQ		;Special case for CONNECT_REQ
	RETSKP

;See whether we know about this connect ID

	LOAD T1,MH$DCI,(P2)	;Get destination connect-ID
	CALL SC.CSC		;(T1/T1,P1) Is it valid?
	 JRST SC.IN6		;No. Go handle the problem
   IFN SCADBG,<
	CAME P4,.CBSBA(P1) 	;Is address of system block OK
	JRST SC.IN4		;No.
   >				;end IFN SCADBG
;See whether this event is expected given the current state

	IMULI P3,MXCNST		;Compute offset in the table based
	OPSTR <ADD P3,>,CBCNST,(P1) ; on op code and current state
	SOS P3			;States start at 1
	JN K.ERR,(P3),SC.IN4	;If unexpected, go handle the error


	TMNN K.CHK,(P3)		;Want to check this response?
	IFSKP.
	  LOAD T3,MH$MSG,(P2)	;Yes. Get op code
	  OPSTR <CAMN T3,>,CBEXPR,(P1); Is this what we expected?
	  JRST SC.IN2		;Yes.
	  LOAD T1,SBDPA,(P4)	;Get node number
	  LOAD T2,CBSCID,(P1)	;Get out connect id
	  LOAD T4,CBEXPR,(P1)	;Get what we expected
	  BUG. (CHK,SCAUXR,SCAMPI,SOFT,<SCA - Unexpected response>,<<T1,NODE>,<T2,CID>,<T3,OPCODE>,<T4,EXPECT>>,<

Cause:	A connection management response arrived for a particular
	connection, but the op code is not the expected one.

Action:	The v.c. will be closed, on the assumption that the other node
	violated protocol. This may correct the confusion. If this error
	persists, try to determine the events that led to it. Use the
	ring buffer if necessary.

Data:	NODE   - Node number
	CID    - Connect ID
	OPCODE - Op code of incoming packet
	EXPECT - Expected op code for this connection
>)
	  JRST SC.IN7		;Go close the v.c.
	ENDIF.

;We like this packet. Return success to the caller.

SC.IN2:	LOAD T1,K.STAT,(P3)	;It's legal. Get new state
	LOAD T2,K.OP,(P3)	; and op code to send
	RETSKP			;Success
;Something unexpected happened. Handle the error here and return failure

SC.IN4:
	LOAD T1,SBDPA,(P4)	;get node number
	LOAD T2,CBSCID,(P1)	;get our connect ID
	LOAD T3,MH$MSG,(P2)	;get op code
	LOAD T4,CBCNST,(P1)	;get state of connection
	BUG. (CHK,SCAPER,SCAMPI,SOFT,<SCA - Protocol error>,<<T1,NODE>,<T2,CID>,<T3,OPCODE>,<T4,STATE>>,<

Cause:	An incoming message violated the SCS protocol. This message is 
	illegal. Closing the v.c. will eliminate any confusion.

Action:	If this persists, change it to a BUGHLT, and determine the sequence of
	events that led to it. Use the ring buffer, if necessary.

Data:	NODE   - Node number
	CID    - Connect ID at this node
	OPCODE - Op code of incoming packet
	STATE  - state of connection
>)
	JRST SC.IN7		;Go close the v.c.

;Here when destination CID doesn't exist. Complain. Note: Can't use common
;BUGCHK because there's no connection block.

SC.IN6:
	LOAD T1,SBDPA,(P4)	;Get node number
	LOAD T2,MH$DCI,(P2)	;Get destination CID
	LOAD T3,MH$MSG,(P2)	;Get op code
	BUG. (CHK,SCANOC,SCAMPI,SOFT,<SCA - Received packet and connection block doesn't exist>,<<T1,NODE>,<T2,CID>,<T3,OPCODE>>,<

Cause:	An incoming packet's destination CID doesn't match any connection block.
	This may reflect disagreement with another node about the state of
	a previously-existing connection.

Action:	The v.c. will be closed, which will correct the problem.
	If this bug persists, try to determine the events that led to it.
	Use the ring buffer if necessary.

Data:	NODE   - Node number
	CID    - Connect ID
	OPCODE - Op code
>)
	;..
;Close the v.c. and return failure

	;..

SC.IN7:	CALL SC.CVC		;(P4/) Close the v.c.
	RET			;Return failure
	SUBTTL Call from port driver -- Incoming buffer -- SC.ADG/SC.AMG (application datagram/message)

;Accepts:
;	T1/ Flags
;	T2/ Length (bytes if industry compatible; words if high density)
;	P2/ Address of packet
;	P4/ Address of system block

;	CALL SC.ADG/SC.AMG

;Returns +1: Always

;Caller did SAVEP

SC.ADG:
SC.AMG:
	LOAD T3,SBVCST,(P4)	;If the v.c. has already been closed
	CAIE T3,VC.OPN		; return the buffer
	JRST SAG.RT

;Save flags and packet length

	ANDX T1,C%FLGM		;Be sure to keep just the flag bits
	MOVEM T1,P3		;Save flags
	MOVEM T2,P5		;Save length

;Check for error cases -- invalid CID or invalid state

	LOAD T1,MH$DCI,(P2)	;Get destination connect ID from packet
	CALL SC.CSC		;(T1/T1,P1) Check if this connect ID is OK
	 JRST SAG.CL		;No. Close the v.c.
	LOAD T1,CBCNST,(P1)	;Get the connection state
	CAIN T1,.CSOPN		;Is the connect state open?
	JRST SAG.OK		;Yup, allow this to happen
	CAIE T1,.CSDAK		;Are we in the middle of sending
	CAIN T1,.CSDSE		;  or receiving a disconnect?
	JRST SAG.RT		;Yes. It's OK. Return the buffer
	JRST SAG.CL		;No. We shouldn't be getting this packet now
;Here when we are happy to receive this packet

SAG.OK:	STOR P5,MH$PKL,(P2)	;Store packet length where sysap expects it
	LOAD T2,MH$DCI,(P2)	;Sysap wants destination connect ID
	MOVE T3,P2		;Sysap wants address of packet
	LOAD P5,MH$MSG,(P2)	;Which kind of packet was this?
	CAIE P5,.STAMG		;Message?
	IFSKP.
	  SOS .CBRCD(P1)	;Yes. Decrease receive credit
	  LOAD T1,MH$CDT,(P2)	;Get credit from packet
	  ADDM T1,.CBSCD(P1)	; and increase send credit by this amount
	  MOVEM T1,P2		;* * *Note: P2 no longer points to buffer
	  MOVEI T1,.SSMGR	;Get reason code for sysap
	  XMOVEI T4,SC.RBF	;Address of buffer-returning routine
	ELSE.
	  SOSGE .CBDGR(P1)	;Datagram. Do we have a buffer queued?
	  JRST SAG.DD		;NO. Have to drop this datagram
	  MOVEI T1,.SSDGR	;Get reason code for sysap
	  XMOVEI T4,SC.RLD	;Address of buffer-returning routine
	ENDIF.
	IOR T4,P3		;Combine with flags
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1,T2,T3>	;Save smashed ACs
	  MOVE T3,T1		;Get callback notification code
      	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-5(P)		;Get PC of caller to feature routine
	  CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
	ENDBK.
>				;End of IFN SCARNG
	CALL @.CBADR(P1)	;Give the packet to the sysap
	CAIE P5,.STAMG		;Was this a message?
	RET			;No. We've finished, then.

;This was a message.
;If the remote sysap increased our send credit, and our sysap needs
;to be told, tell it now.

	TMNE CBFNNC,(P1)	;Sysap waiting for credit?
	SKIPN P2		;Yes. Did we get any?
	JRST SAG.XX		;No. Don't notify, then
	SETZRO CBFNNC,(P1)	;Indicate sysap no longer waiting
   IFN SCARNG,<
        XMOVEI T1,.		;Get feature routine address
        MOVE T2,(P)		;Get PC of caller to feature routine
        MOVEI T3,.SSCIA		;Get callback notification code
        CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVEI T1,.SSCIA		;Credit is available
	LOAD T2,CBSCID,(P1)	;Connect ID
	MOVE T3,.CBSCD(P1)	;Send credit
	MOVE T4,.CBRCD(P1)	;Receive credit
	CALL @.CBADR(P1)

;If this pushed our receive credit under the minimum, notify the
;sysap that little credit is left.

SAG.XX:	MOVE T1,.CBPRC(P1)	;Get the pending receive credit
	MOVE T2,.CBRCD(P1)	;  and the receive credit
	ADD T1,T2		;Get the sum of the two
	LOAD T2,CBMNRC,(P1)	;Get the minimum receive credit
	SUB T1,T2		;Differenec between threshold and what we have
	SKIPLE T1		;Is there more left???
	RET			;Yes return now...
	MOVM T3,T1		;Get the positive number of buffers to get
	AOS T3			;Increment just have an extra around
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T3>		;Save smashed ACs
      	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-3(P)		;Get PC of caller to feature routine
	  MOVEI T3,.SSLCL	;Get callback notification code
	  CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
	ENDBK.
>				;End of IFN SCARNG
	MOVX T1,.SSLCL		;Get the reason for our call
	LOAD T2,CBSCID,(P1)	;Get our connect ID
	CALL @.CBADR(P1)	;Call the SYSAP
	RET			;And return.
;Have to drop this datagram.

SAG.DD:
   IFN SCARNG,<
	XMOVEI T1,.		;Get feature routine address
        MOVE T2,(P)		;Get PC of caller to feature routine
        MOVEI T3,.SSDDG		;Get callback notification code
        CALL RG.SCS		;(T1,T2,T3,P1) Record callback event
>				;End of IFN SCARNG
	MOVEI T1,.SSDDG		;Get callback reason code
	LOAD T2,MH$DCI,(P2)	;Sysap wants destination connect ID
	CALL @.CBADR(P1)	;Call the SYSAP
	INCR CBCDD,(P1)		;Count a dropped datagram
	AOS .CBDGR(P1)		;Restore the count that we decremented
	JRST SAG.RT		;Go return the buffer

;Here when the packet shouldn't have come. Close the v.c.

SAG.CL:	CALL SC.CVC		;(P4/) Close the v.c.

;Return the buffer to the port.
;* * * *
;Might be better to adjust the count in the connection block and return
;the buffer to SCA. WOuld have to do this only when the c.b. still exists.
; * * * *

SAG.RT:	SETZM (P2)		;Clear FLINK word in buffer
	LOAD T1,MH$MSG,(P2)	;Get op code
	CAIE T1,.STAMG		;Message?
	IFSKP.
   IFN SCARNG,<
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,(P)		;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  MOVE T4,P2		;Get buffer address
	  TXO T3,RPQFLK   	;Set port link flag
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>				;End of IFN SCARNG
	  BLCAL. (LNKMFQ,<P4,P2>) ;Yes. Return buffer to port
	ELSE.
   IFN SCARNG,<
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,(P)		;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  MOVE T4,P2		;Get buffer address
	  TXO T3,RPQFLK   	;Set port link flag
	  TXZ T3,RPQFMG   	;Clear message free queue flag since datagram
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>				;End of IFN SCARNG
	  BLCAL. (LNKDFQ,<P4,P2>) ;No. Return datagram buffer
	ENDIF.
	RET
	SUBTTL Periodic functions

	SUBTTL Periodic functions -- SC.CLK (Dispatch)

;This routine is called by the scheduler at CLK2. 

;For debugging, it is useful to patch out the call to SC.IDL.

;
; Usage:
;	Call
;	No arguments
;
;	Return (+1) Always
;	No arguments returned
;

; * * * Seems to be called before initialization takes place. Should
;check that
; * * * 

SC.CLK::CALL SC.IDL		;Do idle chatter
	RET			;All done
	SUBTTL Periodic functions -- SC.IDL (Idle chatter)

; This routine handles idle chatter.
;	If a remote has not sent us a packet lately we will send it a credit
;request over an open connect. (Hence if there are no open connections then
;there is no idle chatter) 
;
; Usage:
;	Call
;	No arguments
;
;	Return (+1) Always
;	No data returned
;
SC.IDL:	SKIPE CITIMR		;TIMERS OFF FOR DEBUGGING?
	RET			;YES
	SAVEP			;NO
	MOVX T1,C%STIM		;Get the cycle time for the next loop
	MOVEM T1,SCATIM		;Reset the timer
	AOS T1,TMGSBI		;Get the next SBI we should look at
	CAIL T1,C%SBLL		;Have we gone off the end of the list???
	SETZB T1,TMGSBI		;Yes, reset to the start of the list
	SKIPN P4,SBLIST(T1)	;Is there an SB here???
	RET			;No, all done
	LOAD T1,SBVCST,(P4)	;Get the port to port virtual circuit state
	CAIE T1,VC.OPN		;If it's not open,
	RET			; punt on this SB
	SKIPN .SBFCB(P4)	;Are there any connections on this SB???
	RET			;No, we have nothing to do this time around
	SKIPN T1,.SBTIM(P4)	;Has this node ever spoken to us???
	RET			;No, ignore it
	SUB T1,TODCLK		;Yes, build long ago that was
	CAMLE T1,TMGTIM		;Has it been too long???
	RET			;No, return

;It's been a while since we heard from this node. If we already sent a
;timed message the last time we came through here, give up on it and close
;the v.c. Otherwise, go send a timed message.

	TMNN SBFTMG,(P4)	;Has a timed message been sent on this SB???
	JRST SCL.LP		;No.
	AOS TMGCNT		;Yes, count another system biting the dust
	LOAD T2,SBDPA,(P4)	;Get remote node number
	BUG. (INF,SCATMO,SCAMPI,SOFT,<SCA - SCA timed out remote node>,<<T2,NODE>,<T1,TIME>>,<

Cause:	SCA sent a message to another node, and did not receive a response
	within a timeout period.

Action:	This happens legitimately if a node crashes. If this timeout
	is occurring for nodes that appear to be running, try to determine
	why they are not communicating.

Data:	NODE - Node number
	TIME - time since we sent timed message
>)
	CALL SC.CVC		;(P4/) Close the v.c.
	RET			;  and we are all done with this SB
;Find a connection on this system block that is fully open
;If node goes offline while we're doing this, all attempts at sending
;will fail because connection state will be closed for each c.b.,
;and v.c. will be closed

;NOSKED is sufficient to protect the list of connection blocks, because
;the reaper runs in process context.

SCL.LP:
	NOSKED			;Prevent reaper from removing entries

;The following check needs some verification. However, it seems that if
;the buffer is in use, there's no need to send another message for timing
;purposes, because a message was just sent.

;	SKIPN .SBOBB(P4)	;Is the buffer in use now?
;	JRST SCL.EX		;Yes. Don't need to send another message, then

	SKIPN P1,.SBFCB(P4)	;Get addr of first CB
	JRST SCL.EX		;All CB's are gone, all done with this SB

;Try this connection block. If the connection state is OK, we'll send it
;a credit_request

SCL.TC:	CALL SC.LOK		;(P1/) Lock the connection block
	SETOM P3		;Assume we'll need to send something
	CALL SC.CD7		;(P1,P4/) Queue credit request if possible
	 SETZM P3		;Don't need to send a message
	CALL SC.ULK		;(P1/) Unlock the connection block
	SKIPN P3		;Can we send the credit_request?
	JRST SCL.NC		;No. Try another one

;We sent a credit_request to this node

	CALL SC.SNM		;(P4/) Send next message
	SETONE SBFTMG,(P4)	;Light the timed message sent flag
	JRST SCL.EX

;Step to next connection block on this system block

SCL.NC:	SKIPE P1,.CBANB(P1) 	;Is there a next connection?
	JRST SCL.TC		;Try it

SCL.EX:	OKSKED
	RET
	SUBTTL Periodic functions -- SC.RAP (Reap old connections)

; This routine is called by job 0. We don't need
;to be nearly that prompt so we only do anything real every 15 seconds.
;When we do go off, loop over the total set of connections known to SCA and
;reap connection blocks that have the reap bit lit. Also, light the reap bit
;for connections with the abort bit lit.
;
;	Call
;	No arguments
;
;	Return (+1) Always
;	No data returned
;
;

;This routine assumes that it is the only deleter of connection blocks.
;In particular, it assumes that no block in the chain can be deleted by
;some other process while it is searching through the chain.

SC.RAP::SAVEAC <P1,Q1,P5>

;Loop through all the system blocks

SRA.LP:	SETZRO CIREP		;WE'RE NOW REAPING
	SETO Q1,		;Fudge so we start with the zero'th SB
SRA.NS:	AOS Q1			;Move on to the next system block
	CAILE Q1,C%SBLL-1	;Have we run off the end of the list???
	JRST SRA.DC		;Yes, go do the dont care list
	SKIPN T2,SBLIST(Q1)	;Is there an entry here???
	JRST SRA.NS		;No, try the next system block

;Loop through all connection blocks for this system block

	SKIPN P1,.SBFCB(T2)	;Is there a first CB???
	JRST SRA.NS		;No, try the next system block
	;..
;We're interested in this block only if it's reapable. 
;This is indicated by the "reap" bit. If we are debugging, we'll make some
;sanity checks first. The sysap may have queued a buffer for output after
;the reap bit was set. If one or more buffers is still outstanding,
;we will wait a while.

	;..
SRA.CC:	MOVE P5,.CBANB(P1)	;Save the address of the next CB
	TMNN CBFRAP,(P1)	;Is it reapable?
	JRST SRA.CL		;No. Go check the next one

;Reap bit is set. Make sure we really mean it.

	TMNE CBNPO,(P1)		;Are packets still on the command queue?
	JRST SRA.PO		;Yes. Wait a while
   IFN SCADBG,<
	CALL SC.RRR		;(P1/) Is it really ready to reap?
	 JRST SRA.PO		;No. Postpone it, then
   >				;End of IFN SCADBG

;We mean it. Do the job.

	CALL SC.RCB		;(P1/) Reap the connect data
	JRST SRA.CL		;  and go on

;Postpone reaping because something hasn't been cleaned up. But if we do
;this several times, give up and reap anyway.

SRA.PO:	INCR CBRCNT,(P1)	;Count another postponement
	LOAD T1,CBRCNT,(P1)	;Have we had enough of this?
	CAIGE T1,RPMAX
	JRST SRA.CL		;Not yet. Go check next block

;Here when we've postponed reaping a number of times, and we're just going to
;do it anyway! The assumption is that the reason for delaying is invalid,
;that some bug is causing the count or FLINK word never to be zeroed.

	LOAD T1,CBSCID,(P1)	;Get connect ID
	MOVE T2,.CBSBA(P1)	;Get system block address
	LOAD T2,SBDPA,(T2)	;Get node number
	LOAD T3,CBBKST,(P1)	;BLock state
	LOAD T4,CBNPO,(P1)	;Number of queued commands
	BUG. (CHK,SCARTO,SCAMPI,SOFT,<SCA - Reap timed out>,<<T2,NODE>,<T1,CID>,<T3,STATE>,<T4,COUNT>>,<

Cause:	A block that is reapable cannot be reaped because either the count of
	outstanding packets is non-zero or a debugging check has failed. After
	several postponements, these were not corrected. The block is now being
	deleted.

Action:	If COUNT is non-zero, see if the CI-20 was reloaded recently.
	Buffers can be lost legitimately when this happens.

Data:	NODE  - Node number
	CID   - Connect ID at this node
	STATE - Block state
	COUNT - Contents of CBNPO (number of queued messages or datagrams)
>)

;* * * *NOTE: FOR NOW, DON't REAP SO WE CAN DEBUG IT!

;	CALL SC.RCB		;(P1/) Reap the data

;Here when finished with current c.b. Move on to next one.

SRA.CL:	MOVE P1,P5		;Get the address of the next CB in line
	JUMPN P1,SRA.CC		;If there is one, check it for reaping/aborting
	JRST SRA.NS		;Else, try for the next SB
; Here when we have finished all regular CB's and are ready to work on the
;don't care queue. Since these are listeners, there should be no reason to
;postpone reaping.

SRA.DC:	SKIPN P1,TOPDC		;Are there DC blocks to consider???
	RET			;No, return now pls
	CIOFF			;Protect against changes in the list
	MOVE P1,TOPDC		;Get the top of the list
SRA.DL:	SKIPE P1		;Is this a real entry?
	IFSKP.
	  CION			;No. We've finished
	  TMNN CIREP		;IS THERE MORE FOR US TO DO?
	  RET			;NO
	  JRST SRA.LP		;YES
	ENDIF.
	TMNE CBFRAP,(P1)	;Is this reapable?
	IFSKP.
	  MOVE P1,.CBANB(P1)	;No. Get the next one
	  JRST SRA.DL		; and continue
	ELSE.
	  CION			;Yes. Allow interrupts while we do it
	  CALL SC.RCB		;(P1/) Reap this block
	  JRST SRA.DC		;Go start over since list may have changed
	ENDIF.
;SC.RRR - see if we're really ready to reap

;Accepts:
;	P1/ address of connection block

;	CALL SC.RRR

;Returns +1: not ready
;	 +2: ready

   IFN SCADBG,<
SC.RRR:
	LOAD T1,SBDPA,(P4)	;Get node number for optional data
	LOAD T2,CBSCID,(P1)	;Get connect ID

;When we set the reap bit, we cleared the block state. If it's not zero now,
;something is wrong.

	TMNN CBBKST,(P1)	;Not ready if block state isn't zero
	IFSKP.
	  LOAD T3,CBBKST,(P1)	;Get block state
	  BUG. (CHK,SCABSN,SCAMPI,SOFT,<SCA - Block state non-zero when ready to reap>,<<T1,NODE>,<T2,CID>,<T3,STATE>>,<

Cause:	SCA is ready to delete a connection block, and its block state
	is non-zero. The block state should have been cleared when the reap
	bit was set.

Data:	NODE  - Node number
	CID   - Connect ID
	STATE - block state
>)
	  RET
	ENDIF.

;Check requeue credit. If it's non-zero, we must have sent out a credit_request
;to which we expect a reply.

	SKIPE T3,.CBRQC(P1)	;Non-zero implies credit_request outstanding
	TMNN CBFCVC,(P1)	; but it's bad only if v.c. is open
	IFSKP.
	  BUG. (CHK,SCANRC,SCAMPI,SOFT,<SCA - Non-zero requeue credit at SC.RCB>,<<T1,NODE>,<T2,CID>,<T3,CREDIT>>,<

Cause:	SCA is ready to delete a connection block, and its requeue credit is
	non-zero. This indicates that a credit_response is still expected.

Data:	NODE   - Node number
	CID    - Connect ID
	CREDIT - Requeue credit

>)
	  RET
	ENDIF.

;If the lock count is non-zero, some code thinks it still owns the connection
;block.

	SKIPN T3,.CBLCK(P1)
	IFSKP.
	  BUG. (CHK,SCANLC,SCAMPI,SOFT,<SCA - Non-zero lock count at SC.RCB>,<<T1,NODE>,<T2,CID>,<T3,COUNT>>,<

Cause:	SCA is ready to delete a connection block, and its lock count is
	non-zero.

Data:	NODE  - Node number
	CID   - Connect ID
	COUNT - lock count
>)
	  RET
	ENDIF.

;All's well. We reap.

	RETSKP			;Indicate we can reap it.
   >				;End of IFN SCADBG
; This routine dealocates a connection block. Simply call it with P1 set up
;to be the connection block address and it will make the block go away...
;
;Usage:
;	Call
;	P1/	Address of connection block
;
;	Return (+1) Always
;	No data returned, connection block has been dealocated.
;
SC.RCB::SAVEAC <Q1,P4>
	CIOFF			;Allow no other access to CB Q
	AOS RCBCNT		;Count another CB biting the dust
	MOVE P4,.CBSBA(P1)	;Get the pointer to the system block
	JUMPLE P4,SRC.DC	;Was this a dont care CB, if so P4 is -1
	CALL SC.RSQ		;(P1/) Remove from system block queue
	CION			;Has been take off CB queue, allow access

; Remove CID table entry from CIDTAB for this CB.  Keep the uniqueness bits
; stored in UBTTAB for later verification (used in routine SC.FUB).

	LOAD T1,CBSCID,(P1)	;Get the connect ID from the CB
	LOAD T4,INDEX,T1	;Extract the index from the CID
	MOVE T1,T4		;Get a copy we can smash
	ADD T1,CIDTAB		;Add the offset to the CB addr table
	SETZM (T1)		;Zero the address entry for this CB

;Here to get buffers back from the message free queue.

SRC.NJ:	
	MOVE Q1,.CBRCD(P1)	;Get the total current credits
	ADD Q1,.CBPRC(P1)	;add the number of pending credits
	ADD Q1,.CBRQC(P1)	; and number of credits in outstand CDT_REQ
	ADD Q1,.CBRTC(P1)	;Add canceled buffers not yet dequeued
	JUMPE Q1,SRC.DG		;If nothing to dequeue, try datagrams
SRC.B1:	BLCAL. (ULNKMG,<P4>)	;(/T1) Get a buffer back from the port
	IFNSK.
	  LOAD T1,SBDPA,(P4)	;Get node number
	  LOAD T2,CBSCID,(P1)	;Get connect ID
	  BUG. (CHK,SCACGM,SCAMPI,SOFT,<SCA - Can't get message buffer when reaping>,<<T1,NODE>,<T2,CID>,<Q1,COUNT>>,<

Cause:	While reaping a connection block, a receive credit indicates that
	message buffers are queued to the port. However, the port's queue has
	been emptied while these buffers were removed.

Data:	NODE  - node number
	CID   - Connect ID
	COUNT - number of buffers remaining to be dequeued
>)
   IFN SCARNG,<
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-3(P)		;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  SETOM T4		;Set buffer address to -1 due to failure
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>	         		;End of IFN SCARNG
	  JRST SRC.DG		;No message buffers left, do datagrams
	ENDIF.
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Save smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-6(P)		;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	CALL SC.RBF		;(T1/) Return the buffer to SCA free pool 
	SOJG Q1,SRC.B1		;  and loop if there are more buffers left
	;..

; Here to get datagram buffers back from the free queue.

	;..
SRC.DG:	MOVE Q1,.CBDGR(P1)	;Get the number of datagrams queued
	JUMPE Q1,SRC.EX		;Is there are none queued, exit now
SRC.DL:	BLCAL. (ULNKDG,<P4>)	;Unlink a datagram
	IFNSK.
	  LOAD T1,SBDPA,(P4)	;Get node number
	  LOAD T2,CBSCID,(P1)	;Get connect ID
	  BUG. (CHK,SCACGD,SCAMPI,SOFT,<SCA - Can't get datagram buffer when reaping>,<<T1,NODE>,<T2,CID>,<Q1,COUNT>>,<

Cause:	When reaping a connection block, a buffer count indicates that
	datagram buffers are queued to the port. However, the port's queue has
	been emptied while these buffers were removed.

Data:	NODE  - node number
	CID   - Connect ID
	COUNT - number of buffers remaining to be dequeued
>)
   IFN SCARNG,<
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-3(P)		;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  SETOM T4		;Set buffer address to -1 due to failure
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXZ T3,RPQFMG   	;Clear message free queue flag since datagram
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>	         		;End of IFN SCARNG
          JRST SRC.EX		;Can't get any more
	ENDIF.
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Save smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-6(P)		;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXZ T3,RPQFMG   	;Clear message free queue flag since datagram
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	CALL SC.RLD		;(T1/)  and return it to the SCA free pool
	SOJG Q1,SRC.DL		;Loop if there are more buffers to do

SRC.EX:
;	CALL SC.JSY		;(P1/) Clean up data for JSYS connection
	JRST SRC.KL		;Go kill the buffer

; Here when we are deleting an entry from the dont care listen queue. We can 
;make some nice assumptions about this CB here. It was never in any state other
;than listen, hence no checks need be made for buffers, or blocks hanging
;off this CB. It only needs to be removed from the don't care queue and
;the fork queue of the owning fork (if this is a JSYS connect).
;
SRC.DC:	CALL SC.RDQ		;(P1/) Remove it from don't-care queue
	CION			;Restore CI interrupts

;delete the connection block

SRC.KL:	MOVE T1,P1		;Move addr of CB to be released
	CALL SC.RBF		;Release buffer space back to free pool
	RET			;  and return OK...

COMMENT |

;SC.JSY - Do cleanup required for a JSYS connection
;
;Accepts:
;	P1/ address of connection block
;
;	CALL SC.JSY
;
;Returns +1: always
;
SC.JSY:
;
; If this is a JSYS connection, remove it from the fork CB queue.
;
	MOVE T2,.CBFLG(P1)	;Get the CB flags
	TXNE T2,<CBFJSY>	;Is this a JSYS connection???
	TXNE T2,<CBFKIL>	;A JSYS connect, is the fork gone???
	RET			;Not a JSYS connect, or, if a JSYS connect the
				;   fork has been killed already  

	SETZ Q1,		;Clear the RELCPT flag
	LOAD T4,CBFORK,(P1)	;Get the controlling fork number
	CAME T4,FORKX		;Is this the current fork???
	IFNSK.
	  SETO Q1,		;Set the RELCPT flag
	  LOAD T1,FKPS%,(T4)	;Nope, get the SPT slot for the PSB
	  CALL SETCPT		;Map the target PSB
	  MOVEI T1,SCSTCQ	;Get the rightmost 18 bits of the queue top
	  ANDI T1,777		;Keep only the offset pls...
	  XMOVEI T1,CPTPGA(T1)	;Get the address of the queue top pointer
	  MOVEI T2,SCSBCQ	;Get the right 18 bits of the queue bottom
	  ANDI T2,777		;Keep just the page offset
	  XMOVEI T2,CPTPGA(T2)	;Now get the address of queue bottom pointer
	  MOVES (T2)		;Reduce chance of NOSKED page faults
	ELSE.
	  XMOVEI T1,SCSTCQ	;This is current fork, get Q top pointer
	  XMOVEI T2,SCSBCQ	;  and addr of queue bottom pointer
	 ENDIF.

	NOSKED			;Time to diddle the fork queues
	LOAD T3,CPJNB,(P1)	;Get the addr of the next fork CB
	LOAD T4,CPJPB,(P1)	;  and the addr of the previous
	SKIPN T3		;Is this the last buffer to come off???
	SKIPE T4		;.	.	.
	JRST SRC.NL		;No, handle case of other entries left
	SETZM (T1)		;Last entry, zero the list head
	XMOVEI T1,SCSTCQ	;Always use real top of queue address
	MOVEM T1,(T2)		;  to init tail as pointer to head
	OKSKED			;We are last entry, allow access again
	JRST SRC.BD		;Now go handle any BSD's we have on this CB

; Not the last entry on the fork CB queue.
;
SRC.NL:	SKIPE T3		;Is there a next entry???
	STOR T4,CPJPB,(T3)	;Yes, update previous pointer of next CB
	SKIPE T4		;Is there a previous entry???
	STOR T3,CPJNB,(T4)	;Yes, update next field of previous entry
	OKSKED			;Done with Q pointers allow access again

; Note: We assume here that there are no pending packets on this CB. We make
;this assumption since one of two things has happened. Either the queue has
;been cleared by now or the KLIPA has been reloaded. In either case there
;are no more pending packets for this connect. No matter what the count
;may be...

SRC.BD:	SKIPE Q1		;Do we need to call RELCPT???
	CALL RELCPT		;Yes, release the mapped PSB page...

	OPSTR <SKIPN T1,>,CBTBQ,(P1) ;Are there BSD's on this connection???
	JRST SRC.DQ		;No, go do queue entry deallocation
	CALL SCM.RD		;Return Datagrams

; Here to take entries off all of the JSYS queues (messgae, datagram, DMA, and
;event).
;
SRC.DQ:	OPSTR <SKIPN T1,>,CBTMQ,(P1) ;Are there any messages for this connection???
	JRST SRC.DD		;No, try for datagrams
	XMOVEI T2,MSG		;This is a message block
	CALL SCSDEQ		;Remove it from the fork and CB queues
	CALL SC.RBF		;Return the message buffer
	JRST SRC.DQ		;Loop for all message buffers on the CB

; Here to get entries back from the datagram queue
;
SRC.DD:	OPSTR <SKIPN T1,>,CBTDQ,(P1) ;Are there any datagrams for this connection???
	JRST SRC.DX		;No, try for DMA blocks
	XMOVEI T2,DG		;This is a datagram block
	CALL SCSDEQ		;Remove it from the fork and CB queues
	CALL SC.RLD		;Return the datagram buffer
	JRST SRC.DD		;Loop for all datagram buffers on the CB

; Here to get entries back from the DMA queue
;
SRC.DX:	OPSTR <SKIPN T1,>,CBTXQ,(P1) ;Are there any datagrams for this connection???
	JRST SRC.DE		;No, try for DMA blocks
	XMOVEI T2,XFER		;This is a datagram block
	CALL SCSDEQ		;Remove it from the fork and CB queues
	CALL RELRES		;Release the DMA block
	JRST SRC.DX		;Loop for all DMA block

; Here to get entries back from the event queue
;
SRC.DE:	OPSTR <SKIPN T1,>,CBTEQ,(P1) ;Are there any events for this connection???
	RET			;No. Finished
	XMOVEI T2,EVT		;This is an event block
	CALL SCSDEQ		;Remove it from the fork and CB queues
	CALL RELRES		;Return the event block
	JRST SRC.DE		;Loop for all event blocks on the CB
	RET

| ; End COMMENT 
	SUBTTL Periodic functions -- SC.ALM (Allocate buffers)

;SC.ALM - Allocate buffers

;Called by CIFORK when CIBUF is non-zero.

SC.ALM::SKIPN SCAINI		;Have we inited yet???
	RET			;No, return now
SC.AL1:	SETZRO CIBUF		;WE'RE CREATING BUFFERS
	CALL SC.DEF		;Do buffer deferral requests
	CALL SC.ALC		;Allocate buffers to get us up to thresholds
	TMNN CIBUF		;MORE WORK TO DO?
	RET			;NO
	JRST SC.AL1		;YES
	SUBTTL Periodic functions -- SC.ALC (Allocate buffers for pool)

; Here to check on buffer levels. First do messages.

SC.ALC:	MOVE T1,MINMSG		;Get current min message threshold
	SUB T1,FQCNT		;How many do we need?
	JUMPLE T1,SAL.DG	;We have enough
	CALL SC.CMG		;(T1/T1,T2,T3) Create the message buffers
	IFNSK.
	  MOVE T2,FQCNT
	  BUG. (CHK,SCAMCF,SCAMPI,SOFT,<SCA - Message buffer creation failure>,<<T1,ERROR>,<T2,COUNT>>,<

Cause:	SCA detected that the level of buffers maintained was below minimum.
	The attempt to create more message buffers failed.

Data:	ERROR - error code
	COUNT - number of message buffers in SCA's pool
>)


	 JRST SAL.DG		;  and try for datagrams
	ENDIF.
 	CIOFF			;No interrupts pls...
	MOVEM T1,@BOTFQ		;Link these new buffers onto datagram Q
	MOVEM T2,BOTFQ		;Update the tail pointer
	ADDM T3,FQCNT		;Update the buffer count
	ADDM T3,TOTMGB		;   and the total number of buffers created
   IFN SCADBG,<
	CALL SC.TMQ		;Trace the message free queue
>				;End of IFN SCADBG
	CION			;Allow access again
	;..
;Here to allocate datagrams as needed

	;..
SAL.DG:	MOVE T1,MINDG		;Get the current DG threshold
	SUB T1,DFQCNT		;How many do we need?
	JUMPLE T1,R		;None
	CALL SC.CDG		;(T1/T1,T2,T3) Create the datagram buffers
	IFNSK.
	  MOVE T2,DFQCNT
	  BUG. (CHK,SCADCF,SCAMPI,SOFT,<SCA - Datagram buffer creation failure>,<<T1,ERROR>,<T2,COUNT>>,<

Cause:	SCA detected that the level of buffers maintained was below minimum.
	The attempt to create more datagram buffers failed. The error code is
	in T1. Output is given as additional data.

Data:	ERROR - error code
	COUNT - number of datagram buffers in SCA's pool
>)
	 RET			;  and return
	ENDIF.
	CIOFF
	MOVEM T1,@BOTDFQ	;Link these new buffers onto datagram Q
	MOVEM T2,BOTDFQ		;Update the tail pointer
	ADDM T3,DFQCNT		;Update the buffer count
	ADDM T3,TOTDGB		;  and the total number of buffers created
   IFN SCADBG,<
	CALL SC.TDQ		;Trace the datagram free queue
>				;End of IFN SCADBG
	CION
	RET			;All done...
	SUBTTL Periodic functions -- SC.DEF (Allocate deferred buffers for sysap)

;SC.DEF - Handle buffer deferral

;No arguments

;Returns +1: always

;Called by job 0 in case there are connections waiting for buffers
;before sending connect_request or accept_request messages

SC.DEF:	SKIPN T1,SBSTUK		;Any system blocks stuck?
	RET	
	SAVEP
SBD.FB:	JFFO T1,SBD.ST		;Find first system block that's stuck
	RET			;Could happen if node went offline
SBD.ST:	SKIPN P4,SBLIST(T2)	;Get system block address
	BUG. (HLT,SCANSB,SCAMPI,SOFT,<SCA - System block has gone away>,<<T2,NODE>>,<

Cause:	SC.DEF found a system block marked as stuck for buffers, but the address
	of the system block is 0.

Data:	NODE - Node number
>)

;Mark this system block as no longer stuck. If SC.SNM runs while we're
;in here, and finds some new c.b. stuck, it'll set the bit and we'll detect
;it on the way out.

	MOVE T1,BITS(T2)
	ANDCAM T1,SBSTUK	;Clear stuck bit for this s.b.
	SETZM P3		;Clear record of first c.b. found on list

;Find the first connection block on the work queue.
;We'll process any entry that needs buffers, even if it's not already
;stuck.

SBD.BA:	CALL SC.RWQ		;(P3,P4/P1,P3) Get and lock next entry
	 JRST SBD.XT		;End of the list

;If connection state is closed, sysap did a disconnect after doing a
;connect, and before we had sent the connect_request. No need to allocate
;buffers or send the request.

;To detect SC.ACC followed by SC.REJ, we'd have to look for block state
;of reject_pending while CBIMB or CBIDB was still non-zero. We just
;let that one happen. It will be cleaned up later.

	LOAD T1,CBCNST,(P1)	;Get connection state
	CAIN T1,.CSCLO		;No. Is it closed?
	JRST SBD.CC		;Yes.
	;..
;Get buffers needed by this connection
	;..

	CALL SC.BF2		;Get the buffers if we can
	 JRST SBD.ER		;Failed. This shouldn't happen in process context

;Mark the connection block as no longer stuck, and go find the next
;one

	SETZRO CBFSOB,(P1)	;No longer stuck on buffers
	SKIPN P3		;Have we recorded first moved block?
	MOVEM P1,P3		;No. This is it, then
	CALL SC.AWQ		;(P1,P4/) Put on the end of the queue
	CALL SC.ULK		;(P1/) Unlock the connection block
	JRST SBD.BA		;Go get next connect block for this s.b.

;Connection has been closed since this c.b. was queued. There's no need
;to create buffers or send a message.

SBD.CC:	SETZRO <CBIMB,CBIDB>,(P1); Don't need buffers now
	SETZRO CBFSOB,(P1)	;No longer stuck
	CALL SC.PTC		;(P1/) Finished with this c.b.
	CALL SC.ULK		;(P1/) Unlock the connection block
	JRST SBD.BA		;Go get the next c.b.

;Nothing left to do for this system block. See if another one needs help.

SBD.XT:
	CALL SC.SNM		;(P4/) Maybe we can send something now
	SKIPE T1,SBSTUK		;Any more stuck system blocks?
	JRST SBD.FB		;Go get the next system block that's stuck
	RET
;Here when we couldn't create buffers. Ultimately, we should handle
;this better but for now, we expect process context to succeed in creating
;a page.

SBD.ER:
	LOAD T2,SBDPA,(P4)	;Get node number
	LOAD T3,CBSCID,(P1)	;Get CID
	BUG. (HLT,SCAEBD,SCAMPI,SOFT,<SCA - Error handling buffer deferral request>,<<T2,NODE>,<T3,CID>,<T1,ERROR>>,<

Cause:	SCA was unable to create buffers when running in job 0. This should 
	never happen since job 0 can create pages as needed.

Data:	NODE  - Node number
	CID   - Connect ID
	ERROR - error code
>)

;If we turn this into a BUGCHK, this code should work:

REPEAT 0,<
	SETONE CBFSOB,(P1)	;Leave it stuck
	SKIPN P3
	MOVEM P1,P3		;Record this as having been moved
	CALL SC.AWQ		;Requeue it
	CALL SC.ULK		;(P1/) Unlock the connection block
	LOAD T1,SBDPA,(P4)
	MOVE T1,BITS(T1)
	IORM T1,SBSTUK
	JRST SBD.BA
   >				;END OF REPEAT 0
	SUBTTL Connection management utility routines

	SUBTTL Connection management utility routines -- SC.SCA (Send connection management message)

;SC.SCA - Set block state and queue SCS control message

;Accepts:
;	T1/ new state
;	P1/ address of connection block
;	P4/ address of system block

;	CALL SC.SCA

;Returns +1: always

;Caller must have locked connection block

;It is possible to find block state non-zero here. This can happen,
;for example, if we had the c.b. queued waiting to send a credit_request,
;and a disconnect_request came in. In that case, we will store the new
;state on top of the old one. The block will already be queued, so we won't
;try to queue it again. This should happen only rarely.

SC.SCA:
	TMNN CBBKST,(P1)	;Is state zero?
	IFSKP.
	  MOVE T3,.CBSBA(P1)	;Get address of system block
	  LOAD T3,SBDPA,(T3)	;Get node number
	  LOAD T4,CBSCID,(P1)	;Get CID
	  LOAD T2,CBBKST,(P1)	;Get block state
	  BUG. (INF,SCASBN,SCAMPI,SOFT,<SCA - Block state already non-zero>,<<T3,NODE>,<T4,CID>,<T2,OLDSTA>,<T1,NEWSTA>>,<

Cause:	While trying to set a connection's block state, it is found to be 
	already non-zero. This can happen legitimately under some conditions.

Action:	If the old state is anything except CREDIT_PEND, something is wrong.
	Try to trace the events that led to this, using the ring buffer, if
	necessary.

Data:	NODE   - Node number
	CID    - Connect ID
	OLDSTA - existing block state
	NEWSTA - state we're trying to set
>)
	  STOR T1,CBBKST,(P1)	;Store over it
	  RET			;But don't try to queue it again
	ENDIF.
	STOR T1,CBBKST,(P1)	;Set state as requested
	CALL SC.AWQ		;(P1,P4/) Add this c.b. to the work queue
	RET
	SUBTTL Connection management utility routines -- SC.SNM (Send next connection management message)

;SC.SNM - send an SCS control message

;Accepts:
;	P4/ Address of system block

;	CALL SC.SNM

;Returns +1: always

;Sends an SCS control message for this system block if the buffer is
;available and there's a waiting connnection block. If the c.b. requires
;buffers, creates them if possible. Otherwise, moves the c.b. to the
;end of the queue and tries the next one.

SC.SNM:
	SKIPN .SBTWQ(P4)	;Is there a c.b. that needs something?
	RET			;No. Nothing to do.
	SAVEP
	SETZM P2		;Prepare to clear the address of the buffer
	EXCH P2,.SBOBB(P4)	;Grab outbound buffer if it's there
	JUMPE P2,R		;It was in use. We'll come here later
	SETZM P3		;Initialize address of first c.b. moved

;Here when buffer is available, and there's something to be done.
;Remove first entry from work queue

SSN.BA:	CALL SC.RWQ		;(P3,P4/P1,P3) Get and lock next entry
	 JRST SSN.XT		;There isn't one.

;Block state shouldn't be zero. Complain if it is

   IFN SCADBG,<
	TMNE CBBKST,(P1)	;Is block state still non-zero?
	IFSKP.
	  LOAD T1,SBDPA,(P4)	;Get node number
	  LOAD T2,CBSCID,(P1)	;Get connect ID
	  LOAD T3,CBCNST,(P1)	;Get connection state
	  BUG. (CHK,SCABSZ,SCAMI,SOFT,<SCA - Block state is zero when trying to send connection management request>,<<T1,NODE>,<T2,CID>,<T3,STATE>>,<

Cause:	A connection block is on the system block's work queue, but its block
	state is zero. This value should be non-zero to indicate the kind of
	request to be sent.

Data:	NODE  - Node number
	CID   - Connect ID
	STATE - Connection state

>)
	  CALL SC.PTC		;(P1/) Allow reaper to get this block
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  JRST SSN.BA		;Don't try to send.
	ENDIF.
   >				;end of ifn scadbg

;This probably isn't necessary, but we'll do it just in case.
;If the "reap" bit is on, we shouldn't be sending any requests.
;If block state is non-zero, reap shouldn't be set.

   IFN SCADBG,<
	TMNN CBFRAP,(P1)	;Are we ready to reap this block?
	IFSKP.
	  LOAD T1,SBDPA,(P4)	;Get node number
	  LOAD T2,CBSCID,(P1)	;Get CID
	  BUG. (CHK,SCARBS,SCAMPI,SOFT,<SCA - Reap bit is set when block state is non-zero>,<<T1,NODE>,<T2,CID>>,<

Cause:	A connection block is marked as both waiting to send a request 
	message as reapable. The reapable bit should be set only when
	there is no need to send further requests.

Action:	The message is not sent and the block is deleted. If the
	problem persists, use the ring buffer to trace the events leading
	to it.

Data:	NODE - Node number
	CID  - Connect ID at this node
>)
	  CALL SC.PTC		;(P1/) Finish off this block
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  JRST SSN.BA		;Go handle next c.b.
	ENDIF.
   >				;END IFN SCADBG

;It is possible for the connection state to be closed here. We could
;check for that and refuse to send connect_request. Instead, we just
;let it go. When accept_request comes in, we'll send accept_response NM

;If this connection block is already stuck on buffers, move it to the
;end of the queue.

	TMNE CBFSOB,(P1)	;Are we stuck on buffers?
	JRST SSN.SB		;Yes. Move it to the end of the queue
;Get buffers that we want, if possible


	CALL SC.BF1		;(P1/) Allocate buffers if we need them
	 JRST SSN.SB		;Couldn't get them all

;Here when we got the buffers we wanted, or didn't want any. Create the
;packet and send it.

	CALL SC.RQS		;(P1,P2,P4/) Build packet, set new state, send
	IFNSK.
	  CALL SC.ULK		;(P1/) Unlock the connection block
	  JRST SSN.SF		;Couldn't send
	ENDIF.
	CALL SC.ULK		;(P1/) Unlock the connection block
	RET

;Here when we couldn't get the buffers needed or connection block was already
;stuck. Mark the connect block as "stuck on buffers" so that job 0 can
;fix things. Mark the system block, too.


SSN.SB:
	SETONE CBFSOB,(P1)	;Mark c.b. as stuck on buffers
	SKIPN P3		;Is this the first block moved to end?
	MOVEM P1,P3		;Yes. record it
	CALL SC.AWQ		;(P1,P4/) Move entry to end of queue
	CALL SC.ULK		;(P1/) Unlock the connection block
	LOAD T1,SBDPA,(P4)	;Get node number
	MOVE T1,BITS(T1)	;Get bit position for this index
	IORM T1,SBSTUK		;Mark system block as stuck
	JRST SSN.BA		;Go see if another entry exists
;Here when all the connection blocks that are left require buffers
;or there aren't any blocks

;We have to keep the buffer that we had planned to use for the message
;Job 0 will run eventually and create the buffers needed, and send
;the next message.

;If v.c. has been closed, then SC.ERR has already checked SBOBB. We
;must give the buffer to the port, since we already took one from it.

SSN.XT:	CIOFF
	LOAD T1,SBVCST,(P4)	;Is v.c. open?
	CAIE T1,VC.OPN
	IFSKP.
	  MOVEM P2,.SBOBB(P4)	;Yes. Return buffer to system block
	  CION
	  SKIPN SBSTUK		;Is a system block stuck?
	  IFSKP.
	     SETONE CIBUF	;Ask CIFORK fork to run for us
	  ENDIF.
	  RET
	ENDIF.
	CION

;Here when the v.c. has been closed. Give the buffer to
;the port, since we won't be needing it.

SSN.SF:
   IFN SCARNG,<
	XMOVEI T1,.		;Get feature routine address
	MOVE T2,(P)		;Get PC of caller to feature routine
	MOVEI T3,1		;Set buffer count
	MOVE T4,P2		;Get buffer address
	TXO T3,RPQFLK   	;Set port link flag
	TXO T3,RPQFMG   	;Set message free queue flag
	CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>				;End of IFN SCARNG
	SETZM 0(P2)		;Tell PHYKLP there's only one buffer
	BLCAL. (LNKMFQ,<P4,P2>) ;Link buffer onto port's message free queue
	RET
	SUBTTL Connection management utility routines -- SC.AWQ (Add entry to work queue)

;SC.AWQ - add an entry to the work queue

;Accepts:
;	P1/ address of connection block
;	P4/ address of system block

;	CALL SC.AWQ

;Returns +1: always

;Adds c.b. to end of s.b.'s work queue

;Caller must lock the connection block

SC.AWQ:	CIOFF			;Protect the work queue
	LOAD T1,SBVCST,(P4)	;If v.c. is not open
	CAIN T1,VC.OPN
	IFSKP.
	  CION			; don't try to send
	  RET
	ENDIF.
	MOVE T1,.SBBWQ(P4)	;Get last entry in queue
	XMOVEI T2,.SBTWQ(P4)	;Get head of queue
	CAMN T1,T2		;Empty if equal
	IFSKP.
	  MOVEM P1,.CBNWQ(T1)	;Make old "last" point to this
	ELSE.
	  MOVEM P1,.SBTWQ(P4)	;Make this be the first
	ENDIF.
	MOVEM P1,.SBBWQ(P4)	;Make this be the last
	CION
	RET
	SUBTTL Connection management utility routines -- SC.RWQ (Remove entry from work queue)

;SC.RWQ - remove entry from system block work queue

;Accepts:
;	P3/ address of connection block to stop at
;	P4/ address of system block

;	CALL SC.RWQ

;Returns +1: no more entries
;	 +2: entry available and locked
;		P1/ address of connection block
;		P3/ updated if necessary

;Returns non-skip when there are no more entries to be processed.
;Caller initializes P3 to 0. If it returns a block to the queue, it
;stores that block's address in P3. It does this only once, to record
;the first block that has already been seen. This routine will detect when it
;has looped around to the first block. Also, if this routine finds a connection
;block locked, it will move the block to the end of the queue, and update
;P3 appropriately.

;NOTE: This routine is closely coupled to SC.SNM and SC.DEF. It is 
;not meant to be called by other routines.

SC.RWQ:
	CIOFF			;Protect the work queue
SCR.LP:	SKIPN P1,.SBTWQ(P4)	;Get first entry on queue
	JRST SRW.EX		;Empty.
	CAMN P1,P3		;Have we found this buffer before?
	JRST SRW.EX		;Yes. We've finished with this system block
	SKIPE T1,.CBNWQ(P1)	;Point to the second entry
	IFSKP.
	  XMOVEI T2,.SBTWQ(P4)	;This is the end. Make tail point
	  MOVEM T2,.SBBWQ(P4)	; to head
	ENDIF.
	MOVEM T1,.SBTWQ(P4)	;Make head point to next or 0
	SETZM .CBNWQ(P1)	;Indicate no longer on queue
	MOVX T1,CBFSNM		;Flag to set if we have to defer
	CALL SC.LAH		;(T1,P1/) Get the lock if possible
	 JRST SRW.NX		;We have to defer
	CION
	RETSKP

;Here when the connection block was locked. Move it to the end of the
;list and continue looking for a good entry.

SRW.NX:	SKIPN P3		;Have we recorded first moved block?
	MOVEM P1,P3		;No. This is it, then
	CALL SC.AWQ		;(P1,P4/) Move it to the end of the queue
	JRST SCR.LP		;Go try for the next entry

;Here when we're at the end of the list, or it's empty

SRW.EX:	CION
	SETZM P1		;Precaution
	RET
	SUBTTL Connection management utility routines -- SC.ACB (Allocate a connection block)

; This routine allocates and initializes a connection block.
;
; Usage:
;	Call
;	T1/ SYSAP bits to be placed in CID
;
;	Return (+1)
;	T1/ Error code
;
;	Return (+2)
;	P1/ Address of connection block
;
SC.ACB::STKVAR <SYBITS,IDX,UBTS,CID>
	MOVEM T1,SYBITS		;Save the SYSAP bits

;Create and store the CID pls...
;
	CALL SC.FNI		;(/T1) Get the next available index
	 RETBAD (SCSTBF)	;No more, return with error code in T1
	SETZ T4,		;Start with zero as CID
	STOR T1,INDEX,T4	;Store index
	MOVEM T1,IDX		;Save the index
	CALL SC.FUB		;(T1/T1,T2) Get uniqueness bits to use for CID
	STOR T2,UBITS,T4	;Store the unique bits
	MOVEM T2,UBTS		;Save the unique bits
	MOVE T2,SYBITS		;Get the SYSAP bits back again
	STOR T2,SID,T4		;Store these bits in the CID
	MOVEM T4,CID		;Save newly created CID
	MOVEI T1,1		;We want only one quanta of memory for CB
	CALL SC.ABF		;(T1/T1,T2,T3) Get it from the allocator
	 RETBAD ()		;Return with the error code in T1
	MOVE T4,CID		;Get the created CID back again
	STOR T4,CBSCID,(T1)	;Store the source connect ID in the CB
	MOVE P1,T1		;Save connect block address

	MOVE T1,IDX		;Get the index back again
	ADD T1,CIDTAB		;Add the base addr of the CB addr table
	MOVEM P1,(T1)		;Store the address of the CB
	MOVE T1,IDX		;Get the index once more
	ADD T1,UBTTAB		;Add the base addr of the unique bits table
	MOVE T2,UBTS		;Get said bits back
	MOVEM T2,(T1)		;Store the unique bits

;Init the JSYS queue pointers in the CB
;
	SETZRO CBTMQ,(P1)	;Zero the FLINK for the message queue
	OPSTR <XMOVEI T2,>,CBTMQ,(P1) ;Address of the FLINK
	STOR T2,CBBMQ,(P1)	;Init message BLINK as pointer to FLINK

	SETZRO CBTDQ,(P1)	;Zero datagram FLINK
	OPSTR <XMOVEI T2,>,CBTDQ,(P1)	;Address of datagram FLINK
	STOR T2,CBBDQ,(P1)	;Init DG BLINK as pointer to FLINK

	SETZRO CBTXQ,(P1)	;Zero DMA Q FLINK
	OPSTR <XMOVEI T2,>,CBTXQ,(P1) ;Pointer to DMA FLINK
	STOR T2,CBBXQ,(P1)	;Init BLINK as pointer to FLINK

	SETZRO CBTEQ,(P1)	;Zero FLINK of event queue
	OPSTR <XMOVEI T2,>,CBTEQ,(P1) ;Address of event FLINK
	STOR T2,CBBEQ,(P1)	;Init BLINK as pointer to FLINK

	SETZRO CBTBQ,(P1)	;Zero FLINK for buffer queue
	OPSTR <XMOVEI T2,>,CBTBQ,(P1) ;Pointer to buffer FLINK
	STOR T2,CBBBQ,(P1)	;Init BLINK as pointer to FLINK

	MOVEI T2,.CSCLO		;Initial state is "closed"
	STOR T2,CBCNST,(P1)	;Set that in connection block
	RETSKP			;Return happy with address in P1

	ENDSV.
; This routine finds and updates the next index into the CID tables.
;
; Usage:
;	Call
;	No arguments
;
;	Return (+1)
;	No free slots left in the table
;
;	Return (+2)
;	T1/	Next available index
;
; Smashes T2 and T3

SC.FNI:	MOVEI T3,C%CIDL		;Init count of entries searched
SFI.LP:	SOSGE T1,NXTIDX		;Try for the next index
	IFNSK.			;Failed, time to recycle
	  MOVEI T1,C%CIDL-1	;Init NXTIDX to highest CIDTAB entry
	  MOVEM T1,NXTIDX	
	  AOS CIDRFL		;Indicate CIDTAB recycling
	ENDIF.
	MOVEM T1,T2		;Get a copy we can play with
	ADD T2,CIDTAB		;Add the offset to the CID address table
	SKIPN (T2)		;Is there an entry there???
	IFSKP.			;Yes
	  SKIPN CIDRFL		;Are we in recycle mode?
	  JRST SFI.LP		;No, try for another index
	  SOSE T3		;Have we checked the entire CIDTAB?
	  JRST SFI.LP		;No, look at next index
	  RET			;Yes, table must be full, return failure
	ENDIF.
	RETSKP			;No entry so return index found

; This routine finds and updates the next uniqueness bits for a CID.
;
; Usage:
;	Call
;	T1/	Index into CIDTAB of CID being formed
;
;	Return +1: Always
;	T1/	Index into CIDTAB of CID being formed
;	T2/	Next uniqueness bits to use for CID

SC.FUB:	SOSG T2,UNQBTS		;Try for the next identifier
	IFNSK.			;No more left, recycle
	  SETONE UBITS,T2	;Set all bits in the unique bits field
	  LSH T2,-<C%RMBU>	;Right justify said bits
	  MOVEM T2,UNQBTS	;Store as the uniquness bits
	  AOS UNQRFL		;Indicate recycling
	ENDIF.
	SKIPN UNQRFL		;Are we in recycle mode for the bits?
	RET			;No, return success
	ADD T1,UBTTAB		;Obtain address of old entry
	CAME T2,(T1)		;Yes, are the old and new uniqueness bits equal?
	IFSKP.			;Yes, make new bits different
	  SOS T2		;Decrement to insure uniqueness for entry
	  SKIPLE T2		;Is this new value valid?
	  IFSKP.		;No, adjust
	    SETONE UBITS,T2	;Set all bits in the unique bits field
	    LSH T2,-<C%RMBU>	;Right justify said bits
	  ENDIF.
	ENDIF.
	RET			;Return success
	SUBTTL Connection management utility routines -- SC.LCB (Link a new CB)

; This routine links a new conection block into the list of connection
;blocks hanging off a system block.
;
;Accepts:
;	P1/	Address of CB
;	P4/	System block address (or -1 for don't care listener)
;
;	CALL SC.LCB

;Returns +1: Failure
;	 +2: Success

;CIOFF protects from node's going offline, and from changes in the
;list of c.b.'s

;Caller must have locked the connection block

;If this was previously on the don't-care queue, the caller must have
;removed it.

SC.LCB::CIOFF
	JUMPL P4,SLC.DC		;Special case, handle linking dont cares
	LOAD T1,SBVCST,(P4)	;Get state of connection
	CAIE T1,VC.OPN		;Is it open?
	RETBAD (KLPX9,<CION>)	;No. Don't try to link, then

;Remove entry from current list if it's on one. This shouldn't happen.
;If it was on the don't-care queue, the caller has removed it. And it should
;never move from one system block queue to another

	SKIPN T3,.CBANB(P1) 	;Is there a current forward link
	SKIPE T4,.CBAPB(P1) 	;  or a link to a previous buffer???
	IFNSK.
	  LOAD T1,SBDPA,(P4)	;Get node number
	  LOAD T2,CBSCID,(P1)	;Get connect ID
	  BUG. (CHK,SCABAL,SCAMPI,SOFT,<SCA - Connection block already linked>,<<T1,NODE>,<T2,CID>,<T3,FLINK>,<T4,BLINK>>,<

Cause:	SCA is linking a connection block onto a system block. However, the
	connection block's pointers indicate that it is already linked to some
	other block

Data:	NODE  - node number
	CID   - Connect ID
	FLINK - Address of next connection block
	BLINK - Address of previous connection block
>)
	  CALL SC.RSQ		;(P1/) Dequeue CB from current queue
	ENDIF.

;Add entry to the queue

	MOVE T2,.SBLCB(P4)	;Get the pointer to current last
	XMOVEI T3,.SBFCB(P4)	;Get the address of the SB CB FLINK
	CAME T2,T3		;Are we about to store an SB addr as BLINK???
	MOVEM T2,.CBAPB(P1)	;No, make this the pointer to previous
	MOVEM P1,@.SBLCB(P4)	;Link on the new buffer
	MOVEM P1,.SBLCB(P4)	;Set up the new last pointer
	CION			;Turn on CI interrupts, unlock CB list
	RETSKP			;Indicate success

;Here to link dont care listeners togther...

SLC.DC:
	MOVE T1,BOTDC		;Get the address of the last buffer on the Q
	MOVEM P1,@BOTDC		;Link this to the end of the DC queue
	XMOVEI T3,TOPDC		;Get the address of the top pointer
	CAMN T1,T3		;Is previous CB the top pointer???
	SETZ T1,		;Yes, make it zero instead
	MOVEM T1,.CBAPB(P1)	;Make this CB point to the previous one
	MOVEM P1,BOTDC		;Now show it as the end of the queue
	CION			;Restore the state of the PI
	RETSKP			;And we are all done
;SC.RSQ - remove c.b. from its current system block queue

;Accepts:

;	P1/ address of connection block

;	CALL SC.RSQ

;Returns +1: always

; Here to dequeue a CB from its current queue before we go on to put it on
;the new one. 

;Caller must ensure that connection block is not on the don't-care queue.
;Caller must be CIOFF

SC.RSQ:
	MOVE T1,.CBANB(P1)	;Get forward pointer for CB queue
	MOVE T2,.CBAPB(P1)	;  and link to previous on CB queue
	MOVE T3,.CBSBA(P1)	;No previous or next, this is last, get SB pntr
	SKIPN T1		;Is there a next link???
	SKIPE T2		;  or a previous link???
	JRST SLC.NL		;Yes, not last entry, do a real dequeue
	XMOVEI T4,.SBFCB(T3)	;Get pointer to head of CB queue
	MOVEM T4,.SBLCB(T3)	;Init tail as pointer to head
	SETZM .SBFCB(T3)	;Init head as zero
	RET			;All done

; Here when there were other things on the queue.
;
SLC.NL:	SKIPE T1		;Is there a next link???
	MOVEM T2,.CBAPB(T1)	;Yes, update pointer to previous of next
	SKIPE T2		;Is there a previous link???
	MOVEM T1,.CBANB(T2)	;Yes, update pointer to next of previous
	SKIPN T1		;Is there a next buffer???
	MOVEM T2,.SBLCB(T3)	;No, deleted last, update queue BLINK
	SKIPN T2		;Is there a previous buffer
	MOVEM T1,.SBFCB(T3)	;No, deleted first, update queue FLINK
	RET			;  and return
;SC.RDQ - remove entry from don't-care queue

;Accepts:
;	P1/ address of connection block

;	CALL SC.RDQ

;Returns +1: always

SC.RDQ:	MOVE T1,.CBANB(P1)	;Get the addr of the next CB
	MOVE T2,.CBAPB(P1)	;  and the addr of the previous CB (on CB Q)
	SKIPN T1		;Is there a next entry???
	SKIPE T2		;   or a previous entry???
	JRST SRC.MT		;Yes, not the last buffer...
	XMOVEI T1,TOPDC		;No, this is the last CB on DC queue
	MOVEM T1,BOTDC		;Init tail as pointer to head
	SETZM TOPDC		;Init head as zero
	RET

SRC.MT:	SKIPE T1		;Is there a next entry???
	MOVEM T2,.CBAPB(T1)	;Yes, update previous of next CB
	SKIPE T2		;Is there a previous entry???
	MOVEM T1,.CBANB(T2)	;Yes, update next of previous CB
	SKIPN T1		;Was there a next entry???
	MOVEM T2,BOTDC		;No, update the queue BLINK
	SKIPN T2		;Was there a previous entry???
	MOVEM T1,TOPDC		;No, update the queue FLINK
	RET
	SUBTTL Connection management utility routines -- SC.SCM (Search for connection match)

; This routine searches the connection blocks for a match between a 
;local listen and a destination connect request.
;
; Usage:
;	Call
;	P2/	Address of datagram/message buffer
;
;	Return (+1)
;	No match, no data returned
;
;	Return (+2)
;	P1/	Address of connection block with a match
;
; This routine assumes that the message type is CONNECT_REQUEST. If it is not
;we will have real problems...
;
;
; AC usage within this routine:
;	T1/	Address of the message
;	T2/	Scratch
;	T3/	Scratch
;	T4/	Scratch
;
;	Q1/	Current system block index (SBI)
;	Q2/	Address of the current system block
;	Q3/	Copy of initial P1
;
;	P1/	Address of current CB
;	P2/	Address of message (Touch not the contents of P2!!!)
;	P3/	Touch not the contents of P3!!
;	P4/	System block address of remote we got connect request from
;			*** Set up by port driver on call to SCA ***
;				    *** Touch it not ***
;	P5/	Unused here
;
;This code assumes it is called at interrupt level, and therefore
;doesn't protect itself from changes in the list of connection blocks
;on a system block

SC.SCM:	SAVEQ
	MOVEM P1,Q3		;Save P1 here in case we have to restore it

; Here to start looping over the system blocks.
;
	SETO Q1,		;Start with the first SB
SSC.SL:	AOS Q1			;Next SB please...
	CAILE Q1,C%SBLL-1	;Have we run off the end of the list???
	JRST SSC.DC		;No more SB's, try for the dont care Q
	SKIPN Q2,SBLIST(Q1)	;Get the address of an SB
	JRST SSC.SL		;No S.B. here, try for the next one
	;..
; Here to loop over the connection blocks hung off an SB.
;
	;..
	MOVE P1,.SBFCB(Q2)	;Get the pointer to the first CB
	$SKIP			;Dont smash what we just did...
SSC.CL:	MOVE P1,.CBANB(P1)	;Get the address of the next connection block
	JUMPE P1,SSC.SL		;If no connection blocks, do next SB
	LOAD T1,CBCNST,(P1)	;Get the connection state
	CAIE T1,.CSLIS		;Is the connect state listen???
	JRST SSC.CL		;No, loop to next connection block

;Here to do system address checking
;
	LOAD T1,CBDNOD,(P1)	;Get the destination node number
	CAMN T1,[XWD 0,-1]	;Is this the DONT CARE of system index's???
	JRST SSC.AS		;Yes, dont do a system index check
	MOVE T1,SBLIST(T1)	;Now the system block address
	CAME T1,P4		;Do we have a match???
	JRST SSC.CL		;Nope, wrong system, next connection block

;Here to do name checking
;
SSC.AS:	SKIPN .MGDPN(P2)	;Is there a requested process name??
	SKIPE .CBDPN(P1)	;And do we care who we talk to??
	$SKIP			;We care, do regular name checking
	  JRST SSC.FX		;We have a dont care situation, match now
	XMOVEI T1,.CBSPN(P1)	;Point to our name for me
	XMOVEI T2,.MGDPN(P2)	;Point to the remotes name for me
	CALL SC.C4S		;Do they match???
	 JRST SSC.CL		;No, try the next connection block

	XMOVEI T1,.CBDPN(P1)	;Point to CB's destination proc name
	XMOVEI T2,.MGSPN(P2)	;  and the source name of the connect request
	CALL SC.C4S		;Compare the two strings...
	 JRST SSC.CL		;No match, next connection block please
	JRST SSC.FX		;Else, we have a match, return
; Here when all that is left is the dont care queue.
;
SSC.DC:	MOVE P1,TOPDC		;Get the addr of the first CB on dont care Q
	$SKIP			;Smash not on the first time through
SSC.DL:	MOVE P1,.CBANB(P1)	;Get the address of the next CB on DC Q
	JUMPE P1,SSC.YL		;No next CB, we are done and you loose
	LOAD T1,CBCNST,(P1)	;Get state of connection
	CAIE T1,.CSLIS		;Listening?
	JRST SSC.DL		;No. Go check the next one
	SKIPN .MGDPN(P2)	;Is there a requested process name???
	SKIPE .CBDPN(P1)	;  and do we care who we talk to???
	$SKIP			;Yes, not dont care case, do regular name check
	JRST SSC.LC		;No, we have default match, put CB on SB queue

	XMOVEI T1,.CBSPN(P1)	;Point to our name
	XMOVEI T2,.MGDPN(P2)	;  and to the remotes name for us
	CALL SC.C4S		;Do they match???
	JRST SSC.DL		;No, try for the next CB on DC q
	SKIPN .CBDPN(P1)	;Do we care who we talk to???
	JRST SSC.LC		;No, then match this connect
	XMOVEI T1,.CBDPN(P1)	;We care, get target name pointer
	XMOVEI T2,.MGSPN(P2)	;  and pointer to remotes name
	CALL SC.C4S		;Does our target name match remote source name?
	 JRST SSC.DL		;No, try the next entry on don't care queue

;We have a match, delink us from the dont care queue and put us on the CB list
;for the SB we have found a home with.
;
SSC.LC:	CALL SC.RDQ		;(P1/) remove block from queue
	LOAD T1,SBDPA,(P4)	;Get node number for this system block
	STOR T1,CBDNOD,(P1)	;Save it in this connect block
	MOVEM P4,.CBSBA(P1)	;Be sure the CB reflects the new SB address
	SETZM .CBANB(P1)	;We just dequeued, zero links so SCLCB
	SETZM .CBAPB(P1)	;   does not dequeue again
	CALL SC.LCB		;(P1,P4/) Link this CB onto the remote's SB
	IFNSK.
	  LOAD T2,SBDPA,(P4)	;Get node number
	  BUG. (HLT,SCACLB,SCAMPI,SOFT,<SCA - Incoming connect_request on closed v.c.>,<<T2,NODE>>,<

Cause:	SCAMPI received a connect_request and matched it to a listener.
	But when SCAMPI tried to queue the connection block to the system 
	block, it found that the v.c. was closed. Since SCAMPI had checked 
	for that state earlier, and this is happening at interrupt level, 
	something unexpected has happened.

Data:	NODE - Node number
>)
	ENDIF.
	RETSKP			;And return success

; Here when there is no match. You lose...
;
SSC.YL:	MOVE P1,Q3		;Get the initial contents of P1 back again
	RET			;Return with no match

; Here to fix things up for a match. We are here to insure the CB has good info
;about the SB.
;
SSC.FX:	MOVEM P4,.CBSBA(P1)	;Store the system block address
	LOAD T1,SBDPA,(P4)	;Get node number for this system block
	STOR T1,CBDNOD,(P1)	;Save it in this connect block
	RETSKP			;And return success

; This routine compares four word strings. The strings are always
;be padded out to their full four word size. Hence we can do this whole
;operation in a set of full word compares. This is infinitly faster than
;an ILDB/CAME loop.
;
; Usage:
;	Call
;	T1/	Address of one four word string
;	T2/	Address of another four word string
;
;	Return (+1)
;	T1 and T2 are preserved - Strings do not match
;
;	Return (+2)
;	T1 and T2 are preserved - Strings match
;
SC.C4S:	MOVE T3,(T1)		;Get first word from string
	CAME T3,(T2)		;Does the first word match?
	RET			;No, return no match
	MOVE T3,1(T1)		;Do the next word
	CAME T3,1(T2)		;Check for a match
	RET			;Nope...
	MOVE T3,2(T1)		;Next word along please...
	CAME T3,2(T2)		;A match???
	RET			;Nope...
	MOVE T3,3(T1)		;Now for the last word
	CAME T3,3(T2)		;A match
	RET			;Nope
	RETSKP			;Yes!!! Return matching strings!!
	SUBTTL Connection management utility routines -- SC.CSC (CID sanity check)

; This routine checks the validity of a connect ID.
;
; Usage
;	Call
;	T1/	Connect ID to check
;
;	Return (+1)
;	T1/	error code
;
;	Return (+2)
;	T1/	Connect ID
;	P1/	Address of connection block where match was found
;

;Alternate entry point, SC.CAL, checks the c.b. and locks it

SC.CSC::TDZA P1,P1		;Flag = 0 means we don't want to lock
SC.CAL:	SETOM P1		;Flag = -1 means we do want to lock
	CIOFF			;Insure we are the only ones in the CID table
				; and protect connection block until locked
	LOAD T2,INDEX,T1	;Get the index from the connect ID
	MOVEM T2,T3		;Save a copy of the index
	CAIL T2,C%CIDL		;Is it within range???
	JRST SCC.XT		;No, fail
	ADD T2,CIDTAB		;Add the offset to the CID table
	SKIPN T2,(T2)		;Now get the address of the CB
	JRST SCC.XT		;No, fail
	LOAD T4,UBITS,T1	;Get the uniqueness bits from the CID
	MOVE T2,T3		;Get a copy of the index
	ADD T2,UBTTAB		;Add the offset to the uniqueness table
	MOVE T2,(T2)		;Get the bits from the unique table
	CAME T2,T4		;Do we have a match???
	JRST SCC.XT		;No, fail
	ADD T3,CIDTAB		;Yes, T3 = CID table base addr + index
	MOVE T3,(T3)		;Get address of the connection block
	EXCH T3,P1		;Put it in P1; retrieve entry flag
	SKIPE T3		;Want to lock?
	CALL SC.LOK		;(P1/) Yes. Lock the connection block
	CION			;Restore the state of the PI
	RETSKP			;Return success

;Here to failure exit
SCC.XT:	CION			;Restore the state of the PI
	RETBAD (SCSIID)		;Return "invalid Connect ID"
	SUBTTL Connection management utility routines -- SC.CDT (Send credit_request)

;SC.CDT - Send credit_request if necessary

;Accepts:
;	P1/ address of connection block
;	P4/ address of system block

;	CALL SC.CDT

;Returns +1: didn't send it
;	 +2: did send it

;Four entry points:
;	SC.CDT - when sysap queues buffer for message reception
;	SC.CD1 - when credit_response arrives
;	SC.CD5 - when sysap takes a buffer back
;	SC.CD7 - idle chatter

;Caller must lock connection block

;If this routine returns +2, caller must call SC.SNM after unlocking
;the connection block

;Here when sysap queues buffer. Send if pend_rec_credit .GT. 0 and
;rec_credit .LT. min_rec_credit

SC.CDT:	
	SKIPG T1,.CBPRC(P1)	;Give up if pending receive credit
	JRST SCC.RT		; is not positive
	JRST SC.CD3		;Go check on receive credit

;Here when credit_response arrives. We may have wanted to send another
;one earlier, but only one can be outstanding at a time. Send if
;pend_rec_credit is negative, or if pend_rec_credit is positive and
;rec_credit .LT. minimum_receive_credit.

SC.CD1:	
	SKIPGE T1,.CBPRC(P1)	;Send if pending receive credit is negative
	JRST SCC.SM
	JUMPE T1,SCC.RT		;Don't send if there's no change

;Send if receive creidt .LT. minimum_receive_credit or if pending
;receive credit is getting large

SC.CD3:	LOAD T2,CBMNRC,(P1)	;Send if receive credit is below the
	CAMLE T2,.CBRCD(P1)	; minimum
	JRST SCC.SM
	CAIGE T1,C%MBCR		;Send if pending is getting large
	JRST SCC.RT		;Don't send
	JRST SCC.SM		;Send

;Here when sysap takes a buffer back. Send only if pend_rec_credit is
;negative

SC.CD5:	
	SKIPL .CBPRC(P1)	;Give up if pending receive credit
	JRST SCC.RT		; is not negative
	JRST SCC.SM		;It's negative. Tell the other end.

;Here for idle chatter

SC.CD7:
	;..
;Here because credit values suggest sending a credit_request. See
;if the state of the connection will allow it. We don't send if the connection
;isn't open. If we're still opening it, there's a risk of confusing the
;other side. If we're closing it, there's no need to send a credit_request.
;Also, we want to avoid sending anything after the disconnect sequence
;has started, because we will declare protocol complete and reap the block
;when the final disconnect_response comes in. We don't want to receive
;a credit_response after that.

	;..
SCC.SM:	LOAD T1,CBCNST,(P1)	;Do this only if we're open
	CAIE T1,.CSOPN
	JRST SCC.RT

;Racefree, indicate that we're setting up for a credit_request, and make
;sure no other context is already doing it. If someone got here ahead of
;us, we don't need to send a credit_request, because our change is already
;reflected in .CBPRC. And we don't want to send one, because we might try
;to queue the same c.b. twice. Also, the second message would contain 0,
;so why bother? If credit is still pending when the credit_response comes
;in, we'll send another credit_request.

	SETOM T1		;Indicate credit_request is pending
	EXCH T1,.CBPND(P1)	;Get the old value
	JUMPL T1,SCC.RT		;Already pending. Don't want to do this
	LOAD T1,CBBKST,(P1)	;Get the block state
	SKIPN T1
	IFSKP.
	  MOVE T1,.CBSBA(P1)	;Get address of system block
	  LOAD T1,SBDPA,(T1)	;Get port number
	  LOAD T2,CBSCID,(P1)	;Get CID
	  LOAD T3,CBBKST,(P1)	;Get state
	  BUG. (CHK,SCACSC,SCAMPI,SOFT,<SCA - Can't send credit request>,<<T1,NODE>,<T2,CID>,<T3,STATE>>,<

Cause:	SCA wants to send a credit request, but the connection block already
	has some other message pending. This reflects some sort of
	inconsistency, since the state was "open", and the interlock word
	for credit requests was 0.

Data:	NODE  - Node number
	CID   - Connect ID
	STATE - BLock state
>)
	  SETZM .CBPND(P1)	;We're not doing credit_request after all
	  RET
	ENDIF.
	MOVEI T1,.BSCRP		;Set block state to credit_pending
	CALL SC.SCA		;(T1,P1,P4/) Set block state and queue block
	RETSKP			;Tell caller to get it sent

SCC.RT:	
	RET
;SC.GCB - Reclaim buffers according to return_credit field of connect block

;Accepts:
;	P1/ address of connect block
;	P4/ address of system block

;	CALL SC.GCB

;Returns +1: always

;Caller must lock connection block

SC.GCB:
	SAVEAC <P3>
	SETZM P3
	EXCH P3,.CBRTC(P1)	;Get old value, zero it
	JUMPE P3,SCG.EX		;Nothing to do if it already was zero
SCG.CL:	BLCAL. (ULNKMG,<P4>)	;(/T1) Get a buffer from the port driver
	IFNSK.
   IFN SCARNG,<
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-2(P)		;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  SETOM T4		;Set buffer address to -1 due to failure
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
>	         		;End of IFN SCARNG
	  LOAD T1,SBDPA,(P4)	;get node number
	  LOAD T2,CBSCID,(P1)	;get our connect ID
	  BUG. (CHK,SCACRB,SCAMPI,SOFT,<SCA - Can't reclaim buffers>,<<T1,NODE>,<T2,CID>,<P3,COUNT>>,<

Cause:	Based on the return_credit field for this connection, SCAMPI is trying
	to reclaim buffers from the port's queue. The queue is empty. This
	reflects confusion about credit, since these buffers should have 
	been queued at some time in the past.

Data:	NODE  - Node number
	CID   - Connect ID at this node
	COUNT - Number of buffers we couldn't get
>)
	  JRST SCG.EX	  
	ENDIF.
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Save smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-5(P)		;Get PC of caller to feature routine
	  MOVEI T3,1		;Set buffer count
	  TXZ T3,RPQFLK   	;Clear port link flag since unlinking
	  TXO T3,RPQFMG   	;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	CALL SC.RBF		;(T1/) Return the buffer to SCA
	SOJG P3,SCG.CL		;Continue until we've gotten them all
SCG.EX:	RET
	SUBTTL Connection management utility routines -- SC.CVC (Close a virtual connection)

; Usage:
;	Call
;	P4/	Address of system block
;
;	Return (+1) Always
;	No data returned

SC.CVC:	LOAD T1,SBDPA,(P4)	;Get port number
	BLCAL. (CLOSVC,<P4>)	;Request close of the connection
				;This will cause callback at SC.ERR
	RET
	SUBTTL Connection management utility routines -- SC.SDM (String and data move to CB)

; This routine moves the source process name, destination process name, and
;connection data from the SYSAPs arguments, into the connect block.
;Note that the addresses provided for destination name and conenction data
;may be zero, but the source name is never zero.
;
; Usage:
;	Call
;	T1/	Address of source process name
;	T2/	Address of destination process name or zero
;	T3/	Address of connection data or zero
;	P1/	Address of connect block
;
;	Return (+1) Always
;	No data returned, T1-T3 are smashed
;
SC.SDM:	STKVAR <DPN,DATA>
	MOVEM T2,DPN		;Save the address of the destintion name
	MOVEM T3,DATA		;  and the connection data

; Move the source process name

	MOVE T2,T1		;Source address for the source process name
	MOVX T1,C%PNLW		;Get the length of a process name in words
	XMOVEI T3,.CBSPN(P1)	;Destination address in CB for source name
	EXTEND T1,[XBLT]	;Move the source name

; Move the destination process name

	SKIPN T2,DPN		;Is there a destination process name to move???
	JRST SDM.DT		;No, do connection data now
	MOVX T1,C%PNLW		;Yes, get its length in words
	XMOVEI T3,.CBDPN(P1)	;Destination addr in CB for destination name
	EXTEND T1,[XBLT]	;Move the destintion process name

; Move the connection data

SDM.DT:	SKIPN T2,DATA		;Is there any data to move???
	RET			;No, all done
	MOVX T1,C%DTLW		;Yes, get its length in words
	XMOVEI T3,.CBDTA(P1)	;Destination addr in CB for connect data
	EXTEND T1,[XBLT]	;Move connetion data please...
	RET			;All done

	ENDSV.
	SUBTTL Connection management utility routines -- SC.OUT (Check sysap call)

;SC.OUT - Handle call from sysap for connection management functions

;Accepts:
;	T1/ event code
;	P1/ address of connection block

;Returns +1: failure
;		T1/ error code
;	 +2: success
;		T1/ new block state (0 if no change)
;		T2/ new connection state (0 if no change)

SC.OUT:
	MOVEM T1,T4		;Save the event
	IMULI T4,MXCNST
	OPSTR <ADD T4,>,CBCNST,(P1)
	SOS T4
	JN X.ERR,(T4),SC.OU5	;Is event legal for current state?
	LOAD T1,X.BSTAT,(T4)	;Yes. Return new block state
	LOAD T2,X.CSTAT,(T4)	;Return new connection state
	RETSKP

SC.OU5:	RETBAD(SCSCWS)
	SUBTTL Connection management utility routines -- SC.RSP (Send a response)

;SC.RSP - Send responses

;Accepts:
;	T1/ op code
;	P1/ address of connection block
;	P2/ address of packet
;	P4/ address of system block

;	CALL SC.RSP

;Returns +1: failure to send,
;		T1/ error code
;	 +2: success

;SC.RS2 - Special entry for credit_rsp to avoid clearing credit field

SC.RSP:	SETZRO MH$CDT,(P2)	;Clear the credit field
SC.RS2:	STOR T1,MH$MSG,(P2)	;Store op code
	LOAD T2,MH$SCI,(P2)	;Get the sending CID
	STOR T2,MH$DCI,(P2)	;Store as the receiving CID
	LOAD T2,CBSCID,(P1)	;Get the source connect-ID
	STOR T2,MH$SCI,(P2)	;Store in packet as sending CID
	CALL @SCMKPK(T1)	;(P2/) Store op-code-specific data
	CALLRET SC.PAK		;(P2,P4/) Send the packet

;Make a connect_response (caller stored MH$STS)

SC.MOS:	SETZRO MH$MCR,(P2)	;Minimum credit field must be 0

;Make an accept_response (caller stored MH$STS)

SC.MAS:

;Make a reject_response

SC.MRS:

;Make a disconnect_response

SC.MDS:

;Make a credit_response

SC.MCS:	RET
	SUBTTL Connection management utility routines -- SC.RQS (Send a request)

;SC.RQS - send an SCS control message

;Accepts:
;	P1/ Address of connection block
;	P2/ Address of packet buffer
;	P4/ address of system block

;	CALL SC.RQS

;Returns +1: failure to send, caller must dispose of buffer
;	 +2: success, buffer was given to port driver

;Sends requests only. Gets data from c.b.

;Caller must lock connection block

;NOTE: Other code depends on CBBKST's being zero when there is nothing
;waiting to be sent

SC.RQS:

;Block state may have gone to zero while the c.b. was queued, if the
;node went offline after it was queued. Return failure so that caller
;will get rid of the buffer.

	LOAD T1,CBBKST,(P1)	;Get block state
   IFN SCADBG,<
	SKIPE T1		;Shouldn't be zero
	CAILE T1,YSIZE		;Too big?
	IFNSK.
	  LOAD T2,SBDPA,(P4)	;Get node number
	  LOAD T3,CBSCID,(P1)	;Get connect ID
	  BUG. (HLT,SCAIBS,SCAMPI,SOFT,<SCA - Invalid block state>,<<T2,NODE>,<T3,CID>,<T1,BSTATE>>,<

Cause:	This caller to SC.RQS provided a block state larger than the table 
	(or zero).

Data:	NODE   - Node number
	CID    - Connect ID
	BSTATE - Block state
>)
	ENDIF.
   >				;End IFN SCADBG
	LOAD T4,Y.OP,(T1)	;Get op code to be sent
	STOR T4,MH$MSG,(P2)	;Store it in the packet
	LOAD T1,CBDCID,(P1)	;Get destination connect ID
	STOR T1,MH$DCI,(P2)	;Store it in the packet
	LOAD T1,CBSCID,(P1)	;Get source connect ID
	STOR T1,MH$SCI,(P2)	;Store it in the packet
	CALL @SCMKPK(T4)	;(P1,P2/)Call specific routine for this op code
	LOAD T1,CBBKST,(P1)	;Get block state again
	OPSTR <SKIPN T1,>,Y.STAT,(T1) ;Get new connection state
	IFSKP.
	   STOR T1,CBCNST,(P1)	;Store in connection block
	ENDIF.
	LOAD T1,MH$MSG,(P2)	;Get op code
	OPSTR <SKIPN T1,>,Z.RSP,(T1) ;If we expect a response,
	IFSKP.
	   STOR T1,CBEXPR,(P1)	; store its op code in connection block
	ENDIF.
	CALL SC.PAK		;(P2,P4/) Send the packet
	 RET
	SETZRO CBBKST,(P1)	;Indicate nothing is pending
	RETSKP

;Not necessary to clear block state as long as failure occurs only
;when node goes offline.
;SC.MOQ - Make a connect request

SC.MOQ:	CALL SCACDT		;(P1,P2/) Store credit field in packet
	SETZRO MH$DCI,(P2)	;We don't know the destination's CID
	JRST SCM.AC

;SC.MAQ - Make an accept_request

SC.MAQ:	CALL SCACDT		;(P1,P2/) Store credit field in packet
SCM.AC:	SETZRO MH$STS,(P2)	;Status field must be zero
	LOAD T1,CBMNSC,(P1)	;Get the minimum send credit
	STOR T1,MH$MCR,(P2)	;Store in minimum_credit field

; Move the destination process name.

	MOVEI T1,<C%PNMN+3>/4	;The number of words to move
	XMOVEI T2,.CBDPN(P1)	;Source address of destination process name
	XMOVEI T3,.MGDPN(P2)	;It goes here...
	XBLT. T1		;Move the destination process name

; Move the source process name

	MOVEI T1,<C%PNMN+3>/4	;How many words to move
	XMOVEI T2,.CBSPN(P1)	;Source address for source process name
	XMOVEI T3,.MGSPN(P2)	;Destination address
	XBLT. T1		;Move the source process name

; Move the initial connection data

	MOVEI T1,<C%CDMN+3>/4	;The number of words to move
	XMOVEI T2,.CBDTA(P1)	;Source
	XMOVEI T3,.MGSDT(P2)	;Destination address
	XBLT. T1		;Move the initial connection data
	RET

;SC.MRQ - Make a reject request

SC.MRQ:

;SC.MDQ - Make a disconnect request

SC.MDQ:	SETZRO MH$CDT,(P2)	;Credit field must be zero
	LOAD T1,CBSDRE,(P1)	;Get the reason for disconnecting
	STOR T1,MH$STS,(P2)	;Store it in the packet
	SETZRO MH$MCR,(P2)	;Minimum_credit field must be zero
	RET

;SC.MCQ - Make a credit request

SC.MCQ:	CALL SCACDT		;(P1,P2/) Store credit field in packet
	RET
; Routine to set credit in a packet and update .CBPRC
;
;
;Usage:
;
;	CALL SCACDT
;
;	P1/	Address of Connection block
;	P2/	Message buffer to send
;	
;	Does not alter any AC's except T1


SCACDT:	CIOFF			;Credit play time again 
	LOAD T1,MH$MSG,(P2)	;Get op code from packet
	CAIE T1,.STCRQ		;Is this a credit request we are sending???
	IFSKP.
	  MOVE T1,.CBPRC(P1)	;Get the pending receive credit
	  MOVEM T1,.CBRQC(P1)	;Store curr pend receive credit as REQ_CREDIT
	ELSE.
	  MOVE T1,.CBPRC(P1)	;Get the pending receive credit
	  ADDM T1,.CBRCD(P1) 	;Update the receive credit
	 ENDIF.
	STOR T1,MH$CDT,(P2)	;Stor the credit field
	SETZM .CBPRC(P1)	;zero the pending credit
	CION			;Restore the state of the PI
	RET			;RETURN
	SUBTTL Connection management utility routines -- SC.PAK (Send a packet)
;SC.PAK - send a packet

;Accepts:
;	P2/ address of packet
;	P4/ address of system block

;	CALL SC.PAK

;Returns +1: failure to send,
;		T1/ error code
;	 +2: success


SC.PAK:	STKVAR <OPCODE>
   IFN SCARNG,<
SCPAK:	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-3(P)		;Get caller to feature routine
	LOAD T3,MH$MSG,(P2)	;Get opcode
	LOAD T4,Z.LEN,(T3)	;Get length based on opcode
	LOAD T3,Z.PRI,(T3)	; and priority also
	HRL T4,T3		;Place priority correctly
	SETZ T3,0		;No flags
	CALL RG.PKT		;(T1,T2,T3,T4,P2,P4) Record packet transmission
>				;End of IFN SCARNG
	LOAD T1,MH$MSG,(P2)	;Get op code
	MOVEM T1,OPCODE
	LOAD T2,Z.LEN,(T1)	;Get length of this message
	CALL SC.ROU		;Byte swap the packet header for output
	LOAD T3,Z.PRI,(T1)	;Get priority for this op code
	BLCAL. (SNDMSG,<T2,[0],P4,P2,T3>) ;Send the packet (no flags)
	 RETBAD ()		;Return failure
	MOVE T1,OPCODE		;Restore op code
	AOS SNDTAB(T1)		;Increment count for sending this code
	RETSKP
	ENDSV.
;SC.PTC - Declare protocol complete

;Accepts:
;	P1/ address of connection block

;	CALL SC.PTC

;Returns +1: always

;This routine is called when we believe that no more output should be sent
;to a node, and we don't expect any input from it. In theory, we can delete
;the connection block now. In practice, we have to wait until all outstanding
;buffers (used for sending) have been returned. Also, if this is a JSYS
;connection, the SCSJSY code will decide when to reap the block. It doesn't
;do this until the user has run, because event blocks are queued off the
;connection block

;NOTE: It is legal for the block state to be non-zero here. This can happen
;if the node goes offline.

SC.PTC:
   IFN SCADBG,<
	LOAD T3,CBCNST,(P1)
	CAIN T3,.CSCLO		;Should be closed
	IFSKP.
	  MOVE T4,(P)		;Get address of caller
	  LOAD T1,CBSCID,(P1)	;Get connect ID
	  CALL SC.NOD		;(T1/T1,T2) Get node number
	  BUG. (CHK,SCAPCC,SCAMPI,SOFT,<SCA - Protocol complete set and connect state not closed>,<<T2,NODE>,<T1,CID>,<T3,CSTATE>,<T4,CALLER>>,<

Cause:	A call was made to SC.PTC indicating that the protocol was complete.
	When this happens, the connect state should be closed.  It was not.

Data:	NODE   - Node number
	CID    - Connect ID
	CSTATE - Connect state
	CALLER - Address of caller to SC.PTC
>)
	ENDIF.
  >
	SETONE CBFPTC,(P1)	;Indicate we've quit talking to other end
	SETZRO CBBKST,(P1)	;Clear block state
	TMNE CBFJSY,(P1)	;If it's not a JSYS block
	IFSKP.
	  SETONE CBFRAP,(P1)	; then we can go ahead and reap it
	  SETONE CIREP		;TELL CIFORK TO RUN
	ENDIF.
	RET
	SUBTTL Buffer management routines

	SUBTTL Buffer management routines -- SC.SBT (Set buffer thresholds)

; This routine set buffer thresholds based on the number of systems currently
;online.
;
; Usage:
;	Call
;	No arguments
;
;	Return (+1) Always
;	MINMSG/	New message buffer threshold
;	MINDG/	New datagram buffer threshold
;
SC.SBT:	MOVE T1,SBCNT		;Get current number of online systems
	IMUL T1,MBPS		;Multiply by threshold per SB to get threshold
	ADD T1,MGTRSH		;Add the threshold we must have around
	MOVEM T1,MINMSG		;Update the minimum message buffer count

	MOVE T1,SBCNT		;Get the system count again
	IMUL T1,DBPS		;Mult by DG buffers per sys to get threshold
	ADD T1,DGTRSH		;Add on the treshold we must keep about
	MOVEM T1,MINDG		;Update min datagram buffer count
	RET			;Return
; Routine to Link Multiple Messages onto the Port Free Queue
;
; Usage:
;
;	T1/ Address of buffer chain
;	T2/ Count of the buffers
;	P1/ address of connection block
;	P4/ address of system block

;	CALL SCL.MC
;
;	Returns +1 always
;

SCL.MC:	SAVEAC <Q2>		;Save a temporary for buffer count
	MOVEM T2,Q2		;Save the count of buffers
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Saved smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-5(P)		;Get PC of caller to feature routine
	  MOVE T3,Q2		;Get buffer count
	  TXO T3,RPQFLK		;Set port link flag
	  TXO T3,RPQFMG		;Set message free queue flag
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	BLCAL. (LNKMFQ,<P4,T1>)	;Link buffer chain onto Message Free queue
	ADDM Q2,.CBPRC(P1)	;Update credit counts
	RET
; Routine to Link Multiple Datagrams onto the Port Free Queue
;
; Usage:
;
;	T1/ Address of buffer chain
;	T2/ Count of the buffers
;	P1/ address of connection block
;	P4/ address of system block

;	CALL SCL.DC
;
;	Returns +1 always
;

SCL.DC:	SAVEAC <Q2>		;Save a temporary for buffer count
	MOVEM T2,Q2		;Save the count of buffers 
   IFN SCARNG,<
	BLOCK.
	  SAVEAC <T1>		;Save smashed AC
	  MOVE T4,T1		;Get buffer address
	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-5(P)		;Get PC of caller to feature routine
	  MOVE T3,Q2		;Set buffer count
	  TXO T3,RPQFLK   	;Set port link flag
	  TXZ T3,RPQFMG   	;Clear message free queue flag since datagram
	  CALL RG.PQM		;(T1,T2,T3,T4,P4) Record port manipulation
	ENDBK.
>				;End of IFN SCARNG
	BLCAL. (LNKDFQ,<P4,T1>)	;Link buffer chain onto Datagram Free queue
	ADDM Q2,.CBDGR(P1)	;Update Datagram counts
	RET
; Routine to return Multiple Message buffers to the Message pool
;
;Usage
;
;	T1/	Address of Buffer list
;	Call SCM.RM
;
;	Returns +1 always

SCM.RM:	SAVEAC <Q1>		;Save a place for the header
SCM.LM:	MOVE Q1,0(T1)		;Get the pointer to the next buffer
	CALL SC.RBF		;Return the buffer
	SKIPN T1,Q1		;Was there another buffer?
	RET			;Return no more to do
	JRST SCM.LM		;Yes try again for more
; Routine to return Multiple Datagrams buffers to the Datagrams pool
;
;Usage
;
;	T1/	Address of Buffer list
;	Call SCM.RD
;
;	Returns +1 always

SCM.RD:	SAVEAC <Q1>		;Save a place for the header
SCM.LP:	MOVE Q1,0(T1)		;Get the pointer to the next buffer
	CALL SC.RLD		;Return the buffer
	SKIPN T1,Q1		;Was there another buffer?
	RET			;Return no more to do
	JRST SCM.LP		;Yes try again for more
	SUBTTL Buffer management routines -- SC.BUF

;SC.BUF - get buffers for SC.SNM or SC.DEF

;Accepts:
;	P1/ address of connection block
;	P4/ address of system block

;	CALL SC.BF1 (if can't create buffers)
;	CALL SC.BF2 (if can create buffers)

;Returns +1: failed to create buffers
;	 +2: buffers were created

;This routine attempts to allocate buffers from SCA's free pool. If
;the caller can tolerate page faults, it tries to create new buffers if
;the pool is empty

SC.BF1:	TDZA T1,T1		;Can't create buffers
SC.BF2:	SETOM T1		;Can create buffers
	SAVEP
	MOVEM T1,P2		;Save flag
	OPSTR <SKIPN T1,>,CBIMB,(P1) ;Get the number of message buffers needed
	JRST SBF.DG		;None. Go try for datagram buffers
	CALL SC.ABF		;(T1/T1,T2,T3) Try to get them from the pool
	 SKIPA			;Failed. HAve to create them
	JRST SBF.QM		;Succeeded. Go give them to the port

;Didn't have enough in SCA's pool. Create them.

	IFE. P2			;Can we create them?
	  AOS DMRCNT		;No. Count failure
	  RET
	ENDIF.
	LOAD T1,CBIMB,(P1)	;Get number of buffers needed
	CALL SC.CMG		;(T1/T1,T2,T3) Create the message buffers 
	 RET			;Indicate failure
	ADDM T3,TOTMGB		;Add to total number of message buffers created

;SC.CMG may have created more than we needed. If so, make a chain of the
;extra buffers and return them to SCA's pool.

	LOAD P5,CBIMB,(P1)	;See how many buffers we wanted
	CAMN P5,T3		;Did we get exactly what we wanted???
	JRST SBF.QM		;Yes, queue the buffer chain immediatly

;We got more than we wanted. Make a chain out of the desired number.

	MOVEM T1,P3		;Save the address of the buffer chain
	MOVE T2,T1		;No, loop to get address of last desired buffer
	MOVE T3,T2		;Save the address of the previous buffer
	MOVE T2,(T2)		;Get the address of the next buffer
	SOJG P5,.-2		;Loop until request count is exhausted
	SETZM (T3)		;Zero the forward pointer of last req buffer

;Return the excess buffers created by CMG to the SCA free pool.

	MOVE T1,T2		;Get the address of the current buffer
	CALL SCM.RM		;Return messages to free pool
	MOVE T1,P3		;Get the address of the buffer chain

; Here when we are ready to queue the buffers to the port queue.

SBF.QM:	LOAD T2,CBIMB,(P1)	;Get the count of the buffers in the chain
	CALL SCL.MC		;(T1,T2,P1,P4/) Queue up the Messages to the port
				; and update pending receive credit
	SETZRO CBIMB,(P1)	;No longer need these buffers
	;..
; Here to do datagrams.
	;..

SBF.DG:	OPSTR <SKIPN T1,>,CBIDB,(P1) ;Get the number of datagrams to create
	JRST SBF.EX		;None
	CALL SC.ALD		;(T1/T1,T2,T3) Try to get them from the pool
	 SKIPA			;Failed. HAve to create them
	JRST SBF.QD		;Succeeded. Go give them to the port

;Didn't have enough in SCA's pool. Create them.

	IFE. P2
	  AOS DDRCNT
	  RET
	ENDIF.
	LOAD T1,CBIDB,(P1)	;Get number of buffers needed
	CALL SC.CDG		;(T1/T1,T2,T3) Create the datagrams 
	 RET			;Indicate failure
	ADDM T3,TOTDGB		;Add to total datagram buffers created

;SC.CMG may have created more than we needed. If so, make a chain of the
;extra buffers and return them to SCA's pool.

	LOAD P5,CBIDB,(P1)	;Get the number of buffer requested
	CAMN P5,T3		;Did we get excatly what we asked for???
	JRST SBF.QD		;Yes, go queue the datagrams

;We got more than we wanted. Make a chain out of the desired number.

	MOVEM T1,P3		;Save the address of the buffer chain
	MOVE T2,T1		;Get the base addr of the chain
	MOVE T3,T2		;Save the address of the previous buffer
	MOVE T2,(T2)		;Move on to the next buffer
	SOJG P5,.-2		;Loop until we have the number we requested
	SETZM (T3)		;Zero the FLINK of the last req buffer

; Here to put the excess buffers created by CDG on the SCA free queue.

	MOVE T1,T2		;Get the address of the current buffer
	CALL SCM.RD		;Return Datagrams
	MOVE T1,P3		;Get the address of the buffer chain

; Here to link the new buffers onto the hardware free queue.

SBF.QD:	LOAD T2,CBIDB,(P1)	;Get the number of datagrams queued
	CALL SCL.DC		;Put the Datagrams on the Free q
	SETZRO CBIDB,(P1)	;No longer need these buffers

SBF.EX:	RETSKP
	SUBTTL Buffer management routines -- SC.ALD (Allocate long datagram buffers)

; This routine allocates long datagram buffers. In order to receive a long 
;datagram you must queue a buffer obtained with this routine.
;
; Usage:
;	Call
;	T1/	Number of buffers desired
;
;	Return (+1)
;	Not enough buffers available to fill request, try again later
;
;	Return (+2)
;	T1/	Address of first buffer on chain
;	T2/	Number of buffers returned
;	T3/	Address of routine to return buffers
;
; Local AC usage:
;	T1/	Pointer to current buffer
;	T3/	Saved copy of current buffer pointer
;	T4/	Number of buffer left in request
;
SC.ALD::MOVE T2,T1		;A copy we can work with
	CIOFF			;Interlock the buffer counts
   IFN SCADBG,<
	CALL SC.TDQ		;Trace the datagram free queue
>				;End of IFN SCADBG
	SUB T2,DFQCNT		;(T2) = (request) - (available)
	SKIPLE T2		;Is the request more than we have available???
	JRST SAL.RF		;Yes, refuse the request
	MOVMS T2		;(T2) = (available) - (request)
	CAML T2,DGTRSH		;Will there be enough left over after request??
	IFSKP.
	 CAML T1,LRGREQ		;No, but is this a small request???
	 JRST SAL.RF		;No, a large request, refuse it
	 AOS DBUST		;Count another small request busting threshold
	ENDIF.

; Here to honor the request.
;
	STKVAR <NUMBUF>
	MOVEM T1,NUMBUF		;Save the number of buffers requested
	MOVE T4,T1		;Working copy of the request size
	SKIPN T1,TOPDFQ		;Is there a first buffer, get its address
	JRST SAL.ER		;Handle a bad buffer count

	MOVE T2,T1		;Start buffer loop with addr of first buffer
SAL.BL:	SOJLE T4,SAL.CR		;If no more buffers,fix up count and Q pointers
	SKIPN T2,(T2)		;Now on to the next buffer
	JRST SAL.ER		;No entry!!! Recover from a bad FQCNT
	JRST SAL.BL		;Loop for more entries

; Here when we have completed the request.
;
;	Expects:
;	T1/	Address of first buffer to be returned
;	T2/	Address of last buffer to be returned
;
SAL.CR:	SKIPE T3,(T2)		;Get the addr of the new first buffer
	IFSKP.
	  XMOVEI T4,TOPDFQ	;No next buffer, get pointer to top of the Q
	  MOVEM T4,BOTDFQ	;  and init the queue BLINK as pointer to FLINK
	  SETONE CIBUF		;Ask CIFORK fork to run for us
	ENDIF.
	MOVEM T3,TOPDFQ		;In any case update the q FLINK
	SETZM (T2)		;Zero forward link of last buffer
	MOVN T3,NUMBUF		;Get the number of buffers issued
	ADDM T3,DFQCNT		;Account for these in buffer counts
   IFN SCADBG,<
	CALL SC.TDQ		;Trace the datagram free queue
>				;End of IFN SCADBG
	MOVE T3,MINDG		;Number of buffers we should have onhand 
	CAMGE T3,DFQCNT		;Are there enough buffers around these days???
	JRST SAL.EX		;Yes, bail out now...
	SETONE CIBUF		;Ask CIFORK fork to run for us

SAL.EX:	CION			;Restore the channel
   IFN SCARNG,<
	MOVE T3,NUMBUF		;Get buffer count
	BLOCK.
	  SAVEAC <T1>		;Save the base address of buffer chain
	  MOVE T4,T1		;Get base address of buffer chain
     	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-6(P)		;Get PC of caller to feature routine
	  CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
	ENDBK.
>				;End of IFN SCARNG
	MOVE T2,NUMBUF		;Return the number of buffers queued
	XMOVEI T3,SC.RLD	;Tell caller where to return this buffer pls...
	RETSKP			;Return all OK

; Here to refuse the request. We have some book keeping to do.
;
;	T1/	Request size
;
SAL.RF:	ADD T1,ASRDR		;Add current average size to  new request
	SKIPE RDRCNT		;Don't averge if this is the first time through
	IDIVI T1,2		;Take the average of the two
	MOVEM T1,ASRDR		;Update the average size of refused request
	AOS RDRCNT		;Increment the number of refused requests
	CION			;Release the counters
   IFN SCARNG,<
     	XMOVEI T1,.		;Get feature routine address
	MOVE T2,(P)		;Get PC of caller to feature routine
	MOVE T3,RDRCNT		;Get count of refused requests
	SETOM T4		;Indicate buffer was not created
	CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
>				;End of IFN SCARNG
	RETBAD (SCSNBA)		;Return not enough buffers

; Here when we discover that the count was incorrect and that we have fewer
;buffers than we thought.
;
; Expects:
;	T1/	Address of first buffer on returned chain
;
SAL.ER:	SETONE CIBUF		;Ask CIFORK fork to run for us
	AOS NDBCNT		;Count this event
	AOS RDRCNT		;Increment the number of refused requests
	MOVE T1,NUMBUF		;Get the request size again
	ADD T1,ASRDR		;Add current average size to  new request
	IDIVI T1,2		;Take the average of the two
	MOVEM T1,ASRDR		;Update the average size of refused request

; Now readjust the buffer count
;
	SETZ T2,		;Zero the buffer count
	SKIPE T1,TOPDFQ		;Are there any buffers here???
	IFSKP.
	  XMOVEI T1,TOPDFQ	;No, get a pointer to the Q FLINK
	  MOVEM T1,BOTDFQ	;Init the Q tail pointer
	  SETZM TOPDFQ		;Init the Q head pointer
	  SETZM DFQCNT		;Reset count of buffers
	  JRST SAL.EE		;  and error exit
	ENDIF.
	AOS T2			;Count the initial buffer
	SKIPE T1,(T1)		;Is there a next buffer
	AOJA T2,.-1		;Yes, continue to count buffers
	MOVEM T2,DFQCNT		;Restore the buffer count
   IFN SCADBG,<
	CALL SC.TDQ		;Trace the datagram free queue
>				;End of IFN SCADBG

SAL.EE:	CION			;Restore the state of the PI
   IFN SCARNG,<
     	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-3(P)		;Get PC of caller to feature routine
	MOVE T3,RDRCNT		;Get count of refused requests
	SETOM T4		;Indicate buffer was not created
	CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
>				;End of IFN SCARNG
	RETBAD (SCSNBA)		;Return failure

	ENDSV.
	SUBTTL Buffer management routines -- SC.ABF (Allocate a buffer/buffers)

; This routine is used to obtain message buffers from SCA. When you wish to
;receive or send a message, you must obtain the buffer from here. 
;All you need to tell SCA is how many buffers you want. What is returned to you
;is a chain of buffers containing the number of buffer you asked for.
;
; Usage:
;	Call
;	T1/	Number of buffers desired
;
;	Return (+1)
;	T1/	Error code (No buffers returned)
;
;	Return (+2)
;	T1/	Address of the first buffer in the returned chain
;	T2/	Count of buffer returned
;	T3/	Address of routine to call to return buffers
;
SC.ABF::MOVE T2,T1		;A copy we can work with
	CIOFF			;Interlock the buffer counts
   IFN SCADBG,<
	CALL SC.TMQ		;Trace the message free queue
>				;End of IFN SCADBG
	SUB T2,FQCNT		;(T2) = (request) - (available)
	SKIPLE T2		;Is the request more than we have available???
	JRST SAB.RF		;Yes, refuse the request
	MOVMS T2		;(T2) = (available) - (request)
	CAML T2,MGTRSH		;Will there be enough left over after request??
	IFSKP.
	 CAML T1,LRGREQ		;No, but is this a small request???
	 JRST SAB.RF		;No, a large request, refuse it
	 AOS MBUST		;Count another small request busting threshold
	ENDIF.

; Here to honor the request.
;
SAB.PR:	STKVAR <NUMBUF>
	MOVEM T1,NUMBUF		;Save the number of buffers requested
	MOVE T4,T1		;Working copy of the request size
	SKIPN T1,TOPFQ		;Is there a first buffer, get its address
	JRST SAB.ER		;Handle a bad buffer count

	MOVE T2,T1		;Start buffer loop with addr of first buffer
SAB.BL:	SOJLE T4,SAB.CR		;If no more buffers,fix up count and Q pointers
	SKIPN T2,(T2)		;Now on to the next buffer
	JRST SAB.ER		;No entry!!! Recover from a bad FQCNT
	JRST SAB.BL		;Loop for more entries

; Here when we have completed the request.
;
;	Expects:
;	T1/	Address of first buffer to be returned
;	T2/	Address of last buffer to be returned
;
SAB.CR:	SKIPE T3,(T2)		;Get the addr of the new first buffer
	IFSKP.
	  XMOVEI T4,TOPFQ	;No next buffer, get pointer to top of the Q
	  MOVEM T4,BOTFQ	;  and init the queue BLINK as pointer to FLINK
	  SETONE CIBUF		;Ask CIFORK fork to run for us
	ENDIF.
	MOVEM T3,TOPFQ		;In any case update the q FLINK
	SETZM (T2)		;Zero forward link of last buffer
	MOVN T3,NUMBUF		;Get the number of buffers issued
	ADDM T3,FQCNT		;Account for these in buffer counts
   IFN SCADBG,<
	CALL SC.TMQ		;Trace the message free queue
>				;End of IFN SCADBG
	MOVE T3,MINMSG		;Number of buffers we should have onhand 
	CAMGE T3,FQCNT		;Are there enough buffers around these days???
	JRST SAB.EX		;Yes, bail out now...
	SETONE CIBUF		;Ask CIFORK fork to run for us

SAB.EX:	CION			;Restore the channel
   IFN SCARNG,<
	MOVE T3,NUMBUF		;Get buffer count
	BLOCK.
	  SAVEAC <T1>		;Save the base address of buffer chain
	  MOVE T4,T1		;Get base address of buffer chain
     	  XMOVEI T1,.		;Get feature routine address
	  MOVE T2,-6(P)		;Get PC of caller to feature routine
	  CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
	ENDBK.
>				;End of IFN SCARNG
	MOVE T2,NUMBUF		;Return the number of buffers requested
	XMOVEI T3,SC.RBF	;Tell caller where to return this buffer pls...
	RETSKP			;Return all OK

; Here to refuse the request. We have some book keeping to do.
;
;	T1/	Request size
;
SAB.RF:	ADD T1,ASRMR		;Add current average size to  new request
	SKIPE RMRCNT		;If this is the first time, no averaging needed
	IDIVI T1,2		;Take the average of the two
	MOVEM T1,ASRMR		;Update the average size of refused request
	AOS RMRCNT		;Increment the number of refused requests
	CION			;Release the counters
   IFN SCARNG,<
     	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-3(P)		;Get PC of caller to feature routine
	MOVE T3,RMRCNT		;Get count of refused requests
	SETOM T4		;Indicate buffer was not created
	CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
>				;End of IFN SCARNG
	RETBAD (SCSNBA)		;Return not enough buffers

; Here when we discover that the count was incorrect and that we have fewer
;buffers than we thought.
;

SAB.ER:	MOVE T1,FQCNT		;Get number of buffers we thought we had
	MOVE T2,TOPFQ		;Get pointer to top of free queue
	MOVE T3,BOTFQ		;Get pointer to bottom of free queue
	MOVE T3,NUMBUF		;Get number of buffers requested
	BUG. (CHK,SCAMCR,SCAMPI,SOFT,<SCA - Message buffer count was incorrect>,<<T1,COUNT>,<T2,TOPQ>,<T3,BOTQ>,<T4,BUFNUM>>,<

Cause:	There are no message buffers when the count indicated there are enough.

Data:	COUNT  - count of buffers we believed we had
	TOPQ   - pointer to top of message free queue
	BOTQ   - pointer to bottom of message free queue
	BUFNUM - number of buffers requested
>)
   IFN SCARNG,<
     	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-3(P)		;Get PC of caller to feature routine
	MOVE T3,RMRCNT		;Get number of refused requests
	SETOM T4		;Indicate buffer was not created
	CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
>				;End of IFN SCARNG
	SETONE CIBUF		;Ask CIFORK fork to run for us
	AOS NMBCNT		;Count this event
	AOS RMRCNT		;Increment the number of refused requests
	MOVE T1,NUMBUF		;Get the request size again
	ADD T1,ASRMR		;Add current average size to  new request
	IDIVI T1,2		;Take the average of the two
	MOVEM T1,ASRMR		;Update the average size of refused request

; Now readjust the buffer count
;
	SETZ T2,		;Zero the buffer count
	SKIPE T1,TOPFQ		;Are there any buffers here???
	IFSKP.
	  XMOVEI T1,TOPFQ	;No, get a pointer to the Q FLINK
	  MOVEM T1,BOTFQ	;Init the Q tail pointer
	  SETZM TOPFQ		;Init the Q head pointer
	  SETZM FQCNT		;Zero the buffer count...
	  JRST SAB.EE		;  and error exit
	ENDIF.
	AOS T2			;Count the initial buffer
	SKIPE T1,(T1)		;Is there a next buffer
	AOJA T2,.-1		;Yes, continue to count buffers
	MOVEM T2,FQCNT		;Restore the buffer count
   IFN SCADBG,<
	CALL SC.TMQ		;Trace the message free queue
>				;End of IFN SCADBG

SAB.EE: CION			;Restore the state of the PI system
        RETBAD (SCSNBA)		;Return failure

	ENDSV.
	SUBTTL Buffer management routines -- SC.CMG/SC.CDG (Create MSG/DG buffers)

; This routine creates emssage buffers by creating (touching) pages and
;turning them into SCA buffers. The pages used are created by touching them and
;then locking them down. Hence THIS ROUTINE MAY ONLY BE CALLED IN PROCESS 
;CONTEXT.
;
; Usage:
;	Call
;	T1/	Number of buffers to create
;
;	Return (+1)
;	T1/	Error code
;
;	Return (+2)
;	T1/	Address of first buffer on chain
;	T2/	Address of last buffer on chain
;	T3/	Number of buffers actually returned
;
; Note: The number of buffers returned is rounded up to fill an intgeral
;number of pages. Hence the calling routine may get more buffers back than it
;requested.
;
SC.CMG:	TDZA T2,T2		;Clear the datagram flag
SC.CDG: SETO T2,		;Set the datagram flag
	SAVEAC <Q1,Q2,P4,P5>
	STKVAR <BUFSZ,NUMPPG,NUMBUF>
	MOVX T3,C%MGSZ		;Assume messages
	MOVX T4,C%MGPG		;.	.	.
	SKIPE T2		;Good assumption???
	IFNSK.
	 MOVX T3,C%DGSZ		;Nope, get the size oF datagrams
	 MOVX T4,C%DGPG		;  and the number of datagrams per page
	ENDIF.
	MOVEM T3,BUFSZ		;Save the size of the buffers we desire
	MOVEM T4,NUMPPG		;Save the number of buffers per page
	MOVE Q1,T1		;Get the request size in buffers
	IDIV Q1,NUMPPG		;(Q1) = Number of pages in request
	SKIPE Q2		;Any remainder???
	AOS Q1			;Yes, round up the page count
	MOVE T1,Q1		;Get the page count we will create
	IMUL T1,NUMPPG		;Find the total number of buffers created
	MOVEM T1,NUMBUF		;Save for later return
	SETZ P4,		;Zero the page chain foreward pointer
	MOVEI P5,P4		;Make the tail pointer point to the head

; Create a chain of pages from which we can make buffers.

SCM.CP:	NOSKED			;Interlock the first free page in EPG pointer
	MOVE Q2,LSTEPG		;Get the last page we used from EPGSEC
	SKIPE @[EP. EPGMAP(Q2)]	;Is this page in use???
	SOJGE Q2,.-1		;Yes? Loop for the next one
	JUMPL Q2,SCM.ER		;Handle no pages left in EPGSEC
	MOVEM Q2,LSTEPG		;Store as the next page to use
	SOS LSTEPG		;Move pointer to next page
	OKSKED			;Release the last EPG page pointer
	LSH Q2,^D9		;Convert the page number into an address
	HRL Q2,EPGSEC		;Fill in the section number
	MOVE T1,Q2		;Address to lock
	CALL MLKMA		;Lock the page down please
	MOVEM Q2,(P5)		;Add entry to the end of the chain
	MOVEM Q2,P5		;  and update the tail pointer
	SOJG Q1,SCM.CP		;Loop if there are more pages to do

; Make the page chain into an SCA buffer chain

   IFN SCARNG,<
     	XMOVEI T1,.		;Get feature routine address
	MOVE T2,-12(P)		;Get PC of caller to feature routine
	MOVE T3,NUMBUF		;Get buffer count
	MOVE T4,P4		;Get base address of buffer chain
	CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
>				;End of IFN SCARNG
	MOVE T1,P4		;Get the base address of the page chain
	MOVE T2,BUFSZ		;Get the size of the buffers desired
	CALL SC.BBF		;Create the buffer chain
	MOVE T3,NUMBUF		;Return the total buffer count as well
	RETSKP			;Return all OK

; Here when we run out of pages in EPGSEC. This is only an indication of
;a different problem. In any case we should NEVER have so much memory in use
;for SCA buffers that we overrun the section. Hence die here... In general
;this means someone is not lighting F.RTB when it should be and buffers are 
;ending up on the hardware free queue by the dozen...
;
SCM.ER:	OKSKED
	BUG. (CHK,SCABSF,SCAMPI,SOFT,<SCA - Buffer section full>,<>,<

Cause:	SCA went to create more buffers and discovered that the section
	is full. This is an indication that buffers are not being returned.
>)
	RETBAD (SCSNEB)
	ENDSV.
	SUBTTL Buffer management routines -- SC.BBF (Break memory into buffers)

; Give this routine the number of buffers you would like and it will get a
;block of memory and break it up into the number of message buffers
;you asked for. The major use of this routine is the initialization code and 
;the code that gets buffers after we have run out during system operation.
;
; Usage:
;	Call
;	T1/	Address of first page in page list
;	T2/	Buffer size
;
;	Return (+1) Always
;	T1/	Address of first buffer on chain
;	T2/	Address of last buffer on chain
;	
; Local AC usage:
;
;	T1/	Address of first buffer in list
;	T2/	Address of last buffer in list
;	T3/	Number of words left in the current page
;	T4/	Address of the next buffer
;
;	P1/	Address of next page 
;	P2/	Count of buffers obtained so far
;
SC.BBF:	SAVEP			;Save the regs we use for work
	STKVAR <BUFSIZ>		;Allocate space for the buffer size
	ADDI T2,C%BINV		;Add invisible space size to buffer size
	MOVEM T2,BUFSIZ		;Save the alleged buffer size 
	MOVEM T1,P1		;Save the callers list pointer
	ADDI T1,C%BINV		;Create the invisible buffer area
	MOVEM T1,T2		;For init, tail is same as head pointer
	SETZ P2,		;Init the count at zero
	MOVEI T3,PGSIZ		;Get the size of a page
	MOVE P1,(P1)		;Get the address of the next page
	MOVEM T1,T4		;Init next addr as first addr

SBB.BL:	CAMGE T3,BUFSIZ		;Have we run out of room on this page???
	JRST SBB.PL		;Yes we have, do the next page pls...
	AOS P2			;Count this buffer into the total
	MOVEM T4,T2		;Update the tail pointer
	MOVE T4,BUFSIZ		;Get the size of a buffer
	ADDM T2,T4		;Make it the address of the next buffer
	MOVEM T4,(T2)		;Link it onto the list
	SUB T3,BUFSIZ		;Update page space counter
	JRST SBB.BL		;Loop over the whole page

; Here to loop over pages...
SBB.PL:	SETZM (T2)		;Be sure nxt ptr is zero since we might be done
	SKIPN P1		;Is there a next page to do???
	JRST SBB.EX		;Nope, go exit
	MOVE T4,P1		;Yes, get addr of next page
	ADDI T4,C%BINV		;Create the invisible space
	MOVEM T4,(T2)		;Link last page to new page
	MOVE P1,(P1)		;Get the address of the next page
	MOVEI T3,PGSIZ		;Reset the page space counter
	JRST SBB.BL		;And break this page into buffers.

; Here to leave the routine. Place args where we promised them...
;
SBB.EX:	MOVE T3,P2		;Set up the count of buffers
	RET			;And return
	ENDSV.
	SUBTTL Buffer management routines -- SC.RBF (Return a message buffer)

; This routine is called when you wish to return a buffer to SCA which you
;received from SCA. All that must be done is hand SCA a pointer to the
;buffer and away we go.
;
; Usage:
;	Call
;	T1/	Address of buffer to be returned
;
;	Return (+1) Always
;	No data returned, all buffers returned OK
;
SC.RBF::MOVE T4,T1		;Save the address of the buffer
	MOVE T2,T1		;Make this address the source for XBLT
	SUBI T2,C%BINV		;Move the origin to the start of the invisible
	MOVE T3,T2		;  and the destination
	AOS T3			;  is one more than the source
	MOVX T1,<C%BINV+C%MGSZ>-1 ;Number of words to zero
	SETZM (T2)		;Zero the first word
	EXTEND T1,[XBLT]	;Zero the buffer please
	MOVE T1,T4		;Restore the address of the buffer
	CIOFF			;Interlock my queues
	MOVEM T1,@BOTFQ		;Link this buffer after the end of the list
	MOVEM T1,BOTFQ		;Store the new free queue bottom pointer
	SETZM (T1)		;Insure the FLINK of last buffer is zero
	AOS FQCNT		;Update the buffer count
   IFN SCADBG,<
	CALL SC.TMQ		;Trace the message free queue
>				;End of IFN SCADBG
	CION			;Bring back the world again
   IFN SCARNG,<
     	XMOVEI T1,.		;Get feature routine address
	MOVE T2,(P)		;Get PC of caller to feature routine
	SETOM T3		;Buffer is being returned
	CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
>				;End of IFN SCARNG
	RET			;Return
	SUBTTL Buffer management routines -- SC.RLD (Return a datagram buffer)

; This routine is called when you wish to return a long datagram buffer to SCA.
;All that must be done is hand SCA a pointer to the buffer.
;
; Usage:
;	Call
;	T1/	Address of buffer to be returned
;
;	Return (+1) Always
;	No data returned, buffer is now in SCA database
;
SC.RLD::MOVE T4,T1		;Save the address of the buffer
	MOVE T2,T1		;Make this the start address
	SUBI T2,C%BINV		;Move back to start of the invisible area
	MOVE T3,T2		;Destination address is the start address
	AOS T3			;  plus one
	MOVX T1,<C%BINV+C%DGSZ>-1 ;Get the size of the buffer to be zeroed
	SETZM (T2)		;Zero the first word
	EXTEND T1,[XBLT]	;Zero the buffer
	MOVE T1,T4		;Get the address of the buffer back
	CIOFF			;Interlock my queues
	MOVEM T1,@BOTDFQ	;Link this buffer after the end of the list
	MOVEM T1,BOTDFQ		;Store the new free queue bottom pointer
	SETZM (T1)		;Zero the buffer FLINK
	AOS DFQCNT		;Update the buffer count
   IFN SCADBG,<
	CALL SC.TDQ		;Trace the datagram free queue
>				;End of IFN SCADBG
	CION			;Bring back the world again
   IFN SCARNG,<
     	XMOVEI T1,.		;Get feature routine address
	MOVE T2,(P)		;Get PC of caller to feature routine
	SETOM T3		;Buffer is being returned
	CALL RG.BFM		;(T1,T2,T3,T4) Record buffer management
>				;End of IFN SCARNG
	RET			;Return

   IFN SCADBG,<
	SUBTTL Buffer management routines -- SC.TMQ/SC.TDQ (Trace free queue)

; These routines are called whenever a message or datagram buffer is being 
;removed from or replaced to the free queue.  The queue is traced and the count is 
;compared against the known count.  If an inconsistency occurs, a SCATQF 
;BUGHLT will result.
;
; Usage: 
;
;For a trace of the message free queue:
;
;	Call SC.TMQ
;
;	Return (+1) Always
;
;For a trace of the datagram free queue:
;
;	Call SC.TDQ
;
;	Return (+1) Always
;
;No ACs are destroyed by either routine.
;Both routines must be called CIOFF.

SC.TMQ:	SAVEAC <T1,T2,T3>	;Save the ACs we use
	MOVE T1,FQCNT		;Get known count of free queue message buffers
	SKIPE T2,TOPFQ		;Get first buffer on queue
	IFSKP.			;No buffers
	  SKIPN T1		;Did we believe we had any?
	  RET			;No, return ok
	  JRST SCT.ER		;Error, report it
	ENDIF.
	JRST SCT.CC		;Continue at common code

SC.TDQ:	SAVEAC <T1,T2,T3>	;Save the ACs we use
	MOVE T1,DFQCNT		;Get known count of free queue datagram buffers
	SKIPE T2,TOPDFQ		;Get first buffer on queue
	IFSKP.			;No buffers
	  SKIPN T1		;Did we believe we had any?
	  RET			;No, return ok
	  JRST SCT.ER		;Error, report it
	ENDIF.

SCT.CC:	MOVEI T3,1		;Set up initial value of buffers on queue
	SKIPE T2,(T2)		;Is there a next buffer?
	AOJA T3,.-1		;Yes, continue to count buffers
	CAMN T3,T1		;Are the counts the same?
	RET			;Yes, return ok

SCT.ER:	BUG. (HLT,SCATQF,SCAMPI,SOFT,<SCA - Trace of free queue detected inconsistency>,,<

Cause:	The trace of the message or datagram free queue resulted in a count
	which was not equal to the known value which SCA keeps.
>)
>				;End of IFN SCADBG
	SUBTTL Byte-swapping routines
	SUBTTL Byte-swapping routines -- SC.RIN (Byte swap incoming packet)

; This routine performs magic on the packet header words.
;Since VAX and 11's have their heads wedged we must swap the order of the 
;bytes that go out and come in from these systems. 
;
;Usage:
;	Call
;	P2/	Address of packet being sent
;
;	Return (+1) Always
;	Header at address in P2 has been byte swapped
;
;
SC.RIN:	SAVEAC <T1,T2,T3,T4,P5>	;Be sure we smash no ACs
	LOAD T1,MH$TYP,(P2)	;Get the word conatining the message type
	LDB P5,[POINT 1,T1,24]	;Get the -11 style sign bit
	CALL SC.ISW		;Swap to get -10 style bytes
	SKIPE P5		;Was the number of credits negative???
	TXO T1,<3B1>		;Yes, light the bits to make this a -10 neg num
	STOR T1,MH$TYP,(P2)	;Put it back into the packet

	LOAD T1,MH$MSG,(P2)	;Now get the message type
	CAIE T1,.STADG		;Is this an application datagram
	CAIN T1,.STAMG		;  or application message?
	RET			;Yes it is!! Skip status and min credit word

	LOAD T1,MH$SMC,(P2)	;No... get the word uncommon to ADG and AMG
	CALL SC.ISW		;Call the byte swapper
	STOR T1,MH$SMC,(P2)	;Move the word back out to the header
	RET
	SUBTTL Byte-swapping routines -- SC.ISW (Swap bytes from 11 to 10 format)

; This routine byte swaps a word from 11 format to 10 format.
;
; Usage:
;	Call
;	T1/	Word to be swapped
;
;	Return (+1) Always
;	T1/	Byte swapped word
;
; Input format:
;	2 16 bit half words, left justified
;
; !=======================================================!
; !  B (lsb)  !  B (msb)  !  A (lsb)   !   A (msb)  ! IGN !
; !=======================================================!
; 0          7 8        15 16        23 24        31 32  35
;
; Where A and B are the half words, and (lsb) are the least significant bits 
;and (msb) are the most significant bits.
;
;The contents of bits 32 thru 35 are ignored.
;
;  Output format:
; 2 18 bit half words,
;
; !=======================================================!
; !X!    Byte A (msb+lsb)     !X!     Byte B (msb +lsb)   !
; !=======================================================!
; 0  2                      17 	 20			 35
;
; X denotes the 2 bit field within each halfword that will always be zero.
;
SC.ISW::LDB T2,EA$MSB		;Byte A, MSB
	LDB T3,EA$LSB		;Byte A, LSB
	LDB T4,EB$MSB		;Byte B, MSB
	LSH T1,^D<-28>		;Move byte B, LSB into its poisition for the 10
	DPB T4,TB$MSB		;Now replace the bytes into their 10 positions
	DPB T3,TA$LSB		;.	.	.
	DPB T2,TA$MSB		;.	.	.
	RET			;All done
	SUBTTL Byte-swapping routines -- SC.ROU (Byte swap outgoing packet)

; This routine byte swaps a packet for output to the wire...
;
; Usage:
;	Call
;	P2/	Address of packet
;
;	Return (+1) Always
;	P2/	Packet address, packet has been byte swapped
;	
SC.ROU:	SAVET			;Be sure we smash no ACs
	LOAD T1,MH$MSG,(P2)	;Get the message type
	CAIE T1,.STADG		;Is this an application message???
	CAIN T1,.STAMG		;  or application message
	JRST SRO.CN		;Yes it is!! Skip status and min credit word

	LOAD T1,MH$SMC,(P2)	;No... get the word uncommon to ADG and AMG
	CALL SC.OSW		;Call the byte swapper
	STOR T1,MH$SMC,(P2)	;Move the word back out to the header

SRO.CN:	LOAD T1,MH$TYP,(P2)	;Lastly the credit and message type word
	SKIPGE T1		;Non-neg??? If yes, go handle the normal case
	TXZ T1,<3B1>		;Else zero the bits that get in the way
	CALL SC.OSW		;Byte swap this one too pls...
	STOR T1,MH$TYP,(P2)	;   and replace it in the header
	RET			;All done...
	SUBTTL Byte-swapping routines -- SC.OSW (Swap word from 10 to 11 format)

; This routine swaps individual words from PDP-10 format to PDP-11 format. 
;Since these folks number funny we must do this oddity...
;
; Usage:
;	Call
;	T1/	Words to swap
;
;	Return (+1) Always
;	T1/	Byte swapped word
;
;Input format:
; 2 18 bit half words,
;
; !=======================================================!
; !       Byte A (msb+lsb)     !     Byte B (msb +lsb)    !
; !=======================================================!
; 0                          17 18		         35
;
;
;
;
; Output format:
;	2 16 bit half words, left justified
;
; !=======================================================!
; !  B (lsb)  !  B (msb)  !  A (lsb)   !   A (msb)  ! IGN !
; !=======================================================!
; 0          7 8        15 16        23 24        31 32  35
;
; Where A and B are the half words, and (lsb) are the least significant bits 
;and (msb) are the most significant bits.
;
SC.OSW::LDB T2,TA$MSB		;Get ten byte A, MSB
	LDB T3,TA$LSB		;Ten byte A, LSB
	LDB T4,TB$MSB		;Ten byte B, MSB
	LSH T1,^D28		;Move ten byte B, LSB into correct position
	DPB T4,EB$MSB		;Eleven byte B, MSB
	DPB T3,EA$LSB		;Eleven byte A, LSB
	DPB T2,EA$MSB		;Eleven byte A, MSB
	RET			;All done return pls...
	SUBTTL Locking/unlocking routines

	SUBTTL Locking/unlocking routines -- SC.POF (Turn KLIPA channel off)

; This routine is the KLIPA channel controlling routine. it is called by what
;used to be a macro (CIOFF). The macro took no arguments so a CIOFF macro
;expansion or an inline call to this routine are equivalent.
;
; We are rather careful here about a few things. First check if we are at
;KLIPA interrupt level. If we are do nothing at all. If we are not at interrupt
;level but the channel is already off, go NOSKED to lock down the nesting
;counter and increment said counter. Do not set the PIFLAG however. If we are
;not at interrupt level and the channel is on, go NOSKED, increment the
;nesting counter, set PIFLAG, and turn off the channel.
;
; Usage:
;	Call
;	No arguments
;
;	Return (+1) Always
;	The KLIPA channel is either off, or we are at interrupt level
;
; *** Warning ***
;	The pain factor for this routine is approximatly .96. Be sure you
;full understand it before trying to change it...
;
SC.POF::
   IFN SCARNG,<			;If ring buffer recording is on
	SAVEAC <T1,T2>
      	XMOVEI T1,.		;Get feature address
	MOVE T2,-3(P)		;Get caller to this routine
	CALL RG.PIT		;(T1,T2) Record the PI transition
>				;End of IFN SCARNG
   IFE SCARNG, SAVEAC <T1>
	CONI PI,T1		;Get current PI state
	TRNE T1,<1B25>		;Are we in KLIPA interrupt code???
	RET			;Yes. Do nothing at all here
	SKIPN CHNCTL		;If we have been here before, dont NOSKED again
	NOSKED			;Be the only kid on the block
	AOS CHNCTL		;Show another channel off has happened
	TRNN T1,<1B33>		;Is the KLIPA channel already off???
	RET			;Yes, return now
	CHNOFF PHYCHN		;Turn off the CI channel
	SETOM PIFLAG		;Show last CION that it must do channel on
	RET			;Return all OK
	SUBTTL Locking/unlocking routines -- SC.PON (Turn KLIPA channel on)

; This routine turns the KLIPA channel back on only if we are the outermost
;nesting level. It also checks that the outmost loop actually did a channel
;off (PIFLAG -- 0 indicates no channel off was done). Note that whenever
;the nest counter (CHNCTL) is changed we are NOSKED. This MUST be since
;CHNCTL is system wide not per process storage. Also note that we avoid doing
;redundant NOSKEDs by checking CHNCTL for previous invocations.
;
; Usage:
;	Call
;	No arguments
;
;	Return (+1) Always
;	Channel is off or you are already at KLIPA interrupt level
;
; *** Warning **
;	The pain factor for this routine is approximatly .96. Be sure you
;understand it before you try to change it...
;
SC.PON::
   IFN SCARNG,<			;If ring buffer recording is on
	SAVEAC <T1,T2>
      	XMOVEI T1,.		;Get feature address
	MOVE T2,-3(P)		;Get caller to this routine
	CALL RG.PIT		;(T1,T2) Record the PI transition
>				;End of IFN SCARNG
   IFE SCARNG, SAVEAC <T1>
	CONI PI,T1		;Get current PI state
	TRNE T1,<1B25>		;Are we in KLIPA interrupt code???
	RET			;Yes, we have nothing to do here

; Do nothing until we reach the outermost nesting of calls to SC.POF. This
;prevents routine A from going channel off, calling routine B which goes 
;channel off and then channel on. The channel on done by routine B does 
;nothing. The channel on done by routine A will actually turn on the channel.
;
	SOSLE CHNCTL		;Is this an outermost CION in a nest???
	 RET			;No, do nothing
	SKIPE CHNCTL
	BUG. (HLT,SCAODI,SCAMPI,SOFT,<SCA - Overly decremented CI interlock>,,<

Cause:	A CION was done when no previous CIOFF had occurred. This leads to
	an overly-decremented lock.

Action:	If you are unable to determine how this happened, turn on the ring
	buffer tracing of interlocks. (Do this by setting RPITRN in RINGSW.)
	It should be possible to pair each CION with a preceding CIOFF.
	Note that these calls are invoked from several CI-related modules.
>)

; Here at the outermost nesting level, I.E. the first routine to do the channel
;off. See if that channel off really did the CONO or was the channel off when
;we got there (I.E. did someone turn it off behind my back)...
;
	SKIPE PIFLAG		;Should we really turn on the channel again?
	JRST SPO.CO		;Yes, go turn on the channel
	OKSKED			;No! But still at outer loop, go OKSKED
	RET			;  and return

; Here when that first channel off really did the CONO. Turn the channel
;back on and go OKSEKD..
;
SPO.CO:	SETZM PIFLAG		;Clear channel on flag since we are about to
	CHNON PHYCHN		;Turn on the CI channel once more
	OKSKED			;Allow other kids onto the block again
	RET			;  and return
	SUBTTL Locking/unlocking routines -- SC.LOK (Lock connection block)

;SC.LOK - lock a c.b.

;Accepts:
;	P1/ address of c.b.

;	CALL SC.LOK

;Returns +1: always

;Preserves all AC's.

;Caller usually needs to be CIOFF, since it wants to verify the
;existence of the connection block and then lock it without being
;interrupted.

SC.LOK:	SZPI 1B25		;Is channel 5 in progress?
	RET			;Yes. Don't need a lock, then
	NOSKED			;No. Make sure no one else can lock it
	AOS .CBLCK(P1)		;Increment the lock
   IFN SCARNG,<
	SAVET			;Save temporary ACs
      	XMOVEI T1,.		;Get feature address
	MOVE T2,-5(P)		;Get caller to this routine
	CALL RG.ITL		;(T1,T2,P1/) Record the interlock call
>				;End of IFN SCARNG
	RET

;SC.LAH - Lock and honor

;Accepts:
;	T1/ bit to be set if lock is locked
;	P1/ address of connection block

;	CALL SC.LAH

;Returns +1: someone else has it locked
;	 +2: we got the lock


SC.LAH:	SZPI 1B25		;Is channel 5 interrupt in progress?
	IFSKP.
	  NOSKED		;No. We get the lock
	  AOS .CBLCK(P1)	;Increment the lock
   IFN SCARNG,<
	  SAVET			;Save temporary ACs
      	  XMOVEI T1,.		;Get feature address
	  MOVE T2,-5(P)		;Get caller to this routine
	  CALL RG.ITL		;(T1,T2,P1/) Record the interlock call
>				;End of IFN SCARNG
	  RETSKP
	ENDIF.
;	JRST SC.HNR

;SC.HNR - honor the c.b. lock

;Accepts:
;	T1/ bit to be set if it's locked
;	P1/ address of connection block

;	CALL SC.HNR

;Returns +1: someone else has the lock
;	 +2: we got the lock

;Caller must be at interrupt level

SC.HNR:
	SKIPN .CBLCK(P1)	;Is it locked?
	RETSKP			;No. We can proceed
	IORM T1,.CBFLG(P1)	;Indicate what was deferred
   IFN SCARNG,<
	SAVET			;Save temporary ACs
        XMOVEI T1,.		;Get feature address
        MOVE T2,-5(P)		;Get caller to this routine
        CALL RG.ITL		;(T1,T2,P1/) Record the interlock call
>				;End of IFN SCARNG
	RET			;Return failure
	SUBTTL Locking/unlocking routines -- SC.ULK (Unlock connection block)

;SC.ULK - Unlock the connection block

;Accepts:
;	P1/ address of connection block

;	CALL SC.ULK

;Returns +1: always

;Saves T1 because error code is in it

;We're NOSKED, so the reaper can't run and delete the connection block

SC.ULK:	SZPI 1B25		;Is interrupt on level 5 in progress?
	RET			;Yes. Nothing to do, then
	SAVEAC <T1,P3,P4,P5>
   IFN SCARNG,<
	BLOCK.
	  SAVET			;Save temporary ACs
      	  XMOVEI T1,.		;Get feature address
	  MOVE T2,-13(P)	;Get caller to this routine
	  CALL RG.ITL		;(T1,T2,P1/) Record the interlock call
	ENDBK.
>				;End of IFN SCARNG
	MOVE T1,.CBLCK(P1)	;What's the current value of the lock?
	CAIG T1,1		;Quit if it's not 1
	IFSKP.
	  SOS .CBLCK(P1)	;Decrement it
	  OKSKED		;Lock routine went NOSKED
	  RET			;Last unlocker will do the rest
	ENDIF.
   IFN SCADBG,<
	SKIPG T1		;Should never be less than 1
	BUG. (HLT,SCAILC,SCAMPI,SOFT,<SCA - Illegal lock count in connection block>,,<

Cause:	The routine to unlock a connection block found that the count
	is less than 1. Since the caller must have locked the connection
	block earlier, something unexpected has happened.

>)
   >

;Current value is 1. We will be the last unlocker. See what sorts of
;things have been deferred, and call the appropriate routines.

;Each processing routine clears its bit. If the bit gets set again while
;we're in here, we will detect that.

	SETZB P3,P5		;Initialize flags
	MOVE P4,.CBSBA(P1)	;Get address of system block

;See if anything happened while we had this locked. Need to be CIOFF to
;avoid having the bit set after we make the check, and unlocking the
;c.b. without processing the deferred event.

SC.UL2:	CIOFF			;Need to check for newly-set bits race-free
	TMNN CBFDEF,(P1)	;Anything deferred?
	JRST SC.UL6		;No.
	CION			;Yes.

;Test and handle each possible event. Node offline is first.

	TMNN CBFERR,(P1)	;Deferred node offline?
	IFSKP.
	  SETOM P5		;Yes. Indicate we had deferred node offline
	  CALL SC.FN1		;(P1,P4/) Do what's left to be done
	ELSE.
	  TMNE CBFDIS,(P1)	;Sysap wanted disconnect?
	  CALL SC.FN2		;(P1,P4/) Yes. Finish that
	  TMNE CBFDRQ,(P1)	;Disconnect_request arrived?
	  CALL SC.FN3		;(P1,P4/) Yes. FInish that
	ENDIF.
SC.UL3:	TMNN CBFSNM,(P1)	;Wanted to send connect management request?
	IFSKP.
	  SETZRO CBFSNM,(P1)	;Yes. Indicate no longer deferred
	  SETOM P3		;Remember this
	ENDIF.
	JRST SC.UL2		;See if anything new has come up

;Nothing left to do. Unlock the block.

SC.UL6:	SOS .CBLCK(P1)		;Unlock the c.b.
	CION
   IFN SCADBG,<
	SKIPE .CBLCK(P1)	;Better be zero now!
	BUG. (HLT,SCALCC,SCAMPI,SOFT,<SCA - Connection block lock count has changed>,,<

Cause:	The routine to unlock a connection block has found an inconsistency
	in the lock count. Earlier in the routine, the current count was 1.
	Now, after decrementing it, the count is not zero. Some other context
	must have changed it. This should not happen since the locker is
	NOSKED and interrupt level code doesn't change the lock.
>)
   >
	OKSKED			;Lock routine went NOSKED

;If we had wanted to send a connection management request, do it

	SKIPE P3
	CALL SC.SNM		;(P4/) Send if there's anything to send

;If this block's node had gone offline, we have put off reopening the v.c.
;because of the locked c.b. If this is the last one to be unlocked, open
;the v.c.

	SKIPN P5		;Had we deferred node offline?
	RET			;No.
	SOSE .SBCLC(P4)		;Decrement system block count of locked c.b.'s
	RET			;Still have more to go
	SETZRO SBFOVC,(P4)	;No longer waiting to open
	BLCAL. (OPENVC,<P4>)	;Let PHYKLP open the v.c.
	RET
   IFN SCARNG,<

	SUBTTL Ring Buffer routines

	SUBTTL Ring Buffer routines -- SC.RGI (Initialize ring buffer variables)

;This routine initializes the ring buffer
;
; Usage:
;
;	CALL SC.RGI
;
;	Returns:	+1 Failure - could not allocate buffer space
;			+2 Success
;
;	No data is returned and no ACs are smashed.

SC.RGI:	SAVEAC <T1,T2>		;Saved smashed ACs
	MOVEI T1,RBFLEN		;Number of pages for ring buffer
	CALL PGRSKD		;(T1/T1,T2) Get space from extended section
	 RET			;No space, return failure
	IMULI T2,PGSIZ		;Compute actual size of ring buffer
	MOVEM T2,RNGSIZ		;Save it
	MOVEM T1,RNGTOP		;Save as top of ring buffer
	MOVEM T1,RNGADR		;Also save as current pointer
	ADD T1,RNGSIZ		;Add buffer size
	SOS T1			;Account for first word
	MOVEM T1,RNGBOT		;Store as bottom of ring buffer
	SETZM RNGCUR		;There are no completed entries yet
	SETZM RNGNUM		
	RETSKP			;Return success
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- SC.RHD (Write ring buffer entry header)

;This routine will write the common entry header for a ring buffer entry
;
; Usage:
;	T1/ FEATURE ROUTINE ADDRESS
;	T2/ PC OF CALLER TO FEATURE ROUTINE
;	T3/ EVENT CODE
;	T4/ JACKET ROUTINE ADDRESS
;
;	CALL SC.RHD
;
;	Returns:	+1 Always
;
;	No data is returned and T1 and T2 are smashed.
;
;Note:	This routine is designed to allow the ring buffer to wrap upon 
;	itself when it goes beyond RNGBOT.  The entries will continue
;	to be written starting from RNGTOP.  A SCARAP BUGINF will be 
;	issued when the ring buffer wraps.  This indicates that the entries
;	at the top of the ring buffer are being overwritten.
;
;     	This routine has an explicit knowledge of the format of the ring 
;	buffer entry.  The entry header is written in order.  Should the
;	header change, this routine will have to change as well.

SC.RHD:	ASUBR <FRA,PCC,EVC,JKT>	;Save incoming args
	MOVE T2,EVC		;Get the event code
	CAIG T2,EN%CHI		;A valid event code?
	CAIGE T2,EN%CLO		
	JRST SC.RHE		;No, return error
	MOVE T1,RNGADR		;Get current pointer position
	MOVEM T1,RNGCUR		;Save as the top of this new entry
	ADD T1,ENTLTB(T2)	;Determine end of entry
	SOS T1			;Adjust since already pointing at first word
	CAMG T1,RNGBOT		;Will it overflow?
	IFSKP.			;Yes
	  MOVE T1,RNGTOP	;Get pointer to top of buffer
	  MOVEM T1,RNGADR	;Save as current pointer
	  MOVEM T1,RNGCUR	;Also as top of current entry
	  SKIPA	0		;By default, do not report condition

;Do not issue SCARAP whenever the ring buffer wraps because certain settings
;of RNGSW will cause many SCARAPs to be issued.  However, if reporting of 
;this condition is desired, the above SKIPA instruction can be removed.

	  BUG.(INF,SCARAP,SCAMPI,SOFT,<SCA - Ring buffer has wrapped>,,<

Cause:	The ring buffer overflowed and wrapped upon itself.
	The entries at the top are being overwritten and will be lost.
>)				;Report wraping of ring buffer
	ENDIF.
	MOVX T1,RNG%HC		;Get the constant for the ring header
	CALL SC.RWR		;(T1) Place in ring buffer
	MOVE T2,EVC		;Get event code
	HRLZ T1,T2		;Locate event code correctly
	HRR T1,ENTLTB(T2)	;Put length in right half
	CALL SC.RWR		;(T1) Place event code,,length in entry
	MOVE T1,JKT		;Get jacket routine label
	CALL SC.RWR		;(T1) Place in header
	MOVE T1,FRA		;Get feature routine label
	CALL SC.RWR		;(T1) Place in header
	MOVE T1,PCC		;Get PC of caller to feature routine
	CALL SC.RWR		;(T1) Place in header
	MOVE T1,TODCLK		;Get time of day
	CALL SC.RWR		;(T1) Place in entry header
	RET			;Return success

SC.RHE:	MOVE T1,FRA		;Get routine that called jacket routine
	MOVE T2,PCC		;Get PC of caller to feature routine
	MOVE T3,EVC		;Get event code
	MOVE T4,JKT		;Get jacket routine address
	BUG.(HLT,SCAIEC,SCAMPI,SOFT,<SCA - Invalid event code for ring buffer entry>,<<T1,FEATURE>,<T2,PC>,<T3,ENTRY>,<T4,JACKET>>,<

Cause:	A bad event code was passed to SC.RHD to be placed in the ring buffer
	header.  This could cause problems since the entry length table is
	indexed by event code.

Action:	Check the caller of SC.RHD to be sure that a valid event code is being  
	placed in T3 before the call. The caller is indicated by the jacket 
	routine address in T4.

Data: 	FEATURE - feature routine address
	PC      - PC of caller to feature routine
	ENTRY   - entry code
	JACKET  - jacket routine address
>)				;Report error and die
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- SC.RTE (Write ring buffer entry tail)

;This routine will write the common tail of a ring buffer entry
;
; Usage:
;	CALL SC.RTE
;
;	Returns:	+1 Always
;
;	No data is returned and T1 is smashed.

SC.RTE:	MOVE T1,RNGCUR		;Get pointer to top of this entry
	CALL SC.RWR		;(T1) Place in ring buffer entry tail
	AOS RNGNUM		;Increment number of buffer entries written
	RET			;Return success
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- SC.RWR (Write ring buffer entry)

;This routine will write a word of a ring buffer entry
;
; Usage:
;	T1/ WORD TO WRITE
;
;	CALL SC.RWR
;
;	Returns:	+1 Always
;
;	No data is returned and no ACs are smashed.

SC.RWR:	MOVEM T1,@RNGADR	;Put word in ring buffer entry
	AOS RNGADR		;Increment pointer to next location
	RET			;Return success
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- RG.SSC (SYSAP to SCA calls)

;This routine is used to record SYSAP to SCA calls in the ring buffer
;
; Usage:
;	T1/ FEATURE ROUTINE ADDRESS
;	T2/ PC OF CALLER TO FEATURE ROUTINE
;	T3/ ADDRESS OF CONNECT BLOCK
;
;	CALL RG.SSC
;
;	Returns:	+1 Always

RG.SSC:	TMNN RSYSCA		;Are we recording these events?
	RET			;No, just return
	CIOFF			;Do not allow any interrupts
	SAVET			;Make routine transparent
       	STKVAR <CBADDR>
	MOVEM T3,CBADDR		;Save CB address
	MOVEI T3,SYSSCA		;Get event code
      	XMOVEI T4,.		;Get jacket routine address
	CALL SC.RHD		;(T1,T2,T3,T4) Write the entry header
	MOVE T1,CBADDR		;Get CB address
	LOAD T1,CBSCID,(T1)	;Get source connect ID
	CALL SC.NOD		;(T1/T1,T2) Get node number
	EXCH T1,T2		;Get node number in T1
	CALL SC.RWR		;(T1) Record node number in entry
	MOVE T1,CBADDR		;Get CB address
	CALL SC.RWR		;(T1) Record in entry
	MOVE T2,T1		;Move CB address
	MOVE T1,.CBSTS(T2)	;Get CB status word
	CALL SC.RWR		;(T1) Record in entry
	MOVE T1,.CBFLG(T2)	;Get flags
	CALL SC.RWR		;(T1) Record in entry
	LOAD T1,CBSCID,(T2)	;Get source connect ID
	CALL SC.RWR		;(T1) Record in entry
	LOAD T1,CBDCID,(T2)	;Get destination connect ID
	CALL SC.RWR		;(T1) Record in entry
	CALL SC.RTE		;() Write the ring entry tail
	CION			;Enable interrupts again
	RET			;Return

	ENDSV.
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- RG.SCS (SCA to SYSAP calls)

;This routine is used to record SCA to SYSAP calls (callbacks)
;in the ring buffer
;
; Usage:
;	T1/ FEATURE ROUTINE ADDRESS
;	T2/ PC OF CALLER TO FEATURE ROUTINE
;	T3/ CALLBACK REASON CODE
;	P1/ CONNECT BLOCK ADDRESS
;
;	CALL RG.SCS
;
;	Returns:	+1 Always

RG.SCS:	TMNN RSCASY		;Are we recording these events?
	RET			;No, just return
	CIOFF			;Do not allow any interrupts
	SAVET			;Make routine transparent
	STKVAR <REASON>
	MOVEM T3,REASON		;Save reason code
	MOVEI T3,SCASYS		;Get event code
      	XMOVEI T4,.		;Get jacket routine address
	CALL SC.RHD		;(T1,T2,T3,T4) Write the entry header
	LOAD T1,CBSCID,(P1)	;Get source connect ID
	CALL SC.NOD		;(T1/T1,T2) Get node number
	MOVE T1,T2		;Relocate node number
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,P1		;Get connect block address
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,REASON		;Get callback reason code
	CALL SC.RWR		;(T1) Place in entry
	CALL SC.RTE		;() Write the ring entry tail
	CION			;Enable interrupts again
	RET			;Return

	ENDSV.
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- RG.BFM (Buffer manipulation)

;This routine is used to record buffer allocation, creation, and return.
;All calls to SC.CMG, SC.CDG, SC.ABF, SC.ALD, SC.RBF, and SC.RLD
;are recorded.
;
; Usage:
;	T1/ FEATURE ROUTINE ADDRESS
;	T2/ PC OF CALLER TO FEATURE ROUTINE
;	T3/ NUMBER OF BUFFERS REQUESTED FOR CREATION/ALLOCATION
;	T4/ ADDRESS OF FIRST BUFFER CREATED/ALLOCATED
;
;	CALL RG.BFM
;
;	Returns:	+1 Always

RG.BFM:	TMNN RBUFMG		;Are we recording these events?
	RET			;No, just return
	CIOFF			;Do not allow any interrupts
	SAVET			;Make routine transparent
	STKVAR <NUMBUF,ADDR>
	MOVEM T3,NUMBUF		;Save number of buffers
	MOVEM T4,ADDR		; and address of first buffer on chain
	MOVEI T3,BUFMAN		;Get event code
      	XMOVEI T4,.		;Get jacket routine address
	CALL SC.RHD		;(T1,T2,T3,T4) Write the entry header
	MOVE T1,NUMBUF		;Get number of buffers requested
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,ADDR		;Get address of first buffer in chain
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,FQCNT		;Get number of buffers on message free queue
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,TOPFQ		;Get pointer to top of message free queue
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,BOTFQ		;Get pointer to bottom of message free queue
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,DFQCNT		;Get number of buffers on datagram queue
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,TOPDFQ		;Get pointer to top of datagram free queue
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,BOTDFQ		;Get pointer to bottom of datagram free queue
	CALL SC.RWR		;(T1) Place in entry
	CALL SC.RTE		;() Write the ring entry tail
	CION			;Enable interrupts again
	RET			;Return

	ENDSV.
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- RG.PKT (Packet movement)

;This routine is used to record packet movement; both outgoing
;(calls to SNDMSG and SNDDG) and incoming (arriving at SC.INT).
;
; Usage:
;	T1/ FEATURE ROUTINE ADDRESS
;	T2/ PC OF CALLER TO FEATURE ROUTINE
;	T3/ FLAGS,,
;	T4/ PRIORITY,,PACKET LENGTH
;	P2/ PACKET ADDRESS
;	P4/ SYSTEM BLOCK ADDRESS
;
;	CALL RG.PKT
;
;	Returns:	+1 Always

RG.PKT:	TMNN RPACKT		;Are we recording these events?
	RET			;No, just return
	CIOFF			;Do not allow any interrupts
	SAVET			;Make routine transparent
	STKVAR <FLAGS,PRPL>
	MOVEM T3,FLAGS		;Save flags 
	MOVEM T4,PRPL		; and priority,,packet length
	MOVEI T3,PKTEVT		;Get event code
      	XMOVEI T4,.		;Get jacket routine address
	CALL SC.RHD		;(T1,T2,T3,T4) Write the entry header
	LOAD T1,SBDPA,(P4)	;Get node number
	CALL SC.RWR		;(T1) Place in entry
 	MOVE T1,RNGCUR		;Get address if top of entry
	HRRZ T1,.REFRL(T1)	;Get feature routine label
	CAIN T1,SCINT		;Did the entry come from SCINT (incoming)?
	IFSKP.
	  LOAD T1,MH$SCI,(P2)	;No, outgoing packet, use source CID always
	ELSE.
     	  MOVE T1,FLAGS		;Yes, incoming packet, get flags
	  TXNN T1,F.RSP		;Is this a local or remote packet?
	  IFSKP.		;It is local
	    LOAD T1,MH$SCI,(P2)	;Get source connect ID
	  ELSE.			;It is a remote packet
	    LOAD T1,MH$DCI,(P2)	;Get destination connect ID
	  ENDIF.
	ENDIF.
	$LDCID T1,T1		;Obtain connect block address
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,P2		;Get buffer address
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,FLAGS		;Get flags
	CALL SC.RWR		;(T1) Place in entry
	MOVE T1,PRPL		;Get priority,,packet length
	CALL SC.RWR		;(T1) Place in entry
	LOAD T1,MH$TYP,(P2)	;Get message type word
	CALL SC.RWR		;(T1) Place in entry
	LOAD T1,MH$SCI,(P2)	;Get source connect ID
	CALL SC.RWR		;(T1) Place in entry
	LOAD T1,MH$DCI,(P2)	;Get destination connect ID
	CALL SC.RWR		;(T1) Place in entry
	CALL SC.RTE		;() Write the ring entry tail
	CION			;Enable interrupts again
	RET			;Return

	ENDSV.
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- RG.PIT (PI transitions)

;This routine is used to record PI transitions.
;
; Usage:
;	T1/ FEATURE ROUTINE ADDRESS
;	T2/ PC OF CALLER TO FEATURE ROUTINE
;
;	CALL RG.PIT
;
;	Returns:	+1 Always
;
;Note:	There are no CIONs or CIOFFs in this jacket routine since it is 
;	designed to be called from the routines CION and CIOFF.

RG.PIT:	TMNN RPITRN		;Are we recording these events?
	RET			;No, just return
	SAVET			;Make routine transparent
	MOVEI T3,PITRAN		;Get event code
      	XMOVEI T4,.		;Get jacket routine address
	CALL SC.RHD		;(T1,T2,T3,T4) Write the entry header
	MOVE T1,CHNCTL		;Get level of PI nesting
	CALL SC.RWR		;(T1) Record it in the entry
	MOVE T1,PIFLAG		;Get indication of channel on done
	CALL SC.RWR		;(T1) Record it in the entry
	CALL SC.RTE		;() Write the ring entry tail
	RET			;Return
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- RG.PQM (Port queue manipulation)

;This routine is used to record port queue manipulation
;
; Usage:
;	T1/ FEATURE ROUTINE ADDRESS
;	T2/ PC OF CALLER TO FEATURE ROUTINE
;	T3/ FLAGS,,COUNT OF BUFFERS UNLINKED/LINKED
;	    (SEE SCAPAR FOR FLAG DEFINITIONS)
;	T4/ ADDRESS OF FIRST BUFFER UNLINKED/LINKED
;	P4/ ADDRESS OF SYSTEM BLOCK
;
;	CALL RG.PQM
;
;	Returns:	+1 Always

RG.PQM:	TMNN RPRTQU		;Are we recording these events?
	RET			;No, just return
	CIOFF			;Do not allow any interrupts
	SAVET			;Make routine transparent
	STKVAR <COUNT,ADDR>
	MOVEM T3,COUNT		;Save buffer count
	MOVEM T4,ADDR		; and address of first buffer in chain
	MOVEI T3,PORTQU		;Get event code
      	XMOVEI T4,.		;Get jacket routine address
	CALL SC.RHD		;(T1,T2,T3,T4) Write the entry header
	LOAD T1,SBDPA,(P4)	;Get node number
	CALL SC.RWR		;(T1/) Place in entry
	MOVE T1,COUNT		;Get flags,,count word
	CALL SC.RWR		;(T1/) Place in entry
	MOVE T1,ADDR		;Get buffer address
	CALL SC.RWR		;(T1/) Place in entry
	CALL SC.RTE		;() Write the ring entry tail
	CION			;Enable interrupts again
	RET			;Return

	ENDSV.
>				;End of IFN SCARNG

   IFN SCARNG,<
	SUBTTL Ring Buffer routines -- RG.ITL (Interlocks)

;This routine is used to record interlocks.
;
; Usage:
;	T1/ FEATURE ROUTINE ADDRESS
;	T2/ PC OF CALLER TO FEATURE ROUTINE
;	P1/ CONNECT BLOCK ADDRESS
;
;	CALL RG.ITL
;
;	Returns:	+1 Always
;
; Note:  It is assumed that the caller has done a SAVET before the call!

RG.ITL:	TMNN RINTLK		;Are we recording these events?
	RET			;No, just return
	CIOFF			;Do not allow any interrupts
	MOVEI T3,INTLOK		;Get event code
      	XMOVEI T4,.		;Get jacket routine address
	CALL SC.RHD		;(T1,T2,T3,T4) Write the entry header
	MOVE T1,P1		;Get connect block address
	CALL SC.RWR		;(T1/) Place in entry
	MOVE T1,.CBLCK(P1)	;Get connect block lock value
	CALL SC.RWR		;(T1/) Place in entry
	MOVE T1,.CBFLG(P1)	;Get all connect block flags
	CALL SC.RWR		;(T1/) Place in entry
	MOVE T1,.CBSBA(P1)	;Get address of system block
	MOVE T1,.SBCLC(T1)	;Get count of locked connect blocks on S.B.
	CALL SC.RWR		;(T1/) Place in entry
	CALL SC.RTE		;() Write the ring entry tail
	CION			;Enable interrupts again
	RET			;Return
>				;End of IFN SCARNG
; Routine to copy a strings and blank fill
;
;Usage:
;	T3/	Destination address
;	T4/	Source address
;	Always transfers C%PNMN bytes
;	CALL SCG.ST
;
;	Return +1 Always
;

SCG.ST:	MOVEI T2,C%PNMN			;Number of characters to move
SCG.LP:	ILDB T1,T4			;Get a character from the source
	JUMPE T1,SCG.NL			;Found a 0 space fill
	IDPB T1,T3			;Store character in the Destination
	SOJG T2,SCG.LP			;Try for another character
	RET				;Done return

SCG.NL:	MOVX T1," "			;Get a space as padding character
	IDPB T1,T3			;Store it in the Destination
	SOJG T2,.-1			;Do until count runs out
	RET				;Return to caller all done
	SUBTTL	General Routines
	SUBTTL	General Routines -- MXCIND (Return max CI nodes seen)

;This routine is called to obtain the maximum number of nodes we have 
;ever seen on the CI.  It is currently only called by CFSSRV when the 
;delay time is being calculated.
;
;Usage:
;	CALL MXCIND
;
;Returns:	+1 Always with  T2/ max nodes ever seen

MXCIND::MOVE T2,MXSBCT		;Get the max value of SBCNT
	RET			;And return
	SUBTTL	Dummy routines until the port driver supports them

PPDSMD::
PPDRMD::RETBAD (MONX03)
	SUBTTL End of SCS

	END