Trailing-Edge
-
PDP-10 Archives
-
BB-R595B-SM_11-9-85
-
mcb/nsp/ns1.bli
There is 1 other file named ns1.bli in the archive. Click here to see a list.
Module NS1 ( !
ident = 'X01080'
) =
begin
!
! COPYRIGHT (c) 1980, 1981, 1982
! DIGITAL EQUIPMENT CORPORATION
! Maynard, Massachusetts
!
! This software is furnished under a license and may be used
! and copied only in accordance with the terms of such license
! and with the inclusion of the above copyright notice. This
! software or any other copies thereof may not be provided or
! otherwise made available to any other person. No title to
! and ownership of the software is hereby transferred.
!
! The information in this software is subject to change
! without notice and should not be construed as a commitment
! by DIGITAL EQUIPMENT CORPORATION.
!
! DIGITAL assumes no responsibility for the use or reliability
! of its software on equipment which is not supplied by
! DIGITAL.
!
!++
!
! FACILITY: Network Services Layer
!
! ABSTRACT: This module contains all the routines for transmitting
! and receiving Data and Other Data messages.
!
!
! ENVIRONMENT: MCB
!
! AUTHOR: Ron Platukis CREATION DATE: 1-july-80
!
! MODIFIED BY:
!
! Alan Peckham,Ron Platukis 22-Oct-80
! 01 - Move NDB bind in CCB_RETRN.
! Clear C_STS before sending CCB to XPT in XPT_XMIT.
! Set C_PRM4 to PDB address or -1 if Reserve Port in XPT_XMIT.
!
! Ron Platukis 23-oct-80
! 02 - Set PORTstate negative if Reserved Port.
!
! 03 Ron Platukis 1-dec-80
! -Add CMP_LSS and CMP_LEQ macros to perform 12-bit arith.
!
! 04 Ron Platukis 13-jan-81
! -Change linkages to BLISS, add access for NSP Data Base address.
!
! 05 Ron Platukis 20-jan-81
! -Add Network Management event logging code.
!
! 06 Ron Platukis 24-feb-81
! -fix bug in SND_DATA to set ACK_queue to chain word of CCB when
! dequeueing.
!
! 07 Ron Platukis 15-sept-81
! -in routine SEG_BLD set FLAGseg to true if it is false and the
! ACK_queue is empty.
!
! 08 Ron Platukis 4-february-82
! -in routine PROC_DATA_ACK set FLAGseg to true if ACKrcv_dat equals
! NUMsent.
!--
!
! INCLUDE FILES:
!
library
'mcb:xportx';
library
'mcb:mcblib';
library
'mcb:nmxlib';
require
'nspbli:nspdata';
require
'nspbli:nsinfo';
!
! TABLE OF CONTENTS:
!
forward routine
ACK_BLD: novalue, !format an ACK
ACK_DATA_SND: , !send a data ack
ACK_OTH_RCV: novalue, !process Other Ack
ACK_RCV: novalue, !process Data Ack
ACK_OTH_SND: , !send Other ACK
CCB_GET:,
CCB_HDR_GET:,
CCB_RETRN: novalue,
DADD: novalue,
DATA_RECVD: novalue,
DATA_TO_SND: , !check if data to send
DRQ_BLD: novalue, !format a Data Req
DRQ_RCV: novalue, !process Data Request
D_RCV: novalue, !process a Segment
D_REQ_TO_SND: , !check if data req to send
IRQ_BLD: novalue, !format an INT Req
IRQ_RCV: novalue, !process Interrupt Request
INTERRUPT_TO_SND: , !check if int to send
INTR_REQ_TO_SND: , !check if int req to send
INT_BLD: novalue, !format an INT msg
INT_RCV: novalue, !process Interrupt
INT_RECVD: novalue,
LS_RCV: novalue, !dispatch on request type
MSG_RCV: CALL$ novalue, !dispatch on NSP message type
ONCE_A_SECOND: CALL$ novalue, !Resource revovery routine
OTHACK_BLD: novalue, !format an OTH ACK
PROC_DATA_ACK: novalue, !more process Data Ack
PROC_OTH_ACK: novalue, !more process Other Ack
REAS_DATA: novalue, !reassembly routine
SEG_BLD: novalue, !format a Data Seg
SND_DATA: , !send a data segment
SND_MSG: CALL$ novalue, !send a message
SND_INTERRUPT: CALL$, !send int msg
SND_INTR_REQ: , !send int req msg
SND_ONE_DATA: CALL$ novalue, !send one segment only
SND_REQ_DATA: , !send data req msg
TRICKLE: CALL$, !send only one msg and quit
UPDATE_DELAY: novalue, !update round trip delay
XPT_XMIT: novalue; !queue CCB to XPT
!
! macros:
!
!
! equated symbols:
!
!
! own storage:
!
$MCB_PROCESS( name = NS1)
!
! external references:
!
external
%name('.crdat'): vector[2],
$DSPCR;
bind DB = %name('.crdat')[1]: ref block field(NSP_fields);
routine ACK_BLD ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine formats an NSP Data Acknowledgement message and
! queues it to Transport.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
local
PTR;
PTR = .CCB[C_ADDR];
ch$wchar_a( FLG_DAT_ACK, PTR);
ch$wchar_a( .PDB[L_rem_addr], PTR);
ch$wchar_a( .PDB[H_rem_addr], PTR);
ch$wchar_a( .PDB[PID], PTR);
ch$wchar_a( .PDB[ADDran], PTR);
PUT2BYTES( .PDB[ACKdat_xmt] + Q_ACK^12 + true^15, PTR);
CCB[C_CNT] = ch$diff(.PTR, .CCB[C_ADDR]);
PDB[FLAGdat_ack] = false;
XPT_XMIT( .CCB, .PDB)
end;
routine ACK_DATA_SND ( PDB) : = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine transmits a Data Acknowledgement message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
local
CCB: ref block field(C_fields);
If CCB_HDR_GET( 0, CCB, .PDB)
Then
begin
ACK_BLD( .CCB, .PDB);
return true
end;
return false
end;
routine ACK_OTH_RCV ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes a received Other Data Acknowledgement message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
PROC_OTH_ACK( .CCB, .PDB);
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB)
end;
routine ACK_OTH_SND ( PDB) : = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine allocates a CCB and passes control to the Other Data
! Acknowledgement Format routine.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
local
CCB: ref block field(C_fields);
If CCB_HDR_GET( 0, CCB, .PDB)
Then
begin
OTHACK_BLD( .CCB, .PDB);
return true
end;
return false
End;
routine ACK_RCV ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes a received Data Acknowledgement message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
PROC_DATA_ACK( .CCB, .PDB);
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB)
end;
routine CCB_GET (CCB, PDB) = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine allocates a CCB.
!
! FORMAL PARAMETERS:
! CCB = CCB address
! PDB = Port Data Base address
!
! IMPLICIT INPUTS:
! None
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
local
LCCB: ref block field(C_fields);
If not CCBGT$(LCCB)
Then
return false;
LCCB[C_STK] = 0;
LCCB[C_CHN] = 0;
LCCB[C_BIAS] = 0;
LCCB[C_ADDR] = 0;
LCCB[C_PRM1] = 0;
LCCB[C_PRM2] = 0;
LCCB[C_PRM3] = 0;
LCCB[C_PRM4] = 0;
LCCB[C_PRM5] = 0;
If .PDB neq -1
Then
PDB[COUNTres] = .PDB[COUNTres] + 1;
.CCB = .LCCB;
return true;
end;
routine CCB_HDR_GET ( CCB, LCCB, PDB ) = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine allocates a CCB and a header buffer from DSR space.
!
! FORMAL PARAMETERS:
! LCCB = CCB Address to stack
! PDB = Port Data Base address
! CCB = CCB address
!
! IMPLICIT INPUTS:
! none
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
map LCCB: ref block field(C_fields);
If not CCBGT$(.LCCB)
Then
return false;
begin
bind XCCB = .LCCB: ref block field(C_fields);
XCCB[C_STK] = 0;
XCCB[C_CHN] = 0;
XCCB[C_PRM1] = 0;
XCCB[C_PRM2] = 0;
XCCB[C_PRM3] = 0;
XCCB[C_PRM4] = 0;
XCCB[C_PRM5] = 0;
XCCB[C_BIAS] = 0;
If not $MCB_GET_DSR(hdb_size, XCCB[C_ADDR])
Then
begin
CCBRT$(..LCCB);
return false;
end;
If .CCB neq 0
Then
XCCB[C_STK] = .CCB;
end;
If .PDB neq -1
Then
PDB[COUNTres] = .PDB[COUNTres] + 1;
return true;
end;
routine CCB_RETRN ( CCB, PDB): novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine deallocates a CCB.
!
! FORMAL PARAMETERS:
! CCB = CCB address
! PDB = Port Data Base address
!
! IMPLICIT INPUTS:
! None
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
local
temp,
NDB : ref block field(NODE_fields),
CLZ_CCB: ref block field(C_fields);
CCBRT$( .CCB);
If .PDB neq -1
Then
begin
PDB[COUNTres] = .PDB[COUNTres] - 1;
If .PDB[PORTstate] eql N$SCL and
.PDB[COUNTres] eql 0
Then
begin
NDB = .PDB[NODElnk];
PDB[FLAGinuse] = false;
CMQRM$( PDB[MSG_queue], CLZ_CCB);
CLZ_CCB[C_FNC] = FC_XCP;
CLZ_CCB[C_STS] = N$SSUC;
LLCRS$( .CLZ_CCB);
end;
End;
end;
routine DADD ( double_word, value ) :novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine performs double percision arithemitic.
!
! FORMAL PARAMETERS:
! DOUBLE_WORD = address to add VALUE to
! VALUE = value to add to DOUBLE_WORD
!
! IMPLICIT INPUTS:
! None
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
builtin ROT;
map double_word: ref block field(long_word);
if rot(double_word[low] = .double_word[low] + .value, 1)
then
begin
if rot(double_word[hi] = .double_word[hi] + 1, 1)
then
begin
double_word[low] = -1;
double_word[hi] = -1;
end
end
end;
routine DATA_TO_SND ( PDB) : = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine checks to see if flow control permission allows
! a data segment to be transmitted.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
If ((.PDB[PORTstate] eql N$SRUN) or
(.PDB[PORTstate] eql N$SDI and
(CMP_NEQ(.PDB[NUMhigh], .PDB[ACKrcv_dat]))))
Then
begin
If not .PDB[FLOWsw_rem]
Then
return false;
If (CMP_LEQ( .PDB[NUMdat], .PDB[NUMhigh])) or
.PDB[FLAGseg] eql false
Then
begin
Case .PDB[FLOWtyp_rem] from FLOWnone to FLOWmsg of
Set
[FLOWnone]:
return true;
[FLOWseg]:
begin
If .PDB[FLAGseg] eql true
Then
begin
If (CMP_LEQ( .PDB[NUMdat], (.PDB[ACKrcv_dat] + .PDB[FLOWdat_rem])))
Then
return true
end
Else
begin
bind CCB = .PDB[ACK_queue]: block field(C_fields);
If (CMP_LEQ( .CCB[C_STS], (.PDB[ACKrcv_dat] + .PDB[FLOWdat_rem])))
Then
return true
end;
end;
[FLOWmsg]:
If (0 lss .PDB[FLOWdat_rem]) or
.PDB[FLAGseg] eql false
Then
return true;
Tes;
end;
return false
end
Else
return false;
end;
routine DATA_RECVD ( CCB, PDB): novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine generates a DATA-RECIEVED call to Session Control.
!
! FORMAL PARAMETERS:
! DB = NSP Data Base Address
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! None
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
map CCB: ref block field(C_fields);
bind STK_CCB = .CCB[C_STK]: block field(C_fields);
local
PTR,
CHR;
PTR = .STK_CCB[C_ADDR];
MAP$( .STK_CCB[C_BIAS]);
CHR = ch$rchar( .PTR);
If (.CHR and FLG_EOM) neq 0
Then
CCB[C_PRM1] = N$FEOM;
If (.CHR and FLG_BOM) neq 0
Then
CCB[C_PRM1] = .CCB[C_PRM1] or N$FBOM;
PTR = ch$plus( .STK_CCB[C_ADDR], 6 );
CHR = ch$rchar( .PTR);
If .CHR<7, 1>
Then
CHR = 9
Else
CHR = 7;
MAP$( .DB[BIASports]);
CCB[C_FNC] = FC_RCP;
CCB[C_MOD] = N_RDAT;
CCB[C_LIX] = .PDB[PID];
CCB[C_BIAS] = .STK_CCB[C_BIAS];
CCB[C_CNT] = .STK_CCB[C_CNT] - .CHR;
CCB[C_ADDR] = ch$plus( .STK_CCB[C_ADDR], .CHR);
CCB[C_STS] = N$SSUC;
CCB[C_PIX] = .DB[NSPsc_pix];
LLCRS$( .CCB);
end;
routine DRQ_BLD ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine formats an NSP Data Request message and queues it to
! Transport.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
bind STK_CCB = .CCB[C_STK]: block field(C_fields);
local
PTR;
PTR = .CCB[C_ADDR];
ch$wchar_a( FLG_REQ, PTR);
ch$wchar_a( .PDB[L_rem_addr], PTR);
ch$wchar_a( .PDB[H_rem_addr], PTR);
ch$wchar_a( .PDB[PID], PTR);
ch$wchar_a( .PDB[ADDran], PTR);
PUT2BYTES( (.PDB[ACKoth_xmt] and %o'7777') + Q_ACK^12 + true^15, PTR);
PUT2BYTES( (.PDB[NUMoth] and %o'7777'), PTR);
If .STK_CCB[C_PRM1] eql 0
Then
ch$wchar_a( FC_NCHG + FC_DATA^2, PTR)
Else
ch$wchar_a( FC_SEND + FC_DATA^2, PTR);
ch$wchar_a( .STK_CCB[C_PRM1], PTR);
CCB[C_CNT] = ch$diff(.PTR, .CCB[C_ADDR]);
STK_CCB[C_STS] = .PDB[NUMoth];
PDB[OTHtyp] = OTHdrequest;
PDB[FLAGoth_ack] = false;
PDB[OTHstate] = OTHsent;
XPT_XMIT( .CCB, .PDB)
end;
routine DRQ_RCV ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes a received Data Request message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
MAP$( .DB[BIASports]);
If .DB[Q_FLG]
Then
PROC_OTH_ACK( .CCB, .PDB);
If .DB[SEGNUM] eql ((.PDB[ACKoth_xmt] + 1) and %o'7777')
Then
begin
PDB[FLOWsw_rem] = (Selectone .DB[FCMOD] of
Set
[FC_SEND]: true;
[FC_DONT]: false;
Tes);
Selectone .PDB[FLOWtyp_rem] of
Set
[FLOWseg]:
begin
If (-128 leq .PDB[FLOWdat_rem] + .DB[FCVAL]) and
(127 geq .PDB[FLOWdat_rem] + .DB[FCVAL])
Then
begin
PDB[FLOWdat_rem] = .PDB[FLOWdat_rem] + .DB[FCVAL];
PDB[ACKoth_xmt] = .PDB[ACKoth_xmt] + 1;
PDB[FLAGoth_ack] = true;
end
Else
CALL$E( EVENT_LOG, .DB[NSPns2_pix], invflw, .PDB[FLOWdat_rem], .PDB, .CCB);
end;
[FLOWnone]:
begin
PDB[ACKoth_xmt] = .PDB[ACKoth_xmt] + 1;
PDB[FLAGoth_ack] = true;
end;
[FLOWmsg]:
begin
If (0 leq .DB[FCVAL]) and
(127 geq .DB[FCVAL])
Then
begin
PDB[FLOWdat_rem] = .PDB[FLOWdat_rem] + .DB[FCVAL];
PDB[ACKoth_xmt] = .PDB[ACKoth_xmt] + 1;
PDB[FLAGoth_ack] = true;
end
Else
CALL$E( EVENT_LOG, .DB[NSPns2_pix], invflw, .PDB[FLOWdat_rem], .PDB, .CCB);
end
Tes;
end
Else
begin
If (CMP_LEQ( .DB[SEGNUM], .PDB[ACKoth_xmt]))
Then
PDB[FLAGoth_ack] = true
end;
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB)
end;
routine D_REQ_TO_SND ( PDB) : = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine tests all the conditions needed to transmit a Data
! Request message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
If .PDB[PORTstate] eql N$SRUN or
(.PDB[PORTstate] eql N$SDI and
(CMP_NEQ(.PDB[NUMhigh], .PDB[ACKrcv_dat])))
Then
begin
If (.PDB[DATRhead] neq 0 and .PDB[OTHstate] eql OTHready)
Then
return true;
return false;
end
Else
return false;
end;
routine D_RCV ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes a received Data Segment.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
local PTR;
MAP$( .DB[BIASports]);
If .DB[Q_FLG]
Then
PROC_DATA_ACK( .CCB, .PDB);
If (CMP_EQL( .DB[SEGNUM], (.PDB[ACKdat_xmt] + 1)))
Then
REAS_DATA( .CCB, .PDB)
Else
begin
If (CMP_LEQ( .DB[SEGNUM], .PDB[ACKdat_xmt]))
Then
PDB[FLAGdat_ack] = true;
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB)
end
end;
routine IRQ_BLD ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine formats an NSP Interrupt Request message and queues it to
! Transport.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
bind STK_CCB = .CCB[C_STK]: block field(C_fields);
local
PTR;
PTR = .CCB[C_ADDR];
ch$wchar_a( FLG_REQ, PTR);
ch$wchar_a( .PDB[L_rem_addr], PTR);
ch$wchar_a( .PDB[H_rem_addr], PTR);
ch$wchar_a( .PDB[PID], PTR);
ch$wchar_a( .PDB[ADDran], PTR);
PUT2BYTES( (.PDB[ACKoth_xmt] and %o'7777') + Q_ACK^12 + true^15, PTR);
PUT2BYTES( (.PDB[NUMoth] and %o'7777'), PTR);
ch$wchar_a( FC_INTERRUPT^2, PTR);
ch$wchar_a( 1, PTR);
CCB[C_CNT] = ch$diff(.PTR, .CCB[C_ADDR]);
STK_CCB[C_STS] = .PDB[NUMoth];
PDB[OTHtyp] = OTHirequest;
PDB[FLAGoth_ack] = false;
PDB[OTHstate] = OTHsent;
XPT_XMIT( .CCB, .PDB)
end;
routine IRQ_RCV ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes a received Interrupt Request message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
MAP$( .DB[BIASports]);
If .DB[Q_FLG]
Then
PROC_OTH_ACK( .CCB, .PDB);
If .DB[SEGNUM] eql ((.PDB[ACKoth_xmt] + 1) and %o'7777')
Then
begin
If .DB[FCVAL] gtr 0 and
0 leq .PDB[FLOWint_rem] + .DB[FCVAL] and
127 geq .PDB[FLOWint_rem] + .DB[FCVAL]
Then
begin
PDB[ACKoth_xmt] = .PDB[ACKoth_xmt] + 1;
PDB[FLAGoth_ack] = true;
PDB[FLOWint_rem] = .PDB[FLOWint_rem] + .DB[FCVAL]
end
Else
CALL$E( EVENT_LOG, .DB[NSPns2_pix], invflw, .PDB[FLOWint_rem], .PDB, .CCB);
end
Else
begin
If (CMP_LEQ( .DB[SEGNUM], .PDB[ACKoth_xmt]))
Then
PDB[FLAGoth_ack] = true
end;
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB)
end;
routine INT_BLD ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine formats an NSP Interrupt message and queues it to
! Transport.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
bind STK_CCB = .CCB[C_STK]: block field(C_fields);
local
PTR;
PTR = .CCB[C_ADDR];
ch$wchar_a( FLG_INT, PTR);
ch$wchar_a( .PDB[L_rem_addr], PTR);
ch$wchar_a( .PDB[H_rem_addr], PTR);
ch$wchar_a( .PDB[PID], PTR);
ch$wchar_a( .PDB[ADDran], PTR);
PUT2BYTES( (.PDB[ACKoth_xmt] and %o'7777') + Q_ACK^12 + true^15, PTR);
PUT2BYTES( (.PDB[NUMoth] and %o'7777'), PTR);
CCB[C_CNT] = ch$diff(.PTR, .CCB[C_ADDR]);
CCB[C_CHN] = .CCB[C_STK];
STK_CCB[C_STS] = .PDB[NUMoth];
PDB[OTHtyp] = OTHinterrupt;
PDB[FLAGoth_ack] = false;
PDB[OTHstate] = OTHsent;
XPT_XMIT( .CCB, .PDB)
end;
routine INT_RECVD ( CCB, PDB): novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine generates an INTERRUPT-RECIEVED call to Session Control.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
map CCB: ref block field(C_fields);
bind STK_CCB = .CCB[C_STK]: block field(C_fields);
local
PTR,
CHR;
PTR = ch$plus( .STK_CCB[C_ADDR], 6);
MAP$( .STK_CCB[C_BIAS]);
CHR = ch$rchar( .PTR);
If .CHR<7, 1>
Then
CHR = 9
Else
CHR = 7;
MAP$( .DB[BIASports]);
CCB[C_FNC] = FC_RCP;
CCB[C_MOD] = N_RINT;
CCB[C_LIX] = .PDB[PID];
CCB[C_BIAS] = .STK_CCB[C_BIAS];
CCB[C_CNT] = .STK_CCB[C_CNT] - .CHR;
CCB[C_ADDR] = ch$plus( .STK_CCB[C_ADDR], .CHR);
CCB[C_STS] = N$SSUC;
CCB[C_PIX] = .DB[NSPsc_pix];
LLCRS$( .CCB);
end;
routine INT_RCV ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine processses a received Interrupt message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
local
temp,
NDB : ref block field(NODE_fields),
WK_CCB: ref block field(c_fields);
NDB = .PDB[NODElnk];
temp = 7;
MAP$( .DB[BIASports]);
If .DB[Q_FLG]
Then
begin
temp = 9;
PROC_OTH_ACK( .CCB, .PDB);
end;
If .DB[SEGNUM] eql (.PDB[ACKoth_xmt] + 1 and %o'7777') and
.PDB[COUNTloc_int] gtr 0 and
.PDB[BUFFrcv_int] eql 0
Then
begin
PDB[COUNTloc_int] = .PDB[COUNTloc_int] - 1;
PDB[FLAGoth_ack] = true;
PDB[ACKoth_xmt] = .PDB[ACKoth_xmt] + 1;
MAP$( .DB[BIASnodes]);
DADD( NDB[NDb_rcv], .CCB[C_CNT] - .temp);
MAP$( .DB[BIASports]);
If CCB_GET( WK_CCB, .PDB)
Then
begin
WK_CCB[C_STK] = .CCB;
INT_RECVD( .WK_CCB, .PDB);
return
end;
PDB[BUFFrcv_int] = .CCB;
end;
If (CMP_LEQ( .DB[SEGNUM], .PDB[ACKoth_xmt]))
Then
PDB[FLAGoth_ack] = true;
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB)
end;
routine INTERRUPT_TO_SND ( PDB) : = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine tests all the conditions needed to transmit an
! Interrupt message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
IF .PDB[PORTstate] neq N$SRUN
Then
return false;
If ((.PDB[INThead] neq 0) and (.PDB[OTHstate] eql OTHready) and
(.PDB[FLOWint_rem] gtr 0)) or .PDB[OTHstate] eql OTHtimeout
Then
return true;
return false;
end;
routine INTR_REQ_TO_SND ( PDB) : = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine tests all the conditions needed to transmit an Interrupt
! Request message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
If .PDB[PORTstate] neq N$SRUN
Then
return false;
If (.PDB[INTRhead] neq 0) and (.PDB[OTHstate] eql OTHready) and
(.PDB[COUNTloc_int] eql 0) and (.PDB[BUFFrcv_int] eql 0)
Then
return true;
return false;
end;
routine LS_RCV ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine dispatches to th appropriate routine bases on the
! type of Link Service message received.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
local PTR;
MAP$( .CCB[C_BIAS]);
If not .DB[Q_FLG]
Then
PTR = ch$plus( .CCB[C_ADDR], 7 )
Else
PTR = ch$plus( .CCB[C_ADDR], 9 );
DB[LSFLAGS] = ch$rchar_a( PTR);
DB[FCVAL] = ch$rchar_a( PTR);
MAP$( .DB[BIASports]);
If not (.DB[LSFLAGS] and LS_RSV)
Then
begin
If .DB[FCVALINT] eql FC_INTERRUPT
Then
IRQ_RCV( .CCB, .PDB)
Else
DRQ_RCV( .CCB, .PDB)
end
Else
begin
CALL$E( EVENT_LOG, .DB[NSPns2_pix], invmsg, 0, .PDB, .CCB);
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB)
end
end;
global routine MSG_RCV ( CCB, PDB) :CALL$ novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine dispatches on the type of NSP message received.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
local
SC_CCB:ref block field(C_fields),
PTR;
MAP$( .CCB[C_BIAS]);
PTR = ch$plus( .CCB[C_ADDR], 5 );
DB[ACKNUM] = GET2BYTES( PTR);
If not .DB[Q_FLG]
Then
PTR = ch$plus( .PTR, -2);
MAP$( .DB[BIASports]);
If .PDB[PORTstate] eql N$SCC or
.PDB[PORTstate] eql N$SRUN or
(.PDB[PORTstate] eql N$SDI and
(CMP_NEQ(.PDB[NUMhigh], .PDB[ACKrcv_dat])))
Then
begin
If .PDB[PORTstate] eql N$SCC and
(.DB[MSGFLG] eql FLG_INT or .DB[MSGFLG] eql FLG_REQ or
.DB[MSGFLG] eql FLG_DAT_ACK)
Then
begin
PDB[PORTstate] = N$SRUN;
UPDATE_DELAY( .PDB);
PDB[CONFIDENCE] = true;
PDB[TIMERcon] = 0;
PDB[COUNTdat_retrans] = 0;
If CMQRM$( PDB[MSG_queue], SC_CCB)
Then
begin
SC_CCB[C_STS] = N$SSUC;
SC_CCB[C_FNC] = FC_XCP;
LLCRS$( .SC_CCB);
end
end;
PDB[TIMERinact] = .DB[NSPact_tim];
IF not ((.DB[MSGFLG] eql FLG_DAT_ACK) or
(.DB[MSGFLG] eql FLG_OTH_ACK))
Then
begin
MAP$( .CCB[C_BIAS]);
DB[SEGNUM] = GET2BYTES( PTR);
MAP$( .DB[BIASports]);
end;
Selectone .DB[MSGFLG] of
Set
[FLG_INT]: INT_RCV( .CCB, .PDB);
[FLG_REQ]: LS_RCV( .CCB, .PDB);
[FLG_DAT_ACK]: ACK_RCV( .CCB, .PDB);
[FLG_OTH_ACK]: ACK_OTH_RCV( .CCB, .PDB);
[FLG_EOM]: D_RCV( .CCB, .PDB);
[FLG_BOM]: D_RCV( .CCB, .PDB);
[FLG_BEOM]: D_RCV( .CCB, .PDB);
[FLG_NBEOM]: D_RCV( .CCB, .PDB);
Tes;
end
Else
begin
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB)
end;
CALL$L(SND_MSG, .PDB)
end;
global routine ONCE_A_SECOND : CALL$ novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine is called every second to attempt to clear up any
! resource deadlocks that may have occured.
!
! FORMAL PARAMETERS:
! None
!
! IMPLICIT INPUTS:
! DB = NSP data base address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
!********************************************************************
! Now check thru the Session Control ports for any stalled transmits
!********************************************************************
begin
local PORT: ref blockvector[0, PDB_size] field(PORT_fields),
CCB: ref block field(C_fields);
port = .DB[ADDRports];
MAP$( .DB[BIASports]);
Incr J from 0 to (.DB[NSPtotal] - 1) do
begin
bind PDB = PORT[.DB[NSPnxt_port],0,0,0,0]: block field(PORT_fields);
If .DB[NSPnxt_port] + 1 lss .DB[NSPtotal]
Then
DB[NSPnxt_port] = .DB[NSPnxt_port] + 1
Else
DB[NSPnxt_port] = 0;
If .PDB[FLAGinuse]
Then
begin
If .PDB[BUFFctl] neq 0
Then
CALL$E(CTL_RECVD, .DB[NSPns2_pix], PDB);
If .PDB[RCVmsg_queue] neq 0
Then
begin
If CCB_GET( CCB, PDB)
Then
begin
CMQRM$( PDB[RCVmsg_queue], CCB[C_STK]);
DATA_RECVD( .CCB, PDB);
end;
end;
If .PDB[OTHres]
Then
begin
If .PDB[PORTstate] eql N$SRUN
Then
begin
PDB[OTHres] = false;
CALL$L( TRICKLE, PDB);
end
Else
begin
If CCB_HDR_GET( 0, CCB, PDB)
Then
begin
PDB[OTHres] = false;
If not CMQRM$( PDB[MSG_queue], CCB[C_STK])
Then
SIGNAL_STOP( NSP$_ICE);
Selectone .PDB[PORTstate] of
Set
[N$SCI]:
CALL$E(CI_BLD, .DB[NSPns2_pix], .CCB, PDB);
[N$SCC]:
CALL$E(CC_BLD, .DB[NSPns2_pix], .CCB, PDB);
[N$SDI, N$SDR]:
CALL$E(DI_BLD, .DB[NSPns2_pix], .CCB, PDB);
Tes;
end;
end;
end;
If .PDB[DATres]
Then
begin
PDB[DATres] = false;
CALL$L(SND_ONE_DATA, PDB);
end;
If .PDB[FLAGsnd_dc] and
CCB_HDR_GET( 0, CCB, PDB)
Then
CALL$E(DC_BLD, .DB[NSPns2_pix], .CCB, PDB);
end;
If (.PDB[BUFFrcv_int] neq 0) and
CCB_GET( CCB, PDB)
Then
begin
CCB[C_STK] = .PDB[BUFFrcv_int];
PDB[BUFFrcv_int] = 0;
INT_RECVD(.CCB, PDB);
end;
end;
!********************************************************************
! Now check thru the reserved ports for any stalled transmits
!********************************************************************
begin
local PORT: ref blockvector[0, RDB_size] field(PORT_fields);
MAP$( .DB[BIASresv]);
port = .DB[ADDRresv];
Incr j from 0 to (.DB[NSPt_rsv] -1 ) do
begin
bind RDB = PORT[.j,0,0,0,0]: block field(PORT_fields);
If .RDB[MSGtyp] neq MSG_NONE
Then
begin
If CCB_HDR_GET( 0, ccb, -1)
Then
begin
If .RDB[MSGtyp] eql N_LNK
Then
CALL$E(NL_BLD, .DB[NSPns2_pix], .CCB, RDB)
Else
CALL$E(NR_BLD, .DB[NSPns2_pix], .CCB, RDB);
RDB[MSGtyp] = MSG_NONE;
exitloop
end
Else
exitloop;
end;
end;
end;
end;
routine OTHACK_BLD ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine formats an NSP Other Data Acknowledgement message
! and queues it to Transport.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
local
PTR;
PTR = .CCB[C_ADDR];
ch$wchar_a( FLG_OTH_ACK, PTR);
ch$wchar_a( .PDB[L_rem_addr], PTR);
ch$wchar_a( .PDB[H_rem_addr], PTR);
ch$wchar_a( .PDB[PID], PTR);
ch$wchar_a( .PDB[ADDran], PTR);
PUT2BYTES( (.PDB[ACKoth_xmt] and %o'7777') + Q_ACK^12 + true^15, PTR);
CCB[C_CNT] = ch$diff(.PTR, .CCB[C_ADDR]);
PDB[FLAGoth_ack] = false;
XPT_XMIT( .CCB, .PDB)
end;
routine PROC_DATA_ACK ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes the NUMBER and QUAL fields of a received
! Data Acknowledgement message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
local
WK_CCB: ref block field(C_fields),
NDB : ref block field(NODE_fields),
temp;
MAP$( .DB[BIASports]);
NDB = .PDB[NODElnk];
If (CMP_LSS( .PDB[ACKrcv_dat], .DB[NUMBER]) and
(CMP_LEQ( .DB[NUMBER], .PDB[NUMsent])) and .DB[QUAL] eql Q_ACK) or
(CMP_LEQ( .PDB[ACKrcv_dat], .DB[NUMBER]) and
(CMP_LEQ( .DB[NUMBER], .PDB[NUMsent])) and .DB[QUAL] eql Q_NAK)
Then
begin
PDB[CONFIDENCE] = true;
PDB[COUNTdat_retrans] = 0;
If .PDB[FLOWtyp_rem] eql FLOWseg
Then
PDB[FLOWdat_rem] = .PDB[FLOWdat_rem] - (( .DB[NUMBER] - .PDB[ACKrcv_dat]) and %o'7777');
PDB[ACKrcv_dat] = .DB[NUMBER];
temp = .PDB[ACKhead];
While (CMQPT$( temp, WK_CCB)) do
begin
If CMP_LEQ( .WK_CCB[C_STS], .PDB[ACKrcv_dat])
Then
begin
WK_CCB = .PDB[ACK_queue];
PDB[ACK_queue] = .WK_CCB[C_LNK];
If (.WK_CCB[C_PRM3] and N$FCMP) neq 0
Then
begin
bind SC_CCB = .WK_CCB[C_STK]: block field(C_fields);
SC_CCB[C_FNC] = FC_XCP;
SC_CCB[C_STS] = N$SSUC;
LLCRS$( SC_CCB);
If .PDB[FLOWtyp_rem] eql FLOWmsg
Then
PDB[FLOWdat_rem] = .PDB[FLOWdat_rem] - 1;
end;
CCB_RETRN( .WK_CCB, .PDB);
end
Else
exitloop;
end;
PDB[TIMERdat] = 0;
If .PDB[ACKrcv_dat] eql .PDB[NUMsent]
Then
PDB[FLAGseg] = true;
If (CMP_LSS( .PDB[ACKrcv_dat], .PDB[NUMsent]) and .DB[QUAL] eql Q_ACK)
Then
begin
MAP$( .DB[BIASnodes]);
temp = .NDB[NDdelay];
MAP$( .DB[BIASports]);
PDB[TIMERdat] = .temp * .DB[NSPdelay]
end;
If (CMP_LEQ( .PDB[DELAYmsg_num], .PDB[ACKrcv_dat]))
and .PDB[DELAYstr_tim] neq 0
Then
UPDATE_DELAY( .PDB);
If .PDB[PORTstate] eql N$SDI and
(CMP_EQL( .PDB[NUMhigh], .PDB[ACKrcv_dat])) and
.PDB[BUFFsync_dsc] neq 0
Then
begin
If CCB_HDR_GET( 0, WK_CCB, .PDB)
Then
begin
WK_CCB[C_STK] = .PDB[BUFFsync_dsc];
CALL$E(DI_BLD, .DB[NSPns2_pix], .WK_CCB, .PDB)
end
Else
begin
CMQIN$( PDB[MSG_queue], .PDB[BUFFsync_dsc]);
PDB[OTHres] = true
end;
PDB[BUFFsync_dsc] = 0;
end;
end
end;
routine PROC_OTH_ACK ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes the NUMBER and QUAL fields of a received
! Other Data Acknowledgement message.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
local
temp: ref block field(C_fields);
MAP$( .DB[BIASports]);
If .PDB[OTHstate] neq OTHready and
((.DB[NUMBER] eql ((.PDB[NUMoth] -1) and %o'7777') and .DB[QUAL] eql Q_NAK) or
(.DB[NUMBER] eql .PDB[NUMoth] and .DB[QUAL] eql Q_ACK))
Then
begin
PDB[CONFIDENCE] = true;
PDB[COUNToth_retrans] = 0;
PDB[TIMERoth] = 0;
If .DB[QUAL] eql Q_ACK
Then
begin
PDB[OTHstate] = OTHready;
PDB[NUMoth] = .PDB[NUMoth] + 1;
If CMQRM$( PDB[OTHACK_queue], temp)
Then
begin
If .temp[C_MOD] eql N_XBUF
Then
begin
temp[C_STS] = N$SSUC;
CMQIN$( PDB[BUFF_queue], .temp);
end
Else
begin
temp[C_FNC] = FC_XCP;
temp[C_STS] = N$SSUC;
LLCRS$( .temp);
end
end;
If .PDB[OTHtyp] eql OTHinterrupt
Then
PDB[FLOWint_rem] = .PDB[FLOWint_rem] - 1;
end
end
end;
routine REAS_DATA ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine is the reassembly process.
!
! FORMAL PARAMETERS:
! CCB = CCB address
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
bind BUFF_CCB = .PDB[BUFF_queue]: block field(C_fields);
local
TO_ADDR,
TEMP,
size,
XFRCNT,
NDB : ref block field(NODE_fields),
GOT_CCB: ref block field(C_fields);
NDB = .PDB[NODElnk];
If not .DB[Q_FLG]
Then
size = 7
Else
size = 9;
MAP$( .DB[BIASnodes]);
DADD( NDB[NDb_rcv], .CCB[C_CNT] - .size);
MAP$( .DB[BIASports]);
If .PDB[FLOWloc_typ] eql FLOWmsg
Then
begin
If .PDB[BUFFhead] eql 0
Then
begin
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB);
return
end
Else
begin
If .PDB[REAS_PTR] neq 0 and
(.DB[MSGFLG] and NSPbom) neq 0
Then
begin
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB);
return
end;
XFRCNT =
begin
If (.PDB[REAS_PTR] + .CCB[C_CNT] - .SIZE) leq .BUFF_CCB[C_CNT]
Then
.CCB[C_CNT] - .SIZE
Else
begin
BUFF_CCB[C_STS] = N$ELST;
.BUFF_CCB[C_CNT] - .PDB[REAS_PTR]
end
end;
If .XFRCNT neq 0
Then
begin
TEMP = ch$plus( .CCB[C_ADDR], .SIZE);
TO_ADDR = ch$plus( .BUFF_CCB[C_ADDR], .PDB[REAS_PTR]);
MAP$( .CCB[C_BIAS]);
MTBF$S( .XFRCNT, .temp, .BUFF_CCB[C_BIAS], .TO_ADDR);
MAP$( .DB[BIASports]);
end;
PDB[REAS_PTR] = .PDB[REAS_PTR] + .XFRCNT;
IF (.DB[MSGFLG] and NSPeom) neq 0
Then
begin
BUFF_CCB[C_CNT] = .PDB[REAS_ptr];
BUFF_CCB[C_FNC] = FC_XCP;
PDB[REAS_PTR] = 0;
LLCRS$( BUFF_CCB);
CMQRM$( PDB[BUFF_queue], temp)
end;
CCB[C_FNC] = FC_RCE;
LLCRS$( .CCB);
end
end
Else
begin
If .PDB[RCVmsg_queue] eql 0 and
CCB_GET( GOT_CCB, .PDB)
Then
begin
GOT_CCB[C_STK] = .CCB;
DATA_RECVD( .GOT_CCB, .PDB);
end
Else
CMQIN$( PDB[RCVmsg_queue], .CCB);
end;
PDB[FLAGdat_ack] = true;
PDB[ACKdat_xmt] = (.PDB[ACKdat_xmt] + 1 and %o'7777');
end;
routine SEG_BLD ( CCB, PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine formats an NSP Data Segment message and queues it to
! Transport.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map PDB: ref block field(PORT_fields);
bind CHN_CCB = .CCB[C_CHN]: block field(C_fields);
local
xtemp,
PTR,
FLG;
If .PDB[FLAGseg] eql false
Then
xtemp = .CHN_CCB[C_STS]
Else
xtemp = .PDB[NUMdat];
xtemp = (.xtemp and %o'7777');
PTR = .CCB[C_ADDR];
FLG = 0;
If (.CHN_CCB[C_PRM3] and N$FBOM) neq 0
Then
FLG = FLG_BOM;
If (.CHN_CCB[C_PRM3] and N$FEOM) neq 0
Then
FLG = .FLG or FLG_EOM;
ch$wchar_a( .FLG, PTR);
ch$wchar_a( .PDB[L_rem_addr], PTR);
ch$wchar_a( .PDB[H_rem_addr], PTR);
ch$wchar_a( .PDB[PID], PTR);
ch$wchar_a( .PDB[ADDran], PTR);
PUT2BYTES( .PDB[ACKdat_xmt] + Q_ACK^12 + true^15, PTR);
PUT2BYTES( .xtemp, PTR);
CCB[C_CNT] = ch$diff(.PTR, .CCB[C_ADDR]);
CCB[C_STK] = .CCB[C_CHN];
CHN_CCB[C_STS] = .xtemp;
CHN_CCB[C_MOD] = N_XDAT;
PDB[FLAGdat_ack] = false;
If .PDB[DELAYstr_tim] eql 0
Then
begin
PDB[DELAYstr_tim] = 1;
PDB[DELAYmsg_num] = .xtemp;
end;
If .PDB[FLAGseg] eql true
Then
PDB[NUMdat] = .PDB[NUMdat] + 1
Else
begin
if CMP_EQL( .xtemp, (.PDB[NUMdat] -1))
then
PDB[FLAGseg] = true
end;
XPT_XMIT( .CCB, .PDB)
end;
routine SND_DATA ( PDB) : = !
!++
! functional description:
! This routine performs the actual segmentation of Session Control
! transmit buffers into NSP segments. Control is passed to to the
! data segment format routine.
!
! formal parameters:
! PDB = Port Data Base Address
!
! implicit inputs:
! DB = NSP Data Base Address
!
! implicit outputs:
! none
!
! routine value:
! completion codes:
! none
!
! side effects:
! none
!--
begin
map PDB: ref block field(PORT_fields);
bind CHN_CCB = .PDB[MSG_chain]: block field(C_fields);
bind MSG_CCB = .PDB[MSG_queue]: block field(C_fields);
local
SEG_CCB: ref block field(C_fields),
NDB : ref block field(NODE_fields),
CCB: ref block field(C_fields);
NDB = .PDB[NODElnk];
If .PDB[FLAGseg] eql false
Then
begin
If CCB_HDR_GET( .PDB[ACK_queue], CCB, .PDB)
Then
begin
CCB[C_CHN] = .PDB[ACK_queue];
PDB[ACK_queue] = .(.CCB[C_CHN]);
MAP$( .DB[BIASnodes]);
NDB[NDtimeout] = .NDB[NDtimeout] + 1;
MAP$( .DB[BIASports]);
end
Else
begin
PDB[DATres] = true;
return false
end;
end
Else
begin
If CCB_GET( SEG_CCB, .PDB)
Then
begin
If not CCB_HDR_GET( 0, CCB, .PDB)
Then
begin
CCB_RETRN( .SEG_CCB, .PDB);
PDB[DATres] = true;
return false;
end
Else
begin
CCB[C_CHN] = .SEG_CCB;
SEG_CCB[C_STK] = .PDB[MSG_queue];
If .CHN_CCB[C_CNT] - .MSG_CCB[C_STS] leq .PDB[SIZEseg]
Then
begin
SEG_CCB[C_CNT] = .CHN_CCB[C_CNT] - .MSG_CCB[C_STS];
SEG_CCB[C_ADDR] = ch$plus( .CHN_CCB[C_ADDR], .MSG_CCB[C_STS]);
SEG_CCB[C_BIAS] = .CHN_CCB[C_BIAS];
If .CHN_CCB[C_CHN] neq 0
Then
begin
MSG_CCB[C_STS] = 0;
PDB[MSG_chain] = .CHN_CCB[C_CHN]
end
Else
begin
If .MSG_CCB[C_PRM1] eql N$FEOM
Then
SEG_CCB[C_PRM3] = N$FEOM;
SEG_CCB[C_PRM3] = .SEG_CCB[C_PRM3] or N$FCMP;
CMQRM$( PDB[MSG_queue], SEG_CCB[C_STK]);
PDB[MSG_chain] = .PDB[MSGhead]
end
end
Else
begin
SEG_CCB[C_ADDR] = ch$plus( .CHN_CCB[C_ADDR], .MSG_CCB[C_STS]);
SEG_CCB[C_BIAS] = .CHN_CCB[C_BIAS];
SEG_CCB[C_CNT] = .PDB[SIZEseg];
MSG_CCB[C_STS] = .MSG_CCB[C_STS] + .PDB[SIZEseg];
end;
IF .PDB[FLAGnew_msg]
Then
begin
SEG_CCB[C_PRM3] = (.SEG_CCB[C_PRM3] or N$FBOM);
PDB[FLAGnew_msg] = false
end;
If .SEG_CCB[C_PRM3] and N$FEOM
Then
PDB[FLAGnew_msg] = true;
MAP$( .DB[BIASnodes]);
DADD( NDB[NDb_xmt], .SEG_CCB[C_CNT]);
MAP$( .DB[BIASports])
end
end
Else
begin
PDB[DATres] = true;
return false
end
end;
SEG_BLD( .CCB, .PDB);
return true;
end;
global routine SND_MSG ( PDB) : CALL$ novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine prioritises the message transmission process.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
local
sts;
Do ( STS = CALL$L( TRICKLE, .PDB))
While .STS eql true;
end;
global routine SND_INTERRUPT ( PDB) : call$ = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine dequeues an INTERRUPT-XMT CCB and passes to control
! to the Interrupt Format routine.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
local
NDB : ref block field(NODE_fields),
CCB: ref block field(C_fields);
NDB = .PDB[NODElnk];
If .PDB[OTHstate] eql OTHtimeout
Then
begin
If CCB_HDR_GET( 0, CCB, .PDB)
Then
begin
CMQRM$( PDB[OTHack_queue], CCB[C_STK]);
MAP$( .DB[BIASnodes]);
NDB[NDtimeout] = .NDB[NDtimeout] + 1;
MAP$( .DB[BIASports]);
Selectone .PDB[OTHtyp] of
Set
[OTHirequest]:
IRQ_BLD( .CCB, .PDB);
[OTHdrequest]:
DRQ_BLD( .CCB, .PDB);
[OTHinterrupt]:
INT_BLD( .CCB, .PDB);
Tes;
return true;
end
Else
begin
PDB[OTHres] = true;
return false
end
end;
If .PDB[OTHstate] eql OTHready
Then
begin
If CCB_HDR_GET( 0, CCB, .PDB)
Then
begin
CMQRM$( PDB[INT_queue], CCB[C_STK]);
INT_BLD( .CCB, .PDB);
return true;
end
Else
begin
PDB[OTHres] = true;
return false
end
end;
return false
end;
routine SND_INTR_REQ ( PDB) : = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine dequeues an INTERRUPT-REQUEST CCB and passes control
! to the Interrupt Request Format routine.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
local
CCB: ref block field(C_fields);
If CCB_HDR_GET( 0, CCB, .PDB)
Then
begin
CMQRM$( PDB[INTR_queue], CCB[C_STK]);
PDB[COUNTloc_int] = .PDB[COUNTloc_int] + 1;
IRQ_BLD( .CCB, .PDB);
return true;
end
Else
PDB[OTHres] = true;
return false
end;
global routine SND_ONE_DATA ( PDB) : CALL$ novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine sends one data segment.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
If DATA_TO_SND( .PDB)
Then
SND_DATA( .PDB);
end;
routine SND_REQ_DATA ( PDB) : = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine dequeues a DATA-REQUEST CCB and passes control to the
! Data Request Format routine.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
local
CCB: ref block field(C_fields);
If CCB_HDR_GET( 0, CCB, .PDB)
Then
begin
CMQRM$( PDB[DATR_queue], CCB[C_STK]);
DRQ_BLD( .CCB, .PDB);
return true;
end
Else
PDB[OTHres] = true;
return false
end;
routine UPDATE_DELAY ( PDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine calculates the round trip delay for NSp messages.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
local
NDB : ref block field(NODE_fields),
DELAYtime;
NDB = .PDB[NODElnk];
If .PDB[DELAYstr_tim] neq 0
Then
begin
DELAYtime = .PDB[DELAYstr_tim];
If .DELAYtime gtr 1
Then
DELAYtime = .DELAYtime - 1;
MAP$( .DB[BIASnodes]);
If .NDB[NDdelay] eql 0
Then
NDB[NDdelay] = .DELAYtime
Else
begin
DELAYtime = .DELAYtime - .NDB[NDdelay];
NDB[NDdelay] = .NDB[NDdelay] + (.DELAYtime / (.DB[NSPweight] + 1))
end;
MAP$( .DB[BIASports]);
PDB[DELAYstr_tim] = 0;
end
end;
global routine TRICKLE ( PDB) : CALL$ = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine prioritises the message transmission process.
!
! FORMAL PARAMETERS:
! PDB = Port Data Base Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map PDB: ref block field(PORT_fields);
If INTERRUPT_TO_SND( .PDB)
Then
begin
If CALL$L(SND_INTERRUPT, .PDB)
Then
return true
Else
return false
end;
If INTR_REQ_TO_SND( .PDB)
Then
begin
If SND_INTR_REQ( .PDB)
Then
return true
Else
return false
end;
If D_REQ_TO_SND( .PDB)
Then
begin
If SND_REQ_DATA( .PDB)
Then
return true
Else
return false
end;
If .PDB[FLAGoth_ack]
Then
begin
If ACK_OTH_SND( .PDB)
Then
return true
Else
return false
end;
If DATA_TO_SND( .PDB)
Then
begin
If SND_DATA( .PDB)
Then
return true
Else
return false
end;
If .PDB[FLAGdat_ack] and
((.PDB[PORTstate] eql N$SRUN) or
((.PDB[PORTstate] eql N$SDI) and
(CMP_NEQ(.PDB[NUMhigh], .PDB[ACKrcv_dat]))))
Then
begin
If ACK_DATA_SND( .PDB)
Then
return true
Else
return false
end;
false
end;
routine XPT_XMIT ( CCB, XXDB) : novalue = !
!++
! FUNCTIONAL DESCRIPTION:
! This routine queues CCB's to Transport for transmission.
!
! FORMAL PARAMETERS:
! XXDB = Reserved/Port Data Base Address
! CCB = CCB Address
!
! IMPLICIT INPUTS:
! DB = NSP Data Base Address
!
! IMPLICIT OUTPUTS:
! None
!
! ROUTINE VALUE:
! COMPLETION CODES:
! None
!
! SIDE EFFECTS:
! None
!--
begin
map CCB: ref block field(C_fields);
map XXDB: ref block field(PORT_fields);
local
NDB: ref block field(NODE_fields),
temp;
NDB = .XXDB[NODElnk];
If .XXDB[PORTstate] lss 0
Then
CCB[C_PRM4] = -1
Else
CCB[C_PRM4] = .XXDB;
CCB[C_FNC] = FC_XME;
CCB[C_MOD] = FM_DAT;
CCB[C_LIX] = .XXDB[CHANNEL];
CCB[C_PIX] = .DB[NSPxpt_pix];
CCB[C_STS] = 0;
CCB[C_PRM1] = .DB[NSPself];
CCB[C_PRM2] = .XXDB[NODErem];
If .NDB neq 0
Then
begin
SMAP$( temp);
MAP$( .DB[BIASnodes]);
DADD( NDB[NDm_xmt], 1);
MAP$( .temp);
end;
LLCRS$( .CCB)
end;
end
eludom