*DECK     CSCUFS
USETEXT TEXTCS
USETEXT TEXTSS
USETEXT TXTAPSS 
PROC CSCUFS;
# TITLE CSCUFS - UPDATE FLOW STATUS.   #
  
      BEGIN  # CSCUFS # 
# 
**    CSCUFS - UPDATE FLOW STATUS.
* 
*     D. G. DEPEW.           82/06/04.
* 
*     THIS PROCEDURE PERFORMS ALL THE CONNECTION(C) LAYER PROCESSING
*     REQUIRED FOR ALL INBOUND, FLOW CONTROL SUPERVISORY MESSAGES.
* 
*     PROC CSCUFS 
* 
*     ENTRY    WCBUF[0] = WORD COUNT WORD FROM ORIGINAL CONNECTION
*                         TRAFFIC QUEUE (*CNQ*) ENTRY.
*             ABHBUF[0] = APPLICATION BLOCK HEADER FOR THE SM (BASED
*                         ARRAY *ABH* IN *TXTAPSS* POINTS HERE).
*             MSGBUF[0] = BODY OF THE SM (BASED ARRAY *APSM* IN 
*                         *TXTAPSS* POINTS HERE).  THE POSSIBLE PFC/SFC 
*                         VALUES ARE:  FC/INIT/R, FC/ACK, FC/NAK, 
*                         FC/BRK, AND FC/INACT. 
* 
*     EXIT    ANY OF THE FOLLOWING IN VARIOUS COMBINATIONS ACCORDING TO 
*             THE SM RECEIVED AND THE STATE OF THE ACN LIST ENTRY FOR 
*             THE NOP IN QUESTION.
*             - THE STATE OF THE ACN LIST ENTRY HAS BEEN UPDATED. 
*             - AN FC/INIT/N OR AN FC/RST SM HAS BEEN PLACED IN THE 
*               OUTGOING TRAFFIC QUEUE (*OTQ*). 
*             - AN FC/INACT ENTRY HAS BEEN PLACED IN THE PROTOCOL EVENT 
*               QUEUE (*PEQ*).
*             - ONE OR MORE ENTRIES IN THE WAITING BLOCK QUEUE (*WBQ*)
*               FOR THE NOP IN QUESTION HAVE BEEN TRANSFERRED TO THE
*               OUTGOING TRAFFIC QUEUE (*OTQ*)
*             - ALL OUTPUT ENQUEUED (IN THE *WBQ*) FOR THE NOP IN 
*               QUESTION HAS BEEN DISCARDED.
*             - A TERMINAL TEXT ENTRY HAS BEEN PLACED IN THE CONNECTION 
*               TRAFFIC QUEUE (*CNQ*).
*             - AN FC/BRK ENTRY HAS BEEN PLACED IN THE OPERATOR TYPEIN
*               QUEUE (*OPTQ*). 
* 
*     NOTE    THE PROCESSING IS DEFINED BY THE CS/NOP C-LAYER STATE 
*             DIAGRAM.
# 
  
# 
****  PROC CSCUFS - XREF LIST.
# 
      XREF
        BEGIN 
        PROC CSCPNQ;         # PURGE NOP QUEUE                         #
        PROC MOVE;           # MOVE STORAGE DIRECT ADDRESSING          #
        PROC SSSAWR;         # ACCEPT WORKLIST REQUEST                 #
        PROC SSTAQE;         # ACCEPT QUEUE ENTRY                      #
        PROC SSTATS;         # ALLOCATE TABLE SPACE                    #
        PROC SSTRTS;         # REMOVE TABLE SPACE                      #
        END 
# 
****
# 
  
  
      DEF  ODTLW$  #2#;      # *OUTPUT DISCARDED..* TEXT LEN IN WORDS  #
  
  
      ITEM NACN;             # NOP ACN = ORDINAL OF ACN LIST ENTRY     #
      ITEM MSGBLOC  B;       # TRUE IF *MSG* BLOCK IN *WBQ*            #
  
  
      ARRAY DISCARD [00:00] S(ODTLW$);
        BEGIN 
        ITEM D$TEXT     C(00,00,18) = ["OUTPUT DISCARDED.."]; 
        ITEM D$ZERO     U(01,48,12) = [0];
        END 
  
  
  
  
  
CONTROL EJECT;
  
PROC XMITNQ;
  
      BEGIN  # XMITNQ # 
# 
*     XMITNQ - TRANSMIT NOP QUEUE.
* 
*     THIS EMBEDDED PROC FINDS BLOCKS QUEUED FOR THE NOP IN QUESTION IN 
*     THE WAITING BLOCK QUEUE (*WBQ*) AND MOVES THEM TO THE OUTGOING
*     TRAFFIC QUEUE (*OTQ*) UNTIL THE NUMBER OF UNACKNOWLEDGED BLOCKS 
*     IS EQUAL TO THE APPLICATION BLOCK LIMIT, OR THE *WBQ* ENTRIES ARE 
*     EXHAUSTED FOR THIS NOP. 
* 
*     PROC XMITNQ 
* 
*     ENTRY   1. THE *WBQ* CONTAINS ZERO OR MORE ENTRIES FOR THE NOP
*                IN QUESTION. 
*             2. THE ACN LIST ENTRY FOR THE NOP CONTAINS ALL REQUIRED 
*                INFORMATION - NAMELY, THE COUNT OF *WBQ* ENTRIES, THE
*                COUNT OF OUTSTANDING BLOCKS AND THE APPLICATION BLOCK
*                LIMIT FOR THE CONNECTION.
* 
*     EXIT    1. ZERO OR MORE ENTRIES, FOR THE NOP IN QUESTION, HAVE
*                BEEN REMOVED FROM THE *WBQ* AND PLACED IN THE *OTQ*. 
*             2. THE COUNTS OF WAITING BLOCKS AND UNACKNOWLEDGED BLOCKS 
*                HAVE BEEN UPDATED APPROPRIATELY. 
* 
*     NOTE    NOP ENTRIES IN THE *WBQ* ARE ALREADY IN CORRECT NETWORK 
*             BLOCK FORMAT, AND MAY BE MOVED TO THE *OTQ* UNCHANGED.
# 
  
  
      ITEM I;                # LOOP INDUCTION VARIABLE                 #
      ITEM SIZ;              # ENTRY SIZE                              #
      ITEM OORD;             # OUTGOING TRAFFIC QUEUE ORDINAL          #
      ITEM WORD;             # WAITING BLOCK QUEUE ORDINAL             #
  
  
      WORD = 0; 
      FOR I=0  WHILE ACN$WBCNT[NACN] NQ 0 
        AND ACN$BLCNT[NACN] LS ACN$ABL[NACN]
      DO                               # MOVE BLOCKS                   #
        BEGIN 
        FOR WORD = WORD STEP WBQ$ESIZE[WORD]
          WHILE WBQ$ABHACN[WORD] NQ NACN
        DO                             # FIND NOP'S ENTRY              #
          BEGIN END 
  
        OORD = OTQL;                   # WHERE *OTQ* ENTRY WILL BE     #
        SIZ = WBQ$ESIZE[WORD];         # SIZE OF ENTRY TO BE MOVED     #
        SSTATS (P<OTQ>, SIZ);               # MAKE ROOM                #
        MOVE (SIZ, WBQ[WORD], OTQ[OORD]); 
        SSTRTS (P<WBQ>, WORD, SIZ);         # DELETE WAITING BLOCK     #
  
        IF OORD EQ 0
        THEN                           # FIRST ENTRY IN *OTQ*          #
          SSSAWR(CSWDF"SACNI"); 
  
        ACN$BLCNT[NACN] = ACN$BLCNT[NACN] + 1;   # OUTSTANDING BLOCKS  #
        ACN$WBCNT[NACN] = ACN$WBCNT[NACN] - 1;   # WAITING BLOCKS      #
        END 
  
  
      END  # XMITNQ # 
  
  
  
  
  
CONTROL EJECT;
  
# 
*     MAIN ROUTINE BEGINS HERE. 
* 
*     SAVE THE ACN NUMBER AND EXECUTE A CASE CONSTRUCT TO PROCESS THE 
*     FIVE TYPES OF INCOMING SM'S.  REFORMAT THE ABH FOR THE I-LAYER. 
# 
      ABHWORD[1] = 0; 
  
      IF WCB$SMID[0] EQ SMID"BIMARK"
      THEN
        BEGIN 
        NACN = ABHADR[0]; 
        ABHADR[1] = NACN; 
        END 
      ELSE
        BEGIN 
        ABHADR[1]  = FCACN[0];
        NACN = FCACN[0];
        END 
  
  
  
      IF WCB$SMID[0] EQ SMID"FCINIT"
      THEN                             # CONNECTION INITIALIZED        #
        BEGIN 
  
  
# 
*       MARK THE CONNECTION AS INITIALIZED, ISSUE THE FC/INIT/N SM, AND 
*       OUTPUT ANY BLOCKS QUEUED (IN THE *WBQ*) FOR THIS NOP. 
# 
        ACN$INIT[NACN] = TRUE;
        PFCSFC[0] = FCINITN;
        SSTAQE (P<OTQ>, WCBUF[0], ABHBUF[0], MSGBUF[0]);
        XMITNQ; 
  
        END                  # FC/INIT                                 #
  
  
  
      ELSE IF WCB$SMID[0] EQ SMID"FCACK"
        OR WCB$SMID[0] EQ SMID"FCNAK" 
      THEN                             # A BLOCK HAS BEEN ACKNOWLEDGED #
        BEGIN 
  
  
# 
*       NOTE THAT WE TREAT A BLOCK NOT DELIVERED MESSAGE THE SAME AS A
*       BLOCK DELIVERED.  THAT IS, CS DOES NOT ATTEMPT ANY RECOVERY OF
*       LOST BLOCKS.  THIS IS BECAUSE LOST BLOCKS ARE, IN PRACTICE, 
*       EXTREMELY RARE.  IF THE CONNECTION IS ACTIVE OR A COMMAND IS IN 
*       PROGRESS, DECREMENT THE OUTSTANDING BLOCK COUNT AND OUTPUT THE
*       NEXT QUEUED (IN THE *WBQ*) BLOCK (IF THERE IS ONE).  OTHERWISE, 
*       IGNORE THE SM.
# 
        IF ACN$NOPST[NACN] EQ S"ACTIVE" 
          OR ACN$NOPST[NACN] EQ S"COMMAND"
          OR ACN$NOPST[NACN] EQ S"BREAK"
          OR ACN$NOPST[NACN] EQ S"CLEARI" 
        THEN                           # CONNECTION IS OK FOR OUTPUT   #
          BEGIN 
          ACN$BLCNT[NACN] = ACN$BLCNT[NACN] - 1;
          XMITNQ; 
          END 
  
        END                  # FC/ACK, FC/NAK                          #
  
  
  
      ELSE IF WCB$SMID[0] EQ SMID"INTRUSR"
      THEN                             # NOP ENTERED A USER BREAK      #
        BEGIN 
  
# 
*       IF THIS IS JUST A USER INTERUPT AND NOT A USER BREAK, THEN SEND 
*       A INTR/RSP SM IN RESPONSE.
# 
        IF INTRCHR[0] GR RIR"UB2" 
        THEN
          BEGIN 
          WCB$WORD[1] = LINTR + 2;
          ABHWORD[1] = LINTR; 
          ABHABT[1] = APPCMD; 
          ABHACT[1] = CT60TRANS;
  
          SPMSG0[1] = 0;
          PFCSFC[1] = INTRRSP;
          INTRACN[1] = INTRACN[0];
  
          SSTAQE(P<OTQ>,WCBUF[1],ABH[1],APSM[1]); 
          END 
  
# 
*       RELEASE ALL OUTPUT QUEUED (IN THE *WBQ*) FOR THIS NOP (IF ANY). 
*       CLEAR THE OUTSTANDING BLOCK COUNT.
*       SEND A RO/MARK SM ON THE CONNECTION TO ALLOW OUT TO RESUME. 
*       IF THE CONNECTION IS ACTIVE AND THERE WAS NO *MSG* BLOCK QUEUED 
*       ENQUEUE A TERMINAL TEXT ENTRY (*CNQ*) CONTAINING THE MESSAGE
*       *OUTPUT DISCARDED..* WITHOUT INPUT ALLOWED.  IF THERE WAS AN
*       *MSG* BLOCK QUEUED, THE *OUTPUT DISCARDED* MESSAGE MUST BE OF 
*       TYPE *MSG* TO TURN AROUND THE HALF-DUPLEX MODE AND TO STAY IN 
*       SYNCH WITH NIP.  TO ACCOMPLISH THIS WE ENQUEUE (IN THE *CNQ*) 
*       A TERMINAL TEXT ENTRY WITH INPUT ALLOWED AND CHANGE THE STATE 
*       TO BREAK IN PROGRESS.  THIS WILL CAUSE THE OUTBOUND TEXT
*       PROCESSOR (*CSCPNT*) TO GENERATE THE FC/RST FOLLOWED BY THE 
*       CORRECT MESSAGES.  IF A COMMAND IS IN PROGRESS, SEND THE BREAK
*       TO THE I-LAYER AS AN OPERATOR TYPEIN (*OPTQ*).
# 
        ELSE
          BEGIN 
          CSCPNQ (NACN, MSGBLOC);      # DELETE NOP'S OUTPUT (IF ANY)  #
  
          IF ACN$NOPST[NACN] EQ S"ACTIVE" OR
             ACN$NOPST[NACN] EQ S"COMMAND"
          THEN
            BEGIN                      # SEND RO/MARK SM               #
            WCB$WORD[1] = 3;
            ABHWORD[1] = LROMARK; 
            ABHABT[1] = APPCMD; 
            ABHADR[1] = INTRACN[0]; 
            ABHACT[1] = CT8ASCII; 
  
            SPMSG0[1] = 0;
            PFCSFC[1] = ROMARK; 
  
            IF ACN$BLCNT[NACN] LS ACN$ABL[NACN] 
            THEN
              BEGIN 
              ABHABN[1] = ACN$ABN[NACN];
              ACN$ABN[NACN] = ACN$ABN[NACN] + 1;
              ACN$BLCNT[NACN] = ACN$BLCNT[NACN] + 1;
              SSTAQE(P<OTQ>,WCBUF[1],ABH[1],APSM[1]); 
              END 
  
            ELSE
              BEGIN 
              ABHABN[1] = ACN$ABN[NACN];
              ACN$ABN[NACN] = ACN$ABN[NACN] + 1;
              ACN$WBCNT[NACN] = ACN$WBCNT[NACN] + 1;
              SSTAQE(P<WBQ>,WCBUF[1],ABH[1],APSM[1]); 
              END 
            END 
  
          IF ACN$NOPST[NACN] EQ S"ACTIVE" 
          THEN                         # BREAK UNSOLICITED STATUS RPTS #
            BEGIN 
            WCB$WORD[1] = ODTLW$ + 2;  # TERM TEXT NTRY SIZ, IAF=FALSE #
            WCB$SMID[1] = SMID"TTEXT";
  
            IF MSGBLOC
            THEN                       # MUST TURN AROUND HALF DUPLEX  #
              BEGIN 
              WCB$IAF[1] = TRUE;
              ACN$NOPST[NACN] = S"BREAK"; 
              END 
            ELSE                       # SET BREAK FLAG TO INDICATE A  #
              BEGIN                      # BREAK OCCURRED WHILE IN THE #
              ABHBRK[1] = 1;             # ACTIVE STATE.               #
              ACN$NOPST[NACN] = S"CLEARI";
              END 
  
            SSTAQE (P<CNQ>, WCBUF[1], ABHBUF[1], DISCARD);
            END 
  
          ELSE                         # BREAK COMMAND IN PROGRESS     #
            BEGIN 
            WCB$WORD[1] = 2;           # MINIMUN QUEUE ENTRY SIZE      #
            ABHBRK[1]   = 1;
            SSTAQE(P<OPTQ>, WCBUF[1], ABHBUF[1], MSGBUF[0]);
            ACN$NOPST[NACN] = S"BREAK"; 
            END 
  
          END 
        END                  # FC/BRK                                  #
  
# 
*     IF THIS MESSAGE IS A BREAK MARKER, THEN SEND A INTR/RSP FOR THE 
*     CONNECTION TO ALLOW ANOTHER BREAK AND SET THE STATE OF THE CONNEC-
*     TION TO ACTIVE. 
# 
      ELSE IF WCB$SMID[0] EQ SMID"BIMARK" 
      THEN
        BEGIN 
        IF ACN$NOPST[NACN] EQ S"BREAK" OR 
           ACN$NOPST[NACN] EQ S"CLEARI" 
        THEN
          BEGIN 
          WCB$WORD[1] = LINTR + 2;
          ABHWORD[1] = LINTR; 
          ABHABT[1] = APPCMD; 
          ABHACT[1] = CT60TRANS;
  
          SPMSG0[1] = 0;
          PFCSFC[1] = INTRRSP;
          INTRACN[1] = NACN;
  
          SSTAQE(P<OTQ>,WCBUF[1],ABH[1],APSM[1]); 
  
          ACN$NOPST[NACN] = S"ACTIVE";
          END 
        END 
  
  
      ELSE                             # MUST BE CONNECTION INACTIVE   #
        BEGIN 
  
  
# 
*       RELEASE ALL OUTPUT QUEUED FOR THIS NOP AND FORWARD THE FC/INACT 
*       TO THE I-LAYER (AS PROTOCOL EVENT). 
# 
        CSCPNQ (NACN, MSGBLOC);        # DELETE NOP'S OUTPUT (IF ANY)  #
  
        IF ACN$NOPST[NACN] EQ S"ACTIVE" 
          OR ACN$NOPST[NACN] EQ S"COMMAND"
        THEN
          SSTAQE (P<PEQ>, WCBUF[0], ABHBUF[1], MSGBUF[0]);
  
        END                  # FC/INACT                                #
  
      END  # CSCUFS # 
  
      TERM
