SUBTTL Init code
XRESCD ;[7.1043]
; This routine initializes the SCS% JSYS SYSAP.
;
SCSINI::BLCAL. (<XENT SC.SOA>,<<.,SCSONT>>) ;[7.1043]Tell SCA about this address
BUG. (CHK,SCSNOI,SCSJSY,SOFT,<SCSJSY - SCS% cannot receive node online/offline interrupts>,,<
Cause: SCA has told the JSYS SYSAP that there are too many SYSAPs and the JSYS
is not allowed to see online/offline interrupts. The system can run but
many diagnostics, or anything using the JSYS, fail.
Action: If this BUGCHK is reproducible, set it dumpable and send in an SPR
along with how to reproduce the problem.
>)
RET ;All done...

; Here when an ERJMP takes. In this case we have a user datagram address that
;needs to be placed back into the database and a datagram that should be
;linked back onto the FRONT of the fork and connection datagram queues.
;
;Note:
;
; It is assumed that we are NOINT when we get here...
;
; Expects:
; P1/ CB addr
; USRBUF/ User virtual address that goes back into database or zero
; PAKADR/ Monitor virtual address of datagram buffer or zero
;
RDGER1: MOVX T1,SCSIAB ;Fill in the error code for bad address
RDGERR: MOVEM T1,ERRCOD ;Save the error code
SKIPN T1,USRBUF ;Is there a user buffer to worry about???
JRST RDGER2 ;No, try for the packet
MOVX T2,.BDFMG ;Assume we are doing messages
SKIPN MSGFLG ;A good assumption???
MOVX T2,.BDFDG ;No, get BSD offset for datagrams
CALL SCSLUB ;(T1,T2,P1) Link this user address back into database
IFNSK.
MOVE T2,FORKX ;Say who we are
MOVE T3,USRBUF ; and what buffer we tried for
BUG.(INF,SCSUBL,SCSJSY,SOFT,<SCSJSY - User buffer lost during error recovery>,<<T1,ERRCOD>,<T2,CURFRK>,<T3,BUFADR>>,<
Cause: Bad access to user memory or a failing routine caused SCS to try to
place the currently owned user buffer back on the buffer list. The
attempt failed and the buffer address has been lost. Note that there
is no memory loss, the monitor has just forgotten one user buffer
address.
Action: If this BUGINF is reproducible, set it dumpable and send in an SPR
along with how to reproduce the problem.
Data: ERRCOD - Erro code
CURFRK - Current fork
BUFADR - Buffer address
>);End of BUG. SCSUBL
ENDIF. ;Fall into packet return code please...

SUBTTL SCS% error handlers -- A2MHLT (PSB mapping bug)
A2MHLT: BUG.(HLT,SCSA2M,SCSJSY,SOFT,<SCSJSY - Attempt to map second PSB>,<<MPSFRK,OWNFRK>,<T1,CURFRK>>,<
Cause: Some routine mapped a PSB but did not release it, or did not use the
correct interlock. The net result was that we are trying to map another
PSB while we still have the first one mapped.
Data: OWNFRK - The number of the fork that did the first map
CURFRK - The fork doing the second lock
>)

SUBTTL SCA call handlers -- Main entry point
XRESCD ;[7.1043]Called at interrupt level
; This routine is the entry point to the SYSAP from SCA.
;Note that this code is not in process context, but rather is at interrupt
;level for the CI.
;
SCSINT: SAVEP ;[7.1043]Save the ACs we will kill here
JRST @CALTAB(T1) ;Goto the handler routine for SCA calls

SUBTTL SCA call handlers -- SCSONT (Handle online/offline interrupts)
; This routine handles anline/offline interrupts from SCA. We are only called
;here when SCAMPI is scanning NOTTAB for addresses to notify. Hence we get
;called here once per system and with no connect ID.
;
; Expects
; T1/ .SSPBC or .SSNCO
;
; T3/ Node number for .SSPBC
; or
; T2/ Node number for .SSNCO
;
; Return (+1) Always
; No data returned
;
SCSONT: TRVAR <NOD,CODE,FORK>
CAIN T1,.SSPBC ;Did the node go offline???
MOVX T4,.SEPBC ;Yes, get the event code for node offline
CAIE T1,.SSNCO ;[8936] Did the node come online???
IFSKP. ;[8936]
MOVX T4,.SENCO ;Yes, get the event code for node online
MOVEM T2,T3 ;Reposition node number
ENDIF.
MOVEM T4,CODE ;Save the code we must give the user
MOVEM T3,NOD ;Save the node that just changed state
; Loop over FRKTAB looking for forks the need to be poked.
SETO T1,0 ;Make the AOS get fork zero
ONTLOP: AOS T1 ;Increment to the next fork
CALL SCSGNF ;(T1) Get the next fork with PSI's enabled
RET ;No more forks enabled, all done
CALL ONTBLD ;Build and queue a block for this fork
$SKIP ;Failed, BUGCHK and loop again
JRST ONTLOP ;All went OK, loop for more forks
BUG.(CHK,SCSPBF,SCSJSY,SOFT,<SCSJSY - PSI block build failure>,<<T1,ERRCOD>>,<
Cause: The routine to build an event block failed. It is very likely that
ASGRES did not have the space available.
Data: ERRCOD - Error code returned by ONTBLD
>,ONTLOP)

; Here when we have found the entry we are looking for.
;
; Expects:
; T1/ Base address of the entry we desire
; T2/ Buffer name for completed xfer
;
MSCOK: MOVE P1,.MQCBA(T1) ;Setup the CB address
MOVE Q1,.MQBUF(T1) ;Save the address of the entry
CALL SCSDMD ;Dequeue this entry from the maint Q
JRST MSCER1 ;Handle bizzare failures
CALLX (MSEC1,RELRES) ;[7.1043]Return the entry's free space
MOVX T1,<XWD .RESP2,C%MDCL> ;Priority,,length of block
MOVX T2,.RESGP ;Resident pool number
CALLX (MSEC1,ASGRES) ;[7.1043]Get space for the event block
CALL SCSAER ;(T1) Handle ASGRES failure
MOVEM Q1,.EBDAT(T1) ;Store the buffer name in event entry
LOAD T2,CBSCID,(P1) ;Get the "CID" from this connect
STOR T2,MECID,(T1) ;Store in event entry
MOVX T2,.ETEVT ;Get the entry code for events
STOR T2,METYP,(T1) ;Store the event type in the block
MOVX T2,C%MDCL ;Get the length of the block
STOR T2,EBLEN,(T1) ;Store in the event block
MOVX T2,.SEMDC ;The event code
STOR T2,METYP,(T1) ; which goes in the event block as well
SETZRO MEFLG,(T1) ;Zero the flags
CALLRET SCSQUE ;Place this entry on the appropriate q's
; Here when we cannot find the buffer name SCA has just given us...
;
MSCERR: BUG.(CHK,SCSCFB,SCSJSY,SOFT,<SCSJSY - Can't find maintainance buffer name>,<<T2,BFRNAM>>,<
Cause: SCA called us with a buffer name for a completed maintenance data
transfer. Upon trying to find this name in the database of outstanding
JSYS maint transfers, no match was found. The fork which performed the
maint data transfer request will never be notified of the completion of
the request.
Action: If this BUGCHK is reproducible, set it dumpable and send in an SPR
along with how to reproduce the problem.
In the dump, try to find the buffer name in the port driver database of
BSD/BHD's and see if this is a valid buffer name. If so, check the
consistancy of the SCA maint queue. Other than this, not much can be
done.
Data: BFRNAM - Buffer name
>)
RETBAD ()

; Here on a bizzare failure.
;
; Expects:
; T1/ Error code
;
MSCER1: BUG.(CHK,SCSBIZ,SCSJSY,SOFT,<SCSJSY - Maintenance data transfer queue smashed>,<<T1,ERRCOD>>,<
Cause: A routine which should not return (+1), did. This indicates that a
maintenance data transfer queue is damaged.
Action: If this BUGCHK is reproducible, set it dumpable and send in an SPR
along with how to reproduce the problem.
Data: ERRCOD - The error code
>)
RETBAD ()
> ;End of REPEAT 0

SUBTTL Support routines -- SCSDMU (Data monitor to user)
XSWAPCD ;[7.1043]
; This routine moves data from monitor space into user space. Checks are made
;to insure that the page we will write to is accessable to the monitor.
;
;Note:
; This routine assumes the data being moved is less than one page long. If the
;length is more than one page, the page access checks will be wrong...
;
; Usage:
; Call
; T1/ Length in words of block to move
; T2/ Source address in monitor space
; T3/ Destination adddress in user space
;
; Return (+1)
; T1/ Error code
;
; Return (+2)
; No data returned
;
SCSDMU: XCTU [MOVES (T3)] ;Try to write the page
ERJMP DMUER1 ;Failed, back out pls...
MOVE T4,T3 ;Get the base address in user space
ADD T4,T1 ;Build the last address we move things into
XCTU [MOVES (T4)] ;Can we write the end of the block???
ERJMP DMUER1 ;Nope, back out
CALLX (MSEC1,BLTMU) ;[7.1043]Move the data into user space
RETSKP ;All done, return success
; Here when an ERJMP takes on page access failure.
DMUER1: RETBAD (SCSIAB) ;Fail with error code please...

SUBTTL Support routines -- SCSRUB (Remove user buffer)
XSWAPCD ;[7.1043]
; This routine removes a user buffer entry from the BSD set for a connection.
;
; Usage:
; T1/ User buffer address entry to be removed
; T2/ Offset into BSD for buffer type
; P1/ Address of CB
;
; This routine should be called NOINT.
;
; Return (+1)
; No entry found
;
; Return (+2)
; Entry has been removed
;
SCSRUB: SKIPN T3,.CBTBQ(P1) ;Is there a BSD on this connection???
RET ;Nope, return failure to find buffer entry
SAVEAC <Q1>
SETZ Q1, ;Be sure initial back pointer is zero
MOVE T4,T3 ;Build offset to first buffer
ADD T4,T2 ; by adding offset to base address of BSD
SKIPN T4,(T4) ;Is there an address of the first entry
JRST RUBNXB ;Nope, try the next BSD
RUBCLP: CAMN T1,.BBUVA(T4) ;Is this the entry we want???
JRST RUBWIN ;Yes, put the entry on the free queue and ret
MOVE Q1,T4 ;Save the address of the current buffer
SKIPE T4,.BBNXT(T4) ;Is there a next entry in this BSD
JRST RUBCLP ;Yep, loop for it pls...
; Here to do the next BSD.
RUBNXB: SKIPN T3,.BDNXT(T3) ;Is there a next BSD???
RET ;Nope, we loose, no entry found
MOVE T4,T3 ;Build the addr of the queue FLINK
ADD T4,T2 ; by adding the offset to the base address
SKIPN T4,(T4) ;Is there a first entry here???
JRST RUBNXB ;Nope, get the next BSD pls...
SETZ Q1, ;Be sure back pointer is zero
JRST RUBCLP ;Yup, check it pls...
; Here when an entry matches. Delete it from the queue its currently on, and
;add it to the free list.
;
; Expects:
; T2/ Offset into BSD for queue FLINK
; T3/ Base addr of BSD
; T4/ Addr of current entry (one to be deleted)
; Q1/ Address of previous entry
RUBWIN: SETZM .BBUVA(T4) ;Zero the user virtual address
SKIPN Q1 ;Is there a previous entry???
SKIPE T1,.BBNXT(T4) ; or a next entry???
TRNA ;Yes, queue is not empty
JRST RUBQIE ;No previous or next, queue is empty
ADD T2,T3 ;Build the address of the queue FLINK
SKIPN Q1 ;Is there a previous entry???
MOVEM T1,(T2) ;No previous, update FLINK to show new first
SKIPN T1 ;Is there a next entry???
MOVEM Q1,.BDF2B(T2) ;No next, update BLINK for new last entry
SKIPE Q1 ;Is there a previous entry???
MOVEM T1,.BDNXT(Q1) ;Yes, point it to the next entry
; Here when the buffer has been deleted from the appropriate queue and is now
;ready to be added to the free queue.
RUBMBF: MOVEM T4,@.BDLFD(T3) ;Link this buffer onto the free queue
MOVEM T4,.BDLFD(T3) ; and update the BLINK
RETSKP ; and return all OK
; Here when we are deleting the last entry on a BSD queue.
RUBQIE: MOVE T1,T3 ;Get base addr of BSD
ADD T1,T2 ;Build it into address of queue FLINK
MOVEM T1,.BDF2B(T1) ;Store FLINK address in BLINK
SETZM (T1) ;Init FLINK as zero
JRST RUBMBF ;Now go put the entry on the free queue

SUBTTL Support routines -- SCSUDM (User connection data move)
; This routine moves connection data from user space to monitor space.
;The data is stored in a resident free sace block that the caller is
;responsible for returning. The caller does not need to know what kind
;of space was used since the base address of the block and the address of
;the space return routine are provided.
;
; Usage:
; Call
; T1/ Base address of connection data in user space
;
; Return (+1)
; T1/ Error code
;
; Return (+2)
; T1/ Monitor address of the connection data
; T2/ Address of the routine to return the free space used
;
; Note:
; It is assumed that this routine is called NOINT since it will
;allocate resources. Rather than return NOINT when the success return
;is taken, the caller must be NOINT at the time of the call.
;
SCSUDM: STKVAR <DATADR,USRDAT>
MOVEM T1,USRDAT ;Save the address of the user conn data
MOVX T1,<XWD .RESP2,C%DTLW> ;Priority,,length of block
MOVX T2,.RESGP ;Resident pool number
CALLX (MSEC1,ASGRES) ;[7.1043]Get the resident space for the block
RETBAD () ;Return with an error from ASGRES
MOVEM T1,DATADR ;Store the address of the free space used
MOVE T3,T1 ;Make this address the destination address
MOVX T1,C%DTLW ;Get the length of the block to move
MOVE T2,USRDAT ;Now the address of the block in user space
CALL SCSDUM ;(T1,T2,T3)Move data from user space to
;monitor space
IFNSK.
EXCH T1,DATADR ;SAVE ERROR CODE,GET FREE SPACE ADDRESS
CALLX (MSEC1,RELRES) ;[7.1043](T1) Return the free space please
MOVE T1,DATADR ;Get the error code back again
RETBAD () ; and report failure
ENDIF.
MOVE T1,DATADR ;Return the address of the data as promised
MOVE T2,[MSEC1,,RELRES] ;[7.1043]Also report addr of free space return
RETSKP ; and return
ENDSV.

SUBTTL Support routines -- SCSCBI (Connect block data init)
; This routine initializes the connect block with the data required
;by the JSYS.
;
; Note:
; This routine assumes that it is being called to add data to a connect
;block owned by the current fork. PSB cells (SCSPS0,SCSPS1) are accessed and
;it is assumed that the current PSB is the desired one.
;
; Usage:
; Call
; P1/ Address of connect block
;
; Return (+1) Always
; P1/ Address of connect block
;
; Note:
; Today the PSB cells used here do not have a MSKSTR associated with
;them for use with LOAD/STOR. Hence the MOVE/MOVEM is used to move the
;PSI information around. These PSB cells should be defined and LOAD/STOR
;used to move the data around.
;
SCSCBI: SETONE CBFJSY,(P1) ;Set the "CB is for JSYS" flag
MOVE T1,FORKX ;Get my fork number
STOR T1,CBFORK,(P1) ;Store in CB as owning fork
MOVE T1,JOBNO ;Get my job number as well
STOR T1,CBJOB,(P1) ; which is also stored in the CB
MOVE T1,SCSPS0 ;Get the first word of fork PSI channels
MOVEM T1,.CBPS0(P1) ;Store in the CB
MOVE T1,SCSPS1 ;Now get the second word of PSI channels
MOVEM T1,.CBPS1(P1) ;Store these as well
RET ;All done...

SUBTTL Support routines -- SCSABT/SCSRBT (Add/remove bit from table)
;SCSABT
; This routine adds a bit to the table who's address is specified.
;If the bit was already lit, the (+1) return is taken. If the bit was off
;it is turned on and the (+2) return is taken.
;
;SCSRBT
; This routine turns off a bit in a bit table whos base address is given.
;If the bit was already off then the (+1) return is taken. If the bit
;was on then it is cleared and the (+2) return is taken.
;
; Usage (SCSABT and SCSRBT):
;
; Call
; T1/ Bit number
; T2/ Base address of table
;
; Return (+1)
; SCSABT: Bit was already on
; SCSRBT: Bit was already off
;
; Return (+2)
; SCSABT: Bit was not on, but is now
; SCSRBT: Bit was not off, but is now
;
SCSRBT: TDZA T3,T3 ;Show we are in RBT code
SCSABT: SETO T3, ;Show we are in ABT code
SAVEAC <T1>
STKVAR <ABTCOD>
MOVEM T3,ABTCOD ;Save entry point info
MOVE T3,T1 ;Get the bit number
IDIVI T3,^D36 ;Turn bit number into word + bit offset
ADD T3,T2 ;Add table offset to table base addr
MOVE T4,BITS(T4) ;Light the bit from the bit number
MOVE T1,(T3) ;Save the origional contents of the table
SKIPE ABTCOD ;[8936] Are we adding the bit???
IFSKP. ;[8936]
ANDCAM T4,(T3) ;Turn off the bit please
TDNE T4,T1 ;No, we are removing the bit
RETSKP ;Bit was on before, say so
RET ;Bit was off before, say so
ENDIF.
IORM T4,(T3) ;Yes, turn the bit on please
TDNN T4,T1 ;We are adding the bit, was it on before?
RETSKP ;No, return it was off
RET ;Yes, return it was on...
ENDSV.

SUBTTL Support routines -- SCSGNB (Get next bit)
XRESCD ;[7.1043]Called at interrupt level
; This routine finds the next bit lit in a bit table. An origin bit is
;specified. The first bit tested is the first bit to the right of the
;origin bit.
;
; Usage:
; Call
; T1/ Origin bit
; T2/ Base address of bit table
; T3/ Length of table in words
;
; Return (+1)
; All bits after origin bit to end of table are zero
;
; Return (+2)
; T1/ Bit number of next lit bit in table
;
SCSGNB: STKVAR <BASADR,ADDR,LEN>
MOVEM T2,BASADR ;Save the base address for later
MOVEM T2,ADDR ; as well as for computation
IDIVI T1,^D36 ;(T1) = word offset (T2) = bit offset into word
SUB T3,T1 ;Offset table length to current word offset
JUMPL T3,R ;If neg, we are off the end of the table...
MOVEM T3,LEN ;Save the corrected length of the table
ADDB T1,ADDR ;Convert word offset to address in table
MOVE T1,(T1) ;Get the first word to be considered
LSH T1,(T2) ;Punt any bits left of the origin bit
MOVNS T2 ;Now put the bits back
LSH T1,(T2) ; where they came from
$SKIP ;Don't smash what we just did
GNBLOP: MOVE T1,@ADDR ;Get the next word to be considered
JFFO T1,GNBEND ;If there are bits set, we are done
SOSG LEN ;Have we goen off the end of the table???
RET ;Yes, all done, no more bits let
AOS ADDR ;Otherwise point to the next word
JRST GNBLOP ; and test it...
; Here with:
; ADDR/ Address of desired bit
; T2/ Bit position of desired bit
;
GNBEND: MOVE T1,ADDR ;Get the address of the desired bit
SUB T1,BASADR ;Turn it into a table index
IMULI T1,^D36 ; and then into a bit number
ADD T1,T2 ;Add the offset into the word
RETSKP ;All done, report bit number in T1
ENDSV.

SUBTTL Support routines -- SCSAFT (Add fork to table)
XSWAPCD ;[7.1043]
; This is a jacket routine (for SCSABT) to add forks to the interrupt bit
;table. There is one bit for each possible fork in the system. When the bit
;is lit the fork has enabled interrupts for configuration changes on the CI.
;
; Usage:
; Call
; T1/ Fork number
;
; Return (+1)
; Fork was already enabled for SCS interrupts
;
; Return (+2)
; Fork was not enabled for SCS interrupts but is now
;
SCSAFT: XMOVEI T2,FRKTAB ;Get the address of the fork bit table
CALLRET SCSABT ;(T1,T2)Add the bit to the table

SUBTTL Support routines -- SCSLFQ (Link packet to front of queue's)
XSWAPCD ;[7.1043]
; This routine links a monitor packet onto the front of the fork and
;CB queues. This routine is mainly used by error recovery code to put
;buffers back onto queues after an error has been detected. Note that this
;routine assumes the packet is for the current fork. I.E. the currently
;mapped PSB contains the correct pointers.
;
; Usage:
; Call
; T1/ Address of packet to be linked
; T2/ Address of four word list header block
; P1/ Address of CB
;
; This routine should be called NOINT.
;
; Return (+2)
; All calling AC's preserved, packet has been linked onto the front of
; the fork and CB queues.
;
SCSLFQ:
MOVE T3,@.TOPFQ(T2) ;Get the addr of the first buffer on the fork Q
MOVEM T3,.MEANF(T1) ;Link new buffer at the front
SETZM .MEAPF(T1) ;Make backward link be zero (first on Q)
MOVEM T1,@.TOPFQ(T2) ; and update the queue FLINK
MOVE T3,@.TOPCQ(T2) ;Get addr of first buffer on CB Q
MOVEM T3,.MEANC(T1) ;Link new packet onto front of queue
SETZM .MEAPC(T1) ;Zero the backward link (first on queue)
MOVEM T1,@.TOPCQ(T2) ; and update the queue FLINK
RETSKP ;Return ok...

SUBTTL Support routines -- SCSAER (ASGRES error handler)
XRESCD ;[7.1043]Called from interrupt level
; This routine handles an allocation failure from ASGRES. It causes a
;BUGINF with enough data to try to figure out what has happened from just
;the BUGINF data.
;
; Usage
; Call
; T1/ Error code from ASGRES
;
; Return (+1) Always
; No data
;
; Note:
; This routine is branched to with a PUSHJ P,. This is only to
;obtain the PC of the caller. The routine POPs this PC off the stack and
;returns to the stack loc before the call to this routine. Hence you cannot
;have and explicit PUSH's pending before the call to this routine...
;
SCSAER: POP P,T2 ;Get the callers PC back
TXZ T2,<777740,,0> ;Keep just the PC part
BUG. (INF,SCSACF,SCSJSY,SOFT,<SCSJSY - Can't get resident space from ASGRES>,<<T1,ERRCOD>,<T2,CALLPC>>,<
Cause: A call to ASGRES (by the JSYS) has failed. With the error code and
caller's PC given by the BUGINF, figuring out why it failed should be
easy enough.
Action: If this BUGCHK is reproducible, set it dumpable and send in an SPR
along with how to reproduce the problem.
Data: ERRCOD - Error code
CALLPC - PC of caller
>,,<DB%NND>) ;[7.1210]
RETBAD ;Return to callers caller with error code in T1

SUBTTL Support routines -- SCSLCB (Link CB onto fork CB queue)
XSWAPCD ;[7.1043]
; This routine links a CB onto the CB queue of a fork
;
; Usage:
; Call
; P1/ Address of the CB to be linked
; Note that at present, this routine is only called for the
; current fork. Hence we make the assumption that we are
; always the current fork. We also assume that we are ALWAYS
; in process context, and that it is always called NOINT.
;
; Return (+1) Always
; P1/ Address routine was called with
;
SCSLCB:
MOVE T1,SCSBCQ ;Get addr of last entry on the queue
XMOVEI T2,SCSTCQ ; and the addr of the top of queue pointer
CAMN T1,T2 ;[8936] Is BLINK a pointer to the FLINK???
IFSKP. ;[8936]
MOVEM T1,.CBJPB(P1) ;No, update previous pointer of new CB
ADDI T1,.CBJNB ; and offset to the forward pntr for last CB
ENDIF.
MOVEM P1,(T1) ;Link new buffer onto the fork CB queue
MOVEM P1,SCSBCQ ; and update the queue BLINK
RET ; and return all OK

SUBTTL Support routines -- SCSKIL (Clean up SCS% data)
; XSWAPCD ;[7.1043]
; Routine to call to release all SCS% resources owned by a fork. Currently
;the only way here is from KSELF, FLOGO, KFORK% JSYS and the CLZFF% JSYS.
;
; Note: No ACs are smashed
;
; Usage:
; Call
; T1/ Fork number of fork being killed
;
; Return (+1) Always
; No data returned
;
; Note:
; Most callers of SCSKIL/SCSLGO assume that NO ACs are smashed.
;
XNENT (SCSLGO,G) ;[7.1043]SCSLGO::, XSCSLG::
;[7.1043]Alternate entry name for FLOGO (MEXEC)
XNENT (SCSKIL,G) ;[7.1043]SCSKIL::, XSCSKI::
SAVEAC <T1,T2,T3,T4,P1> ;Save ALL ACs used here
TRVAR <FRKN,PSBADR,FLNK,BLNK>
MOVEM T1,FRKN ;Save the fork number for later
; NOTE: The following two lines are a temporary hack to prevent SCSFR1 BUGCHKs
; from FRKCHK when SCSKIL is called from CLZFF%. The correct action here is to
; allow SCSKIL to clean up CI connections owned by a fork inferior to the
; current fork.
CAME T1,FORKX ;IS THE CURRENT FORK
RET ;NO. RETURN QUIETLY
; CALL FRKCHK ;(T1) CURRENT FORK?
; RETBAD() ;NO.
NOINT
CALL SCSRFT ;(T1)Remove this fork from the PSI table
NOP ;I don't care if it wasn't in the table
XMOVEI T1,SCSTCQ
MOVEM T1,FLNK ;Save the address of the queue FLINK
XMOVEI T3,SCSBCQ ;Get 18 bits of queue BLINK address
MOVEM T3,BLNK ;Save the address of the queue BLINK
SKIPE P1,(T1) ;Are there any connections for this fork???
CALL KILCLP ;(P1) Yes, loop to kill them
CALL SCSCXN ;Delete any DMA resources owned by
;this fork
OKINT
RET ;All done, return

; Here to loop over all connection opened by a fork.
;
; P1/ Pointer to the first CB in the list
; FLNK/ Address of queue FLINK
; BLNK/ Address of queue BLINK
;
; Note: KILCHK assumes that the error recovery from the failing SC.DIS call
;will eventually loop back to get the rest of the connections. It assumes the
;queue is always empty.
;
KILCLP: LOAD T1,CBFORK,(P1) ;GET FORK NUMBER OF CB
CALL FRKCHK ;(T1) IS IT FOR THIS FORK?
JRST [MOVE P1,.CBJNB(P1) ;NO. TRY THE NEXT CB.
JRST KILCHK] ;
SETONE CBFKIL,(P1) ;Set the fork is dead flag in CB flag word
CALL SCSCBD ;(P1/P1)Delete JSYS CB data from this CB
MOVE T1,.CBSCI(P1) ;Get the CID of the current CB
MOVE P1,.CBJNB(P1) ;Save the addr of the next block
BLCAL. (<XENT SC.DIS>,<T1,[0]>) ;[7.1043]Abort the connection
JRST KILERR ;Failed??? Check the error code
KILCHK: JUMPN P1,KILCLP ;If more blocks left, delete them
XMOVEI T1,SCSTCQ ;Get extended address of queue FLINK
MOVEM T1,@BLNK ;Re-init headers for now empty queue
SETZM @FLNK ;Zero the queue FLINK
RET ;No more connect blocks, all done
; Here when SC.DIS fails.
;
KILERR: OKINT ;SCA is done, allow interrupts again
CAIN T1,SCSIID ;Is the error, bad CID
JRST KILCHK ;Yes, then connect is already gone, no problem
BUG.(CHK,SCSABF,SCSJSY,SOFT,<SCSJSY - Connection abort failure on fork delete>,<<T1,ERRCOD>>,<
Cause: During the deletion process for a fork we tried to abort the
connections it had open. We failed in the attempt.
Action: If this BUGCHK is reproducible, set it dumpable and send in an SPR
along with how to reproduce the problem.
Data: ERRCOD - Error code returned by SC.DIS
>)
JRST KILCHK ;No continue looping for connects
ENDTV.

SUBTTL Support routines -- SCSCBD (JSYS CB data delete)
; ***** CROCK ALERT *****
;This code needs to be updated to reflect the correct scheme for deletion
;of connection data.
;
; This routine deletes JSYS data from a connect block. Buffers on the port
;queues will be returned by SC.RAP. Only the buffer database is handled here.
;
; Usage:
; Call
; P1/ Connect block address
;
; This routine should be called NOINT.
;
; Return (+1) Always
; P1/ Connect block address
;
; Note:
; This routine should only be called from process context!
;
SCSCBD:
; Clean up entries on the message available queue
XMOVEI T1,.CBTMQ(P1) ;Point to top of the queue
XMOVEI T2,.CBBMQ(P1) ; and the bottom of the queue
MOVE T3,[MSEC1,,SC.RBF] ;[7.1043] and the routine to call to return the space
XMOVEI T4,MSG ; and the 4 word block for messages
CALL SCSGPR ;(T1,T2,T3,T4,P1)Return the packets
; Clean up entries on the datagram available queue
XMOVEI T1,.CBTDQ(P1) ;Point to the top of the queue
XMOVEI T2,.CBBDQ(P1) ; and the bottom of the queue
MOVE T3,[MSEC1,,SC.RLD] ;[7.1043] and the routine to return the space
XMOVEI T4,DG ; and the 4 word block for datagrams
CALL SCSGPR ;(T1,T2,T3,T4,P1)Return the packets
; Clean up entries on the DMA transfer complete queue
XMOVEI T1,.CBTXQ(P1) ;Point to the top of the queue
XMOVEI T2,.CBBXQ(P1) ; and the bottom of the queue
MOVE T3,[MSEC1,,RELRES] ;[7.1043] and the routine to return the space
XMOVEI T4,XFER ; and the 4 word block for DMA
CALL SCSGPR ;(T1,T2,T3,T4,P1)Return the blocks on the queue

; Clean up entries on the event queue
XMOVEI T1,.CBTEQ(P1) ;Point to the top of the queue
XMOVEI T2,.CBBEQ(P1) ; and the bottom of the queue
XMOVEI T3,RELRES ; and the routine to return the space
XMOVEI T4,EVT ; and the 4 word block for events
CALL SCSGPR ;(T1,T2,T3,T4,P1)Return the blocks on the queue
; Clean up any BSD's that are around
XMOVEI T1,.CBTBQ(P1) ;Point to the top of the queue
XMOVEI T2,.CBBBQ(P1) ; and the bottom of the queue
CALL SCSCBS ;Clean up any BSD's that are around
; Now remove this connect block from the owning fork CB queue
CALL SCSRCB ;Remove current CB from owning fork CB queue
CALL CBDCHK ;Failed, BUGCHK and continue
; ***** CROCK ALERT *****
;This is a temporary fix to get SCA to delete the block when it wants to...
SETZRO CBFJSY,(P1) ;Turn off the JSYS flag bit
TMNE CBFPTC,(P1) ;Is protocol complete lit???
IFNSK.
SETONE CBFRAP,(P1) ;Yes, light reap as well
SETONE CIREP ;[7122] TELL CIFORK TO RUN
ENDIF.
RET ;All done
CBDCHK: BUG.(CHK,SCSCDC,SCSJSY,SOFT,<SCSJSY - Cannot delete connect block from fork queue>,<<T1,ERRCOD>>,<
Cause: We tried to remove a connect block from the owning fork's list of
connect blocks. The most likely failure is a +1 return from SCSMPS.
This fails only when we map a PSB but do not unmap it.
Action: If this BUGCHK is reproducible, set it dumpable and send in an SPR
along with how to reproduce the problem.
Data: ERRCOD - Error code
>,R)

SUBTTL Support routines -- SCSGPR (General packet return)
; This routine returns a set of packets/blocks linked with a standard queue
;header. The header is the one used by SCS% to queue up EVERYTHING it hangs off
;the connect block.
;
; Usage:
; Call
; T1/ Queue FLINK
; T2/ Queue BLINK
; This routine assumes that the routine address given expects
; nothing more than the space address in T1.
; T4/ Address of 4 word list header block (if there is one)
; P1/ ADDRESS OF CONNECT BLOCK
;
; Note:
; This routine will try to use the address of the 4 word list header
;block (T4) first. If this address is zero it will use just the FLINK and BLINK
;specified in T1/T2. The FLINK and BLINK must be specified, even when a 4 word
;header block address is specified.
;
; Note:
; This routine assumes that the caller will provide whatever interlock
;is necessary for the queue. This allows this routine to be used by callers
;that require different interlocks.
;
; Return (+1) Always
; No data returned
;
SCSGPR: SAVEAC <Q1>
STKVAR <RTNADR,BLKADR>
MOVEM T3,RTNADR ;Save the return routine address
MOVEM T4,BLKADR ; and the 4 word block address
SKIPN Q1,(T1) ;Anything at all on the queue???
RET ;No, all done, return
GPRBLK: MOVE T1,Q1 ;Get the address of the current entry
MOVE Q1,(Q1) ;Get the addr of the current packet/block
SKIPE T2,BLKADR ;Is there a 4 word block address???
CALL <XENT SCSDEQ> ;[7.1043](T1,T2,P1/T1)Yes, dequeue the packet/block
;please
SKIPA ;ERROR, BUT WHAT ELSE CAN BE DONE. MAY WANT
;A BUGCHK HERE.
CALL @RTNADR ;Call the routine to return the space
JUMPN Q1,GPRBLK ;Loop until the queue is empty
RET
ENDSV.

SUBTTL Support routines -- SCSULK (Unlock pages in a DMA buffer)
; This routine unlocks the pages associated with a DMA buffer name. SCSMAP
;logged all of the pages it locked in a datagram buffer as a stack. The address
;of this stack is stored in the DMA name queue entry.
;
; Usage:
; Call
; T1/ Entry address
;
; Return (+1) Always
; No data returned
;
; Note: This routine returns the datagram buffer being used as a page stack.
;
SCSULK: SAVEAC <Q1,Q2>
STKVAR <STKADR>
SKIPN Q1,.XNSTK(T1) ;Get the address of the stack
RET ;What stack... Return now
MOVE T1,Q1 ;Get the address of the stack
MOVEM T1,STKADR ;Save the stack address
SKIPN Q1,(Q1) ;Is there anything on the stack???
JRST ULKEXI ;Stack is empty, release the buffer
AOS Q2,T1 ;Point to the base of the stack
ADD Q2,Q1 ;Now point to the end of the stack
ULKLOP: POP Q2,T1 ;Get the page number to unlock
NOINT ;Make sure this finishes
CALLX (MSEC1,MULKCR) ;[7.1043]Unlock it please
OKINT ;We are done...
SOJG Q1,ULKLOP ;Loop for all locked pages
ULKEXI: MOVE T1,STKADR ;Get the entry address again
CALL <XENT SC.RLD> ;[7.1043]Release it please
RET ;All done
ENDSV.

SUBTTL Support routines -- SCSCLK (Clock service routine)
; XRESCD ;[7.1043]
; This routine is called by the scheduler when it is doing the 2nd level
;clock routines (CLK2) and when SCSTIM is zero. Here the entries that have
;been queued to the SCSTHQ (by SCSQUE at PI interrupt level) are moved
;to the SCSTPQ queue. All entries in SCSTPQ are then processed by
;SCSPSI code, on a per fork/interrupt basis when PSISC% is set. The
;SCSPSI code will then put the entries into the SCS% data portion
;of the CB and issue a channel interrupt.
;
; Usage
; Call
; No arguments
;
; Return (+1) Always
; No arg returned
;
XRENT (SCSCLK,G) ;[7.1043]SCSCLK::, XSCSCL::
SAVEAC <Q1>
SKIPN T1,SCSTHQ ;Anything on the events queue???
JRST CLKEXI ;Nope, return now
SKIPE SCSLCK ;IS THE SCSTPQ QUEUE LOCKED?
JRST CLKEX2 ;YES. WAIT UNTIL NEXT TIME IN CLK2 CODE.
CIOFF ;NO. DON'T LET THE SCSTHQ QUEUE CHANGE
SKIPE SCSTPQ ;IS THE SCSTPQ QUEUE EMPTY?
IFSKP. ;YES.
MOVEM T1,SCSTPQ ;SET THE POINTER TO THE FIRST ENTRY
ELSE. ;NO, QUEUE IS NOT EMPTY
MOVE T2,SCSBPQ ;GET ADDRESS OF THE LAST ENTRY
MOVEM T1,.MEANC(T2) ;SET THE FORWARD POINTER IN THE LAST ENTRY.
MOVEM T2,.MEAPC(T1) ;SET THE BACKWARD POINTER IN FIRST ENTRY TO
;BE ADDED.
ENDIF.
MOVE T1,SCSBHQ ;GET ADDRESS OF LAST ENTRY TO BE ADDED.
MOVEM T1,SCSBPQ ;SET NEW ADDRESS OF LAST ENTRY.
SETZM SCSTHQ ;RESET THE SCSTHQ QUEUE FORWARD POINTER.
XMOVEI T1,SCSTHQ
MOVEM T1,SCSBHQ ;RESET TE SCSTHQ QUEUE BACKWARD POINTER.
CALL CLKEXI ;RESET SCSTIM
CION ;CAN NOW LET SYSTEM UPDATE THE SCSTHQ QUEUE.
;NOW WORKING WITH SCSTPQ QUEUE.
MOVE Q1,SCSTPQ
CLKFLP: LOAD T2,MEFRK,(Q1) ;Get the target fork number
MOVX T1,PSISC% ;Get the bit to light in FKINT (if needed)
TMNN FKISC,(T2) ;Has this fork been poked already???
CALLX (MSEC1,PSIGR) ;[7.1043]No, request an interrupt for this fork
SKIPE Q1,.MEANC(Q1) ;Is there a next entry???
JRST CLKFLP ;Yes, loop for the next entry pls...
RET
CLKEXI: MOVX T1,<1B1> ;Get a VERY large positive number
MOVEM T1,SCSTIM ;Turn our clock off pls...
; OKSKED ;Allow other queue deletes again
CLKEX2: RET ; and return

SUBTTL Support routines -- SCSPSI (Add entry to fork queue)
; This routine is called by SCHED at PIRQ when PSISC% is on in FKINT. We
;need to look down the queue of packets and see if there is one for this
;fork. This routine processes entries in the queue pointed to by
;SCSTPQ. When it removes entries from this queue, SCSLCK must be
;set so that SCSCLK: code will not be able to change the SCSTPQ queue.
;An alternate way of preventing such damage, would be to go NOSKED
;while removing an entry from the SCSTPQ queue.
;
; Call
; No arguments
;
; Return (+1) Always to PIRQR
; No data returned
;
;The .MEANC offset of each queue entry is used as a forward pointer to the next
;entry. The .MEAPC offset is used as a backward pointer. This is true only
;between the times when the entry is queued (via QUEFRK) and when it is removed
;(via SCSPSI). After the entry is removed from the SCSTPQ list, the .MEANC and
;.MEAPC offsets are used for another purpose.
XRENT (SCSPSI,G) ;[7.1043]SCSPSI::, XSCSPS::
SKIPN SCSTPQ ;Is there anything at all on the queue???
RET ;No, nothing to do here
SAVEAC <Q1,Q2,Q3,P1> ;Save the ACs we will need here
STKVAR <BLKADR,EVTTYP,LSTENT> ;Address of the current event block
;LSTENT IS THE ENTRY PRECEDING THE
;ENTRY THAT WAS REMOVED FOR THIS FORK.
;IT IS NEEDED BECAUSE SCSCLK: CODE CAN
;ADD ENTRIES TO THE SCSTPQ QUEUE IF SCSLCK
;IS NOT SET..
PSIELP: SKIPN T1,SCSTPQ ;Is there another entry???
JRST PSIEXI ;No, bail out here
JRST PSIFRK ;GO CHECK IF ENTRY IS FOR THIS FORK.
PSINXT:
SKIPN T1,LSTENT ;GET THE LAST ENTRY THAT WAS ON QUEUE.
IFSKP. ;FOUND ONE.
SKIPN T1,.MEANC(T1) ;IS THERE ANOTHER ENTRY ON THE QUEUE?
JRST PSIEXI ;NO. FINISHED.
ELSE. ;DID NOT KNOW OF ANY OTHER ENTRIES ON QUEUE.
SKIPN T1,SCSTPQ ;HAVE ANY ENTRIES BEEN ADDED?
JRST PSIEXI ;NO. FINISHED FOR THIS FORK.
ENDIF.

;T1 SHOULD NOW HAVE THE ADDRESS OF AN ENTRY
;ON THE QUEUE THAT HAS NOT BEEN LOOKED AT.
PSIFRK: LOAD T2,MEFRK,(T1) ;Get the target fork number
CAMN T2,FORKX ;Is this one for us???
IFSKP.
SKIPN T1,(T1) ;Get the addr of the next entry
JRST PSIEXI ;No next entry, fall out here
JRST PSIFRK ;Test the next entry
ENDIF.
;YES THIS ENTRY IS FOR THIS FORK.
AOS SCSLCK ;SET THE LOCK, THE SCSTPQ QUEUE WILL NOT
;BE TOUCHED BY ANYTHING BUT THIS.
MOVE T2,.MEAPC(T1) ;GET ADDRESS OF THE PREVIOUS ENTRY
MOVEM T2,LSTENT ;SAVE IT.
;NOW DELETE THIS ENTRY FROM THE SCSTPQ LIST.
SKIPE T2,.MEANC(T1) ;IS THERE A NEXT ENTRY?
IFSKP. ;NO.
SKIPE T2,.MEAPC(T1) ;IS THERE PREVIOUS ENTRY?
IFSKP. ;NO. THEN THIS IS THE ONLY ENTRY.
SETZM SCSTPQ ;RESET THE SCSTPQ AND SCSBPQ POINTERS.
XMOVEI T2,SCSTPQ
MOVEM T2,SCSBPQ
ELSE. ;YES. THEN THIS IS THE LAST ENTRY.
SETZM .MEANC(T2) ;ZERO THE FORWARD POINTER IN PREVIOUS ENTRY.
MOVEM T2,SCSBPQ ;RESET THE POINTER FOR NEXT TIME AROUND.
ENDIF.
ELSE. ;YES, THERE IS A NEXT ENTRY.
SKIPE T3,.MEAPC(T1) ;IS THERE A PREVIOUS ENTRY ON THE QUEUE?
IFSKP. ;NO, THEN THIS IS THE FIRST ENTRY.
SETZM .MEAPC(T2) ;SETUP BACKWARD POINTER.
MOVEM T2,SCSTPQ ;SET UP SCSTPQ
ELSE. ;YES, THERE IS PREVIOUS ENTRY.
MOVEM T3,.MEAPC(T2) ;SET NEXT TO POINT TO PREVIOUS.
MOVEM T2,.MEANC(T3) ;SET PREVIOUS TO POINT TO NEXT.
ENDIF.
ENDIF. ;ENTRY NOW DELETED FROM SCSTPQ. CONTINUE ON.
SETZM SCSLCK ;UNDO THE SCSLCK LOCK.
MOVEM T1,BLKADR ;Save the event block address
LOAD T1,MECID,(T1) ;Get the CID from the event block
CAME T1,[-1] ;[8936] Is this a special block with no CID???
IFSKP. ;[8936] yes
SETO P1,0 ;Yes, special block, show address of CB as -1
JRST PSINDL ;Yes, no CB work to do
ENDIF.

; Here to see if this event requires bits to be set in the connect block.
CALL <XENT SC.CSC> ;[7.1043]Sanity check the CID
JRST PSIBER ;Stale CID, do not queue this block
MOVX T1,CBFRAP ;Get reap bit
TDNE T1,.CBFLG(P1) ;Is this still a valid CB???
JRST PSIBER ;No, loop for next entry
; Here to put the new entry onto the fork and connection queues.
MOVE T1,BLKADR ;Get the event block address again
$LDCID P1,.MECID(T1) ;Now for the CB address
LOAD T2,METYP,(T1) ;Get the entry type
MOVEM T2,EVTTYP ;Save the event type
MOVE T2,PSITAB(T2) ;Now the address of the list pointer block
; Add the entry to the CB queue.
MOVE Q1,.TOPCQ(T2) ;Pointer to CB queue top pointer
XMOVEI Q1,@Q1 ;Turn index into CB into a real address
MOVE Q2,.BOTCQ(T2) ;Pointer to CB queue bottom pointer
XMOVEI Q2,@Q2 ;Turn index into CB into a real address
TXO Q2,C%IND ;Turn on the indirect bit for this address
SETZM .MEANC(T1) ;There is no next buffer since we are last
SETZM .MEAPC(T1) ; and for now assume there is no previous
MOVE T3,(Q2) ;Get the current last entry
CAME T3,Q1 ;Is this a pointer to the q head pointer???
MOVEM T3,.MEAPC(T1) ;No, update the previous pointer of new entry
MOVEM T1,@Q2 ;Link this entry onto the end of the queue
MOVEM T1,(Q2) ; and update the tail pointer

; Here to put the new entry onto the fork queues.
PSINDL: MOVE T1,BLKADR ;Get the entry address
LOAD T2,METYP,(T1) ;Get the entry type
MOVEM T2,EVTTYP ;Save the event type
MOVE T2,PSITAB(T2) ;Now the address of the list pointer block
; Add the entry to the fork queue
MOVE Q1,.TOPFQ(T2) ;Get addr of the fork queue FLINK
MOVE Q2,.BOTFQ(T2) ;Get addr of the fork queue BLINK
SETZM .MEANF(T1) ;No next on fork queue since we are last
SETZM .MEAPF(T1) ; and for now, assume no previous
MOVE T4,@Q1 ;Save the current state of the queue
MOVE T3,@Q2 ;Get addr of current last entry
CAME T3,Q1 ;[8936] Is this a pointer to the FLINK???
IFSKP. ;[8936]
MOVEM T1,(Q1) ;Yes, update the fork Q FLINK
ELSE.
MOVEM T3,.MEAPF(T1) ;No, update link to previous of new entry
MOVEM T1,.MEANF(T3) ;Update next field of previous entry
ENDIF.
MOVEM T1,(Q2) ;In any case, update the fork queue BLINK
JUMPN T4,PSINXT ;If there were entries before, don't give a PSI
MOVE T4,EVTTYP ;Get the event type
XCT PSIXCT(T4) ;Fetch the PSI channel from the PSB
CAIN T1,-1 ;Is it the null channel???
JRST PSINXT ;Yes, don't give a PSI
MOVE T3,BLKADR ;Get the event block address again
LOAD T2,MEFRK,(T3) ;Get the fork to interrupt
CALLX (MSEC1,PSIRQ) ;[7.1043]Queue a PSI interrupt for the fork
JRST PSINXT ;Loop for more entries

SUBTTL Support routines -- SCSQUE (Queue a block for list queueing)
; This routine places blocks on a system wide queue for the scheduler.
;This is the routine called by interrupt level to get a block moved up to
;the user. The route is as follows:
;
; 1. Interrupt level calls SCSQUE which places blocks on a system wide queue
; and sets off a timer. This is the queue that is pointed to by SCSTHQ.
; 2. The timer goes off and the scheduler runs SCSCLK. SCSCLK takes all
; of the entries on the SCSTHQ and puts them on the SCSTPQ loops over
; the SCSTPQ queue placing an interrupt for the indicated target
; forks.
; 3. The interrupt happens (at SCSPSI) and in the target fork's context we
; take entries off the SCSTPQ queue and places them on the fork's
; queue. We also queue a PSI interrupt for the fork if needed.
;
; Note:
; This routine assumes that if the CID in the block is -1 the block
; is a special fork only block. Hence the target fork number has already been
; filled in and there is no connect block to retrieve data from.
;
; Usage:
; Call
; T1/ Addr of block to be queued
; T2/ Block type code
;
; Return (+1) Always
; T1/ Addr of block which was queued
; T2/ Block type code
;
SCSQUE: SAVEAC <P1> ;We need the CB addr AC here...
SETZM .MEANC(T1) ;Zero any old link pointers
SETZM .MEAPC(T1) ;. . .
SETZM .MEANF(T1) ;. . .
SETZM .MEAPF(T1) ;. . .
STOR T2,METYP,(T1) ;Store the block type in the event block
LOAD P1,MECID,(T1) ;Get the CID from the event block
CAMN P1,[-1] ;Is this a special fork only block???
JRST QUEFRK ;Yes, do no CID checking
$LDCID P1,P1 ;Now the CB addr
LOAD T3,CBFORK,(P1) ;Get the fork this block applies to
STOR T3,MEFRK,(T1) ;Save in the block
;BETWEEN THE TIME THE ENTRY IS QUEUED (VIA
;QUEFRK) AND REMOVED FROM THE SCSTPQ LIST,(VIA
;SCSPSI)THE .MEANC OFFSET OF THE ENTRY WILL BE
;USED AS A FORWARD LINK AND THE .MEAPC
;OFFSET WILL BE USED AS A BACKWARD LINK.
;A ZERO IN EITHER ENTRY INDICATES
;THE END OF THE CHAIN IN THAT PARTICULAR
;DIRECTION. NOTE THAT SCSCLK: CODE TRANFERS
;ENTRIES ON THE SCSTHQ/SCSBHQ QUEUE TO THE
;SCSTPQ/SCSBPQ QUEUE.
QUEFRK: SKIPN SCSTHQ ;ANY ENTRIES ON THE QUEUE
IFSKP. ;YES.
MOVE T3,SCSBHQ ;GET ADDRESS OF LAST ENTRY
MOVEM T3,.MEAPC(T1) ;UPDATE THE BACKWARD LINK IN ENTRY TO BE ADDED.
ENDIF.
MOVEM T1,@SCSBHQ ;UPDATE THE FORWARD LINK OR SCSTHQ
MOVEM T1,SCSBHQ ;UPDATE SCSBHQ
SETZM SCSTIM ;Tell scheduler that its time to run SCSCLK
RET ;All done...

SUBTTL Support routines -- SCSMBS (Make another BSD)
XSWAPCD ;[7.1043]
;This routine creates a BSD and links it onto the list of BSD's for a
;connection.
;
; Note: This routine needs to be protected from user interrupts. SC.ALD must
;be allowed to complete and the obtained resource must not be lost.
;
; Call
; P1/ Address of connection block
;
; This routine should be called NOINT.
;
; Return (+1)
; T1/ Error code
;
; Return (+2)
; T1/ Address of the new BSD
; P1/ Address of the connection block
;
SCSMBS: MOVX T1,1 ;We only need one buffer thank you.
CALL <XENT SC.ALD> ;[7.1043]Allocate a long datagram buffer
RETBAD () ;No buffers, we loose, return badness
XMOVEI T2,.BDFMG(T1) ;Addr of first message pointer
MOVEM T2,.BDLMG(T1) ;Init message tail as pointer to head
SETZM .BDFMG(T1) ;Zero the message entry head
XMOVEI T2,.BDFDG(T1) ;Addr of first datagram pointer
MOVEM T2,.BDLDG(T1) ;Init tail as pointer to head
SETZM .BDFDG(T1) ;Init head as zero
MOVX T4,C%NBSD ;Get the number of entries in a BSD
MOVEM T1,T2 ;A copy we can play with
ADDI T2,.BDBDB ;Offset this to the first slot address
MOVEM T2,.BDFFD(T1) ;Store as the addr of the first free entry
MOVEM T2,T3 ;Dont smash the pointer to last entry
MBSLOP: ADDI T3,.BBLEN ;Add the offset to the next entry
MOVEM T3,(T2) ;Link on this next entry
MOVE T2,T3 ;Move to the next buffer
SOJG T4,MBSLOP ;Loop for the entire BSD
MOVEM T3,.BDLFD(T1) ;Store the list tail pointer
SETZM (T3) ;Insure a null last entry pointer
MOVEM T1,@.CBBBQ(P1) ;Link this new buffer onto the end of the queue
MOVEM T1,.CBBBQ(P1) ; and update the tail pointer
RETSKP ;Return all happy...

SUBTTL Support routines -- SCSDEQ (Dequeue a buffer from fork+CB Q's)
; This routine dequeues a packet from the fork and connection lists it is on.
;
; Note:
; May only be called from process context.
;
; Call
; T1/ Address of packet
; T2/ Address of 4 word list header block
; P1/ Address of CB or -1, if -1 there is no CB entry to delete
;
; Should be called NOINT.
;
; Return (+1) Error
; T1/ Error code
;
;
; Return (+2) No error
; T1/ Address of packet
;
XNENT (SCSDEQ,G) ;[7.1043]SCSDEQ::, XSCSDE::
SAVEQ
STKVAR <PAKADR,BLKADR>
MOVEM T1,PAKADR ;Save the packet address
MOVEM T2,BLKADR ; as well as the addr of the list header block
JUMPL P1,DEQFRK ;This a fork only entry? If yes, skip CB stuff
MOVE T3,.MEANC(T1) ;Get next connection entry
SKIPN T4,.MEAPC(T1) ;Is there another entry
SKIPE T3 ; on the queue???
JRST DEQMEL ;No, there are entries left on the queue
XMOVEI T3,@.TOPCQ(T2) ;Get the addr of the top of the queue
MOVEM T3,@.BOTCQ(T2) ;Init tail pointer as pointer to head
SETZM @.TOPCQ(T2) ;Init head pointer as zero
JRST DEQFRK ;Now do the fork list
DEQMEL: SKIPE T3 ;Is there a next entry???
MOVEM T4,.MEAPC(T3) ;Yes, update previous entry pointer in nxt buff
SKIPN T3 ;Is there a next entry???
MOVEM T4,@.BOTCQ(T2) ;No, update the tail pointer in the CB
SKIPE T4 ;Is there a previous entry???
MOVEM T3,.MEANC(T4) ;Yes, update next pointer of previous
SKIPN T4 ;Is there a previous entry???
MOVEM T3,@.TOPCQ(T2) ;No, update the head pointer in the CB

SUBTTL Support routines -- SCSMPS (Map a forks PSB)
REPEAT 0,<
; Jacket routine for SETCPT. Maps the target forks PSB if the target is
;not the current fork. Also not that it is expected that multiple routines
;will try to map the PSB for the same fork at the same time. This is a result
;of more than one routine needing access to the PSB to perform its function.
;It is not normal however to try to map the PSB of two different forks at the
;same time. This would indicate that someone neglected an interlock.
;
; Usage:
; Call
; T1/ Fork number
;
; Return (+1)
; T1/ Fork number
;
; Return (+2)
; T1/ Fork number
; T2/ Base address of target fork's PSB
;
; Note:
; It is the responsibility of the caller to provide an interlock while
;we own the PSB.
;
SCSMPS: SKIPGE T2,MPSFRK ;[8936] Have we got a fork mapped already???
IFSKP. ;[8936]
CAME T1,T2 ;Yes, are we mapping the same fork again???
RETBAD (MONX03) ;NO! Someone missed an interlock, fail
AOS MPSCNT ;Increment the nesting count
AOS MPSNST ;Count a nested fork map event
MOVE T2,MPSADR ;Get the address we reported the last time
RETSKP ; and return as if we did the work again
ENDIF.
MOVEM T1,MPSFRK ;Save the fork number of last fork mapped
CAME T1,FORKX ;[8936] Are we the target fork???
IFSKP. ;[8936]
AOS MPSCNT ;Increment the nesting level
AOS MPSFKX ;Count a mapped ourselves occurance
XMOVEI T2,PSBPGA ;Point to the base of our PSB
MOVEM T2,MPSADR ;Save the last reported address
RETSKP ; and return
ENDIF.

;Routine to check if the current fork matches the fork number
;to be checked.
; Call
; T1/ Fork number to be checked
;
; Return (+1) Fork number does not match
; T1/ Error code
;
; Return (+2) Fork number does match
FRKCHK: SAVEAC <T1,T2,T3>
CAMN T1,FORKX ;FOR THIS FORK?
IFSKP. ;NO.
MOVE T2,FORKX
MOVE T3,(P) ;CALLING ADDRESS
BUG.(CHK,SCSFR1,SCSJSY,SOFT,<SCSJSY - SCS% fork removing entries that do not belong to it>,<<T1,FRKNUM>,<T2,CURFRK>,<T3,ADDRESS>>,<
Cause: SCS% fork is remving entries that don't belong to it. It is assumed
that only the owning fork can manipulate SCS% in a CB or in its own
PSB.
Action: If this BUGCHK is reproducible, set it dumpable and send in an SPR
along with how to reproduce the problem.
Data: FRKNUM - Fork number to be checked
CURFRK - Current fork
ADDRESS - Address of calling routine.
>)
AOS MPSFR1
RETBAD (SCSFRK)
ENDIF.
RETSKP