Google
 

Trailing-Edge - PDP-10 Archives - BB-R595B-SM_11-9-85 - mcb/xpt/xpesel.bli
There is 1 other file named xpesel.bli in the archive. Click here to see a list.
module XPESEL	(
		IDENT = 'X01090'
		) =
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:	Transport
!
! ABSTRACT:
!
!	Transport Select extension module: Contains INTERCEPT, which
!	maintains the Link Translate Table.
!	This routine was originally part of the XPTSEL module.
!
! ENVIRONMENT:	MCB
!
! AUTHOR: L. Webber , CREATION DATE:  5-Mar-81
!
! MODIFIED BY:
!
!	L. Webber, 5-Mar-81 VERSION 1.00
!
! 1.01	L. Webber, 19-Mar-81
!	Added $XPECLN to explicitly clean out an LTT entry.
!	Broke SCAN out as a top-level routine so that both other routines
!	could call it.
!
! 1.02	L. Webber, 14-Apr-81
!	Fix SCAN so that if it is given a 0 link address, any table entry
!	containing the specified node address is a hit.  This allows
!	$XPECLN to clear out all links for a specified node.
!
! 1.03	L. Webber, 5-May-81
!	Change INTERCEPT so that when a duplicate CI is found, the matching
!	LTT entry is stolen for use by the new link.  (Note: this will do
!	horrible things if a real duplicate CI is encountered, i.e., one
!	where the duplicated link does not correspond to a defunct logical
!	link.)
!
! 1.04	L. Webber, 25-Jun-81
!	Add SEND_DC, a routine to format and send a DC message over a line.
!	Modify $XPECLN to send a DC if it is killing an ILT entry whose
!	"other end" (the one does not lead to the node responsible for the
!	table entry being killed) is a Phase II or TOPS20 node.
!
! 1.05	L. Webber, 21-Dec-81
!	Add CLN_RETRY to clean a specified circuit's CCBs out of the retry
!	queue.  This is called when the circuit goes down.
!
! 1.06	L. Webber, 3-Feb-81
!	Fix CLN_RETRY to tell _TERMINATE not to decrement INPUTcount when
!	returning a buffer; buffers on the retry queue aren't counted in
!	the first place.
!
! 1.07	L. Webber, 8-Feb-81
!	Fix 1.06 not to modify the buffer's CCB when returning it.
!
! 1.08	A. Peckham,20-Apr-82
!	Move $XPECLN global to low psect.
!       Eliminate GETLINE and GETNODE.
!
! 1.09	A. Peckham,2-Jul-82
!	Rename INTERCEPT to INTPH2.
!
!--
!
! INCLUDE FILES:
!

require 'XPTMAC';

!
! TABLE OF CONTENTS
!

forward routine
	SCAN,
	INTPH2: CALL$,
	CLEAN_LINK: CALL$ novalue,
	SEND_DC: CALL$ novalue,
	CLN_RETRY: novalue;

!
! MACROS:
!

!
! EQUATED SYMBOLS:
!

!
! OWN STORAGE:
!

literal JUMP_TO = %o'137';

psect
    global = XPEJMP (nowrite, execute);

global
    $XPECLN : vector [2] initial (JUMP_TO, CLEAN_LINK);

undeclare JUMP_TO;

!
! EXTERNAL REFERENCES:
!

external routine
    _TERMINATE: CALL$ novalue;
routine SCAN (TABLE,HALF,NODE,LINK) =

!++
! FUNCTIONAL DESCRIPTION:
!
! Scans the Link Translate Table for an entry matching a specified one.
!
! FORMAL PARAMETERS
!
!	TABLE	Address of a BLISS value to be set to the address of
!		the LTT entry found (if any).
!
!	HALF	Address of a BLISS value to be set to the "half" of
!		the table entry containing specified node/link pair:
!		0 for first half, 1 for second.
!
!	NODE	Node address of node/link pair to find.
!
!	LINK	Link address of node/link pair to find, or 0 for
!		"any link for the node"
!
! IMPLICIT INPUTS
!
!	Ph2link_table, Ph2link_allocation
!
! ROUTINE VALUE: "Success" or "failure"
! COMPLETION CODES:
!
!	-1	Failure: LTT and HALF contents are undefined.
!	other	Index (from 1 to the number of entries) of the LTT
!		entry of the first match found.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

begin

require 'XPTSYM';
bind LTT = .TABLE: ref block field(LTTfields);

NODE = .NODE<0,16,0>;			! Mask node address and
LINK = .LINK<0,16,0>;			!  link address to 16 bits
LTT = .Ph2link_table;                   ! Address the first entry

incr I from 1 to .Ph2link_allocated do  ! Scan the LTT entries
    begin
    .HALF = 0;				! Try the first pair first
    if ((.NODE eql .LTT[LTTnode1])	! Compare the pair in
    and ((.LINK eql 0) or		!  the entry with
	(.LINK eql .LTT[LTTlink1])))	!  the specified pair
	then exitloop(.I);		! HIT
    .HALF = ..HALF + 1;			! Now try the second pair in the entry
    if ((.NODE eql .LTT[LTTnode2])	! Compare the pair in
    and ((.LINK eql 0) or		!  the entry with
    (.LINK eql .LTT[LTTlink2])))	!  the specified pair
	then exitloop(.I)		! HIT
    else LTT = LTT[LTTlen];		! Go on to the next LTT entry
    end
end;				!End of SCAN
global
routine INTPH2 (CCB,TYPE,DESTNODE,SRCNODE): CALL$ =

!++
! FUNCTIONAL DESCRIPTION:
!
! This routine handles Phase II packets without routing headers.
! It maintains the Link Translate Table in the Transport Data Base
! and uses it to map link addresses into a destination node address.
!
! The routine is called in two contexts: TYPE 0, when a message is
! received without a routing header and the link addresses must be
! mapped into a destination; and TYPE 1, when a Phase II message is
! received destined for another Phase II node and an LTT entry must
! be created and maintained to allow TYPE 0 calls for other messages
! on the same link.
!
! FORMAL PARAMETERS
!
!	CCB - the pass-through CCB for the packet to be processed
!	TYPE - the message type: 0 = packet has no header
!				 1 = packet has a header or is a CI
!	DESTNODE - the destination node address for the packet.  This
!		   is an output for TYPE 0 and an input for TYPE 1.
!	SRCNODE - the source node address for the packet.  This is an
!		  output for TYPE 0 and an input for TYPE 1.
!
! IMPLICIT INPUTS
!
!	Nty, Nid, Nnm, Tid
!
! ROUTINE VALUE: "Success" or "failure" (TYPE 1 always returns "success")
! COMPLETION CODES:
!
!	CS_SUC		Success; for TYPE 0, the destination or source node
!			addresses are returned.
!     - $XPT$E_FMT	Failure; packet header format error. This may mean
!			that the packet cannot be associated with an active
!			LTT entry.
!     - $XPT$E_RNG	Failure; node number out of range.
!
! SIDE EFFECTS:
!
!	Maintains and modifies the Link Translate Table.
!
!--

begin

local LINEb;
require 'XPTSYM';
require 'MCBCOM';
pointer PTR;
local ILINE,MSGFLG,SLINK,DLINK,DLINKX,RET,HALF,PTRA,LTTx;
local LTT: ref block field(LTTfields);

MAPBUF(.CCB,PTRA,RET);			!Map to and address message buffer
PTR = .PTRA;

		!******************************!
		!  TYPE 0 - no routing header  !
		!******************************!

if .TYPE eql 0 then begin

!
!  Determine the source node address
!

ILINE = .CCB[C_LIN];			!Determine input line
LINEb = $XPT_GET_LINE_DB(.ILINE);	!  and address its data base entry
if ((.Nty neq PhTwo)			!If the line doesn't have
and (.Nty neq TOPS20))			!  a Phase II adjacent node
then SIGNAL_STOP (CE_ERR)		!  then return "failure"
else .SRCNODE = .Nid;			!Otherwise, pick up source node address

!
!  Parse the NSP header for the message
!

MSGFLG = getb(PTR);			!NSP message flags
DLINK = getw(PTR);			!Destination link address
SLINK = getw(PTR);			!Source link address

!
!  Scan the LTT for a match with the source node/link pair
!

if SCAN (LTT,HALF,..SRCNODE,.SLINK)

!
!  No match - only valid for CI and CC
!

eql -1 then
    if ((.MSGFLG eql CI_MSGflgs)	!Any CI or CC message
    or (.MSGFLG eql CC_MSGflgs))	!with no routing header
    then begin				!must be assumed to be for self
	.DESTNODE = .Tid;		!    Indicate that message is for Self
	INTPH2(.CCB,1,.DESTNODE,	!    Re-call INTPH2
	    .SRCNODE);			!      for Type 1 processing
	return (CS_SUC)			!    Return "success"
	end
    else return (-$XPT$E_FMT)		!Not a CI or CC message - invalid

!
!  Match - pick up the destination node/link pair from the LTT
!

else begin
    if .HALF eql 0 then LTT = LTT[LTTnode2]; !Choose which half to use
    .DESTNODE = .LTT[LTTnode];
    DLINKX = .LTT[LTTlink];

!
!  Invalid destination pair - return error
!

    if ..DESTNODE gtru NN then
	return (-$XPT$E_RNG)
    else if .DLINK neq .DLINKX then
	return (-$XPT$E_FMT)
!
!  Destination pair is OK - return "success"
!	Also, delete the table entry if the message is a DC
!

    else begin
	if .MSGFLG eql DC_MSGflgs then INTPH2(.CCB,1,.DESTNODE,.SRCNODE);
	return (CS_SUC)
	end
    end
end


		!***********************************!
		!  TYPE 1 - routing header present  !
		!***********************************!


else begin

!
!  Skip over the routing header, if any
!

MSGFLG = getb(PTR);
if biton(.MSGFLG,2) then begin		!Routing header present -
    RET = getb(PTR);			!Pick up dest. node name length
    PTR = ch$plus(.PTR,.RET);		!Skip over name
    RET = getb(PTR);			!Pick up source node name length
    PTR = ch$plus(.PTR,.RET);		!Skip over name
    MSGFLG = getb(PTR);			!Pick up NSP message flags
    end;

!
!  Pick up source and destination link addresses
!

DLINK = getw(PTR);
SLINK = getw(PTR);

!
!  Message not CI, CC, DI or DC - ignore it
!

select .MSGFLG of
set

!
!  CI message
!

[CI_MSGflgs]:		begin
    if SCAN(LTT,HALF,..SRCNODE,.SLINK)	!Scan for a match on the source pair
    neq -1 then begin			 !Found: cannibalize the entry -
	BPT(XPT$_ICPT0,..SRCNODE,.SLINK, !  flag the "duplicate
	    ..DESTNODE,.DLINK);          !    CI" event
	if .HALF eql 0 then		 !  determine which half of
	    LTT = LTT[LTTnode2];	 !    the entry the match was on
	LTT[LTTnode] = ..DESTNODE;	 !  fill in the
	LTT[LTTlink] = 0;		 !    other half
	end
    else				 !Not found -
	if SCAN(LTT,HALF,-1,-1)		 !  scan for a free entry
	    eql -1 then	BPT(XPT$_NFI)	 !  none found - ignore message
	else begin
	    LTT[LTTnode1] = ..SRCNODE;	 !  fill in pair 1 in the entry
	    LTT[LTTlink1] = .SLINK;	 !    with the source pair from the msg
	    LTT[LTTnode2] = ..DESTNODE;	 !  fill in node slot 2 with dest. node
	    LTT[LTTlink2] = 0;		 !    and clear link slot 2 for CC
	    end
		end;

!
!  CC, DI or DC message - scan LTT for match on destination node/link pair
!

[CC_MSGflgs,DI_MSGflgs,DC_MSGflgs]:	begin
    RET = SCAN (LTT,HALF,..DESTNODE,.DLINK);
    LTTx = .LTT;
    if .RET eql -1 then begin		!No match - BUG
	if .MSGFLG neq DC_MSGflgs then
	    BPT(XPT$_ICPT1,.MSGFLG,..SRCNODE,.SLINK,..DESTNODE,.DLINK);
	return(CS_SUC)
	end
    else if .HALF eql 0 then LTT = LTT[LTTnode2];	!Match - choose half
				end;

!
!  CC or DI message - fill in second half of LTT entry
!

[CC_MSGflgs,DI_MSGflgs]: begin
    if ..SRCNODE neq .LTT[LTTnode] then		!No source node match - BUG
	BPT(XPT$_ICPT2,.MSGFLG,..SRCNODE,.SLINK,
	    ..DESTNODE,.DLINK)
    else LTT[LTTlink] = .SLINK;			!Fill in other link entry
			 end;

!
!  DC message - delete matched entry from LTT
!

[DC_MSGflgs]:		begin
    if ((..SRCNODE eql .LTT[LTTnode])		! If the source node/link
    and (.SLINK eql .LTT[LTTlink]))		!   pair matches the
    then begin					!   LLT entry,
	LTT = .LTTx;				!   clear out
	incr I from 0 to 3 do			!   the entry
	    VECTOR[.LTT,.I] = -1;		!
	end;
!	then BPT(XPT$_ICPT2,.MSGFLG,..SRCNODE,		!* Old "unmatch" code:
!	    .SLINK,..DESTNODE,.DLINK);          	!* eliminate eventually
			end;
tes;

return (CS_SUC)		!Always return success; caller never looks
end;
end;				!End of INTPH2
global
routine CLEAN_LINK (NODE,LINK): CALL$ novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
! Cleans out the Link Translate Table.  All entries containing the
! node/link pair specified are deleted from the table.  If the link
! address specified is 0, all entries containing the specified node
! address are deleted.
!
! The purpose of this routine is to allow a link which has been closed
! due to timeout or other abnormal conditions, and which has not gone
! through the standard DI/DC interchange which would clean the link out
! of the Link Translate Table, to be cleaned out explicitly by NSP (for
! a local link) or the Decision module (for a route-through link).
!
! FORMAL PARAMETERS
!
!	NODE	Node address of link(s) to be deleted.  This will be the
!		local node address (if NSP called), or the address of a
!		node that has become unreachable.
!
!	LINK	Link address of link(s) to be deleted, or 0 for "all links
!		for the node".
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	Any messages which come into Transport for the link will cause
!	debugging SIGNALS (if present) to be invoked by INTPH2.
!
!--

begin

local LINEb,NODEb;
require 'XPTSYM';
local HALF,DN,DL,SL,DN_L,DN_P,SN_L,SN_P;
local LTT: ref block field(LTTfields);
local CCB: ref block field(C_XPT_fields);

while (SCAN(LTT,HALF,.NODE,.LINK) neq -1)	! Scan for a matching entry
do begin
    if .HALF eql 0 then begin
	DN = .LTT[LTTnode2];
	DL = .LTT[LTTlink2];
	SL = .LTT[LTTlink1];
	end
    else begin
	DN = .LTT[LTTnode1];
	DL = .LTT[LTTlink1];
	SL = .LTT[LTTlink2];
	end;
    NODEb = $XPT_GET_NODE_DB(.DN);
    LINEb = $XPT_GET_LINE_DB(.OL);
    if (not .Local_node
    and ((.Nty eql PhTwo) or (.Nty eql TOPS20))
    and (.Nid eql .DN)
    and $MCB_GET_CCB_AND_BUFFER(22,CCB)) then begin
	CCB[C_XPT_ALLOCATION] = 22;
	DN_L = .Nnml;
	DN_P = byt$ptr(Nnm);
	SN_L = .NODEname_length;
	SN_P = byt$ptr(NODEname,0);
	SEND_DC(.CCB,.LINEb,.DN_L,.DN_P,.SN_L,.SN_P,.DL,.SL,NO_PATH_ERROR);
	end;
    LTT[LTTnode1] = -1;				!   Found one -
    LTT[LTTlink1] = -1;				!     clear it out
    LTT[LTTnode2] = -1;
    LTT[LTTlink2] = -1;
    end;
    
end;				!End of CLEAN_LINK
global
routine SEND_DC (CCB,LINEb,DEST_L,DEST_P,SOURCE_L,SOURCE_P,
                 DESTLNK,SRCLNK,REASON): CALL$ novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
! Constructs and sends a Phase II DC message over a given line.
!
! FORMAL PARAMETERS
!
!	CCB		CCB to use to send the DC.
!			CCB[C_BIAS]	A buffer large enough to contain the DC
!			CCB[C_ADDR]	  (anywhere from 12 to 22 bytes)
!			CCB[C_XPT_ALLOCATION]	The length of the buffer
!				  	(for its eventual release)
!
!	DEST_L		Length of the destination node name.  If this value
!			is zero, a routing header is not built.
!
!	DEST_P		Pointer to the destination node name.
!
!	SOURCE_L	Length of the source node name.
!
!	SOURCE_P	Pointer to the source name name.
!
!	DESTLNK		Destination link address.
!
!	SRCLNK		Source link address.
!
!	REASON		DC reason code.
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

begin

require 'XPTSYM';
map CCB: ref block field(C_XPT_fields);
pointer P;

P = .CCB[C_ADDR];				! Address message buffer
if .DEST_L neq 0 then begin			! Build a routing header:
    putb(PH2_RTflgs,P);				!   Routing flags
    putb(.DEST_L,P);				!   Dest. node name length
    P = ch$move(.DEST_L,.DEST_P,.P);		!   Destination node name
    putb(.SOURCE_L,P);				!   Source node name length
    P = ch$move(.SOURCE_L,.SOURCE_P,.P);	!   Source node name
    end;					! Build the message:
putb(DC_MSGflgs,P);				!   Message flags
putw(.DESTLNK,P);				!   Destination link address
putw(.SRCLNK,P);				!   Source link address
putw(.REASON,P);				!   Reason code
CCB[C_CNT] = ch$diff(.P,.CCB[C_ADDR]);		! Set up message length

CCB[C_XPT_TYPE] = NOcode;			! Set "don't use counters" code

CCB[C_HANDLE] = .TLIhandle;
CCB[C_FNC] = FC_XME;				! Send the
CCB[C_MOD] = TM_DAT;				!   message out
$MCB_SCHEDULE_CCB(.CCB);

end;				!End of SEND_DC
global
routine CLN_RETRY (LINEb): novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
! This routine cleans out of the retry queue all CCBs which:
!
!	1)  arrived over a specific circuit, or
!	2)  have as a destination the adjacent node over that circuit.
!
! FORMAL PARAMETERS
!
!	LINEb	Address of a circuit's data base entry.
!
! IMPLICIT INPUTS
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

begin

require 'XPTSYM';
local CCB: ref block field(C_XPT_fields);

local TEMP_QUEUE: vector[2];
local LEN;
pointer P;

$MCB_INITIALIZE_QUEUE(TEMP_QUEUE);

!
!  Pick up each CCB on the retry queue.  If the CCB doesn't "belong" to
!  the specified circuit, place in the temporary holding queue.
!

while $MCB_DEQUEUE_CCB(REqueue,CCB) do
    if not
	((.CCB[C_LIN] eql .LINEnumber)		! CCB arrived over circuit
	or begin
	    MAP$(.CCB[C_BIAS]);			! Map to and
	    P = .CCB[C_ADDR];			!   address buffer
	    if bitoff((getb(P)),%o'10') then	! No header -
		FALSE				!   for local node
	    else begin
		LEN = getb(P);			! Pick up dest. name length
		((.LEN eql .Nnml)		! Name length must match
		and ch$eql(.LEN,.P,.LEN,	!   and names must compare
		    byt$ptr(Nnm),0))    	! equal
		end
	    end)
    then CMQIN$(TEMP_QUEUE,.CCB)		! No match - keep this one
    else begin
	local SAVE;				! Otherwise -
	SAVE = .CCB[C_XPT_TYPE];		!   throw the CCB
	CCB[C_XPT_TYPE] = NOcode;               !   out (but don't
	_TERMINATE(.CCB,CE_DIS);		!   affect the quotas)
	CCB[C_XPT_TYPE] = .SAVE;
	end;

!
!  Now put back everything we kept into the retry queue.
!

while CMQRM$(TEMP_QUEUE,CCB) do
    CMQIN$(REqueue,.CCB);

end;				!End of CLN_RETRY

end				!End of module XPESEL
eludom