Trailing-Edge
-
PDP-10 Archives
-
BB-JR93L-BB_1990
-
10,7/mon/latser.mac
There are 10 other files named latser.mac in the archive. Click here to see a list.
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1985,1986,1988,1990.
;ALL RIGHTS RESERVED.
IFNDEF FTOPS20,<FTOPS20==0>
IFNDEF FTOPS10,<FTOPS10==1>
SALL
IFN FTOPS20,<
SEARCH MACSYM,MONSYM,PROLOG,TTYDEF
SEARCH NIPAR
TTITLE (LATSRV,,< -- LAT-20 Terminal Host>)
XRESCD ;[7.1024]
>
IFN FTOPS10,<
SEARCH F,S,D36PAR,MACSYM
SEARCH ETHPRM
.CPYRT<1985,1990>
TITLE LATSER -- LAT-10 Terminal Host
$RELOC
$HIGH ;SO BEGSTR DOESN'T OVERLAY LOW SEG WITH JUNK
XP VLATSER,6 ;PUT VERSION NUMBER IN STORAGE MAP AND GLOB
>
SUBTTL Table of Contents
; Table of Contents for LATSER
;
;
; Section Page
; 1. Definitions - Literals - Circuit Parameters. . . . . . 3
; 2. Definitions - Literals - Slot Parameters . . . . . . . 4
; 3. External References. . . . . . . . . . . . . . . . . . 5
; 4. Definitions - Data Structures. . . . . . . . . . . . . 7
; 5. CIRCUIT BLOCK data structure definitions . . . . . . . 8
; 6. SLOT BLOCK data struction definitions. . . . . . . . . 10
; 7. Miscellaneous Structure Definitions. . . . . . . . . . 11
; 8. Symbol Definitions
; 8.1. Macros MIN.,MAX.,MAXENT . . . . . . . . . . . 12
; 9. LATOP% JSYS
; 9.1. Definitions . . . . . . . . . . . . . . . . . 13
; 9.2. Entry point . . . . . . . . . . . . . . . . . 15
; 9.3. SET/CLEAR Functions . . . . . . . . . . . . . 16
; 9.4. SET/CLEAR SERVICE . . . . . . . . . . . . . . 17
; 9.5. SET LAT HOST NAME . . . . . . . . . . . . . . 19
; 9.6. SET/CLEAR HOST IDENTIFICATION STRING. . . . . 20
; 9.7. SET/CLEAR HOST GROUP CODES. . . . . . . . . . 21
; 9.8. SET MAXIMUM CIRCUITS. . . . . . . . . . . . . 22
; 9.9. SHOW CHARACTERISTIC HOST. . . . . . . . . . . 24
; 9.10. SHOW TERMINAL CONNECTS. . . . . . . . . . . . 26
; 9.11. SHOW SERVERS. . . . . . . . . . . . . . . . . 27
; 9.12. SHOW/ZERO COUNTERS. . . . . . . . . . . . . . 28
; 9.13. Utility Routines
; 9.13.1. FNDSRV . . . . . . . . . . . . . . . 29
; 9.13.2. GTSRVR . . . . . . . . . . . . . . . 30
; 9.13.3. SCMPAR String Compare. . . . . . . . 31
; 10. LATINI - LAT Initialization. . . . . . . . . . . . . . 33
; 11. Multicast Transmitter. . . . . . . . . . . . . . . . . 36
; 12. Routines to Build the Host Multicast Message
; 12.1. BMCFXD. . . . . . . . . . . . . . . . . . . . 37
; 12.2. BMCFXD. . . . . . . . . . . . . . . . . . . . 38
; 12.3. BMCNID. . . . . . . . . . . . . . . . . . . . 39
; 12.4. BMCSRV. . . . . . . . . . . . . . . . . . . . 40
; 12.5. BMCRAT. . . . . . . . . . . . . . . . . . . . 41
; 13. Multicast Transmit Check Routine . . . . . . . . . . . 42
; 14. Build the START Message Template . . . . . . . . . . . 43
; 15. LAINTR
; 15.1. LAT DLL Callback Routinea . . . . . . . . . . 44
; 15.2. Interrupt Level Virtual Circuit Message Receiver 45
; 16. LAINTX - Interrupt Level Virtual Circuit Message Receiver 46
; 17. LARSCH - Scheduler Level Virtual Circuit Message Receiver 47
; 18. LATLSC - Ethernet Link State Change Callback . . . . . 49
; 19. Message Receiver - HMSTRT. . . . . . . . . . . . . . . 50
; 20. HSTRCB . . . . . . . . . . . . . . . . . . . . . . . . 51
; 21. CBINIT - Circuit Block Initialization. . . . . . . . . 52
; 22. CMNIAD - Find CB base on NI address. . . . . . . . . . 53
; 23. HMRUN. . . . . . . . . . . . . . . . . . . . . . . . . 55
; 24. HSTRCB . . . . . . . . . . . . . . . . . . . . . . . . 56
; 25. HMSTOP . . . . . . . . . . . . . . . . . . . . . . . . 57
; 26. Message Transmit Routines. . . . . . . . . . . . . . . 59
; 27. Message Transmitter
; 27.1. XMTMSG. . . . . . . . . . . . . . . . . . . . 67
; 27.2. XMTDON. . . . . . . . . . . . . . . . . . . . 68
; 28. Receive Message Handling Routines. . . . . . . . . . . 69
; 29. Transmit Message Handling Routines . . . . . . . . . . 70
; 30. Slot Demultiplexor - LSDMUX. . . . . . . . . . . . . . 72
; 31. HSSTRT . . . . . . . . . . . . . . . . . . . . . . . . 73
; 32. Slot Processing Routines
; 32.1. STOP Slots. . . . . . . . . . . . . . . . . . 74
; 32.2. DATA_A,DATA_B Slots . . . . . . . . . . . . . 75
; 33. Slot Block Allocation and Deallocation Routines. . . . 77
; 34. Slot Multiplexor - Main Loop . . . . . . . . . . . . . 83
; 35. BLDMSL . . . . . . . . . . . . . . . . . . . . . . . . 85
; 36. Slot Formatting Routines
; 36.1. XSLSTA. . . . . . . . . . . . . . . . . . . . 87
; 36.2. XSLSTP. . . . . . . . . . . . . . . . . . . . 88
; 36.3. XSLDTA. . . . . . . . . . . . . . . . . . . . 89
; 36.4. XSLDTB. . . . . . . . . . . . . . . . . . . . 91
; 37. Queue Handling Routines. . . . . . . . . . . . . . . . 94
; 38. Buffer Handling Routines
; 38.1. Transmit Buffers. . . . . . . . . . . . . . . 96
; 38.2. Receive Buffers . . . . . . . . . . . . . . . 100
; 39. TTYSRV DEVICE DEPENDENT ROUTINES . . . . . . . . . . . 101
; 40. General Untility Routines. . . . . . . . . . . . . . . 102
SUBTTL TOPS20 definitions
IFN FTOPS20,<
;[7.1039] Add XBLT exec to user
;
DEFINE XBLTXU (AC<T1>),<XCT 1,[EXTEND AC,[XBLT]]>
;[7.1039] Add XBLT user to exec
;
DEFINE XBLTUX (AC<T1>),<XCT 2,[EXTEND AC,[XBLT]]>
> ;END IFN FTOPS20
SUBTTL Definitions -- TOPS-10 -- Redefinitions of TOPS-20 Things
IFN FTOPS10,<
OPDEF NOP[TRN]
DEFINE RESCD <$HIGH> ;Resident (nonpagged) code
DEFINE SWAPCD <$HIGH> ;Swappable code
DEFINE XRESCD <$XHIGH>;Resident (XRCOD PSECT)
DEFINE XSWAPCD <$XHIGH>;Swappable (XNCOD PSECT)
DEFINE RESDT <$LOW> ;
DEFINE NOSKD1 <> ;Don't have to worry
DEFINE OKSKD1 <> ; about these
DEFINE MCENT <> ; in TOPS-10
DEFINE UNSPI,<UNSID> ;Secondary portal ID
DEFINE UN.SPI,<UN.SID> ; (NIPAR/ETHPRM)
DEFINE BITS,<BITTBL##>
DEFINE MAXACB,<MAXCIR##>
DEFINE MAXACC,<MAXCIR##>
DEFINE TODCLK,<SYSUTM##>;[7.xxxx]System uptime in milliseconds
EXTERN RTRADR
EXTERN LAHNDB
EXTERN NTTLAH
EXTERN SBBWDS
EXTERN SBBITS
EXTERN LDLIDL
EXTERN RTN
; Redefine the D36PAR line states.
;
LS.OFF==0 ;Off
LS.ON==1 ;On
LS.SHT==2 ;Shutdown
; XCTU is used for "normal" instructions which move data from User to eXec
; and eXec to User
;
DEFINE XCTU <PXCT 4,> ;For all "normal" instructions
DEFINE XCTBU <PXCT 3,> ;To load from and deposit to user
;with byte pointer in eXec
SUBTTL Definitions -- TOPS-10 -- LATOP. UUO
;Still in IFN FTOPS10
; CALL: MOVEI AC,ADR
; LATOP. AC,
; <NON-SKIP>
; <SKIP>
;LATOP. Function Code Definitions
.LASET==0 ;Set
.LACLR==1 ;Clear
.LASCH==2 ;Show characteristics of host
.LASTC==3 ;Show terminal connects
.LASAS==4 ;Show adjacent servers
.LASCO==5 ;Show counters
.LAZCO==6 ;Zero counters
.LARHC==7 ;[7.1120]Request host-initiated connect
.LATHC==10 ;[7.1120]Terminate host-initiated connect
.LASHC==11 ;[7.1120]Show host-initiated connects
;Argument list offsets
.LAACT==0 ;Argument block count
.LAFCN==1 ;LATOP% function code
.LAPRM==2 ;SET/CLEAR parameter number
LA%PSI==1B0 ;Use PSI to interrupt (TOPS-20)
LA%WAI==1B0 ;Wait for completion (TOPS-10)
LA%QUE==1B1 ;Queue the request at the remote server
LA%SYS==1B2 ;Show all host-initiated connects
LA%JOB==1B3 ;Show all host-initiated connects for the job
LA%CID==777777 ;Connect id
.LAVAL==3 ;SET/CLEAR new parameter value
LA%CHN==0,,-1 ;[7.1120]Interrupt channel
.LABCT==2 ;Buffer count
LA%ECB==1B0 ;Use the Extended Connect Block
.LABFA==3 ;Buffer Address
.LAQUA==4 ;Qualifier
.LADSC==5 ;(ASCIZ string pointer)
.LASVR==4 ;[7.1120]Server name
.LASVC==5 ;[7.1120]Service name
.LAPRT==6 ;[7.1120]Port name
LA%RAT==1B0 ;Set the rating specified
LA%DSC==1B1 ;Set the service description
;Parameter numbers for SET/CLEAR
.LPMAC==1 ;Maximum number of active circuits
.LPMCO==2 ;Maximum number of simultaneous connects
.LPNUM==3 ;Host number
.LPLAS==4 ;LAT access state
.LPRLI==5 ;Circuit retransmit limit
.LPTIM==6 ;Circuit timer initial value
.LPMTI==7 ;Multicast timer initial value
.LPCOD==10 ;Access codes
.LPNNM==11 ;Host node name
.LPNID==12 ;Host node identification string
.LPSRV==13 ;Service rating or description (depends on .LAQUA)
;Port type codes
.LATTY==1 ;[7.1120]Standard LAT terminal connection
.LADLP==2 ;[7.1120]Dial-up Lat terminal connection
.LAAPP==3 ;[7.1120]LAT application terminal
;Status and rejection codes
.LASOL==377777 ;[7.1120]Request is being solicited
.LAQUE==377776 ;[7.1120]Request is queued
.LACAN==377775 ;[7.1120]Request was cancelled by user
.LATMO==377774 ;[7.1120]Request has timed out
.LAUNK==00 ;[7.1120]Unknown error
.LAURD==01 ;[7.1120]User requested disconnect
.LASSP==02 ;[7.1120]System shutdown in progress
.LAISR==03 ;[7.1120]Invalid slot received
.LAISC==04 ;[7.1120]Invalid service class
.LAIRS==05 ;[7.1120]Insufficient resources
.LASIU==06 ;[7.1120]Service is in use
.LANSS==07 ;[7.1120]No such service
.LASDI==10 ;[7.1120]Service is disabled
.LASNP==11 ;[7.1120]Service is not offered by requested port
.LANSP==12 ;[7.1120]No such port name
.LAIPW==13 ;[7.1120]Invalid password
.LAENQ==14 ;[7.1120]Entry is not in queue
.LAIAR==15 ;[7.1120]Immediate access rejected
.LAACD==16 ;[7.1120]Access denied
.LACSR==17 ;[7.1120]Corrupted solicit request
.LACTI==20 ;[7.1120]Command type code is illegal
.LASCS==21 ;[7.1120]Start slot can't be sent
.LAQED==22 ;[7.1120]Queue entry deleted by local node
.LAIRP==23 ;[7.1120]Inconsistent or illegal request parameters
SUBTTL Definitions -- TOPS-10 -- Error Codes
;Still in IFN FTOPS10
DEFINE ITERR (ERRCOD),<
IFB <ERRCOD>,<CALLRET STOTAC##>
IFNB <ERRCOD>,<
CALLRET [ MOVEI T1,ERRCOD
CALLRET STOTAC##]>>
DEFINE RETBAD (ERRCOD),<
IFB <ERRCOD>,<RET>
IFNB <ERRCOD>,<
CALLRET [ MOVEI T1,ERRCOD
RET]>>
DEFINE .ERRT (A,B,C,D) <
B==A
C==A> ;internal and external name
.ERRT (00,LATX01,LABTS%,<Buffer size too small for available data>)
.ERRT (01,LATX02,LAVOR%,<LAT parameter value out of range>)
.ERRT (02,LATX03,LALNO%,<LAT is not operational>)
.ERRT (03,LATX04,LASVR%,<Invalid or unknown LAT server name>)
.ERRT (04,LATX05,LAIPN%,<Invalid LAT parameter>)
.ERRT (05,LATX06,LAIPV%,<Invalid LAT parameter value>)
.ERRT (06,LATX07,LASVC%,<Invalid or unknown LAT service name>)
.ERRT (07,LATX08,LAILR%,<Insufficient LAT Resources>)
.ERRT (10,LATX09,LAHAS%,<LAT Host name already set>)
.ERRT (11,ARGX02,LAIVF%,<Function code out of range>)
.ERRT (12,ARGX04,LAABS%,<Argument list too small>)
.ERRT (13,LATXAC,LAADC%,<Address check for argument list>)
.ERRT (14,LATXPV,LAPRV%,<No privilege for attempted operation>)
.ERRT (15,LATX10,LAPRT%,<Invalid or unknown LAT port name>) ;[7.1120]
.ERRT (16,LATX11,LACID%,<Invalid or unknown connect id>) ;[7.1120]
SUBTTL Definitions -- TOPS-10 -- KS10 conditionals
;Still in IFN FTOPS10
IFE FTXMON,<
; Redefine some stuff if we running non-extended (KS10 especially)
;
DEFINE OWGP. (SS,ADR,POS),<POINT SS,ADR,POS>
DEFINE XBLT.(AC<T1>),<
IFN <AC>-T1,<PRINTX ? CAN'T XBLT VIA AC, USE T1>
CALL XBLTA##
>
> ;End IFN FTXMON
SUBTTL Definitions -- TOPS-10 -- Symbol purging macros
;Still in IFN FTOPS10
; Define some macros which will help purge all symbols of
; the form ..nnnn at the end of assembly. This will get rid
; of about 200 useless symbols generated by .IFSKP and friends
define eq(a,b),<a==b>
define highest(sym,%tg),< ;;Macro to find highest generated symbol
....==sixbit/%tg/&000077777777 ;;Isolate the nnnn part of ..nnnn
eq(sym,\'....)
purge ....>
define prgnum(n),< ;;Macro to purge symbol named ..nnnn
....==sixbit/n/ ;;given a number n
ifl <n-1000>,<....==<..../100>!sixbit/0/> ;;make leading zero fill
ifl <n-100>,<....==<..../100>!sixbit/0/>
ifl <n-10>,<....==<..../100>!sixbit/0/>
prgsym(..,\'....)
purge ....>
define prgsym(sy1,sy2),<
purge sy1'sy2
>
define prgall,< ;;End product: macro to purge all symbols
if2,< ;;of the form ..nnnn
highest XX ;;Use this just before END statement
nn==XX
repeat XX,<prgnum(\nn)
nn==nn-1>
nn==.npac
repeat .npac,<prgsym(.fpac,\nn) ;;get rid of .fpacN symbols
nn==nn-1>
purge nn,XX,.npac>
>
SUBTTL Definitions -- TOPS-10 -- Accumulators
;Still in IFN FTOPS10
; Allocate some ACs for use in LATOP. UUO
; Use W, since we don't use it for anything else.
; Use M, since it is W+1 for 7.03
; We don't bother saving W, since it is useless.
; We save M at start of LATOP. UUO and restore just before end
; because it contains the actual UUO and AC field to store to
;
Q1==W ;redefine some TOPS-20 ACs
Q2==M ;( = W+1)
; Don't let TRVAR allocate storage for TOPS-10, since TOPS-10 cannot
; maintain a frame pointer. If TRVAR is used, it will create undefined
; global symbols.
;
DEFINE TRVAR(LIST),<>
DEFINE ACDEF(N,AC),<.FPAC'N==AC>
DEFINE FREEAC(AC),<
.NPAC==0
IRP AC,<
ACDEF(\.NPAC,AC)
.NPAC==.NPAC+1
>>
FREEAC <W,M,P1,P2,P3,P4,J> ;These are all the ACs available for ACVAR
;Explicitly do NOT use "U" since it is used
;for the normal TOPS-10 function to point to
;an LDB throughout the code
;Still in IFN FTOPS10
SUBTTL Definitions -- Title
DEFINE ACVAR (LIST)<
..NAC==0 ;;INIT NUMBER OF ACS USED
IRP LIST,<
.ACV1 (LIST,\..NAC) ;;PROCESS ITEMS
..NAC==..NAC+1>
SAVEAC (<LIST>) ;;SAVE ACS USED (QUICK AND DIRTY)
DEFINE ENDAV.<.ENAV1 <LIST>>>
DEFINE .ACV1 (ITEM,N)<
.ACV2 (ITEM,N)> ;;PEEL OFF ANGLEBRACKETS IF ANY
DEFINE .ACV2 (NAM,N)<
IFDEF NAM,<.IF NAM,SYMBOL,<PRINTX ACVAR NAM ALREADY DEFINED>>
NAM==.FPAC'N ;;DEFINE VARIABLE
$'NAM==NAM ;;FOR DDT
>
DEFINE .ENAV1 (ARGS)<
IRP ARGS,<
.ENAV2 (ARGS)>>
DEFINE .ENAV2 (ARG)<
.ENAV3 (ARG)>
DEFINE .ENAV3 (NAM,SIZ)<
PURGE NAM,NAM
>
XOFFC=="S"-100 ;XOFF CHARACTER
XONC=="Q"-100 ;XON CHARACTER
> ;End IFN FTOPS10
SUBTTL Definitions -- Literals -- Circuit Parameters
;
;LAT Virtual Circuit Message Types
;
MT.RUN==0 ;RUN message
MT.STA==1 ;START message
MT.STP==2 ;STOP message
MT.MCA==^D10 ;Multicast message
MT.CMD==^D12 ;[7.1120]Command message
MT.STS==^D13 ;[7.1120]Status message
MT.SIN==^D14 ;[7.1120]Solicit Information message
MT.RIN==^D15 ;[7.1120]Response Information message
MT.EID==^D10 ;[7.1150]Offset to Entry ID field in command msg
;LAT Virtual Circuit States
;
CS.HLT==0 ;HALTED
CS.STA==1 ;STARTING
CS.RUN==2 ;RUNNING
CS.TRN==-1 ;In transition between HALTED and STARTING
;
;Circuit STOP message reason codes
;
CE.NSL==1 ;No slots connected on circuit
CE.ILL==2 ;Illegal message or slot format
CE.HLT==3 ;Circuit halted by local system
CE.NPM==4 ;No progress being made
CE.TIM==5 ;Time limit expired
CE.LIM==6 ;Retransmit limit exceeded
CE.RES==7 ;Insufficient resources
CE.STO==10 ;Server circuit timer out of range
CE.SKW==11 ;Protocol version skew
CE.INV==12 ;Invalid Message
;Circuit STOP reason codes of local significance only
CE.NIH==200 ;Local NI halted
MMHDSI==^D8 ;Minimum Message Header Size
MSTMSI==^D16 ;Minimum START Message Size(excluding header)
SUBTTL Definitions -- Literals -- Slot Parameters
;
;LAT Slot Types
;
ST.DTA==0 ;DATA_A slot
ST.STA==11 ;START slot
ST.DTB==12 ;DATA_B slot
ST.ATT==13 ;ATTENTION slot
ST.REJ==14 ;REJECT slot
ST.STP==15 ;STOP slot
;
; LAT Slot States
;
SS.HLT==0 ;Halted
SS.RUN==1 ;Running
SS.SIN==2 ;[7.1120]Solicit Information
SS.SAI==3 ;[7.1120]Solicit Access (initialize first)
SS.SAC==4 ;[7.1120]Solicit Access
SS.QUE==5 ;[7.1120]Queued
SS.REJ==6 ;[7.1120]Rejected
SS.TMO==7 ;[7.1120]Timed out
SS.CAI==10 ;[7.1120]Cancel (initialize first)
SS.CAN==11 ;[7.1120]Cancel
SS.MAX==SS.CAN ;[7.1120]Maximum state value
;
; SLOT Reject and Stop Reason Codes
;
SE.USR==1 ;User requested disconnect
SE.SHU==2 ;System shutdown in progress
SE.ISR==3 ;Invalid slot received
SE.SER==4 ;Invalid service class
SE.RES==5 ;Insufficient resources available
SE.ENQ==^D12 ;[7.1120]Entry is not in queue
SE.CSR==^D15 ;[7.1120]Corrupted solicit request
;
; DATA_B Slot Control Flag Bit Definitions
; Low order bit always set to enable "HOSTSYNC" flow control ala VAX
; Other bits Enables/Disables "TTSYNC" in VAX terms.
SL.EXF==^B0101 ;[7.1039]Enable XON/XOFF recognition in server
SL.DXF==^B1001 ;[7.1039]Disable XON/XOFF recognition in server
; Connect id's for pending requests have a random portion (determined by
; the array PRRAND) and a fixed protion (the index into PRVECT and
; PRRAND).
;
PR.NDX==000377 ;[7.1120]The LO eight-bits are the index
PR.RAN==000377 ;[7.1120]The HO eight-bits are random
PR%RAN==<PR.RAN>B27 ;[7.1120]Here is the position of PR.RAN
;
; SLOT Size Definitions
;
SLHDSI==4 ;Slot header size
ATTSIZ==SLHDSI ;ATTENTSION slot size
DTBSIZ==SLHDSI+5 ;DATA_B slot size
IFN FTOPS20,<
NIPIA==DLSCHN ;Priority Interrupt Assignment for KLNI
>
;
;Response Information Status Bits
;
RI%NDS==1 ;[7.1120]Node is disabled
RI%NSS==2 ;[7.1120]No such service
RI%CMD==4 ;[7.1120]Node can accept a command message
;
;Miscellaneous Constants
;
LAHPV==5 ;Highest protocol version supported
LALPV==5 ;Lowest protocol version supported
PROVER==5 ;Our LAT protocol version
PROECO==1 ;[7.1120]Our LAT protocol ECO
MXSLSI==^D40 ;[7346]Maximum slot size we will receive
MXSLTS==^D64 ;Maximum slot sessions per circuit
LMRFSI==^D1504 ;Receive buffer size
MXHSRV==10 ;Maximum number of services offered
IFN FTOPS20,<
LHPRID==6 ;Product code type for TOPS-20 host
>
IFN FTOPS10,<
LHPRID==7 ;Product code type for TOPS-10 host
>
SCITTY==1 ;Interactive terminal service class
MAXXBF==2 ;Maximum number of transmit buffers/circuit
CBMAXI==^D255 ;[7.1164]Absolute maximum circuit id
PRMAXI==^D64 ;[7.1120]Maximum pending requests
SLHDSZ==4 ;Slot header size (bytes)
MAXCRE==2 ;Maximum number of credits to extend to remote.
MXBALC==6 ;Number of ticks to wait before sending
; unsolicited message to server
DLL.FL==1B0 ;[7.1120]UNUID: Buffer is in DLL (NI service)
SAV.FL==1B1 ;[7.1120]UNUID: Buffer for pending request
MSB.FL==2 ;[7.1155]Symbol for Master/slave bit
MINXBF==^D46 ;Minimum transmit buffer size
XRESCD ;[7.1024]
SUBTTL Definitions -- Data Structures
; UN Block Extension
BEGSTR UE
WORD LW0 ;Queue Link Word for linking buffers to CB Qs
WORD LW1 ;Queue Link Word for linking buffers to NI Qs
ENDSTR
;
; Buffer offsets
;
UNB.OF==UE.LEN ;Start of UN block for all buffers
MDB.OF==UE.LEN+UN.LEN ;Start of MD block
XBF.OF==UE.LEN+UN.LEN+MD.LEN
SBF.OF==UE.LEN+UN.LEN
SZMSTP==<XBF.OF+SZ.MHD+1>;STOP message size in words
SZ.SHD==4 ;Slot header size
SZ.ATT==1 ;Attention size
SZ.REJ==0 ;Reject slot size
SZ.SDB==5 ;DATA_B slot size
SZ.SSP==0 ;Stop slot size
SZ.SST==6 ;Start slot size
SZ.XBF==<^D1500+3>/4
SZ.MSP==^D10 ;Start message size
SZ.MHD==^D8 ;Message header size
ML.NNM==6 ;Max length of node name
ML.SYS==^D16 ;Max length of system name
ML.LOC==^D64 ;Max length of location field
ML.DSC==^D64 ;Max length of description field
ML.SRN==^D16 ;[7.1120]Max length of server name
ML.PRN==^D16 ;[7.1120]Max length of port name
ML.SVN==^D16 ;[7.1120]Max length of service name
ML.SID==^D64 ;Max length of service identification field
ML.HMC==^D33+<1+ML.NNM>+<1+ML.DSC>+MXHSRV*<1+ML.SVN+1+ML.SID>+2
;Host multicast message max length
ML.HSM==^D12+<1+ML.NNM>+<1+ML.LOC>+<1+ML.SYS>+1
;Host start message max length
ML.HCM==^D54+ML.SRN+ML.SYS+ML.SVN+ML.PRN
;[7.1120]Max length of host command msg
MW.SYS==<ML.SYS+4>/5 ;[7.1039]Max length of system name in words
MW.LOC==<ML.LOC+4>/5 ;[7.1039]Max length of location field in words
MW.SHC==4+<ML.SRN+4>/5+<ML.PRN+4>/5+<ML.SVN+4>/5
;[7.1120]Length of an .LASSC Status block
MW.OCB==<<ML.SYS+4>/5>+2;[7.1120]Length of an "old style" connect
;block
MW.ECB==MW.OCB+1+<<<ML.SYS+4>/5>*2>
;[7.1120]Length of an "extended" connect
;block
SUBTTL Definitions -- Data Structures -- Host Node (HN) Block
;Host Node Data Structures
;
BEGSTR GB ;SERVICE BLOCK
WORD RAT ;Service Rating.
HWORD NC ;Count of bytes in service name.
HWORD LC ;Count of bytes in service description
WORD NAM,<<ML.SVN+4>/5> ;Storage for up to 16 bytes of service name.
WORD HID,<<ML.SID+4>/5> ;Storage for up to 64 bytes of service id.
ENDSTR
BEGSTR HN ;HOST NODE Data Base
FIELD FLG,^D18
BIT RUN ;NI run state
BIT ANY ;Reconstruct of START msg necessary
BIT CIP ;Virtual circuit connect in progress
FILLER ^D10
FIELD CFL,^D8 ;Multicast message change flags
BIT OTH ;Something other than above changed
BIT FIL
BIT CLS ;A host service class changed
BIT SVD ;A host service description changed
BIT SVR ;A host service rating changed
BIT SVN ;A host service name changed
BIT NDD ;Host Node Description changed
BIT ACS ;Access Codes changed
;START OF PARAMETERS DISPLAYED BY .LASCH
HWORD MXC ;Maximum allocatable circuit blocks
HWORD NCC ;Number of currently allocated circuit blocks
HWORD MAC ;Maximum number of active circuits
HWORD NAC ;Number of currently active circuits
HWORD MCO ;Maximum number of simultaneous connects
HWORD CON ;Current number of active connects
HWORD NUM ;Host number
HWORD LAS ;LAT access state
HWORD RLI ;Virtual circuit message retransmit limit
HWORD TIM ;Virtual circuit timer initial value (ms)
HWORD MTI ;Multicast timer initial value (sec)
;END OF PARAMETERS DISPLAYED BY .LASCH
HWORD RAT ;Host node dynamic rating
HWORD PRG ;Host progress timer
HWORD NRB ;Number of receive buffers allocated
;[7.xxxx]Remove definition of HNRTX
HWORD CMT ;[7.1120]Command message retry timer (ms)
HWORD CMX ;[7.1120]Command message retry limit
WORD HST ;Address of state table
WORD QAC,2 ;Queue header for active circuit blocks
WORD QIC,2 ;Queue header for inactive circuit blocks
WORD NIQ,2 ;Interrupt level message queue
WORD SCQ,2 ;Scheduler level message queue
WORD PID ;NI Portal ID
HWORD NXI ;Next circuit block index to assign
HWORD NSV ;Number of offered services
WORD LOK ;Lock for HN data base
HWORD NMC ;Host node name count
HWORD IDC ;Host identification string count
WORD NAM,2 ;Host node name string
WORD ID,<<ML.DSC+4>/5> ;Host identification string
WORD SMT,<<<ML.HSM+3>/4>+SBF.OF>;Start message template
WORD MCM,<<ML.HMC+3>/4> ;Copy of the multicast message.
WORD SRV,<GB.LEN*MXHSRV>;Storage for service blocks
ENDSTR
BEGSTR AC,HN.LST ;ACCESS CODES
WORD LNG ;Access code string length in bytes
WORD COD,^D32 ;Storage for 256 bit bit-mask
ENDSTR
;LAT Circuit counters for all servers
BEGSTR HC,AC.LST
WORD RCV ;Messages received
WORD XMT ;Messages transmitted
WORD RTR ;Messages retransmitted
WORD SEQ ;Receive message sequence errors
WORD IMR ;Illegal messages received
WORD ISR ;Illegal slots received
WORD RES ;Resource errors
WORD MSK ;Illegal message error mask
ENDSTR
SUBTTL Definitions -- Data Structures -- Circuit Block (CB)
BEGSTR CB ;CIRCUIT BLOCK
WORD LNK,2 ;Queue Link words (must be first words)
HWORD RID ;Circuit handle assigned by the remote
HWORD LID ;Local circuit index
FIELD FLG,3 ;Virtual circuit flags
BIT RRF ;Reply requested flag
BIT MRS ;Must reply soon flag
BIT MRN ;Must reply now flag
HWORD CSB ;Count since balanced
HWORD SDC ;Number of slots with data waiting
HWORD TSQ ;Next transmit sequence number
HWORD RSQ ;Next expected receive sequence number
HWORD LRA ;Sequence number of last message ack'd by remote node.
WORD TIM ;Current value of circuit timer.
HWORD RTC ;Current retransmit count
WORD KAV ;[7295]2*Server Keep-alive-timer in ms.
; (in jiffies for TOPS-10)
WORD KAT ;TODCLK last time message receieved from server
HWORD QUA ;Circuit quality
HWORD ERR ;Reason code for last time circuit stopped
HWORD DLL ;Number of transmit buffers in the DLL
WORD XBQ,2 ;Queue of free transmit buffers
WORD AKQ,2 ;Unacknowledged queue header
WORD SBQ,2 ;Circuit slot queue
;
;The following are returned as part of the LATOP Get Server information info.
;
WORD DNI,2 ;NI address of remote server
HWORD MTF ;Maximum transmit frame size for circuit
HWORD RPV ;Remote protocol version and ECO
HWORD MSL ;Maximum slots allowed by remote
HWORD NBF ;Additional transmit buffers allowed by remote
HWORD CTI ;Value of remote's circuit timer
HWORD KTI ;Value of remote's keep-alive timer
HWORD PTC ;Product type code for remote node
HWORD STA ;Virtual circuit state
HWORD NUM ;Remote's system number
HWORD RSC ;Remote's system name count
HWORD RLC ;Remote's location text count
WORD SNM,<<ML.SVN+4>/5> ;Remote's system name
WORD LOC,<<ML.LOC+4>/5> ;Remote's location string
ENDSTR
BEGSTR CC,CB.LST ;CIRCUIT COUNTERS
WORD RCV ;Messages received
WORD XMT ;Messages transmitted
WORD RTR ;Messages retransmitted
WORD SEQ ;Receive message sequence errors
WORD IMR ;Illegal messages received
WORD ISR ;Illegal slots received
WORD RES ;Resource errors
WORD MSK ;Illegal message error mask
ENDSTR
; Boundary definitions in the CB for CLEAR and SHOW
; LAT Control Program functions.
CLRBEG==CB.FLG ;First clear field for .LACLR
CLREND==CB.DLL ;End of clear field for .LACLR
SASBEG==CB.DNI ;Start of .LASAS fields for single server
SASBG==CB.STA ;Start of .LASAS fields for multiple servers
SASEN==CB.SNM+<ML.SYS+4>/5 ;End of .LASAS fields for single server
SASEND==CB.LOC+<ML.LOC+4>/5 ;End of .LASAS fields for multiple servers
SUBTTL Definitions -- Data Structures -- Slot Block (SB)
BEGSTR SB
WORD LNK,2 ;Queue link word (must be first)
FIELD FLG,^D18 ;Flags
;*** Beginning of bits to be kept in order ***
BIT SDP ;Slot data present (must be sign bit)
BIT REJ ;Send REJECT Slot
BIT STR ;Send START Slot
BIT FOU ;Flush output
BIT OUT ;Output data available
BIT FCC ;Flow control change
BIT STO ;Send STOP Slot(Must be last)
;*** End of bits to be kept in order ***
SBSMSK==SBREJ!SBSTR!SBFOU!SBOUT!SBFCC!SBSTO ;[7.1120]
;[7.1120]Mask of bits which match BLSDSP
BIT DLP ;[7.1120]This slot is a dialup line
HWORD ATS ;Maximum attention slot size
HWORD MDS ;Maximum slot data size
HWORD STA ;Slot state
HWORD RID ;Remote slot id
HWORD LID ;Local slot id
HWORD XCR ;Transmit credits available to us
HWORD RCR ;Receive credits still outstanding
HWORD REA ;Reason code for stop or reject
HWORD SRC ;[7.1120]Server name count
HWORD PRC ;[7.1120]Port name count
HWORD SVC ;[7.1120]Service name count
WORD SRN,<<ML.SRN+4>/5> ;[7.1120]Server name
WORD PRN,<<ML.PRN+4>/5> ;[7.1120]Port name
WORD SVN,<<ML.SVN+4>/5> ;[7.1120]Service name
WORD TDB ;Terminal data block
WORD CBA ;Circuit block address for this slot
WORD PRA ;[7.1120]Pending request block address
IFN FTOPS10,<
FIELD REM,^D18 ;More flags for TOPS-10
BIT TTO ;"Character in SBCHR" bit, must be sign bit
BIT XNF ;"XON/XOF processing enabled
HWORD CHR ;space to hold saved character
> ;End IFN FTOPS10
ENDSTR
SUBTTL Definitions -- Data Structures -- Pending Request Block (PR)
;[7.1120]
BEGSTR PR
FIELD FLG,^D18 ;Flags
BIT WAI ;Wait for the connection
BIT QUE ;Queue this request
HWORD STA ;State (internal use only)
HWORD STS ;Status (visible to user)
HWORD QDP ;Queue depth
HWORD CID ;Local connect id
HWORD EID ;Remote entry id
HWORD JOB ;Job number (JCH for TOPS-10)
HWORD FRK ;Fork number
HWORD PSI ;PSI channel number
HWORD CMC ;Command message retry count
HWORD SRC ;Server name count
HWORD PRC ;Port name count
HWORD SVC ;Service name count
WORD SRN,<<ML.SRN+4>/5> ;Server name
WORD PRN,<<ML.PRN+4>/5> ;Port name
WORD SVN,<<ML.SVN+4>/5> ;Service name
WORD CMT ;Command message retry timer
WORD SBA ;Address of slot block
WORD XBA ;Address of COMMAND message
WORD DNI,2 ;Address of remote server
ENDSTR
SUBTTL Definitions -- Data Structures -- Miscellaneous
BEGSTR QL ;Halfword Queue Link Word
WORD FWD ;Next forward queue element
WORD BWD ;Previous backward queue element
ENDSTR
SUBTTL Definitions -- External References
IFN FTOPS20,<
EXT DNGWDZ
EXT DNFWDS
EXT TTCHI
EXT LATMCT ;CLK2TM table timer for multicast
EXT LATCMT ;[7.1120]CLK2TM table timer for command message
>;END IFN FTOPS20
SUBTTL Definitions -- MIN.,MAX.,MAXENT Macros
; Macro MIN. (symbol,list) - Assigns minimum arithmetic value of list of items.
;
DEFINE MIN. (SYM,LIST),
<IRP LIST,<..X==LIST ;;Assign first value in list
STOPI>
IRP LIST,<IFL <LIST-..X>,<..X==LIST>> ;;Assign lowest in list
SYM==:..X> ;;Generate value
;
; Macro MAX. (symbol,list) - Assigns maximum arithmetic value of list of items.
;
DEFINE MAX. (SYM,LIST),
<IRP LIST,<..X==LIST ;;Assign first value in list
STOPI>
IRP LIST,<IFG <LIST-..X>,<..X==LIST>> ;;Assign highest in list
SYM==:..X> ;;Generate value
DEFINE PARTB. (PRM,MAX,MIN,CLRVAL,INSTR,FLAGS) <
.ORG <.LP'PRM+TBRNGE-1>
EXP <MAX,,MIN>
.ORG
.ORG <.LP'PRM+TBFLGS-1>
EXP <FLAGS!CLRVAL>
.ORG
.ORG <.LP'PRM+TBEXEC-1>
IFB <INSTR>,<
STOR T2,HN'PRM,(Q2)
>
IFNB <INSTR>,<
INSTR
>
.ORG
>
SUBTTL Definitions -- Local Variables
RESDT
CBVECT: BLOCK 1
SBVECT: BLOCK 1
PRVECT: BLOCK 1 ;[7.1120]Table of pending requests
PRRAND: BLOCK 1 ;[7.1120]Table of "random" connect id values
PRBITS: BLOCK <PRMAXI+^D35>/^D36 ;[7.1120]Bit table for PRVECT
PRBITN==.-PRBITS ;[7.1120]Length of PRBITS table
LASDEF::EXP LS.ON ;LAT Access Default State
NSLOTS: BLOCK 1
IFN FTOPS20,<
PRWMSK: BLOCK <PRMAXI+^D35>/^D36 ;[7.1120]Wake up mask for LATST
LAHNDB: BLOCK 1
MAX. (TMPLNG,<<GB.LEN+1>,ML.NNM,ML.DSC>)
NR (TMPBLK, TMPLNG)
TMPGB==TMPBLK+1
> ;end IFN FTOPS20
IFN FTOPS10,<
OURNAM: BLOCK 2
OURCNT: BLOCK 1
LATRTQ: BLOCK 2 ;QUEUE FOR LAT LDBS
LATFRE: BLOCK QL.LEN ;QUEUE FOR LAT FREE CORE BLOCKS
LATLOC: BLOCK 1 ;START OF LAT FREE CORE (SET UP AT ONCE TIME)
LATMCT: BLOCK 1 ;Multicast timer (in seconds for TOPS-10)
LATNFB: BLOCK 1 ;Number of free buffers in pool
LATWFB: BLOCK 1 ;Number of free buffers wanted for new circuits
LATRFB: BLOCK 1 ;Number of buffers requested on last cycle
LASBAD: BLOCK 2 ;Ethernet address of sender of last bad msg
MSGDID: BLOCK 1 ;Destination ID from msg
MSGSID: BLOCK 1 ;Source ID from msg
MSGACK: BLOCK 1 ;ACK/SEQ field from msg
STPCOD: BLOCK 1 ;Stop reason
SLTDID: BLOCK 1 ;Destination ID from RUN msg
SLTSID: BLOCK 1 ;Source ID from RUN msg
SLTCNT: BLOCK 1 ;Slot count from RUN msg
SLTTYP: BLOCK 1 ;Slot type/credits/reason
SLTEPT: BLOCK 1 ;Pointer to the next slot
MAX. (TMPLNG,<<GB.LEN+1>,ML.NNM,ML.DSC>)
TMPBLK: BLOCK TMPLNG ;Temporary block for LATOP.
TMPGB==TMPBLK+1
>;end IFN FTOPS10
SUBTTL LATOP% JSYS -- Dispatch
XSWAPCD ;[7.1024]
XNENT (.LATOP,G) ;[7.1024].LATOP::, X.LATO::
IFN FTOPS20,<
MCENT
UMOVE Q1,1 ;Get the argument block address
> ;End IFN FTOPS20
IFN FTOPS10,<
SAVEAC <W,M,P1,P2,P3,P4>;Save W (Q1) and M (Q2)
MOVE Q1,T1 ;Get the argument block address
MOVE J,.CPJOB## ;Also need job number
; For TOPS10, we must address-check the argument block or else we might
; get an IME doing a UMOVE or UMOVEM.
;
MOVE M,T1 ;Point to user's argument block
SNCALL (GETWRD##,MCSEC1);Get the first word (arg count)
ITERR (LATXAC) ;Arg block is not addressable!
MOVE P1,T1 ;Save length of argument block
MOVE T1,Q1 ;Copy address of argument block
MOVE T2,P1 ;Copy length of argument block
SNCALL (ARNGE##,MCSEC1) ;Address check the argument block
NOP ;Not addressable!
ITERR (LATXAC) ;Not writeable!
; (error because .LABCT gets rewritten)
> ;End IFN FTOPS10
; ..
; ..
SKIPN Q2,LAHNDB ;If there is no data base,
ITERR (LATX03) ; then LAT is not operational
UMOVE P1,.LAACT(Q1) ;Get the length of the argument block
UMOVE P2,.LAFCN(Q1) ;Get the function code
SKIPL P2 ;
CAILE P2,FNCMAX ;Range check the function code
ITERR (ARGX02) ;Function code out of range
LDB T1,[POINTR (FNCDSF(P2),LF%MSZ)] ;[7.1120]
CAMGE P1,T1 ;[7.1120]Is the argument block big enough?
ITERR (ARGX04) ;[7.1120]No, argument list too small
MOVE P3,FNCDSF(P2) ;[7.1120]Get the function flags word
TXNN P3,LF%PRV ;[7.1120]Is this a privileged operation?
IFSKP. ;[7.1120]Yes, then check capabilities
IFN FTOPS20,<
MOVE T1,CAPENB ;[7.1120]
TXNN T1,SC%WHL!SC%OPR ;[7.1120]Has WHEEL or OPERATOR privileges?
ITERR (CAPX1) ;[7.1120]No, insufficient privileges
> ;End IFN FTOPS20
IFN FTOPS10,<
MOVSI T1,JP.POK ;[7.xxxx]Has POKE, JACCT, or [1,2]
SNCALL (PRVBIT##,MCSEC1) ; privileges?
TRNA ;Yes, proceed
ITERR (LATXPV) ;No, insufficient privileges
> ;End IFN FTOPS10
ENDIF.
; ..
; ..
IFN FTOPS20,<
NOINT ;Don't allow PSI while owning lock
LOCK HN.LOK(Q2) ;Get the lock
CALL @FNCDSP(P2) ;[7.1120]Dispatch to perform the function
IFSKP. ;[7.1120]
UNLOCK HN.LOK(Q2) ;[7.1120]Release data base lock
OKINT ;[7.1120] and allow interrupts
MRETNG ;[7.1120]Return to the user
ELSE. ;[7.1120]
UNLOCK HN.LOK(Q2) ;[7.1120]Release data base lock
OKINT ;[7.1120] and allow interrupts
ITERR () ;[7.1120]Error already reported
ENDIF. ;[7.1120]
MRETNG ;[7.1120]Return to user
> ;End IFN FTOPS20
; For TOPS-10, check the addressability of the show buffer.
;
IFN FTOPS10,<
TXNN P3,LF%SBF ;Is there a show buffer?
IFSKP. ;Yes, then check addressability
UMOVE T1,.LABFA(Q1) ;Get address of show buffer
XCTU [HRRE T2,.LABCT(Q1)] ;Get length of show buffer
SNCALL (ARNGE##,MCSEC1) ;Address check the show buffer
NOP ;Not addressable!
ITERR (LATXAC) ;Not writeable!
ENDIF.
CALL @FNCDSP(P2) ;Dispatch to perform the function
ITERR () ;Error already reported
RETSKP ;Return to the user
> ;End IFN FTOPS10
;[7.1120]LATOP% JSYS dispatch table
DEFINE FNC,<
XALL ;;List generated table
XX .LASET, LASET, LF%PRV , .LAVAL+1 ;; (0) Set host parameters
XX .LACLR, LACLR, LF%PRV , .LAPRM+1 ;; (1) Clear host parameters
XX .LASCH, LASCH, LF%SBF , .LABFA+1 ;; (2) Show characteristics
XX .LASTC, LASTC, LF%SBF , .LABFA+1 ;; (3) Show terminal connects
XX .LASAS, LASAS, LF%SBF , .LAQUA+1 ;; (4) Show adjacent servers
XX .LASCO, LASCO, LF%SBF , .LABFA+1 ;; (5) Show counters
XX .LAZCO, LAZCO, LF%PRV!LF%SBF, .LABFA+1 ;; (6) Zero counters
XX .LARHC, LARHC, LF%PRV , .LADSC+1 ;; (7) Request host-initiated connect
XX .LATHC, LATHC, LF%PRV , .LAPRM+1 ;;(10) Terminate host-initiated connect
XX .LASHC, LASHC, LF%PRV!LF%SBF, .LAQUA+1 ;;(11) Show host-initiated connects
SALL ;;Turn listing back on
> ;End DEFINE FNC
DEFINE XX (CODE,DISP,FLAG,MNSZ),<
XADDR. DISP ; CODE
> ;End DEFINE XX
; Generate function dispatch table
;
FNCDSP: FNC ;[7.1120]
FNCMAX==.-FNCDSP-1 ;[7.1120]Maximum LATOP% JSYS function code
LF%PRV==1B0 ;[7.1120]Privileged function
LF%SBF==1B1 ;[7.1120]Address check show buffer
LF%MSZ==777 ;[7.1120]Minimum size of the argument block
DEFINE XX (CODE,DISP,FLAG,MNSZ),<
EXP FLAG!MNSZ ; CODE
> ;End DEFINE XX
; Generate function flags table
;
FNCDSF: FNC ;[7.1120]
SUBTTL LATOP% JSYS -- Set/Clear Functions -- SSERVC
;LASET - Set LAT host parameters.
;LACLR - Clear LAT host parameters.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LASET/LACLR
; Return+1: Failure, T1/ error code
; Return+2: Success
LASET:
LACLR: UMOVE T1,.LAPRM(Q1) ;Get the parameter number to set/clear.
CAIL T1,MNSPAR ;Range check it
CAILE T1,MXSPAR ; ...
RETBAD (LATX06) ;Parameter number out of range
CAIE P2,.LACLR
IFSKP.
MOVX T3,LF%CLR ;Is this parameter clearable?
TDNN T3,TBFLGS-1(T1) ; ...
RETBAD (LATX07) ;No, return error
HRRZ T2,TBFLGS-1(T1) ;Get the value to clear to
JRST LASET0 ; and go clear it.
ENDIF.
UMOVE T2,.LAVAL(Q1) ;Get the new value to set
MOVX T3,LF%RNG ;Check if this parameter value should
TDNN T3,TBFLGS-1(T1) ; be range checked.
IFSKP. ;Yes
MOVE T3,TBRNGE-1(T1) ;Get the upper and lower ranges.
HRRZ T4,T3 ;Lower bound
HLRZS T3 ;Upper bound
CAML T2,T4
CAMLE T2,T3
RETBAD (LATX02)
ENDIF.
LASET0: HLRZ T3,TBFLGS-1(T1) ;Change flags to set.
ANDI T3,377
IORM T3,HN.FLG(Q2) ;Set them
XCT TBEXEC-1(T1) ;Do the store.
RETSKP
LF%RNG==1B1 ;Do range check on parameter value to set
LF%LOK==1B2 ;Lock the database before setting parameter
LF%CLR==1B3 ;Parameter may be cleared.
MAX. (MXSPAR,<.LPMAC,.LPMCO,.LPNUM,.LPLAS,.LPRLI,.LPTIM,.LPMTI,.LPCOD,.LPNNM,.LPNID,.LPSRV>)
MIN. (MNSPAR,<.LPMAC,.LPMCO,.LPNUM,.LPLAS,.LPRLI,.LPTIM,.LPMTI,.LPCOD,.LPNNM,.LPNID,.LPSRV>)
TBRNGE: BLOCK <MXSPAR-MNSPAR+1>
TBFLGS: BLOCK <MXSPAR-MNSPAR+1>
TBEXEC: BLOCK <MXSPAR-MNSPAR+1>
PARTB. (MAC,CBMAXI,1,^D10,<JRST SETMAC>,LF%RNG!LF%CLR) ;[7.1164]
PARTB. (MCO,NTTLAH,1,NTTLAH,,LF%RNG!LF%CLR)
PARTB. (NUM,177777,0,RTRADR,,LF%RNG!LF%CLR)
PARTB. (LAS,LS.ON,LS.OFF,0,,LF%RNG!<HNOTH_^D18>)
PARTB. (RLI,100,0,^D30,,LF%RNG!LF%CLR)
;[7.xxxx] Remove subroutine SETRTX.
PARTB. (TIM,^D100000,^D100,^D1000,,LF%RNG!LF%CLR) ;[7.1120]
PARTB. (MTI,60,10,^D30,,LF%RNG!LF%CLR!<HNOTH_^D18>)
PARTB. (COD,0,0,0,<JRST SETCOD>,LF%CLR!<HNACS_^D18>)
PARTB. (NNM,0,0,0,<JRST SETNNM>,0)
PARTB. (NID,0,0,0,<JRST SETNID>,LF%CLR!<HNNDD_^D18>)
PARTB. (SRV,0,0,0,<JRST SSERVC>,LF%CLR)
SUBTTL LATOP% JSYS -- SET/CLEAR SERVICE
;SSERVC - Set LAT Service
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL SSERVC
; Return+1: Failure, T1/ error code
; Return+2: Success
SSERVC: SAVEAC <P3,P4>
CALL FNDSRV ;(T1-T4/T1)Find the service to be set/cleared.
RETBAD ()
MOVEM T1,P3 ;Save the service block address
CAIN P2,.LACLR ;Clearing rather than setting?
JRST CSERVC ;Yes.
SETZ P4,0 ;P4 will be used to assemble the change flags
UMOVE T1,.LAQUA(Q1) ;Get the flags and rating
TXNN T1,LA%RAT ;Set the rating?
IFSKP. ;Yes.
TXO P4,HNSVR ;Set rating change flag
HRRE T2,T1
MOVE T3,T2
AOS T2
CAIL T2,0 ;Range check the rating.
CAILE T2,^D256 ; ...
RETBAD () ;Out of range
STOR T3,GBRAT,+TMPGB ;Store the rating
ENDIF.
TXNN T1,LA%DSC ;Set the description?
IFSKP.
TXO P4,HNSVD ;Description change flag
UMOVE T1,.LADSC(Q1) ;Get the user's pointer to description string
IFN FTOPS10,<
SNCALL (CKSTR##,MCSEC1) ;Is the ASCIZ string addressable?
RETBAD (LATXAC) ;No, address check for argument list
> ;End IFN FTOPS10
MOVX T2,<POINT 7,GB.HID+TMPGB>;Where to put it.
MOVEI T3,ML.SID ;Maximum string count
CALL UMVAZS ;(T1-T3/T3)Move the string
RETBAD (LATX06)
STOR T3,GBLC,+TMPGB ;Store the description length
ENDIF.
SKIPN TMPBLK ;Did we add a new service?
IFSKP.
OPSTRM <AOS>,HNNSV,(Q2);Yes.
TXO P4,HNSVN ;Flag that number of services changed
ENDIF.
IORM P4,HN.FLG(Q2) ;Enter the assebled flags
MOVEI T1,GB.LEN ;Move the new service
XMOVEI T2,TMPGB ; to the service block
MOVE T3,P3 ; supplied by FNDSRV.
XBLT. T1
RETSKP
SUBTTL LATOP% JSYS -- Set/Clear Functions -- CSERVC
;CSERVC - Clear LAT service.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL CSERVC
; Return+1: Failure, T1/ error code
; Return+2: Success
CSERVC: MOVE T3,T1 ;Start of overlay
LOAD T1,HNNSV,(Q2) ;Number of services before clear
CAIN T1,1 ;There must always be at least one service
RETBAD(LATX07) ;So return an error.
IMULI T1,GB.LEN ;Total length of service blocks
XMOVEI T4,HN.SRV(Q2) ;Service block start address
ADD T1,T4 ;Address of first word outside service block
XMOVEI T2,GB.LEN(T3) ;First address to move down
SUB T1,T2 ;Number of words to move down
SKIPG T1 ;Is there a service block above?
JRST CSRVC0 ;No so nothing to move
XBLT. T1 ;Compress all blocks downward
CSRVC0: OPSTRM <SOS>,HNNSV,(Q2) ;One service less.
MOVEI T1,HNCLS!HNSVD!HNSVR!HNSVN
IORM T1,HN.FLG(Q2) ;Indicate service changed.
RETSKP
SUBTTL LATOP% JSYS -- Set/Clear Functions -- SETNNM
;SETNNM - Set LAT host name.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL SETNNM
; Return+1: Failure, T1/ error code
; Return+2: Success
SETNNM: OPSTR <SKIPE>,HNNMC,(Q2);Has one already been set?
RETBAD (LATX09) ;Yes, illegal to reset.
UMOVE T1,.LABFA(Q1) ;Node name string pointer from the user.
IFN FTOPS10,<
SNCALL (CKSTR##,MCSEC1) ;Is the ASCIZ string addressable?
RETBAD (LATXAC) ;No, address check for argument list
> ;End IFN FTOPS10
MOVX T2,<POINT 7,TMPBLK>;Pointer to where to build the string.
MOVEI T3,ML.NNM ;Maximum node name count.
CALL UMVAZS ;(T1-T3/T3)Move the ASCIZ string.
RETBAD (LATX06)
STOR T3,HNNMC,(Q2) ;Store the actual string count
MOVEI T1,<ML.NNM+4>/5 ;Maximum number of words in the string
XMOVEI T2,TMPBLK ;Move the string to
XMOVEI T3,HN.NAM(Q2) ; the host node data base
XBLT. T1 ; ...
RETSKP
SUBTTL LATOP% JSYS -- Set/Clear Functions -- SETNID/CLRNID
;SETNID/CLRNID - Set/Clear host identification string.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL SETNID/CLRNID
; Return+1: Failure, T1/ error code
; Return+2: Success
SETNID: CAIN P2,.LACLR ;Clearing rather than setting?
JRST CLRNID ;Yes.
UMOVE T1,.LABFA(Q1) ;Node description string pointer from the user.
IFN FTOPS10,<
SNCALL (CKSTR##,MCSEC1) ;Is the ASCIZ string addressable?
RETBAD (LATXAC) ;No, address check for argument list
> ;End IFN FTOPS10
MOVX T2,<POINT 7,TMPBLK>;Pointer to where to build the string.
MOVEI T3,ML.DSC ;Maximum node description count.
CALL UMVAZS ;(T1-T3/T3)Move the ASCIZ string.
RETBAD (LATX06)
STOR T3,HNIDC,(Q2) ;Store the actual string count
MOVEI T1,<ML.DSC+4>/5 ;Maximum number of words in the string
XMOVEI T2,TMPBLK
XMOVEI T3,HN.ID(Q2)
XBLT. T1
RETSKP
CLRNID: SETZRO HNIDC,(Q2) ;Clear the string count
RETSKP
SUBTTL LATOP% JSYS -- Set/Clear Functions -- SETCOD
; SETCOD - Set/clear access codes
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL SETCOD
; Return+1: Failure, T1/ error code
; Return+2: Success
SETCOD:
IFN FTOPS10,<
UMOVE T1,.LABFA(Q1) ;Get address of string
MOVEI T2,^D8 ;and length
SNCALL (ARNGE##,MCSEC1) ; so check it.
ITERR (LATXAC) ;not there
NOP ;not writeable (that's ok)
> ;End IFN FTOPS10
SAVEAC <P1>
STKVAR <USRPTR,MSKPTR>
SETZM TMPBLK ;Zero out the storage where mask to be built.
XMOVEI T2,TMPBLK ;Zero the first workd
XMOVEI T3,1(T2) ;Address of second word
MOVEI T1,^D7 ;Number of words to zero.
XBLT. T1 ;
UMOVE T1,.LABFA(Q1) ;Group code address in user space.
HRLI T1,441000 ;Make an 8-bit byte pointer
MOVEM T1,USRPTR ;Save it as pointer to user code string.
MOVX T1,<POINT 8,TMPBLK>;Pointer to temporary storage for mask
MOVEM T1,MSKPTR ;Save it too.
MOVEI P1,^D32 ;Number of bytes to do
DO.
XCTBU [ILDB T1,USRPTR];Get a user group code byte
CALL BITSWP ;(T1/T1)Swap the bits
IDPB T1,MSKPTR ;Put into mask words
SOJG P1,TOP. ;Continue for full count
ENDDO.
MOVEI T1,^D8 ;32 bytes is 8 words
XMOVEI T2,AC.COD+7(Q2) ;Address of last group code word in database
DO.
MOVE T3,TMPBLK-1(T1) ;Get a mask word, going backwards
CAIN P2,.LACLR ;Clearing of Setting?
IFSKP.
IORM T3,(T2) ;Set the bits
ELSE.
ANDCAM T3,(T2) ;Clear the bits
ENDIF.
SOS T2
SOJG T1,TOP.
ENDDO.
RETSKP ;Return success.
;BITSWP - Swap all bits in an 8-bit byte.
;
; T1/ Byte to swap
; CALL BITSWP
; Return+1: Always, T1/ Swapped byte
BITSWP: SAVEAC <P1>
JUMPE T1,RTN ;If no bits, don't bother
MOVEI T3,1 ;Bit to test
MOVEI T4,200 ;Mirror bit
SETZ P1, ;Initialize result
DO.
TRNE T1,(T3) ;Is the bit set?
TRO P1,(T4) ;Yes, set mirror bit in result
LSH T3,1 ;Shift bit to test
LSH T4,-1 ; and mirror bit
JUMPN T4,TOP. ;Done?
ENDDO.
MOVE T1,P1 ;Return swapped byte in T1
RET
SUBTTL LATOP% JSYS -- SET MAXIMUM CIRCUITS
;[7.1164] Add routine SETMAC
;SETMAC - Set Maximum Circuits
;Call: T2/ New Maximum Circuits value
; Q2/ Host node data base address
;RETSKP - always
;
; This routine is called when a user issues the SET MAX CIRCUITS
;command to LCP. When it is called, HNMAC has already been range checked.
;It is in the range of 1 - CBMAXI.
SETMAC: STOR T2,HNMAC,(Q2) ;Store the new value
ADDI T2,MAXACB ;HNMXC should be at least HNMAC+MAXACB
OPSTR <CAMG T2,>,HNMXC,(Q2) ;Is it?
IFSKP. ;No, its not
CAILE T2,CBMAXI ;so make sure its not greater than CBMAXI
MOVEI T2,CBMAXI ; (It was, but its not now)
STOR T2,HNMXC,(Q2) ;And update HNMXC
ENDIF. ;
RETSKP ;All done
XRESCD ;[7.1024]
;UMVAZS - Move a user ASCIZ string into monitor space.
;
; T1/ User's string pointer
; T2/ Monitor's destination pointer
; T3/ Maximum string length in bytes
; CALL UMVAZS
; Return+1: Failure, string too long
; Return+2: Success, T3/ Number of bytes moved
UMVAZS: STKVAR <MAXCNT>
MOVEM T3,MAXCNT ;Save the maximum count
SETZ T3, ;Clear the string count
IFN FTOPS20,<
TLC T1,-1 ;Make an ASCII pointer to the
TLCN T1,-1 ; user's buffer
HRLI T1,(<POINT 7,0>) ; if necessary.
> ;End IFN FTOPS20
UMVAZ0: XCTBU [ILDB T4,T1] ;Get a character from his string.
JUMPE T4,RSKP ;Null found so string ended
CAML T3,MAXCNT ;If we are at the maximum, read no more.
RET
IDPB T4,T2 ;Deposit character in temp storage.
AOJA T3,UMVAZ0 ;Increment string count
ENDSV.
;MMVAZS - Move ASCIZ string within monitor context
;Call: T1/ Source ASCIZ Pointer
; T2/ Destination Pointer
; T3/ Maximum string count permitted
;RET - If string longer than maximum, truncated.
; T3/ Actual string count
MMVAZS: STKVAR <MAXCNT>
MOVEM T3,MAXCNT ;Save the maximum count
SETZ T3, ;Clear the string count
IFN FTOPS20,<
TLC T1,-1 ;[7.1039]Make an ASCII pointer to the
TLCN T1,-1 ;[7.1039] user's buffer
HRLI T1,(<POINT 7,0>) ;[7.1039] if necessary.
> ;End IFN FTOPS20
MMVAZ0: ILDB T4,T1 ;Get a character from his string.
JUMPE T4,RTN ;Null found so string ended
CAML T3,MAXCNT ;If we are at the maximum, read no more.
RET
IDPB T4,T2 ;Deposit character at destination
AOJA T3,MMVAZ0 ;Increment string count
ENDSV.
SUBTTL LATOP% JSYS -- Show Characteristics of Host
XSWAPCD ;[7.1024]
;LASCH - Show LAT host characteristics.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LASCH
; Return+1: Failure, T1/ error code
; Return+2: Success
LASCH: SAVEAC <P1,P2,P3>
UMOVE T3,.LABFA(Q1) ;User buffer address
;Check to see if the user provided buffer is large enough for all the data
;
LOAD T1,HNNSV,(Q2) ;Compute the total buffer size
IMULI T1,GB.LEN ; required.
ADDI T1,<HN.MXC-HN.MTI+<ML.LOC+3>/4+<ML.DSC+3>/4+<ML.NNM+3>/4+^D16>
CALL UBFCHK ;[7.1039](T1,Q1/T1)Is user's buffer big enough?
RETBAD () ;[7.1039]No, too small
;Move fixed length dynamic parameters from the host node database (HN) to the
;user's buffer.
;
MOVEI T1,<HN.MTI-HN.MXC+1>;Number words to move
XMOVEI T2,HN.MXC(Q2) ;Address of first HN parameter to move
XBLTXU T1
;Move static parameters to the user's buffer.
;
MOVEI T1,5 ;Number of words to move
XMOVEI T2,[EXP <LAHPV,,LALPV>;Static parameter address
EXP <PROECO,,PROVER>
EXP <MXSLSI,,MXSLTS>
EXP <LMRFSI,,MXHSRV>
EXP <LHPRID,,0>]
XBLTXU T1
;Move the access code words
;
MOVEI P3,^D32 ;Number of bytes for the access codes
XMOVEI P2,AC.COD(Q2) ;Address of the access codes
TXO P2,<OWGP. 8,0> ;Make global pointer
MOVE P1,T3 ;Current address in user's buffer.
TXO P1,<OWGP. 8,0> ;Make a byte pointer
DO.
ILDB T1,P2 ;Get a byte for group codes
CALL BITSWP ;(T1/T1)Swap the bits
XCTBU [IDPB T1,P1] ;Deposit swapped byte into user buffer.
SOJG P3,TOP. ;Do all bytes
HRRZI T3,1(P1) ;Make user pointer an address again.
ENDDO.
;Move Host node name and host node description
;
MOVEI T1,<<ML.NNM+4>/5+<ML.DSC+4>/5+1> ;[7.1039]
XMOVEI T2,HN.NMC(Q2) ;[7.1039]Address of node name and description
XBLTXU T1 ;[7.1039]
;Move the service blocks
;
LOAD T1,HNNSV,(Q2) ;Number of services currently defined
UMOVEM T1,(T3) ;Move to user buffer
AOS T3 ;Advance buffer address
LOAD T1,HNNSV,(Q2) ;Get the size of the
IMULI T1,GB.LEN ; service blocks.
XMOVEI T2,HN.SRV(Q2) ;Address of service blocks
XBLTXU T1
RETSKP
SUBTTL LATOP% JSYS -- Show Terminal Connects
;LASTC - Show terminal connects.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LASTC
; Return+1: Failure, T1/ error code
; Return+2: Success
;[7.1039]Clean up register usage in LASTC/LAS1C
LASTC: SAVEAC <P1,P2,P3>
STKVAR <LTTCNT>
LOAD T1,HNCON,(Q2) ;How many do we think are connected?
MOVE P1,T1 ;Save count
XMOVEI P3,LAS1C ;[7.1120]Get routine to handle old connect blk
MOVEI T3,MW.OCB ;[7.1120]Initialize T3 with old size
UMOVE T2,.LABCT(Q1) ;[7.1120]Get the ECB flag
TXNN T2,LA%ECB ;[7.1120]Is it set?
IFSKP. ;[7.1120]Yes, so...
XMOVEI P3,LAS2C ;[7.1120] get routine to handled new
MOVEI T3,MW.ECB ;[7.1120] connect block and use new size.
ENDIF. ;[7.1120]
IMUL T1,T3 ;[7.1120]Calculate buffer space requirements
CALL UBFCHK ;[7.1039](T1,Q1/T1)Is his buffer big enough?
RETBAD () ;[7.1039]No, too small
MOVEI T1,NTTLAH ;Get size of SBvect
MOVEM T1,LTTCNT ;Save in local for decrementing
UMOVE T3,.LABFA(Q1) ;Get user's buffer address
MOVE P2,SBVECT ;Point to table of SBs
LASTCL: SKIPE T1,1(P2) ;Is there a slot block there?
CALL 0(P3) ;[7.1120](T1,T3/T3)Yes-move data to user buffer
JRST LASTCN ;No, go for next one
SOJLE P1,LASTCD ;Have we given the user as many as we said?
LASTCN: SOSLE LTTCNT ;Or have we exhausted SBVECT?
AOJA P2,LASTCL ;No, just go for next data block
LASTCD: UMOVE T1,.LABFA(Q1) ;Done, get address of show buffer again
SUB T3,T1 ;Calculate number of words moved
XCTU [HRLM T3,.LABCT(Q1)] ;and store it.
RETSKP ;And give good return
;LAS1C - Move one connect block to the user's show buffer.
;
; T1/ Slow block address
; T3/ Next address in the show buffer
; CALL LAS1C
; Return+1: Failure, no attached terminal or circuit block
; Return+2: Success, T3/ Updated address into show buffer
LAS1C:
IFN FTOPS20,<
SKIPE T2,SB.TDB(T1) ;Any LDB associated with slot?
SKIPN T4,SB.CBA(T1) ;Any circuit block?
RET ;No, skip this one
DYNST ;Get TTY line number (in T2)
> ;End IFN FTOPS20
IFN FTOPS10,<
SKIPE U,SB.TDB(T1) ;Any LDB associated with slot?
SKIPN T4,SB.CBA(T1) ;Any circuit block?
RET ;No, skip this one
LDB T2,@[IW MCSEC1,LDPLNO##] ;Get TTY line number
> ;End IFN FTOPS10
OPSTR <HRLZ T1,>,CBRSC,(T4) ;Get server name string count
UMOVEM T2,0(T3) ;Give the TTY line number to the user
UMOVEM T1,1(T3) ;Store counts
ADDI T3,2 ;Two words have been moved
MOVEI T1,<<ML.SYS+4>/5> ;Get length of string
XMOVEI T2,CB.SNM(T4) ;Source name string
XBLTXU T1 ;Fill in the user's buffer
RETSKP
;LAS2C - Move one extended connect block to the user's show buffer.
;[7.1120]
; T1/ Slow block address
; T3/ Next address in the show buffer
; CALL LAS2C
; Return+1: Failure, no attached terminal or circuit block
; Return+2: Success, T3/ Updated address into show buffer
LAS2C: MOVE T4,T1 ;Stash the SB address here
IFN FTOPS20,<
SKIPE T2,SB.TDB(T4) ;Any LDB associated with slot?
SKIPN SB.CBA(T4) ;Any circuit block?
RET ;No, skip this one
DYNST ;Get TTY line number (in T2)
> ;End IFN FTOPS20
IFN FTOPS10,<
SKIPE U,SB.TDB(T4) ;Any LDB associated with slot?
SKIPN SB.CBA(T4) ;Any circuit block?
RET ;No, skip this one
LDB T2,@[IW MCSEC1,LDPLNO##] ;Get TTY line number
> ;End IFN FTOPS10
UMOVEM T2,0(T3) ;Give the TTY line number to the user
MOVEI T2,.LATTY ;Assume standard tty
OPSTR <SKIPE>,SBDLP,(T4);Is this a dialup?
MOVEI T2,.LADLP ;Maybe, if it isn't an application terminal...
OPSTR <SKIPE>,SBPRA,(T4);Is it an application terminal?
MOVEI T2,.LAAPP ;Yes
OPSTR <HRL T2,>,SBSRC,(T4) ;Get server name string count
UMOVEM T2,1(T3) ;Store counts
ADDI T3,2 ;Two words have been moved
MOVEI T1,<<ML.SYS+4>/5> ;Get length of string
XMOVEI T2,SB.SRN(T4) ;Source name string
XBLTXU T1 ;Fill in the user's buffer
OPSTR <HRL T2,>,SBPRC,(T4) ;Get the port name count
OPSTR <HRR T2,>,SBSVC,(T4) ;Get the service name count
UMOVEM T2,0(T3) ;Give these counts to the user
AOS T3 ;Another word has been moved
MOVEI T1,<<ML.SYS+4>/5>*2 ;Get length of the string
XMOVEI T2,SB.PRN(T4) ;Port/service name strings
XBLTXU T1 ;Fill in the user's buffer
RETSKP
SUBTTL LATOP% JSYS -- Show Adjacent Servers
;LASAS - Show adjacent servers.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LASAS
; Return+1: Failure, T1/ error code
; Return+2: Success
LASAS: CAIL P1,.LAQUA+1 ;[7.1120]
XCTU [SKIPN T1,.LAQUA(Q1)] ;Is there a server name?
IFSKP. ;Yes, return information for that one
IFN FTOPS20,<
CALL MAKPTR ;(T1/T1)Make a valid ASCIZ pointer.
>
IFN FTOPS10,<
SNCALL (CKSTR##,MCSEC1) ;Is the ASCIZ string addressable?
RETBAD (LATXAC) ;No, address check for argument list
> ;End IFN FTOPS10
CALL GTSRVR ;(T1,Q2/T1)Find circuit block by server name.
RETBAD () ;Unknown server
MOVE T4,T1 ;Save the circuit block address
MOVEI T1,<SASEND-SASBEG>;# words returned for single server
CALL UBFCHK ;[7.1039](T1,Q1/T1)Is user's buffer big enough?
RETBAD () ;No, too small
UMOVE T3,.LABFA(Q1) ;Get his buffer address
XMOVEI T2,SASBEG(T4) ;Address of source
XBLTXU T1 ;Move to user space
RETSKP ;Return successfully.
ENDIF.
LOAD T1,HNNCC,(Q2) ;Get the number of allocated circuit blocks
IMULI T1,<<<ML.SYS+4>/5>+3>;Compute space needed in user's buffer
CALL UBFCHK ;[7.1039](T1,Q1/T1)Is user's buffer big enough?
RETBAD () ;[7.1039]No, too small
UMOVE T3,.LABFA(Q1) ;Get user buffer address
MOVE T4,HN.QAC(Q2) ;First element on the active queue
CALL SASLP ;Get all those on the active queue
MOVE T4,HN.QIC(Q2) ;Do the same for
CALL SASLP ; the inactive queue.
RETSKP ;Return successfully.
SASLP: JUMPE T4,RTN ;No more circuit blocks on this queue
MOVE T1,CB.RSC(T4) ;get <number,,name count>
UMOVEM T1,(T3) ;Give it to user
ADDI T3,1 ;Bump destination address
MOVEI T1,<<ML.SYS+4>/5> ;There are 4 words of name
XMOVEI T2,CB.SNM(T4) ;Address of first to copy
XBLTXU T1 ;Copy to user's space
DMOVE T1,CB.DNI(T4) ;Get Ethernet address
XCTU [DMOVEM T1,(T3)] ;Give it to the user
ADDI T3,2 ;Account for those words
LOAD T4,QLFWD,+CB.LNK(T4);Get the next CB
JRST SASLP ;And continue looping thru queue
SUBTTL LATOP% JSYS -- Show Counters
;LASCO - Show LAT Counters.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LASCO
; Return+1: Failure, T1/ error code
; Return+2: Success
LASCO: UMOVE T1,.LAQUA(Q1) ;Get server name requested
CALL GTLCOB ;(T1/T1,T2)Get counter block given server name.
RET ;Error, already reported
XCTU [HRLM T1,.LABCT(Q1)];Tell user
XCTU [HRRZ T3,.LABCT(Q1)];Get his buffer count.
CAMGE T3,T1 ;Has user allocated large enough buffer?
RETBAD (LATX01) ;No
UMOVE T3,.LABFA(Q1) ;Get his buffer address
XBLTXU T1
RETSKP
SUBTTL LATOP% JSYS -- Zero counters
;LAZCO - Zero LAT Counters.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LAZCO
; Return+1: Failure, T1/ error code
; Return+2: Success
LAZCO: UMOVE T1,.LAQUA(Q1) ;Get server name requested
CALL GTLCOB ;(T1/T1,T2)Get counter block given server name.
RET ;Error, already reported
SETZM (T2) ;Zero the first counter
XMOVEI T3,1(T2) ;
SOSLE T1 ;Compute number of words to zero
XBLT. T1 ;Zero the block
RETSKP ;Return successfully.
;GTLCOB - Get LAT Counter Block. Get the length and address of the LAT
; counter block based on server number.
;CALL: T1/ Pointer to server name or [0,,-1]
;RET: Error - server unknown
;RETSKP:Success with
; T1/ Counter block length in words
; T2/ Counter block address
GTLCOB: XCTU [SKIPN T1,.LAQUA(Q1)] ;[7.1039]Get server name requested
IFSKP. ;Zero a particular server's counters
IFN FTOPS20,<
CALL MAKPTR ;(T1/T1)Make a valid pointer
>
IFN FTOPS10,<
SNCALL (CKSTR##,MCSEC1) ;Check to see if ASCIZ string is addressable
RETBAD (LATXAC) ;Nope, lose
>;end ifn FTOPS10
CALL GTSRVR ;(T1,Q2/T1)Find circuit block given server name
RETBAD () ;Unknown server
XMOVEI T2,CC.BEG(T1) ;Server counter block address
MOVEI T1,CC.LEN ;Server counter block length
ELSE. ;Local host counters wanted
MOVEI T1,HC.LEN ;Host counter block length
XMOVEI T2,HC.BEG(Q2) ;Host counter block address
ENDIF.
RETSKP
SUBTTL LATOP% JSYS -- Request Host-Initiated Connect
;[7.1120]
;LARHC - Request host-initiated connect.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LARHC
; Return+1: Failure, T1/ error code
; Return+2: Success
LARHC: MOVEI T1,PR.LEN ;Length of the pending request block
CALL MMGTZW ;(T1/T1)Allocate memory
RETBAD (LATX08) ;Error, insufficient LAT resources
MOVEM T1,P2 ;Save address of pending request block
CALL CKRHC ;(Q1,Q2,P1,P2)Check the arguments
IFSKP.
LOAD T1,PRCID,(P2) ;Save the connect id
XCTU [HRRM T1,.LAPRM(Q1)]
OPSTR <SKIPN>,PRWAI,(P2) ;Wait for the connection?
RETSKP ;Return (PSI interrupt on connection)
MOVE T1,P2 ;Get address of pending request block
CALL PRWAIT ;(T1)Wait for the connection
MOVE T1,P2 ;Get address of pending request block
LOAD T2,PRSTS,(P2) ;Return with status, rejection code,
UMOVEM T2,.LAVAL(Q1) ; or Terminal Designator
IFN FTOPS20,<
TXNE T2,.TTDES ;Did the connection succeed?
> ;End IFN FTOPS20
IFN FTOPS10,<
CAIL T2,.UXTRM ;
CAILE T2,.UXTRM+777 ;Did the connection succeed?
TRNA ;No, SKIP
> ;End IFN FTOPS10
RETSKP ;Yes - the connection succeeded.
SETZ T2, ;Here if it failed... Clear T2
XCTU [HRRM T2,.LAPRM(Q1)] ;Connect ID is invalid
CALL PRDEL ;Delete the pending request
RETSKP ;Return
ENDIF.
EXCH T1,P2 ;Save the error code and get the
; address of the pending request block
CALL PRDEL ;(T1)Delete the pending request block
MOVE T1,P2 ;Restore the error code
RETBAD () ;
;[7.1120]
;CKRHC - Check the .LARHC argument list and fill in the pending request block.
; This subroutine does almost all of the work for the routine LARHC so
; that LARHC can easily deallocate resources if an error occurs.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ Address of the pending request block
; CALL CKRHC
; Return+1: Failure, T1/ error code
; Return+2: Success
CKRHC: MOVX T1,.LASOL ;Initialize status to "Soliciting"
STOR T1,PRSTS,(P2) ;
UMOVE T3,.LAPRM(Q1) ;Get the parameter word
SETO T1, ;
TXNE T3,LA%QUE ;Should the server queue this request?
STOR T1,PRQUE,(P2) ;Yes, set this bit
IFN FTOPS20,<
SAVEAC <P3> ;Get an AC
MOVE P3,T3 ;Save user's parm's here
MOVE T2,JOBNO ;Get my job number
STOR T2,PRJOB,(P2) ;Save it here
MOVE T2,FORKX ;Get my fork number
STOR T2,PRFRK,(P2) ;Save it here
TXNN T3,LA%PSI ;Using the interrupt system?
IFSKP.
LDB T2,[POINTR (T3,LA%CHN)]
STOR T2,PRPSI,(P2) ;Save the interrupt channel
ELSE.
STOR T1,PRWAI,(P2) ;Save the event wait flag
ENDIF.
> ;End IFN FTOPS20
IFN FTOPS10,<
TXNE T3,LA%WAI ;Is the wait bit set?
STOR T1,PRWAI,(P2) ;Yes, set the event wait flag
MOVE T2,.CPJCH## ;Save the JCH
STOR T2,PRFRK,(P2) ;
ANDI T2,JOBMSK## ;Save the job number
STOR T2,PRJOB,(P2) ;
> ;End IFN FTOPS10
; ..
; ..
; Get the server name, service name, and port name.
;
CALL MVRHC ;(Q1,P1,P2)Move the ASCIZ strings
RETBAD () ;Error, return
OPSTR <SKIPG>,PRSRC,(P2) ;Is there a server name?
RETBAD (LATX04) ;No, invalid or unknown server name
LOAD T1,PRSVC,(P2) ;Get the length of the service name
LOAD T2,PRPRC,(P2) ;Get the length of the port name
SKIPN T1 ;Is there a service name
SKIPE T2 ; or port name?
TRNA ;Yes, all is well
RETBAD (LATX07) ;No, invalid or unknown service name
; Format the Solicit Information message.
;
CALL PRGET ;(/T1)Get a free PRVECT index number
RETBAD (LATX08) ;Error, insufficient LAT resources
STOR T1,PRCID,(P2) ;Save the PRVECT index number
MOVX T1,SBF.OF+<ML.HCM+4>/5 ;Get max length of a command msg
CALL MMGTZW ;(T1/T1)Allocate space for one
RETBAD (LATX08) ;Error, insufficient LAT resources
STOR T1,PRXBA,(P2) ;Save address of transmit buffer
MOVE T1,P2 ;Copy the address of pending request block
CALL FMSIN ;(T1)Format Solicit Information message
RETBAD () ;Error, return
MOVX T1,SS.SIN ;Change to Soliciting Information state
STOR T1,PRSTA,(P2) ; (need the Ethernet address)
LOAD T1,PRCID,(P2) ;Get the PRVECT index number
ANDI T1,PR.NDX ;Throw away the random portion
IFN FTOPS20,<
TXNE P3,LA%PSI ;Does the user want to block?
IFSKP.
MOVE T2,T1 ;Yes, don't destroy T1 (index into PRVECT)
IDIVI T2,^D36 ;Calculate the offset T2,
MOVE T3,BITS(T3) ; and the bit in T3
IORM T3,PRWMSK(T2) ;Set it now, so scheduler test will block
ENDIF.
> ;End IFN FTOPS20
ADD T1,PRVECT ;Calculate address of PRVECT entry
MOVEM P2,(T1) ;Save address of slot block
RETSKP ;
;[7.1120]
;MVRHC - Move the string values for the routine CKRHC.
;
; Q1/ User argument block address
; P1/ Length of user argument block
; P2/ Address of the pending request block
; CALL MVRHC
; Return+1: Failure, T1/ error code
; Return+2: Success
MVRHC: SAVEAC <P3> ;Save P3
MOVN P3,P1 ;
CAILE P1,.LAPRT+1 ;Too many arguments specified?
MOVNI P3,.LAPRT+1 ;Yes, use the maximum
ADDI P3,.LASVR ;Calculate the negative number of strings
HRLZS P3 ;Make it an AOBJN pointer
; Loop for each of the ASCIZ strings specified.
;
MVRHC1: MOVEI T1,.LASVR(P3) ;Calculate the address
ADD T1,Q1 ; of the ASCIZ string pointer
XCTU [SKIPN T1,(T1)] ;Get the string pointer itself
JRST MVRHC2 ;None, try the next one
IFN FTOPS20,<
TLNN T1,777777 ;Is it a valid byte pointer?
JRST MVRHC3 ;No, invalid or unknown name
> ;End IFN FTOPS20
IFN FTOPS10,<
TLNN T1,777777 ;Is it a valid byte pointer?
TXO T1,<POINT 7> ;No, make it a valid byte pointer
SNCALL (CKSTR##,MCSEC1) ;(T1)Is this string addressable?
RETBAD (LATXAC) ;No, address check for argument list
> ;End IFN FTOPS10
XMOVEI T2,(P2) ;Calculate the destination address
ADD T2,RHCDST(P3) ;Make it a global byte pointer
MOVE T3,RHCMXL(P3) ;Get the maximum length
CALL UMVAZS ;(T1,T2,T3/T3)Move the ASCIZ string
JRST MVRHC3 ;Error, invalid or unknown name
XCT RHCXCT(P3) ;Save the length of the string
MVRHC2: AOBJN P3,MVRHC1 ;Save all of the ASCIZ strings
RETSKP ;
; Come here to return with an invalid or unknown name error.
;
MVRHC3: MOVE T1,RHCERR(P3) ;Return with appropriate error code
RET
;[7.1120] Table of destination byte pointers
;
RHCDST: OWGP. 7,PR.SRN ;Server name
OWGP. 7,PR.SVN ;Service name
OWGP. 7,PR.PRN ;Port name
; Table of maximum lengths
;
RHCMXL: EXP ML.SRN ;Server name
EXP ML.SVN ;Service name
EXP ML.PRN ;Port name
; Table of instructions to save the byte count
;
RHCXCT: STOR T3,PRSRC,(P2) ;Server name
STOR T3,PRSVC,(P2) ;Service name
STOR T3,PRPRC,(P2) ;Port name
; Table of error codes if the name is invalid
;
RHCERR: EXP LATX04 ;Invalid or unknown server name
EXP LATX07 ;Invalid or unknown service name
EXP LATX10 ;Invalid or unknown port name
;[7.1120]
;PRGET - Get a free PRVECT index number.
;
; CALL PRGET
; Return+1: Failure, insufficient resources
; Return+2: Success, T1/ PRVECT index number
PRGET: MOVSI T3,-PRBITN ;Look for a free PR block index
IFN FTOPS10,<UUOLOK ;Get the interlock: one user at a time>
PRGET1: SKIPE T1,PRBITS(T3) ; by examining the free PR block words
JFFO T1,PRGET2 ; for the first 1 bit. This represents
AOBJN T3,PRGET1 ; the first free PR block index.
IFN FTOPS10,<UUONLK ;Give up the interlock>
RET ;No PR blocks available
PRGET2: MOVE T1,BITS(T2) ;Clear the bit since the index is
ANDCAM T1,PRBITS(T3) ; no longer free.
IFN FTOPS10,<UUONLK ;Give up the interlock>
HRRZ T1,T3 ;Compute the PR block index,
IMULI T1,^D36 ; which must be greater than zero.
ADDI T1,1(T2) ;
CAILE T1,PRMAXI ;Larger than the maximum?
RET ;Yes, insufficient resources
MOVE T3,T1 ;Copy the index number
ADD T3,PRRAND ;Get address of random number
AOS T2,(T3) ;Get the next random number
ANDI T2,PR.RAN ;Perform modulo arithematic
JUMPG T2,PRGET3 ;Non-zero: use it in the connect id
AOS (T3) ;Get the next random number
AOS T2 ;Wrap around to one
PRGET3: DPB T2,[POINTR (T1,PR%RAN)] ;Fill in the ranom portion
RETSKP ;
XRESCD ;[7.1120]
;[7.1120]
;PRREL - Release a PRVECT index number.
;
; T1/ PRVECT index number
; CALL PRREL
; Return+1: Always
PRREL: ANDI T1,PR.NDX ;Throw away the random portion
JUMPE T1,RTN ;Zero left: return
MOVE T2,T1 ;Copy the index number
ADD T2,PRVECT ;Get address of PRVECT entry
SETZM (T2) ;Clear the address
SOS T1 ;PRVECT index numbers start with one
IDIVI T1,^D36 ;Get the PRBITS index and bit number
MOVE T2,BITS(T2) ;Get a bit to set with
IORM T2,PRBITS(T1) ;Set the bit to indicate that it is free
RET ;
;[7.1120]
;PRDEL - Delete a PRVECT entry.
;
; T1/ Address of pending request block
; CALL PRDEL
; Return+1: Always
PRDEL: SAVEAC <P1> ;
MOVE P1,T1 ;Save address of pending request block
OPSTR <SKIPN T1,>,PRSBA,(P1) ;Is there a slot block?
IFSKP. ;
BUG. (CHK,LATIPR,LATSER,SOFT,<LAT Invalid PR block>,<<P1,PRBLOK>,<T1,SBBLOK>>,<
Cause: A Pending Request block was about to be deleted that still had a
Slot block attached to it.
>)
ENDIF.
OPSTR <SKIPE T1,>,PRCID,(P1) ;Is there a PRVECT index number?
CALL PRREL ;(T1)Yes, release it
OPSTR <SKIPN T1,>,PRXBA,(P1) ;Is there a transmit buffer?
IFSKP.
MOVX T2,DLL.FL ;
EXCH T2,UNUID+UNB.OF(T1) ;Clear the "Keep me" bit
TXNN T2,DLL.FL ;Is this buffer inside NI service?
CALL MMFREE ;(T1)No, release this buffer
ENDIF.
MOVE T1,P1 ;
CALLRET MMFREE ;(T1)Deallocate the slot block
;[7.1120]
;FMSIN - Format a Solicit Information message.
;
; T1/ Address of pending request block
; CALL FMSIN
; Return+1: Failure, T1/ Error code
; Return+2: Success
FMSIN: SAVEAC <P1,P2,P3> ;
MOVE P1,T1 ;Save address of pending request block
LOAD P2,PRXBA,(P1) ;Get address of transmit buffer
SKIPN P3,LAHNDB ;Get address of host node (HN) table
RETBAD (LATX03) ;Error, LAT is not operational
SETZ T3, ;Initialize the byte count
XMOVEI T4,SBF.OF(P2) ;Get address of transmit buffer
TXO T4,<OWGP. 8,0> ;Make it a global byte pointer
STOR T4,UNBFA,+UNB.OF(P2) ;Save the byte pointer
; Build the fixed portion of the message.
;
MOVX T1,MT.SIN_2 ;Message type = Solicit Information
; (RM bits = 0) protocol format = 0
CALL MVBY2 ;(T1,T3,T4/T3,T4)
MOVX T1,LALPV_10+LAHPV ;Hishest protocol version and
; lowest procotol version
CALL MVBY2 ;(T1,T3,T4/T3,T4)
MOVX T1,PROECO_10+PROVER;Current protocol version and
; current protocol ECO level
CALL MVBY2 ;(T1,T3,T4/T3,T4)
MOVX T1,LMRFSI+^D14 ;Data link receive frame size
CALL MVBY2 ;(T1,T3,T4/T3,T4)
LOAD T1,PRCID,(P1) ;Use PRVECT index number
; as the solicit identifier
CALL MVBY2 ;(T1,T3,T4/T3,T4)
LOAD T1,HNCMT,(P3) ;Get the response timer
IDIVI T1,^D1000 ;[7.xxxx]Convert to seconds
CALL MVBY2 ;(T1,T3,T4/T3,T4)
; ..
; ..
LOAD T1,PRSRC,(P1) ;Get the server name count
XMOVEI T2,PR.SRN(P1) ;Get address of server name string
TXO T2,<OWGP. 7,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put string in message
LOAD T1,ACLNG,(P3) ;Get the length of the group code
XMOVEI T2,AC.COD(P3) ;Get address of group code
TXO T2,<OWGP. 8,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put it in the string
LOAD T1,HNNMC,(P3) ;Get the host name count
XMOVEI T2,HN.NAM(P3) ;Get address of the host name
TXO T2,<OWGP. 7,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put string in message
LOAD T1,PRSVC,(P1) ;Get the service name length
XMOVEI T2,PR.SVN(P1) ;Get address of service name
TXO T2,<OWGP. 7,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put string in message
SETZ T1, ;
IDPB T1,T4 ;No parameters specified
ADDI T3,1 ;Update the length of the message
STOR T3,UNBSZ,+UNB.OF(P2) ;Save the length of the message
DMOVE T1,[BYTE (8) 11,00,53,00,00,17,00,00]
OPSTRM <DMOVEM T1,>,UNDAD,+UNB.OF(P2) ;Store multicast address
RETSKP ; (09-00-2B-00-00-0F)
;[7.1120]
;FMSAC - Format a Solicit Access message.
;
; T1/ Address of pending request block
; CALL FMSAC
; Return+1: Failure, T1/ Error code
; Return+2: Success
FMSAC: SAVEAC <P1,P2,P3> ;
MOVE P1,T1 ;Save address of pending request block
LOAD P2,PRXBA,(P1) ;Get address of transmit buffer
SKIPN P3,LAHNDB ;Get address of host node (HN) table
RETBAD (LATX03) ;Error, LAT is not operational
SETZ T3, ;Initialize the byte count
XMOVEI T4,SBF.OF(P2) ;Get address of transmit buffer
TXO T4,<OWGP. 8,0> ;Make it a global byte pointer
STOR T4,UNBFA,+UNB.OF(P2) ;Save the byte pointer
; Build the fixed portion of the command message.
;
MOVX T1,MT.CMD_2 ;Message type = Command Message
; (RM bits = 0) protocol format = 0
CALL MVBY2 ;(T1,T3,T4/T3,T4)
MOVX T1,LALPV_10+LAHPV ;Highest protocol version and
; lowest protcol version
CALL MVBY2 ;(T1,T3,T4/T3,T4)
MOVX T1,PROECO_10+PROVER;Current protocol version and
; current protocol ECO level
CALL MVBY2 ;(T1,T3,T4/T3,T4)
MOVX T1,LMRFSI+^D14 ;Data link receive frame size
CALL MVBY2 ;(T1,T3,T4/T3,T4)
LOAD T1,PRCID,(P1) ;Use PRVECT index number
; as the request number
CALL MVBY2 ;(T1,T3,T4/T3,T4)
SETZ T1,0 ;Entry identifier = 0
CALL MVBY2 ;(T1,T3,T4/T3,T4)
MOVX T1,1 ;Solicit non-queued access and no status
OPSTR <SKIPE>,PRQUE,(P1) ;Do we want queued access?
MOVX T1,2_10+2 ;Solicit queued access and send status
; every time the queue depth changes
CALL MVBY2 ;(T1,T3,T4/T3,T4)
; ..
; ..
; Fill in the first part of the object information: the server name.
;
LOAD T1,PRSRC,(P1) ;Get the server name count
XMOVEI T2,PR.SRN(P1) ;Get address of server name string
TXO T2,<OWGP. 7,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put string in message
; Fill in the subject information.
;
LOAD T1,ACLNG,(P3) ;Get the length of the group code
XMOVEI T2,AC.COD(P3) ;Get address of group code
TXO T2,<OWGP. 8,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put string in message
LOAD T1,HNNMC,(P3) ;Get the host name count
XMOVEI T2,HN.NAM(P3) ;Get address of the host name
TXO T2,<OWGP. 7,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put string in message
SETZ T1, ;
IDPB T1,T4 ;There is no subject port name
IDPB T1,T4 ;There is no subject description name
ADDI T3,2 ;Update the length of the message
; Fill in the object information.
;
LOAD T1,PRSVC,(P1) ;Get the service name length
XMOVEI T2,PR.SVN(P1) ;Get address of service name
TXO T2,<OWGP. 7,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put string in message
LOAD T1,PRPRC,(P1) ;Get the port name length
XMOVEI T2,PR.PRN(P1) ;Get address of port name
TXO T2,<OWGP. 7,0> ;Make it a global byte pointer
CALL MVSTC ;(T1-T4/T3,T4)Put string in message
SETZ T1, ;
IDPB T1,T4 ;No parameters specified
ADDI T3,1 ;Update the length of the message
STOR T3,UNBSZ,+UNB.OF(P2) ;Save the length of the message
OPSTR <DMOVE T1,>,PRDNI,(P1) ;Use the correct Ethernet address
OPSTRM <DMOVEM T1,>,UNDAD,+UNB.OF(P2)
RETSKP ;
;[7.1120]
;FMCAN - Change the Solicit Access to a Cancel Entry message.
;
; T1/ Address of pending request block
; CALL FMCAN
; Return+1: Failure, no entry id
; Return+2: Success
FMCAN: SAVEAC <P1,P2> ;
MOVE P1,T1 ;Save address of slot block
OPSTR <SKIPE T1,>,PREID,(P1) ;Is there an entry id?
OPSTR <SKIPN P2,>,PRXBA,(P1) ;Is there a transmit buffer?
RET ;No, no Status messages received
XMOVEI T3,<SBF.OF>(P2) ;[7.1150]Get address of transmit buffer
TXO T3,<OWGP. 8,0> ;[7.1150]Make it a global byte pointer
MOVEI T4,MT.EID ;[7.1150]Get the offset to the entry id
ADJBP T4,T3 ;[7.1150]Point there
CALL MVBY2 ;(T1,T3,T4/T3,T4)Put entry-id in message
MOVX T3,3 ;[7.1150]Command type = Cancel
IDPB T3,T4 ;[7.1150]Put it in the message
RETSKP ;
;[7.1120]
;MVSTC - Move a counted string (including the byte count).
;MVSTR - Move a counted string.
;
; T1/ Source count
; T2/ Source byte pointer
; T3/ Destination count
; T4/ Destination byte pointer
; CALL MVSTC or MVSTR
; Return+1: Always
; T3/ Destination count
; T4/ Destination byte pointer
MVSTC: IDPB T1,T4 ;Put the byte count in the message
ADDI T3,1 ;Update the length of the message
MVSTR: SAVEAC <P1> ;
MVSTR1: SOJL T1,RTN ;Negative: finished
ILDB P1,T2 ;Get the next character
IDPB P1,T4 ;Put it in the message
AOJA T3,MVSTR1 ;Count this character and continue
;[7.1120]
;MVBY2 - Move two bytes (LO first).
;
; T1/ Source
; T3/ Destination count
; T4/ Destination byte pointer
; CALL MVBY2
; Return+1: Always
; T3/ Destination count
; T4/ Destination byte pointer
MVBY2: IDPB T1,T4 ;Save the LO byte first
LSH T1,-^D8 ;Shift the HO byte into position
IDPB T1,T4 ;Save the HO byte
ADDI T3,2 ;Update the byte count
RET ;
;[7.1120]
IFN FTOPS20,<
RESCD
LATST:: IDIVI T1,^D36 ;Bit number in T1: Calculate the offset in T1
MOVE T2,BITS(T2) ; and the bit number in T2.
TDNE T2,PRWMSK(T1) ;Skip if bit clear
RET ;Keep sleeping
RETSKP ;Wake user
> ;End IFN FTOPS20
XRESCD
;[7.1120]
;PRWAIT - Wait for a connection.
;
; T1/ Address of pending request block
; CALL PRWAIT
; Return+1: Always
PRWAIT:
IFN FTOPS20,<
LOAD T2,PRSTS,(T1) ;Get the status of the connection
CAIE T2,.LASOL ;Is it being solicited
CAIN T2,.LAQUE ; or queued?
TRNA ;Yes, go ahead.
RET ;No, return
LOAD T2,PRCID,(T1) ;Get the connect id
ANDI T2,PR.NDX ;Just keep the index into PRVECT
HRL T1,T2 ;Save it for later, LH of T1
HRRI T1,LATST ;Scheduler test in the right
UNLOCK HN.LOK(Q2) ;Unlock the database so others can use it
OKINT ;So we can receive interrupts (and type ^C)
MDISMS ;Wait...
NOINT ;We woke up, so go NOINT again
LOCK HN.LOK(Q2) ;Lock the database again
RET ;All done...
>;END IFN FT0PS20
IFN FTOPS10,<
SAVEAC <J,W,P1> ;
MOVE P1,T1 ;Save address of pending request block
PRWAI1: LOAD T1,PRSTS,(P1) ;Get the status of the connection
CAXE T1,.LASOL ;Is it being solicited
CAXN T1,.LAQUE ; or queued?
TRNA ;Yes, continue waiting
RET ;No, return
MOVX T1,EV.LAT ;LAT event
LOAD J,PRJOB,(P1) ;Get the job number
SNCALL (ESLEEP##,MCSEC0) ;[7.yyyy](T1,J)Go to sleep
JRST PRWAI1 ;Awake for some reason: check connection
> ;End IFN FTOPS10
;[7.1120]
;PRWAKE - Wake up a job.
;
; T1/ Address of pending request block
; CALL PRWAKE
; Return+1: Always
PRWAKE:
IFN FTOPS20,<
OPSTR <SKIPN>,PRWAI,(T1);Waiting for the connection?
IFSKP.
LOAD T2,PRCID,(T1) ;Yes, Get the connect id
ANDI T2,PR.NDX ;Strip off the random part
IDIVI T2,^D36 ;Calculate offset in T2,
MOVE T3,BITS(T3) ; mask in T3
ANDCAM T3,PRWMSK(T2) ;Clear the bit
ELSE.
LOAD T2,PRFRK,(T1) ;Get the Fork number
LOAD T1,PRPSI,(T1) ;Get the PSI channel
CALLX (MSEC1,PSIRQ) ;(T1,T2/)Interrupt him
ENDIF.
RET ;All done
>;END IFN FTOPS20
IFN FTOPS10,<
SAVEAC <J> ;
OPSTR <SKIPN>,PRWAI,(T1);Wait for the connection?
IFSKP.
LOAD T1,PRFRK,(T1) ;Get the JCH
SNCALL (CTXEWK##,MCSEC1) ;(T1)Wake that job
JFCL ;
RET ;
ENDIF.
LOAD J,PRFRK,(T1) ;Get the JCH
SIGNAL C$LAT ;Signal a LAT event
JFCL ;
RET ;
> ;End IFN FTOPS10
;[7.1120]
;LATXPR - Transmit Command Messages for pending requests.
;
; CALL LATXPR
; Return+1: Always
XRENT (LATXPR,G) ;LATXPR:: XLATXP::
SAVEAC <P1,P2,P3,P4,Q1,Q2>
STKVAR <MAXCMC,NXTCMT> ;
IFN FTOPS20,<
MOVEI T1,^D1000 ;1000 Milliseconds
MOVEM T1,LATCMT ;Re-initialize the Command Message Timer
> ;End IFN FTOPS20
SKIPN P4,LAHNDB ;Get address of host node (HN) data base
RET ;None, don't transmit
LOAD T1,HNLAS,(P4) ;Get the LAT access state
CAXE T1,LS.ON ;Is it ON?
RET ;No, don't transmit
LOAD T1,HNCMX,(P4) ;Get the maximum command message
MOVEM T1,MAXCMC ; retry count
MOVE P3,TODCLK ;Get the system uptime
LOAD T1,HNCMT,(P4) ;Calculate the next time to transmit
ADD T1,P3 ; a command message
MOVEM T1,NXTCMT ;
; Find a PRVECT entry whose timer has expired.
;
MOVX P1,PRMAXI ;Get the number of entires
MOVE P2,PRVECT ;Get address of PRVECT table (minus one)
XLATP1: SOJL P1,RTN ;None left, return
SKIPE Q1,1(P2) ;Is there an entry?
OPSTR <CAMGE P3,>,PRCMT,(Q1) ;Is it time to transmit?
AOJA P2,XLATP1 ;No, keep looking
MOVX T1,DLL.FL ;Get a bit to test with
OPSTR <SKIPE Q2,>,PRXBA,(Q1) ;Get address of transmit buffer
OPSTR <TDNE T1,>,UNUID,+UNB.OF(Q2) ;Does DLL still have it?
AOJA P2,XLATP1 ;Yes, can't touch it at this time
LOAD T1,PRSTA,(Q1) ;Get the current (internal) state
AOJA P2,@XMTDSP(T1) ;Increment the PRVECT entry address
; and take care of this entry
; ..
; ..
; Table of states for the PRVECT entries
;
XMTDSP: XADDR. XLATP2 ;(0) Halt
XADDR. XLATP2 ;(1) Run
XADDR. XLATP5 ;(2) Solicit Information
XADDR. XLATP3 ;(3) Solicit Access (initialize first)
XADDR. XLATP5 ;(4) Solicit Access
XADDR. XLATP2 ;(5) Queued
XADDR. XLATP2 ;(6) Rejected
XADDR. XLATP2 ;(7) Timed Out
XADDR. XLATP4 ;(8) Cancel (initialize first)
XADDR. XLATP5 ;(9) Cancel
XMTMAX==.-XMTDSP-1
IF1,<IFL <XMTMAX-SS.MAX>,<PRINTX ?Entries missing in XMTDSP>>
; Come here to set the retransmit timer to infinity so that this routine
; will never bother with this PRVECT entry again.
;
XLATP2: HRLOI T1,377777 ;Make the retransmit timer so large
STOR T1,PRCMT,(Q1) ; we will never go through here again
SETZRO PRCMC,(Q1) ;
JRST XLATP1 ;Find another PRVECT entry
; Come here to set up the Solicit Access message.
;
XLATP3: MOVE T1,Q1 ;Get address of pending request block
CALL FMSAC ;(T1)Format a Solicit Access message
JRST XLATP1 ;Error, try again later
MOVX T1,SS.SAC ;Change state to Solicit Access
STOR T1,PRSTA,(Q1) ;
JRST @XMTDSP(T1) ;
; Come here to set up the Cancel Message.
;
XLATP4: MOVE T1,Q1 ;Get address of pending request block
CALL FMCAN ;(T1)Format a Cancel message
JRST XLTIMO ;Error, remove this slot block
MOVX T1,SS.CAN ;Change state to Cancel
STOR T1,PRSTA,(Q1) ;
JRST @XMTDSP(T1) ;
; ..
; ..
; Come here to transmit a message.
;
XLATP5: OPSTRM <AOS T1,>,PRCMC,(Q1) ;Increment the retry count
CAMLE T1,MAXCMC ;Have we retried too many times?
JRST XLTIMO ;Yes, we have timed out
MOVE T1,NXTCMT ;Reset the command message timer
STOR T1,PRCMT,(Q1) ;
LOAD T1,HNPID,(P4) ;Save the PID
STOR T1,UNPID,+UNB.OF(Q2)
STOR Q2,UNRID,+UNB.OF(Q2) ;Save buffer address
MOVX T1,SAV.FL ;Keep this buffer
STOR T1,UNUID,+UNB.OF(Q2)
MOVX T1,UNA.EV ;Use EXEC virtual memory
STOR T1,UNADS,+UNB.OF(Q2)
MOVX T1,NU.XMT ;Function = transmit
XMOVEI T2,UNB.OF(Q2) ;Address of UN block
IFN FTOPS20,<CALL DLLUNI## ;Call NI service>
IFN FTOPS10,<SNCALL (DLLUNI##,MCSEC1) ;Call NI service>
TRN ;Ignore error
JRST XLATP1 ;Look for another PRVECT entry
; Come when we have timed out.
;
XLTIMO: LOAD T1,PRSTA,(Q1) ;Get the current (internal) state
CAXE T1,SS.CAI ;
CAXN T1,SS.CAN ;Was this request cancelled?
TRNA ;Yes, delete the PRVECT entry
IFSKP.
MOVE T1,Q1 ;Get the address of the slot block
CALL PRDEL ;Delete the PRVECT entry
JRST XLATP1 ;Find another PRVECT entry
ENDIF.
MOVX T1,SS.TMO ;Change state to Timed Out
STOR T1,PRSTA,(Q1) ;
MOVX T1,.LATMO ;
STOR T1,PRSTS,(Q1) ;
MOVE T1,Q1 ;Get address of pending request block
CALL PRWAKE ;(T1)Wake the user's job
JRST @XMTDSP+SS.TMO ;Make the retransmit timer so large
; we will never go through here again
SUBTTL LATOP% JSYS -- Terminate Host-Initiated Connects
XSWAPCD ;[7.1120]
;[7.1120]
;LATHC - Terminate host-initiated connects.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LATHC
; Return+1: Failure, T1/ error code
; Return+2: Success
LATHC: UMOVE T2,.LAPRM(Q1) ;Get the connect id and flags
IFN FTOPS20,<
MOVE T1,FORKX ;Get the current fork number
> ; End IFN FTOPS20
IFN FTOPS10,<
MOVE T1,.CPJCH## ;Get the current job number/context
>; End IFN FTOPS10
TXNN T2,LA%JOB ;Terminate all server connects for the job?
IFSKP.
CALL JBTHC ;(T1)Terminate all pending connects
RETBAD () ;Uh oh... Open files!
RETSKP ; for the current fork
ENDIF.
HRRZ T3,T2 ;Get the connect id
ANDI T2,PR.NDX ;Throw away the random portion
SKIPLE T2 ;Less than or equal to zero
CAILE T2,PRMAXI ; or greater than the maximum?
RETBAD (LATX11) ;Yes, invalid or unknown connect id
ADD T2,PRVECT ;Calculate address of PRVECT entry
SKIPN T2,(T2) ;Is this entry in use?
RETBAD (LATX11) ;No, invalid or unknown connect id
OPSTR <CAME T3,>,PRCID,(T2) ;Is this the RIGHT connect id?
RETBAD (LATX11) ;No, invalid or unknown connect id
OPSTR <CAME T1,>,PRFRK,(T2) ;Does this job own the connection?
RETBAD (LATX11) ;No, invalid or unknown connect id
IFN FTOPS20,<
LOAD T1,PRSTS,(T2) ;Get the status
TRZN T1,.TTDES ;Is this a TTY designator?
IFSKP. ;Yes, so...
ADDI T1,DVXTT0 ;Point into the device tables
MOVX T3,DV%OPN ;Get the open flag?
TDNE T3,DEVCHR(T1) ;Is there an open file on this device?
RETBAD (DEVX6) ;Yes!
ENDIF.
> ;End IFN FTOPS20
MOVE T1,T2 ;Get address of pending request block
CALL PRCAN ;(T1)Cancel this pending request
RETSKP ;
;[7.1120]
;LATRST - This routine is called each time TOPS-10 does a RESET UUO.
; The TOPS-20 version is called from KSELF.
; Give up all of the server connections for the specified job.
;
; T1/ Fork number (TOPS-20)
; J/ Job number (JCH) (TOPS-10)
; CALL LATRST
; Return+1: Always
IFN FTOPS20,<
XRENT (LATRST,G) ;LATRST::,XLATRS:
SAVEAC <Q1> ;
SKIPN Q1,LAHNDB ;Do we have lat?
RET ;no
NOINT ;No more interruptions
LOCK HN.LOK(Q1) ;Lock the database
CALL JBTHC ;Release reverse lat resources
NOP ;Don't care
UNLOCK HN.LOK(Q1) ;Let others have the database
OKINT ;I'm not busy any more
RET ;All done
> ;End IFN FTOPS20
IFN FTOPS10,<
RESCD
LATPSI::SETZ T2, ;Dummy PSI callback routine
RET
LATRST::MOVE T1,.CPJCH ;Get the JCH
SE1ENT ;Return in section 1
IFN FTXMON,<
XJRST [JBTHC] ;Do the rest in section 2
XRESCD
> ;End IFN FTXMON
> ;End IFN FTOPS10
;[7.1120]
;JBTHC - Terminate all of the host-initiated connects for a specified job.
;Note: To be called NOINT with the database locked.
; T1/ Fork number
; CALL JBTHC
; Return+1: At least one device has an open file, and hasn't been terminated
; Return+2: All connections terminated
JBTHC: SAVEAC <P1,P2,P3> ;
STKVAR <OPFLG> ;"Device is open" Flag
MOVX P1,PRMAXI ;Get the length of the PRVECT table
MOVE P2,PRVECT ;Get the address of the PRVECT table
MOVE P3,T1 ;Copy the fork number
SETZM OPFLG ;Clear Error flag
JBTHC1: SOJL P1,JBTHC3 ;Negative: no more PRVECT entries
SKIPN T1,1(P2) ;Is this table entry in use?
AOJA P2,JBTHC1 ;No, keep looking
LOAD T2,PRFRK,(T1) ;Get the fork number for this connection
CAME T2,P3 ;Do the fork numbers match?
AOJA P2,JBTHC1 ;Keep looking
IFN FTOPS20,<
LOAD T2,PRSTS,(T1) ;Get the status
TRZN T2,.TTDES ;Is this a TTY designator?
IFSKP. ;Yes, so...
ADDI T2,DVXTT0 ;Point into the device tables
MOVX T3,DV%OPN ;Get the open flag?
TDNN T3,DEVCHR(T2) ;Is there an open file on this device?
JRST JBTHC2 ;No, go cancel it
SETOM OPFLG ;Yes, set the flag
AOJA P2,JBTHC1 ;and keep looking...
ENDIF. ;
> ;End IFN FTOPS20
JBTHC2: CALL PRCAN ;Cancel this connection
AOJA P2,JBTHC1 ;Keep going
JBTHC3:
IFN FTOPS20,<
SKIPE OPFLG ;Any errors?
RETBAD (DEVX6) ;Yes
> ;End IFN FTOPS20
RETSKP ;No, all is well...
ENDSV. ;
;PRCAN - Cancel a pending request.
;[7.1120]
; T1/ Address of pending request block
; CALL PRCAN
; Return+1: Always
PRCAN: LOAD T3,PRSTA,(T1) ;Get the current (internal) state
CALLRET @CANDSP(T3) ;Change state to Cancel or hang up
PRCAN1: MOVX T2,SS.CAI ;
STOR T2,PRSTA,(T1) ;Change to Cancel state
MOVX T2,.LACAN ; (initialize first)
STOR T2,PRSTS,(T1) ;
SETZRO PRCMC,(T1) ;Clear the retransmit timer so that
SETZRO PRCMT,(T1) ; LATXPR will start right away
RET ;Return
PRCAN2: LOAD T2,PRSBA,(T1) ;Get address of slot block
JUMPE T2,@CANDSP+SS.SAC ;None: treat it as still soliciting
IFN FTOPS20,<
LOAD T2,PRSTS,(T1) ;Get the TTY designator
TXZN T2,.TTDES ;Do we have one?
JRST @CANDSP+SS.SAC ;No
SAVEAC <Q1,Q2,P1,P2,P3,P4,P5>
CALLRET LTHNGU ;(T2)Yes, hang up the line.
> ;End IFN FTOPS20
IFN FTOPS10,<
SAVEAC <W,M,P1,P2,P3,P4,J>
LOAD U,SBTDB,(T2) ;Get the LDB address
JUMPE U,@CANDSP+SS.SAC ;[7.xxxx]None: treat it as still soliciting
CALL LTHNGU ;[7.xxxx](U)Got it: hang up the line
NOP ;[7.xxxx]Oh well, we tried
RET ;[7.xxxx]
> ;End IFN FTOPS10
CALLRET @CANDSP+SS.SAC ;None: treat it as still soliciting
; Table of states for the PRVECT entries
;
CANDSP: XADDR. PRCAN2 ;(0) Halt
XADDR. PRCAN2 ;(1) Run
XADDR. PRCAN1 ;(2) Solicit Information
XADDR. PRCAN1 ;(3) Solicit Access (initialize first)
XADDR. PRCAN1 ;(4) Solicit Access
XADDR. PRCAN1 ;(5) Queued
XADDR. PRDEL ;(6) Rejected
XADDR. PRDEL ;(7) Timed out
XADDR. PRCAN1 ;(8) Cancel (initialize first)
XADDR. PRCAN1 ;(9) Cancel
CANMAX==.-CANDSP-1
IF1,<IFL <CANMAX-SS.MAX>,<PRINTX ?Entries missing in CANDSP>>
SUBTTL LATOP% JSYS -- Show Host-Initiated Connects
XSWAPCD ;[7.1120]
;[7.1120]
;LASHC - Show host-initiated connects.
;
; Q1/ User argument block address
; Q2/ LAT host node data base address
; P1/ Length of user argument block
; P2/ LAT function code
; CALL LASHC
; Return+1: Failure, T1/ error code
; Return+2: Success
LASHC: XCTU [HRRZ P3,.LABCT(Q1)] ;Get the length of the show buffer
UMOVE T3,.LABFA(Q1) ;Get address of show buffer
UMOVE T1,.LAQUA(Q1) ;Get the flags,,connect id
IDIVI P3,MW.SHC ;Calculate the maximum number
; of connections that will fit there
SETO P4, ;Use job number minus one (for the search)
TXNE T1,LA%SYS ;Show all server connects on the system?
JRST LASHC1 ;Yes, start the search
TXNN T1,LA%JOB ;Show all server connects for this job?
IFSKP.
IFN FTOPS20,<
MOVE P4,JOBNO ;Get the current job number
> ;End IFN FTOPS20
IFN FTOPS10,<
MOVE P4,.CPJOB## ;Get the current job number
> ;End IFN FTOPS10
JRST LASHC1 ;Find the connections for this job
ENDIF.
; Come here to return the status of a paritcular server connection.
;
LDB T4,[POINTR (T1,LA%CID)] ;Get the connect id
ANDI T4,PR.NDX ;Throw away the random portion
SKIPLE T4 ;Less than or equal to zero
CAILE T4,PRMAXI ; or greater than the maximum?
RETBAD (LATX11) ;Yes, invalid or unknown connect id
ADD T4,PRVECT ;Calculate address of PRVECT entry
SKIPN T4,(T4) ;Is this entry in use?
RETBAD (LATX11) ;No, invalid or unknown connect id
MOVX T1,MW.SHC ;Save the number of words needed
XCTU [HRLM T1,.LABCT(Q1)]
SOSGE P3 ;Is the show buffer large enough?
RETBAD (ARGX04) ;No, argument block too small
CALL MVSHC ;(T2,T4/T2)Move the Status block
RETSKP ;
; ..
; ..
; Find the all server connections (P4=minus one) or all those for a user
; job (P4=n).
;
LASHC1: MOVX P1,PRMAXI ;Get the length of the PRVECT table
MOVE P2,PRVECT ;Get the address of the PRVECT table
LASHC2: SOJL P1,LASHC4 ;Negative: no more PRVECT entries
ADDI P2,1 ;Increment the address of the entry
SKIPN T4,(P2) ;Is this table entry in use?
JRST LASHC2 ;No, keep looking
JUMPL P4,LASHC3 ;Minus one: take all server connections
LOAD T1,PRJOB,(T4) ;Get the job number for this connection
CAME T1,P4 ;Do the job numbers match?
JRST LASHC2 ;No, keep looking
LASHC3: SOJL P3,LASHC2 ;Negative: avoid overflowing the buffer
CALL MVSHC ;(T2,T4/T2)Move the Status block
JRST LASHC2 ;Find all of the server connections
; Return the number of words needed in the show buffer.
;
LASHC4: XCTU [SUB T3,.LABFA(Q1)] ;Calculate the number of words written
JUMPL P3,LASHC5 ;Negative: show buffer is too small
XCTU [HRLM T3,.LABCT(Q1)] ;Save the number of words written
RETSKP ;
LASHC5: MOVMS P3 ;Calculate the additional number
IMULI P3,MW.SHC ; of words needed
ADD T3,P3 ;Calculate the total amount needed
XCTU [HRLM T3,.LABCT(Q1)] ;Save the number of words needed
RETBAD (LATX04) ;Argument block too small
;[7.1120]
;MVSHC - Move the status information for LASHC.
;
; T3/ Destination in user address space
; T4/ Address of pending request block
; CALL MVSHC
; Return+1: Always, T3/ Address of next word to write
MVSHC: LOAD T2,PRJOB,(T4) ;Get the job number
LOAD T1,PRCID,(T4) ;Get the connect id
HRL T1,T2 ;Get job number,,connect id
UMOVEM T1,(T3) ;Put it in the show buffer
LOAD T2,PRSTS,(T4) ;Get the status of the connection
LOAD T1,PRQDP,(T4) ;Get the queue depth
HRL T1,T2 ;Get status,,queue depth
UMOVEM T1,1(T3) ;Put it in the show buffer
LOAD T2,PRSRC,(T4) ;Get the server name count
LOAD T1,PRPRC,(T4) ;Get the port name count
HRL T1,T2 ;Get server name count,,port name count
UMOVEM T1,2(T3) ;Put it in the show buffer
ADDI T3,3 ;Update the destination address
MOVEI T1,<ML.SRN+4>/5 ;Get the maximum length of the name
XMOVEI T2,PR.SRN(T4) ;Get the address of server name
XBLTXU T1 ;Copy the name into user space
MOVEI T1,<ML.PRN+4>/5 ;Get the maximum length of the name
XMOVEI T2,PR.PRN(T4) ;Get the address of the port name
XBLTXU T1 ;Copy the name into user space
LOAD T1,PRSVC,(T4) ;Get the service name count
HRLZ T1,T1 ;Get the service name count,,0
UMOVEM T1,(T3) ;Put it in the show buffer
ADDI T3,1 ;Update the destination address
MOVEI T1,<ML.SVN+4>/5 ;Get the maximum length of the name
XMOVEI T2,PR.SVN(T4) ;Get the address of the service name
XBLTXU T1 ;Copy the name into user space
RET ;
SUBTTL LATOP% JSYS -- Utility Routines -- FNDSRV
;FNDSRV - find the service block requested by the user based on the
; service name provided.
;Call: no arguments
;Return:
; RET - error
; RETSKP - success, T1/ address of service block
FNDSRV: SAVEAC <P1,P2>
MOVEI T1,TMPLNG-1 ;Zero the storage for assembling user's
XMOVEI T2,TMPBLK ; service name.
XMOVEI T3,TMPBLK+1 ; ...
SETZM TMPBLK ; ...
XBLT. T1 ; ...
;Get the Service Name string from the user and put it into the service
;block build area.
;
UMOVE T1,.LABFA(Q1) ;Pointer to user's service name string
IFN FTOPS10,<
SNCALL (CKSTR##,MCSEC1) ;Check to see if ASCIZ string is addressable
RETBAD (LATXAC) ;Nope, lose
>;end ifn FTOPS10
IFN FTOPS20,<
CALL MAKPTR ;(T1/T1)Make a valid ASCIZ pointer
>
XMOVEI T2,TMPGB+GB.NAM ;Pointer of where to put it
TXO T2,<OWGP. 7,0> ; ...
MOVEI T3,<ML.SVN+4/5> ;[7.1120]Maximum length
CALL UMVAZS ;(T1-T3/T3)Move the string to exec space
RETBAD (LATX07) ;Service name too long
STOR T3,GBNC,+TMPGB ;Store the count of service name from user
;Loop through all service blocks looking for a name match.
;
XMOVEI P2,HN.SRV(Q2) ;Address of start of service blocks
OPSTR <SKIPN P1,>,HNNSV,(Q2);Number of currently defined services
JRST FSFALS ;There are none defined.
DO.
XMOVEI T1,GB.NAM(P2) ;Address of service block's service name
TXO T1,<OWGP. 7,0>
LOAD T2,GBNC,(P2) ;Count of service block's service name
XMOVEI T3,TMPGB+GB.NAM;Address of user's service name
TXO T3,<OWGP. 7,0>
LOAD T4,GBNC,+TMPGB ;Count of user's service name
CALL SCMPAR ;Compare the strings
IFSKP. ;MATCH FOUND
MOVEI T1,.LASET ;If a SET...
XCTU [CAME T1,.LAFCN(Q1)]
IFSKP.
MOVEI T1,GB.LEN ; then copy entire service block to the
XMOVEI T2,(P2) ; temporary block so that new values
XMOVEI T3,TMPGB ; overlay the old.
XBLT. T1
ENDIF.
MOVE T1,P2 ;In both cases (SET/CLEAR) return service
RETSKP ; block address.
ENDIF.
ADDI P2,GB.LEN ;No match here so
SOJG P1,TOP. ; advance to next service block
ENDDO.
;Service block not found. If function is SET, see if there is room for
;a new service. If function is CLEAR, nothing further required.
;
FSFALS: MOVEI T1,.LASET ;If service name not found and the function
XCTU [CAME T1,.LAFCN(Q1)]; request is not a SET,
RETBAD (LATX07) ; then return an error. Otherwise,
XMOVEI T1,<GB.LEN*MXHSRV+HN.SRV>(Q2); get end of service block address
CAML P2,T1 ; and compare with first free block address
RETBAD (LATX08) ;There is no room for new service.
SETOM TMPBLK ;There is room. Flag to increment # services.
MOVE T1,P2 ;Return service block address for new entry.
RETSKP
SUBTTL LATOP% JSYS -- Utility Routines -- GTSRVR
;GTSRVR - Routine to get the circuit block address for a particular
; server based on server name.
;
;CALL: T1/ Pointer to server name supplied by user
; Q2/ LAT host node data base address
;RET - Error, no circuit block with the requested server name
;RETSKP Success,
; T1/ Circuit block address for requested server
GTSRVR: SAVEAC Q1 ;Get an AC for circuit block address.
MOVX T2,<POINT 7,TMPBLK>;Pointer to where to move name string.
MOVEI T3,ML.DSC ;Maximum server name string length.
CALL UMVAZS ;(T1-T3/T3)Move the ASCIZ string.
RETBAD (LATX04)
MOVX T1,<POINT 7,TMPBLK>;Pointer to user's name string in local storage
MOVE T2,T3 ;Length of the user's name string.
LOAD Q1,HNQAC,(Q2) ;Get first CB on active queue
CALL GCBNAM ;See if desired server there
IFSKP.
MOVE T1,Q1 ;Return the CB address on successful
RETSKP ; match.
ENDIF.
LOAD Q1,HNQIC,(Q2) ;Get first CB on inactive queue
CALL GCBNAM
IFSKP.
MOVE T1,Q1 ;Return the CB address on successful
RETSKP ; match.
ENDIF.
RETBAD (LATX04) ;Not anywhere, return error.
;GCBNUM - searches a particular queue of circuit blocks looking for a match
; on the server name.
GCBNAM: SAVEAC <T1,T2> ;Preserve string pointer and count.
JUMPE Q1,RTN ;No more circuit blocks on this queue
DO.
XMOVEI T3,CB.SNM(Q1) ;Address of server name
TXO T3,<OWGP. 7,0> ;Make a pointer
LOAD T4,CBRSC,(Q1) ;Count in name
CALL SCMPAR ;(T1-T4)Do the compare
SKIPA ;No match
RETSKP ;Match
OPSTR <SKIPN Q1,>,QLFWD,+CB.LNK(Q1)
RET ;No match for any CBs on queue.
JRST TOP. ;Try next CB.
ENDDO.
SUBTTL LATOP% JSYS -- Utility Routines -- SCMPAR String Compare
;SCMPAR - String Compare
;Call: T1/ First string byte pointer
; T2/ First string count
; T3/ Second string byte pointer
; T4/ Second string count
;RET Mismatch
;RETSKP Match
SCMPAR: SAVEAC <T1,T2,T3,T4> ;Preserve the byte pointers.
STKVAR <PTR1,PTR2>
CAME T2,T4 ;If lengths don't match then obviously
RET ; the strings don't either.
MOVEM T1,PTR1 ;Save the byte pointers
MOVEM T3,PTR2 ; to the strings.
DO.
ILDB T1,PTR1 ;Get next character from
ILDB T2,PTR2 ; each string.
CALL UPPERC ;(T1/T1)Uppercase one.
EXCH T1,T2
CALL UPPERC ;(T1/T1)Uppercase the other.
CAME T1,T2 ;Compare the result.
RET ;Different so return failure.
SOJG T4,TOP. ;Match, so continue with the next.
ENDDO.
RETSKP ;Full match, return success.
ENDSV.
;UPPERC - Uppercase a character
;Call: T1/ Character
;RET Always with T1/ uppercased character
UPPERC: CAIL T1,"a"
CAILE T1,"z"
SKIPA
SUBI T1,40
RET
;UBFCHK - Routine to check if user supplied buffer large enough
;This routine added by 7.1039. It supercedes LABFCK.
; Call:
; T1/ Minimum size required of user buffer
; Q1/ User's argument block address
; Return:
; RET ;Too small (LATX01 in T1)
; RETSKP ;Large enough
UBFCHK: XCTU [HRLM T1,.LABCT(Q1)] ;Tell user
XCTU [HRRZ T2,.LABCT(Q1)] ;Get his buffer count.
CAMGE T2,T1 ;Has user allocated large enough buffer?
RETBAD (LATX01) ;No
RETSKP ;Yes
;MAKPTR- Make a valid ASCIZ pointer if not already
;
IFN FTOPS20,<
MAKPTR: MOVE T2,T1 ;Make a proper pointer in case the user
TLC T2,-1 ; supplied one of the form
TLCN T2,-1 ; -1,,address
HRLI T1,440700 ; ...
RET
> ;End IFN FTOPS20
;[7.1039] Routine LABFCK was here...
; Last thing in LATOP. UUO code
;
IFN FTOPS10,<
PURGE Q1,Q2 ;undefine TOPS-20 ACs
> ;End IFN FTOPS10
SUBTTL TOPS-10 -- SCNSER Interface -- LDBISR Dispatch
RESCD
IFN FTOPS10,<
LATDSP::RET ;( 0)ILLEGAL NOW. DON'T USE!!
RET ;( 1)MODEM CONTROL
XJRST [LATSEC] ;( 2)ONCE A SECOND CALL (NOT PER TTY)
RET ;( 3)INITIALIZE
JRST SETCHP## ;( 4)CHANGE HARDWARE PARMS (let SCNSER do it)
RET ;( 5)LINE PARM CONTROL
RET ;( 6)SET TERMINAL ELEMENT
XJRST [LATREM] ;( 7)STUFF FOR REMOTE TERMINALS
RETSKP ;(10)IS LINE DEFINED ON STATION (YES)
> ;End IFN FTOPS10
SUBTTL TOPS-10 -- NETOP. Functions
;NETDIL - tell user the node and port where his TTY is connected
;
;Call: (in section 1 already)
;
; U/ LDB of LAT terminal
; M/ Address of user's NETOP. arg list
;Return:
; ECDX? depending on error
; RETSKP node name stored in string block pointed to by user's arg list
;
;Uses P1,P2 (already saved by higher routine), T1-T4, M
SWAPCD
IFN FTOPS10,<
NETDIL::MOVE P1,M ;SAVE ADDRESS OF ARG LIST
EXCTUX <SKIPN M,5(P1)> ;POINT TO NODE NAME STRING BLOCK
JRST NTDIL1 ;NO STRING BLOCK FOR NAME
CALL CHKSTB## ;CHECK STRING BLOCK FOR ADDRESSABILITY
JRST NOPADC## ;ADDRESS CHECK
MOVE T3,LDBLAT##(U) ;GET ADDRESS OF SB BLOCK
MOVE T3,SB.CBA(T3) ;GET ADDRESS OF CORRESPONDING CB BLOCK
LOAD T1,CBRSC,(T3) ;GET BYTE COUNT FOR NAME
XMOVEI T3,CB.SNM(T3) ;GET ADDRESS OF NODE NAME
CALL MOV7T8 ;MOVE THE STRING
JRST NOPADC## ;NOT ENOUGH ROOM
NTDIL1: EXCTUX <SKIPN M,6(P1)> ;POINT TO PORT NAME STRING BLOCK
RETSKP ;BELIEVE IT OR NOT, WE'RE DONE
CALL CHKSTB## ;CHECK THE STRING BLOCK
JRST NOPADC## ;NOT THERE
MOVE T3,LDBLAT##(U) ;GET ADDRESS OF SB BLOCK AGAIN
LOAD T1,SBPRC,(T3) ;GET BYTE COUNT OF PORT NAME
JUMPE T1,RSKP ;Nothing to store
XMOVEI T3,SB.PRN(T3) ;GET ADDRESS OF PORT NAME
CALL MOV7T8 ;(M,T1,T2,T3)
JRST NOPADC## ;NOT ENOUGH ROOM
RETSKP
> ;End IFN FTOPS10
;MOV7T8 - Move a 7-bit monitor string to an 8-bit user string.
;
; M/ Address of string block
; T1/ Count of source string
; T3/ Address of source string
; T4/ Count of destination string
; CALL MOV7T8
; Return+1: Failure, address check
; Return+2: Success
IFN FTOPS10,<
MOV7T8:
IFN FTXMON,<
CALL SSPCS## ;PRESERVE PCS FOR CALLER
>
PUSH P,T1 ;SAVE COUNT FOR A BIT
MOVE T1,M ;COPY POINTER TO STRING BLOCK
CALL SXPCS## ;SETUP PCS
JRST TPOPJ## ;I THOUGHT WE KNEW IT WOULD FIT?
POP P,T1 ;RESTORE BYTE COUNT
EXCTXU <HRLM T1,(M)> ;STUFF BYTE COUNT INTO STRING BLOCK
CAILE T1,(T4) ;ENOUGH SPACE TO STORE?
RET ;NO
MOVSI T2,(<POINT 7,>!1B12) ;MAKE GLOBAL BYTE POINTER
PUSH P,T4+1 ;SAVE A COUPLE OF ACS
PUSH P,T4+2 ; T1 HAD BETTER BE LESS THAN 12
MOVSI T4+1,(<POINT 8,>!1B12)
EXCTUX <XMOVEI T4+2,1(M)> ;GLOBAL ADDRESS OF DEST.
PXCT 11,[EXTEND T1,[MOVSLJ
0]] ;MOVE THE BYTES (I HOPE)
JFCL
POP P,T4+2
POP P,T4+1
RETSKP
> ;End IFN FTOPS10
SUBTTL LATINI - LAT Initialization
XRESCD ;[7.1024]
;LATINI - LAT Initialization
;
;Call: CALL LATINI
; Error return - resource failure
; Normal Return
ENTRY LATINI ;Kepp LINK happy in library search mode
XRENT (LATINI,G) ;[7.1024]LATINI::, XLATIN::
ACVAR <HN,XB,W1,W2> ;Reserve AC for Host Node data base address
IFN FTOPS10,<
PUSHJ P,LAGTCR ;[7.xxxx]Get size of LAT freecore needed
IFE FTXMON,<
PUSHJ P,INICOR## ;[7.xxxx]Allocate core
MOVEM T2,LATLOC ;[7.xxxx]Save starting address
> ;End IFE FTXMON
IFN FTXMON,<
MOVE T2,T1 ;[7.xxxx]Copy here for GFWNZN
MOVEI T1,(MS.DCN) ;[7.xxxx]Section number
PUSHJ P,GFWNZN## ;[7.xxxx]Ask ONCMOD for non-zero section core
HALT . ;[7.xxxx]*** FOR NOW
MOVEM T1,LATLOC ;[7.xxxx]Save as lowest address in freecore
> ;End IFN FTXMON
>; End IFN FTOPS10
MOVEI T1,HC.LST ;Get memory for the Host Node (HN) tables
CALL MMGTZW ;(T1/T1)Get zeroed memory
JRST INIRES ;Resource failure. Should not happen.
MOVE HN,T1 ;Base address for host node database references
MOVEM HN,LAHNDB ;Store the data base address
SETONE HNRUN,(HN) ;[7.1039]Start with the NI not running
MOVEI T1,CBMAXI ;Get storage for CBVECT
CALL MMGTZW ;(T1/T1)
JRST INIRES ;Resource failure.
; Circuit block index numbers start with one (not zero).
; When used as an index into the CBVECT array, the first
; word of the array is never used, and the address of the
; last CB is written in some other block.
SOS T1 ;Save the address minus one:
MOVEM T1,CBVECT ; circuit block indices start with one.
MOVEI T1,NTTLAH ;Get storage for SBVECT
CALL MMGTZW ;(T1/T1)
JRST INIRES ;Resource failure.
; Slot block index numbers start with one (not zero).
; When used as an index into the SBVECT array, the first
; word of the array is never used, and the address of the
; last SB is written in some other block.
SOS T1 ;Save the address minus one:
MOVEM T1,SBVECT ;slot block indices start with one.
MOVEI T1,PRMAXI ;[7.1120]
CALL MMGTZW ;[7.1120]Get storage for PRVECT
JRST INIRES ;[7.1120]Resource failure
SOS T1 ;[7.1120]Save the address minus one:
MOVEM T1,PRVECT ;[7.1120] PR slot indices start with one
MOVEI T1,PRMAXI ;[7.1120]
CALL MMGTZW ;[7.1120]Get storage for PRRAND table
JRST INIRES ;[7.1120]Resource failure
SOS T1 ;[7.1120]Save address minus one:
MOVEM T1,PRRAND ;[7.1120] PRRAND indices start with one
IFN FTOPS10,<
;
; Now carve up the core we got at ONCE time
; The free core pool will be turned into a
; linked list of fixed length buffers from which we can allocate
; transmit and receive buffers.
SETZRO QLFWD,+LATFRE ;Clear out the queue
SETZRO QLBWD,+LATFRE
CALL LAGTCR ;()Find out how much memory we got at ONCE time
IDIVI T1,BUFSIZ ;See how many buffers will fit
MOVE T4,T1 ;Put it where we need it later.
MOVEM T4,LATNFB ;Remember how many we have at start
MOVE T2,LATLOC ;Start of first one
CALL ALCBUF ;Link them together
MOVE T1,LATNAM## ;Get our node name
CALL CVTNOD ;Convert to ASCII
>;END IFN FTOPS10
DMOVE T1,OURNAM ;Get the local host name
DMOVEM T1,HN.NAM(HN) ;Store in HN block
MOVE T1,OURCNT ;Host name length in characters
STOR T1,HNNMC,(HN) ;Store in HN block
IFN FTOPS20,<
MOVX T1,<POINT 7,SVN##> ;Pointer to MONNAM.TXT
>
IFN FTOPS10,<
MOVX T1,<POINT 7,CONFIG##> ;Pointer to Monitor name
>
XMOVEI T2,HN.ID(HN) ;Where to put it.
TXO T2,<OWGP. 7,0> ; ...
MOVEI T3,ML.DSC ;Maximum length allowed
CALL MMVAZS ;(T1-3/T3)Move the string
TRN ;Don't care, take truncated string
STOR T3,HNIDC,(HN) ;Store real count
MOVE T1,RTRADR ;Get the default host number
STOR T1,HNNUM,(HN)
MOVEI T1,^D60 ;[7.1039]Default Host message retransmit limit
STOR T1,HNRLI,(HN)
MOVEI T1,^D1000 ;Default host virtual circuit timer (msec)
STOR T1,HNTIM,(HN)
MOVEI T2,^D30 ;Default host multicast timer (sec)
STOR T2,HNMTI,(HN)
MOVEI T1,^D10000 ;[7.1120]Default command message retry time (ms)
STOR T1,HNCMT,(HN) ;[7.1120]
MOVEI T1,^D5 ;[7.1120]Default command message retry limit
STOR T1,HNCMX,(HN) ;[7.1120]
MOVE T1,LASDEF ;[7.1039]Get the default LAT Access State
STOR T1,HNLAS,(HN) ;[7.1039] and store it
CAIN T1,LS.OFF ;[7.1039]If def. state = on, start transmitting
IFSKP. ;[7.1039] multicast messages immediately
IFN FTOPS20,<
IMULI T2,^D1000 ;[7.1039]Multicast in milliseconds
>;END IFN FTOPS20
MOVEM T2,LATMCT ;[7.1039]Initialize scheduler long timer word
ENDIF.
MOVEI T1,MAXACB ;[7.1164]Default max allocatable circuit blocks
STOR T1,HNMXC,(HN)
MOVEI T1,MAXACC ;[7.1164]
STOR T1,HNMAC,(HN) ;[7.1039]And maximum active circuits
MOVEI T1,CBMAXI ;Get a random number in the range or 1 to
CALL RANDOM ; (T1/T1)maximum value of circuit block index
STOR T1,HNNXI,(HN) ;Store as next CB index to assign
MOVEI T1,NTTLAH ;Default max number of simultaneous connects
STOR T1,HNMCO,(HN)
MOVEI T1,^D32 ;Number of access code bytes
STOR T1,ACLNG,(HN)
IFN FTOPS20,<
MOVSI T1,(1B7) ;Set group 0 on
MOVEM T1,AC.COD(HN) ;Store as first byte of access codes
> ;END IFN FTOPS20
IFN FTOPS10,<
IFN FTXMON,<
XMOVEI T3,AC.COD(HN) ;Point to destination of XBLT
XMOVEI T2,LATIGE## ;From MONGENed groups enabled
MOVEI T1,^D8 ;Enough room for 32 bytes
EXTEND T1,[XBLT] ;Move the bytes
> ;END IFN FTXMON
IFE FTXMON,<
MOVEI T1,AC.COD(HN) ;Point to destination of BLT
HRLI T1,LAT.GE## ;From MONGENed groups enabled
BLT T1,AC.COD+7(HN) ;Move the bytes
> ;END IFE FTXMON
> ;END IFN FTOPS10
MOVEI T1,1
STOR T1,HNNSV,(HN) ;Default number of host services offered
XMOVEI W1,HN.SRV(HN) ;Address of the host service blocks
STOR T1,GBRAT,(W1)
MOVE T1,OURCNT ;Default service name is node name so
STOR T1,GBNC,(W1) ; store the count
DMOVE T1,OURNAM ; and the name
DMOVEM T1,GB.NAM(W1)
LOAD T1,HNIDC,(HN) ;[7.1039]Get Host node id count
CAILE T1,ML.SID ;[7.1039]Don't exceed the maximum allowed
MOVEI T1,ML.SID ;[7.1039]
STOR T1,GBLC,(W1) ;[7.1039]Save it
ADDI T1,4 ;[7.1039]Convert from bytes to words
IDIVI T1,5 ;[7.1039]
XMOVEI T2,HN.ID(HN) ;[7.1039]Get address of host descriptor
XMOVEI T3,GB.HID(W1) ;[7.1039]And address of service descriptor
XBLT. T1 ;[7.1039]Make service descriptor same as host
XMOVEI XB,HN.MCM(HN) ;Address of the multicast message block
MOVE T1,[BYTE (8)11,0,53,0,(4)0];Store multicast address
MOVE T2,[BYTE (8)0,17,0,0]; ...
OPSTRM <DMOVEM T1,>,UNDAD,+UNB.OF(XB);09-00-2B-00-00-0F
SETO T1,0 ;Use random number for incarnation count
CALL BMCFXD ;(T1,HN,XB)Build fixed part of message
CALL BMCACS ;(HN,XB)Enter the host access code string
CALL BMCNID ;(HN,XB)Enter the host node name and descriptn
CALL BMCSRV ;(HN,XB)Build the services
SETONE HNLOK,(HN) ;Initialize database lock
STOR XB,UNRID,+UNB.OF(XB);Store for xmit complete processing
CALL BLDSTM ;(HN)Now build the START message template
MOVX T1,NTTLAH ;[7.1120]Get the number of slot blocks
MOVEI T2,SBBITS ;[7.1120]Get address of allocation table
CALL BITON ;[7.1120](T1,T2)Initialize to all ones
MOVX T1,PRMAXI ;[7.1120]Get the number of PR blocks
MOVEI T2,PRBITS ;[7.1120]Get address of allocation table
CALL BITON ;[7.1120](T1,T2)Initialize to all ones
IFN FTOPS20,<
MOVX T1,PRMAXI ;[7.1120]Get the number of PR blocks
MOVEI T2,PRWMSK ;[7.1120]Get addr of scheduler test table
CALL BITOF ;[7.1120](T1,T2)Initialize to all zeros
>;END IFN FTOPS20
SETZRO UNCHN,+UNB.OF(XB);For now, later must read channel list
SETZRO UNPAD,+UNB.OF(XB);We use padding
MOVEI T1,^B0110000000000100 ;Protocol ID is 60-04
STOR T1,UNPRO,+UNB.OF(XB)
XMOVEI T1,LATCBR ;Callback routine address
STOR T1,UNCBA,+UNB.OF(XB)
MOVX T1,NU.OPN ;NISRV Open function
XMOVEI T2,UNB.OF(XB) ;Use this for open as well
IFN FTOPS20,<
CALL DLLUNI##
>
IFN FTOPS10,<
SNCALL (DLLUNI##,MCSEC1)
>
IFSKP.
XMOVEI T2,UNB.OF(XB) ;Load address of UN block
CALL LATLSC ;(T1-2)Check to see if NI is running
LOAD T1,UNPID,+UNB.OF(XB) ;Get the PID return from the DLL
STOR T1,HNPID,(HN) ; and store for later calls to the DLL.
CALL GETRBF ;(HN)Get a buffer for receives
TRN ;Will have to get buffers later
ENDIF.
RET
INIRES:
BUG. (CHK,LATINE,LATSER,SOFT,<LATINI failed to initialize>,,<
Cause: Could not obtain sufficient memory for the LAT host databases.
Action: Determine why there is so little resident memory available at system
startup.
Data: HN.LST words for the host node database, CBMAXI words for CBVECT,
and NTTLAH words for SBVECT.
>)
SKIPE T1,LAHNDB ;Start with a clean slate when we try
CALL MMFREE ; (T1)to initialize later...
SKIPE T1,CBVECT ; ...
CALL MMFREE ; (T1)...
SKIPE T1,SBVECT ; ...
CALL MMFREE ; (T1)...
SKIPE T1,PRVECT ;[7.1120] ...
CALL MMFREE ;[7.1120] ...
SKIPE T1,PRRAND ;[7.1120] ...
CALL MMFREE ;[7.1120] ...
RET
ENDAV.
;[7.1120]
;BITON - Set a number of bits in a table.
;BITOF - Clear a number of bits in a table
;
; T1/ Number of bits to set
; T2/ Address of the array
; CALL BITON/BITOF
; Return+1: Always
BITOF: TDZA T4,T4 ;Clear T4, and skip
BITON: SETO T4, ;T4 = 0 implies BITOF was called.
SAVEAC <P1> ;Don't trash P1
MOVEM T2,T3 ;Copy the destination address
IDIVI T1,^D36 ;Calculate the number of whole words
MOVEM T2,P1 ;Save the number of bits left over
JUMPLE T1,BITON1 ;No whole words: check for bits left
MOVEM T4,(T3) ;Initialize the first word
MOVE T2,T3 ;Make that the source address
AOS T3 ;The destination is the next word
SOSLE T1 ;Do we need to set more than one word?
XBLT. T1 ;Yes, use a block transfer
BITON1: JUMPE P1,RTN ;Zero bits left: return
MOVEI T1,1 ;Calculate the negative number
SUB T1,P1 ; of bits to shift plus one
MOVX T2,1B0 ;Get a bit to be shifted
ASH T2,(T1) ;Build a bit mask for the last word
SKIPN T4 ;BITOF?
SETCA T2, ;Yes. T2 = ~T2
MOVEM T2,(T3) ;Use it
RET ;
SUBTTL Subroutine -- CWHLAT - Type a server spec for WHERE command
;CWHLAT - Types a server spec given a LATSER-owned LDB.
;
; Call:
; U/ Target LDB address
; 0(P)/ Command LDB address
;
; Return:
; RET ;If success
; via CWHNCN ;If line is not owned by LATSER
;
; Used: T1-T4
RESCD
IFN FTOPS10,<
CWHLAT::POP P,T1 ;Can't call SE1ENT with junk on stack!
SE1ENT ;So we can access NZS data
PUSH P,T1 ;RE-save LDB of command term
SKIPN T1,LDBLAT##(U) ;Get slot block associated with target TTY
PJRST CWHNCN## ;Not connected now.
POP P,U ;Point to command terminal for typeout
PUSH P,DEVNAM(F) ;Save TTY name
PUSH P,SB.CBA(T1) ; and Circuit Block address.
CALL TTYKLQ## ;ZAP useless TTY DDB
CALL INLMES## ;Type out an intro
ASCIZ /LAT / ; guess what!
MOVE T2,(P) ;Get LAT circuit block address
LOAD T1,CBRSC,(T2) ;Get server name count from it
ADD T2,[OWGP. 7,CB.SNM] ;Make byte pointer to name
CALL TCSTR ;(T1-T2)Type a counted string
MOVEI T3,"(" ;Separate it
CALL COMTYO## ; from location
POP P,T2 ;Get CB address for last time
LOAD T1,CBRLC,(T2) ;Get server location count from it
ADD T2,[OWGP. 7,CB.LOC] ;Make byte pointer to location
CALL TCSTR ;(T1-T2)Type a counted string
CALL INLMES## ;Close it off
ASCIZ /) / ;and separate it.
POP P,T2 ;Get TTY name
CALL PRNAME## ; and type it.
CALLRET PCRLF## ;and return
;Still in IFN FTOPS10
; Routine TCSTR - type a counted ASCII string
;
;Call: T1/ byte count
; T2/ byte pointer
;
TCSTR: SOJL T1,CPOPJ## ;No chars to type
PUSH P,T1 ;save the count in a safe place
TCST1: ILDB T3,T2 ;Get a character
CALL COMTYO## ; and type it
SOSL (P) ;Count them down
JRST TCST1 ; and do them all
POP P,T1 ;trim the stack
RET ; and return
XRESCD
; Once-A-Second code
;
LATSEC: SKPCPU (0) ;SKIP IF WE'RE ON POLICY CPU
RET ;NO, ONLY RUN ONCE A SECOND!
CALL XLATXP ;[7.1120]Transmit Command messages
SKIPLE LATMCT ;IS the timer non-zero?
SOSLE LATMCT ;Count down the timer
RET ;Not time to do anything yet
; CALLRET LATXMC ;()Fall into multicast transmit code
>;end IFN FTOPS10
SUBTTL Multicast Transmitter
;LATXMC - Transmit Multicast Message
;CALL: CALL LATXMC
; Normal Return
XRENT (LATXMC,G) ;[7.1024]LATXMC::, XLATXM::
ACVAR <HN,XB,W1,W2>
MOVE HN,LAHNDB ;Get the HN data base address
LOAD T1,HNMTI,(HN) ;Reset the multicast timer
IFN FTOPS20,<
IMULI T1,^D1000 ;Convert from seconds to milliseconds
>;END IFN TOPS20
MOVEM T1,LATMCT ;
CALL CHKXMC ;(HN)Transmit the multicast this time?
RET ;No.
CALL GETRBF ;(HN)Post more receive buffers if necessary.
TRN ;Not necessary.
CALL DYNRAT ;(HN)Check if dynamic rating needs update.
XMOVEI XB,HN.MCM(HN) ;Get the address of the multicast msg
OPSTR <SKIPE W1,>,HNCFL,(HN);If nothing changed in HN database
OPSTR <SKIPL>,HNLOK,(HN); or something changed by db id locked
JRST SNDMNC ; then send the old image of mc msg
CAIE W1,HN%SVR ;Did only the ratings change?
JRST LATXM0 ;No, something else changed
CALL BMCRAT ;(HN,XB)Go update the ratings
JRST LATXM2 ; and send the mc msg
LATXM0: SETZ T1,0 ;So BMCFXD will increment incarnation count
TRNE W1,HN%OTH ;Did something in fixed part of mc change?
CALL BMCFXD ;(T1,HN,XB)Yes, go rebuild fixed part of mc msg
TRNE W1,HN%ACS ;Did any access codes change?
CALL BMCACS ;(HN,XB)Yes, go rebuild access code field
TRNE W1,HN%NDD ;Did the host node description change?
CALL BMCNID ;(HN,XB)Rebuild the node description
TRNN W1,HN%NDD ; and the service fields
LATXM1: TRNE W1,HN%SVN!HN%SVD!HN%SVR;Did anything in any service change?
CALL BMCSRV ;(HN,XB)Yes, reconstruct all service fields
LATXM2: SETZRO HNCFL,(HN) ;Clear data base change flags
SENDMC: MOVX T1,<POINT 8,<SBF.OF+1>(XB),23>;Pointer msg change flags
LDB T2,T1 ;Message incarnation field
AOS T2 ;Add one
DPB T2,T1 ; and put back into msg
ILDB T2,T1 ;Load current change flag settings from msg
TDC T2,W1 ;Complement those bits which represent change
DPB T2,T1 ; and put back into msg
SNDMNC: XMOVEI T1,<SBF.OF>(XB) ;Set up one word global to buffer for
TXO T1,<OWGP. 8,0> ; NISRV and
STOR T1,UNBFA,+UNB.OF(XB); store in UN block
LOAD T1,HNPID,(HN) ;Get the PID for the DLL
STOR T1,UNPID,+UNB.OF(XB)
MOVX T1,NU.XMT ;Set NI function to transmit
XMOVEI T2,UNB.OF(XB) ;Address of arguement block for NISRV
IFN FTOPS20,<
CALL DLLUNI## ;Call NI service
>
IFN FTOPS10,<
SNCALL (DLLUNI##,MCSEC1) ;Call NI service
>
TRN ;Ignore error
RET ;Return
SUBTTL Routine to check/compute the Dynamic Rating
;DYNRAT - Routine to check/compute the Dynamic Rating
DYNRAT:
IFN FTOPS20,<
MOVE T1,RJAV+2 ;15 minute load average
FSC T1,2 ;Multiply by 4
FIXR T1,T1 ;and convert/round to integer
SUBI T1,^D255 ;Subtract from 255 to give negative rating.
SKIPLE T1 ;Assure rating
MOVX T1,-1 ; is at least 1
MOVMS T1 ;Make rating positive
OPSTR <CAMN T1,>,HNRAT,(HN) ;Compare with current dynamic rating
RET ;No change; return.
STOR T1,HNRAT,(HN) ;Store new rating in HN block
SETONE HNSVR,(HN) ;Indicate rating has changed.
>;END IFN FTOPS20
IFN FTOPS10,<
MOVEI T1,1 ;No dynamic rating for TOPS-10
>;END IFN FTOPS10
RET
SUBTTL Routines to Build the Host Multicast Message -- BMCFXD
;BMCFXD - Build fixed portion of the multicast message
;Call: T1/ Incarnaction count flag
; HN/ Host Node Data Base Address
; XB/ Address of the multicast message block in HN
; CALL BMCFXD
;
; This routine builds the first ^D12 bytes of the multicast message. It is
; called either to build a new message or to update the fixed portion if any
; of the parameters in the fixed portion have changed since the last multicast
; message was transmitted. This routine does not modify the message count.
BMCFXD: STKVAR <INCFLG> ;Save the incarnaction
MOVEM T1,INCFLG ; flag.
MOVX T1,<POINT 8,<SBF.OF>(XB)> ;Byte pointer to start of msg
STOR T1,UNBFA,+UNB.OF(XB); is needed to fill in the msg header
MOVEI T1,MT.MCA_2 ;Message type for multicast message
OPSTRM <IDPB T1,>,UNBFA,+UNB.OF(XB)
MOVEI T1,^D8 ;Set 80ms preferred server circuit timer
OPSTRM <IDPB T1,>,UNBFA,+UNB.OF(XB)
MOVEI T1,LALPV_^D8+LAHPV;Highest and lowest permitted protocol version
CALL LAP2B0 ;(T1)
MOVEI T1,PROECO_^D8+PROVER ;Enter current protocol version and ECO
CALL LAP2B0 ;(T1)
OPSTR <ILDB T1,>,UNBFA,+UNB.OF(XB);Get old incarnation count and assume
AOS T1 ; we just want to increment it.
SKIPN INCFLG ;If this is initialization, we want a "random"
IFSKP. ; incarnation count instead.
MOVEI T1,^D255 ;Maximum value incarnation count can have.
CALL RANDOM ; (T1/T1)the initial message incarnation count.
ENDIF.
OPSTRM <DPB T1,>,UNBFA,+UNB.OF(XB); and put back
LOAD T1,HNCFL,(HN) ;Get the change flags
OPSTRM <IDPB T1,>,UNBFA,+UNB.OF(XB)
MOVEI T1,LMRFSI+^D14 ;Receive buffer size (including E-net header)
CALL LAP2B0 ;(T1)
LOAD T1,HNMTI,(HN) ;Get the multicast timer interval
OPSTRM <IDPB T1,>,UNBFA,+UNB.OF(XB)
MOVEI T1,0 ;Set status indicating accepting new sessions.
LOAD T2,HNLAS,(HN) ;Get the current LAT access state
CAIE T2,LS.ON ;Is it on?
MOVEI T1,1 ;No, indicate not accepting new sessions.
OPSTRM <IDPB T1,>,UNBFA,+UNB.OF(XB)
RET
SUBTTL Routines to Build the Host Multicast Message -- BMCFXD
;BMCACS - Enter Access Codes into the Multicast Message - BMCACS
;Call: HN/ Host Node Data Base Address
; XB/ Address of the multicast message block in HN
; CALL BMCACS
; Normal Return
;
; This routine builds ^D32 bytes of host access codes. It is called either to
; build a new message or to update the fixed length access code field if any of
; the access codes have changed since the last multicast message was
; transmitted. This routine does not modify the message count.
BMCACS:
MOVX T1,<POINT 8,<SBF.OF+^D12/4>(XB)> ;ACs start at a fixed location
STOR T1,UNBFA,+UNB.OF(XB) ;Store as byte pointer to message buffer
LOAD T1,ACLNG,(HN) ;Count of the access code string
MOVX T2,<POINT 8,AC.COD(HN)> ;Source string byte pointer
CALL PTCST0 ;(XB,T1,T2)Transfer the string to the message
RET
SUBTTL Routines to Build the Host Multicast Message -- BMCNID
;BMCNID - Enter Access Codes into the Multicast Message - BMCNID
;Call: HN/ Host Node Data Base Address
; XB/ Address of the multicast message block in HN
; CALL BMCNID
; Normal Return
;
; This routine enters the host node name and descriptor strings into the
; multicast message block. It is called either to build a new message or to
; update the fixed length access code field if the node name or descriptor
; has changed since the last multicast message was transmitted. If this
; routine is called, the rest of the multicast message must be rebuilt. This
; routine does not modify the message count.
BMCNID:
MOVX T1,<POINT 8,<SBF.OF+^D12/4+^D32/4>(XB),7> ;Node name starts here
STOR T1,UNBFA,+UNB.OF(XB) ;Store as byte pointer to message buffer
LOAD T1,HNNMC,(HN) ;Host name count
MOVX T2,<POINT 7,HN.NAM(HN)> ;Source string byte pointer
CALL PTCST0 ;(XB,T1,T2)Transfer host node name to m.c.msg
LOAD T1,HNIDC,(HN) ;Count of host node description string
MOVX T2,<POINT 7,HN.ID(HN)> ;Move the host node id string to the
CALL PTCST0 ; (XB,T1,T2)m.c. message
RET
SUBTTL Routines to Build the Host Multicast Message -- BMCSRV
;BMCSRV - Build the Available Host Services Data - BMCSRV
;Call: HN/ Host Node Data Base Address
; XB/ Address of the multicast message block in HN
; CALL BMCSRV
; Normal Return
;
; This routine enters all service blocks and the service classes into the
; multicast message block. It is called either to build a new message or to
; update the message when any service name or description has changed since
; the last multicast message was transmitted. This routine does modify the
; message count.
BMCSRV: SAVEAC <W1,W2>
LOAD W1,HNNSV,(HN) ;Get the total number of offered services
SKIPN W1 ;Must be at least one service to offer
RET ;Nope.
MOVEI T4,^D12+^D33+1 ;Initialize msg count
MOVX T3,<POINT 8,<SBF.OF+^D12/4+^D32/4>(XB),7>;Get pointer to node name
ILDB T1,T3 ;Get node name count
ADDI T4,1(T1) ;Include in total msg count
ADJBP T1,T3 ;Adjust to node descriptor
ILDB T3,T1 ;Get the node description count
ADDI T4,1(T3) ;Include in total msg count
ADJBP T3,T1 ;Adjust pointer to start of Service Block
STOR T4,UNBSZ,+UNB.OF(XB);Store msg count so far
STOR T3,UNBFA,+UNB.OF(XB);Current message byte pointer
OPSTRM <IDPB W1,>,UNBFA,+UNB.OF(XB);Already counted
XMOVEI W2,HN.SRV(HN) ;Address of start of service blocks
SRVLP: OPSTR <SKIPGE T1,>,GBRAT,(W2) ;Get the service rating
LOAD T1,HNRAT,(HN) ;If negative, load current host dynamic rating.
OPSTRM <AOS>,UNBSZ,+UNB.OF(XB);Account for rating in the byte count
OPSTRM <IDPB T1,>,UNBFA,+UNB.OF(XB);Store in mc msg
LOAD T1,GBNC,(W2) ;Get the service name count
MOVX T2,<POINT 7,GB.NAM(W2)> ;Pointer to service name
CALL PTCSTR ;(XB,T1,T2)Move name string to mc msg
LOAD T1,GBLC,(W2) ;Get the service description count
MOVX T2,<POINT 7,GB.HID(W2)>;Pointer to the service description string
CALL PTCSTR ;(XB,T1,T2)Move to mc msg
ADDI W2,GB.LEN ;Address of next block
SOJN W1,SRVLP ;Loop through all services
MOVEI T1,1_^D8+1 ;Service class 1 only
CALL LAP2BY ;(XB,T1)
RET
SUBTTL Routines to Build the Host Multicast Message -- BMCRAT
;BMCRAT - Update the MC Msg with the current service ratings - BMCRAT
;Call: HN/ Host Node Data Base Address
; XB/ Address of the multicast message block in HN
; CALL BMCRAT
; Normal Return
;
; This routine loops though all the service blocks and updates the
; corresponding service rating in the multi-cast message. This routine does
; NOT modify the message count itself.
BMCRAT: SAVEAC <W1,W2>
MOVX T3,<POINT 8,<SBF.OF+^D12/4+^D32/4>(XB),7>;Get pointer to node name
ILDB T1,T3 ;Get node name count
ADJBP T1,T3 ;Adjust to node descriptor
ILDB T3,T1 ;Get the node description count
ADJBP T3,T1 ;Adjust pointer to start of Service Block
ILDB W1,T3 ;Get number of services from msg
XMOVEI W2,HN.SRV(HN) ;Address of start of service blocks
RATLP: OPSTR <SKIPGE T1,>,GBRAT,(W2) ;Get the service rating
LOAD T1,HNRAT,(HN) ;If negative, load current host dynamic rating.
IDPB T1,T3 ;Store updated rating in mc msg
LOAD T1,GBNC,(W2) ;Get the service name count
OPSTR <ADD T1,>,GBLC,(W2);Add the service description count
ADDI T1,2 ;Account for the 2 count fields
ADJBP T1,T3 ;Adjust the pointer
MOVE T3,T1 ;Put adjusted pointer back where we want it
ADDI W2,GB.LEN ;Address of next block
SOJN W1,RATLP ;Loop through all services
RET
SUBTTL Multicast Transmit Check Routine
;CHKXMC - Check for Transmit of Multicast Message
;Call: HN/ Address of the Host Node Data Base
;RET - Don't transmit
;RETSKP Transmit
CHKXMC: LOAD T1,HNLAS,(HN) ;Transmit only if LAT access state is ON and
LOAD T2,HNNMC,(HN) ; there is a host name defined.
CAIN T1,LS.ON ; is ON.
SKIPN T2
RET
TMNE HNRUN,(HN) ;Is the NIA running?
RET ;No, don't send any messages.
RETSKP
SUBTTL Build the START Message Template
;BLDSTM - Build the START Message Template
;Call: HN/ Address of the Host Node Data Base
; CALL BLDSTM
; Normal Return
;
; This routine builds the "static" portions of the start message: those
; fields which do not change very frequently. Fields which change frequently
; are set up by the transmitting routines. This routine also sets up the
; message size in UNBSZ of the NISRV UN block.
BLDSTM: SAVEAC <W1>
XMOVEI XB,HN.SMT(HN) ;Address of START message template
MOVX T1,<POINT 8,<SBF.OF+<SZ.MHD>/4>(XB)>;Point beyond the msg header
STOR T1,UNBFA,+UNB.OF(XB); since it will change with each transmission.
MOVEI W1,^D12 ;Count of fixed fields (including count fields)
MOVEI T1,LMRFSI+^D14 ;Minimum receive buffer size
CALL LAP2B0 ;(XB,T1)Store in msg
MOVEI T1,PROECO_^D8+PROVER ;Enter current LAT protocol version
CALL LAP2B0 ;(XB,T1) and ECO
LOAD T1,HNMCO,(HN) ;System-wid maximum LAT connects allowed
CAILE T1,MXSLTS ; compared to max slots per virtual circuit
MOVEI T1,MXSLTS ;Get the smaller of the two
CALL LAP2B0 ;(XB,T1)
MOVEI T1,0 ;Timers are non-zero when from server
CALL LAP2B0 ;(XB,T1) only.
LOAD T1,HNNUM,(HN) ;Get the host number
CALL LAP2B0 ;(XB,T1) and store as 2 bytes in msg
MOVEI T1,LHPRID ;LAT Host product ID is TOPS-20 Host
CALL LAP2B0 ;(XB,T1) and store as 2 bytes in msg
LOAD T1,HNNMC,(HN) ;Host Node Name count
ADDI W1,1(T1) ;Add to the total message byte count
MOVX T2,<POINT 7,HN.NAM(HN)>;Host node name source string
CALL PTCST0 ;(XB,T1,T2)Put into start message as NODE NAME
LOAD T1,HNNMC,(HN) ;Host Node Name count
ADDI W1,1(T1) ;Add to the total message byte count
MOVX T2,<POINT 7,HN.NAM(HN)>;Host node name source string
CALL PTCST0 ;(XB,T1,T2)Put in start message as SYSTEM NAME
LOAD T1,HNIDC,(HN) ;Count of description string
ADDI W1,1(T1) ;Add to the total message byte count
MOVX T2,<POINT 7,HN.ID(HN)>;Description string source pointer
CALL PTCST0 ;(XB,T1,T2)Put into start message
MOVEI T1,0 ;There are no parameters
OPSTRM <IDPB T1,>,UNBFA,+UNB.OF(XB); is zero
ADDI W1,1 ;Include in total count
CAIG W1,MINXBF ;Send at least the minimum
MOVEI W1,MINXBF ; size.
STOR W1,UNBSZ,+UNB.OF(XB);Store message byte count
STOR XB,UNRID,+UNB.OF(XB);Store buffer address for completion routines.
RET
ENDAV.
SUBTTL LAINTR -- LAT DLL Callback Routinea
;LATCBR - dispatch to routine to handle DLL callback
;Call: T1/ NU.RCV
; T2/UN block address
; CALL LATCBR
; Normal return
LATCBR: ACVAR <HN,XB,RB> ;Reserve some registers
MOVE HN,LAHNDB ;Get the host node data base address
MOVE T4,T3 ;Save NISRV's error register
CAIL T1,MINCBF ;Validate the callback function code
CAIG T1,MAXCBF
CALLRET @CBRDSP-MINCBF(T1) ;Valid, call the proper routine
BUG. (CHK,LATICB,LATSER,SOFT,<LATCBR called from NISRV with illegal callback function code>,<<T1,CODE>>,<
Cause: NISRV has called the LATSER callback routine with an invalid function
code.
Data: CODE - Function code
>)
;[7.1024]
;[7.1024] **WARNING** If ILLCBR is moved out of PSECT XRCOD then the
;[7.1024] "IFIW ILLCBR" in the CBRDSP dispatch table must be changed.
;[7.1024]
ILLCBR:
RET
MIN. (MINCBF,<NU.RCV,NU.XMT,NU.EMA,NU.DMA,NU.RCL,NU.RCI,NU.RCC,NU.SCA,NU.RPL,NU.RPI,NU.RPC>) ;Minimum callback function
MAX. (MAXCBF,<NU.RCV,NU.XMT,NU.EMA,NU.DMA,NU.RCL,NU.RCI,NU.RCC,NU.SCA,NU.RPL,NU.RPI,NU.RPC>) ;Maximum callback function
CBRDSP: XADDR. LAINTR ;NU.RCV: Datagram received
XADDR. LAINTX ;NU.XMT: Datagram transmit complete
XADDR. ILLCBR ;NU.EMA: Enable Multicast
XADDR. ILLCBR ;NU.DMA: Disable Multicast
XADDR. ILLCBR ;NU.RCL: Read channel list
XADDR. LATLSC ;NU.RCI: Link state changed
XADDR. ILLCBR ;NU.RCC: Read channel counters
XADDR. LATSCA ;NU.SCA: Set channel address
XADDR. ILLCBR ;NU.RPL: Read portal list
XADDR. ILLCBR ;NU.RPI: Read portal information
XADDR. ILLCBR ;NU.RPC: Read portal counters
SUBTTL LAINTR -- Interrupt Level Virtual Circuit Message Receiver
;LAINTR - Processes a circuit message at NI interrupt level
;Call: T1/ NU.RCV
; T2/UN block address
; T4/NISRV's T3
; CALL LAINTR
; Normal return
LAINTR: LOAD RB,UNRID,(T2) ;Get address of message block
JUMPE T4,LANTR1 ;[7.1039]If error code is 0 proceed
; Here, there was an error on receive. Don't wait for tick time
; to turn the buffer around.
;
MOVE T1,RB ;[7.1039]Get address of receive buffer
CALL RBPOSS ;[7.1039](T1)Repost it now (preserving T1-T4)
TRNA ;[7.1039]Couldn't re-post. Process it later.
RET ;[7.1039]Buffer re-posted. We're done for now.
LANTR1: MOVEI T1,UN.LEN ;[7.1039]Length of the block to copy
XMOVEI T3,UNB.OF(RB) ;Address of where to copy the UN block
XBLT. T1 ;Copy the UN block to buffer header
MOVEI T1,NU.RCV ;Scheduler needs to know buffer type.
MOVE T2,RB ;Address of element to put onto queue
CALL LAINT0 ;(T1,T2,T4)Do common actions
RET ;And return to NISRV dismissing interrupt
SUBTTL LAINTX - Interrupt Level Virtual Circuit Message Receiver
;LAINTX - Processes a circuit message at NI interrupt level
;Call: T1/ NU.XMT
; T2/UN block address
; T4/NISRV's T3
; CALL LAINTX
; Normal return
LAINTX: LOAD XB,UNRID,(T2) ;Get the buffer address
LOAD T3,UNDAD,+UNB.OF(XB);Get first 4 bytes (low order) of NI address
TXNE T3,1B7 ;Is the multicast bit on?
RET ;Yes, nothing to do
MOVX T3,<POINT 8,<SBF.OF>(XB)>;Point to the msg header
ILDB T2,T3 ; and get the message type
LSH T2,-2 ;Shift off M and RRF bits
CAIE T2,MT.STA ;If a START message,
IFSKP. ; then release lock on the START message
SETZRO HNCIP,(HN) ; template and return.
RET
ENDIF.
MOVE T2,XB
CALL LAINT0 ;(T1,T2,T4)Do common actions
RET
; Routine to perform interrupt level actions common to both receive data and
; transmit complete.
;
LAINT0: STOR T1,UNCBA,+UNB.OF(T2);Store callback type for scheduler processing
STOR T4,UNSPI,+UNB.OF(T2);Save NISRV's error return
IFN FTOPS10,<
ETHLOK ;Interlock queue access
>
OPSTR <SKIPN T3,>,HNNIQ,+1(HN);Is the Q currently empty?
IFSKP. ;NO
STOR T2,UELW1,(T3) ;New forward for old Q tail element
SETZRO UELW1,(T2) ;New tail's forward link is zero.
ELSE. ;YES
STOR T2,HNNIQ,(HN) ;New queue header forward pointer
ENDIF.
STOR T2,HNNIQ,+1(HN) ;New queue header tail pointer
IFN FTOPS10,<
ETHULK ;Release interlock
>
RET
ENDAV.
SUBTTL LARSCH - Scheduler Level Virtual Circuit Message Receiver
;LARSCH - Complete circuit message processing at scheduler level
IFN FTOPS10,< ;[7.yyyy]
RESCD ;[7.yyyy]
LATSTO::SKPCPU (0) ;[7.yyyy]On policy CPU?
RET ;[7.yyyy]No, do nothing
; CALLRET LARSCH ;[7.yyyy]Yes, fall into LARSCH
> ;End IFN FTOPS10
XRENT (LARSCH,G) ;[7.1024]LARSCH::, XLARSC::
ACVAR <HN,XB,RB,CB,SB,W1,W2>;Get a set of dedicated ACs
TRVAR <MSGDID,MSGSID,MSGACK,STPCOD>;Message hdr variable, etc.
SETZ CB, ;[7234] No circuit block yet
SKIPN HN,LAHNDB ;Get the host node database address
RET ;If none, not initialized yet.
CALL MOVNIQ ;(T1,T2)Move all messages from NI to Sched que
IFN FTOPS10,<
SETZM LATWFB ;Say we don't want more buffers yet
>
MSGNXT: OPSTR <SKIPN T2,>,HNSCQ,(HN);Get first element on the scheduler Q
CALLRET LAMUX ;No more so call the slot multiplexor
OPSTR <SKIPN T3,>,UELW1,(T2);Get new head or queue if any
STOR T3,HNSCQ,+1(HN) ;None, so clear the queue header tail pointer
STOR T3,HNSCQ,(HN) ;Set new queue header forward pointer
SETZRO UELW1,(T2) ;Clear link word
LOAD T1,UNCBA,+UNB.OF(T2)
CAIE T1,NU.XMT ;Is this a transmit complete?
IFSKP. ;Yes...
CALL XMTDON ;(T1,T2)Do scheduler level transmit done stuff
JRST MSGNXT ; and continue with next message
ENDIF.
MOVE RB,T2 ;Message address obtained
SKIPE T1,UN.SPI+UNB.OF(RB);Was there an error?
JRST MSGDON ;Re-post and ignore
OPSTRM <AOS>,HCRCV,(HN) ;Increment count of received messages
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB) ;[7.1120]Get the message type from the buffer
MOVE T1,T2 ;[7.1120]
LSH T1,-2 ;Shift off the M and RRF bits
CAIL T1,MINMTY ;Range check message type
CAILE T1,MAXMTY ;...
IFNSK.
BUG. (CHK,LATIMT,LATSER,SOFT,<LAT Illegal Message Type>,<<T1,MSGTYP>>,<
Cause: The LAT virtual circuit message was received with a message type out
of range.
Data: MSGID - Message type
>)
ELSE.
TRNE T2,MSB.FL ;[7.1155]Test the Master/Slave bit
IFSKP. ;[7.1155]If it's a slave message...
CAIE T1,MT.RIN ;[7.1155]Is it a Response Information Message
CAIN T1,MT.STS ;[7.1155] or a status message?
TRNA ;[7.1155] Yes, skip
JRST MSGDON ;[7.1155] No. Ignore for now
ENDIF. ;[7.1155]
CALL @MSGDSP-MINMTY(T1) ;Dispatch to process the message
ENDIF.
MSGDON: CALL RELRBF ;(RB)Ignore for now
JRST MSGNXT
MIN. (MINMTY,<MT.RUN,MT.STA,MT.STP,MT.STS,MT.RIN>) ;[7.1120]Minimum message type code
MAX. (MAXMTY,<MT.RUN,MT.STA,MT.STP,MT.STS,MT.RIN>) ;[7.1120]Maximum message type code
MSGDSP: XADDR. HMRUN ;[7.1052]RUN message received
XADDR. HMSTRT ;[7.1052]START message received
XADDR. HMSTOP ;[7.1052]STOP message received
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. RTN ;[7.1120]
XADDR. HMSTAT ;[7.1120]STATUS message received
XADDR. RTN ;[7.1120]
XADDR. HMINFO ;[7.1120]RESPONSE INFORMATION received
;MOVNIQ - Move all messages on the NI queue to the Scheduler queue
;Call: T1/ Pointer to head of NIQ
; T2/ Pointer to tail of NIQ
; CALL MOVNIQ
; Normal return
;
;Uses: T3,T4
MOVNIQ:
IFN FTOPS20,<
CHNOFF NIPIA ;Turn off NI interrupts
>
IFN FTOPS10,<
ETHLOK ;Turn off NI interrupts
>
DMOVE T1,HN.NIQ(HN) ;Get the header contents
SETZM HN.NIQ(HN) ;Clear the queue begin pointer
SETZM HN.NIQ+1(HN) ;Clear the end pointer
IFN FTOPS20,<
CHNON NIPIA ;Turn NI back on
>
IFN FTOPS10,<
ETHULK ;Turn NI back on
>
OPSTR <SKIPN T3,>,HNSCQ,+1(HN);Is there anything on the queue?
IFSKP. ;YES
STOR T1,UELW1,(T3) ;Add new elements at the queue tail.
ELSE. ;NO
STOR T1,HNSCQ,(HN) ;New queue header forward pointer
ENDIF.
STOR T2,HNSCQ,+1(HN) ;New queue header tail pointer.
RET
SUBTTL LATLSC - Ethernet Link State Change Callback
;LATLSC - Process an asynchronous link state change
;Call: T1/ NU.RCI
; T2/ UN block address
; Normal return
;
LATLSC: MOVX T3,HNRUN
TMNN UNRUN,(T2) ;[7.1039]Is the NI running?
IFSKP. ;[7.1039]
ANDCAM T3,HN.FLG(HN) ;[7.1039]NI is up
ELSE. ;[7.1039]
IORM T3,HN.FLG(HN) ;NI went down.
ENDIF.
RET
;LATSCA - Process a set channel address callback
;Call: T1/ NU.SCA
; T2/ UN block address
; Normal return
;
LATSCA: MOVEI T1,1 ;
SKIPLE LATMCT ;Send the multicast message at the
MOVEM T1,LATMCT ; next once-a-second time
RET ;
;[7.1120]
;MSBGN - Parse the beginning of the RUN, START, and STOP messages.
;
; RB/ Address of message block
; CALL MSBGN
; Return+1: Always
MSBGN: OPSTR <ILDB T1,>,UNBFA,+UNB.OF(RB)
MOVEM T1,NSLOTS ;Get number of slots in message
DECR UNBSZ,+UNB.OF(RB) ;Reduce byte count by two
DECR UNBSZ,+UNB.OF(RB)
CALL LAG2BY ;Get the destination ID from msg
MOVEM T1,MSGDID ; (2 bytes, unsigned)
CALL LAG2BY ;Get the source id from the msg
MOVEM T1,MSGSID ; (2 bytes, unsigned)
CALL LAG2BY ;Get the ACK/SEQ field from msg
MOVEM T1,MSGACK ; (2 bytes, unsigned)
RET ;
SUBTTL Message Receiver - HMSTRT
;HMRUN - Process a Host START Message
;
; RB/ Address of receive buffer
; CB/ Address of circuit block
; HN/ Address of host node data base
; CALL HMSTRT
; Return+1: Always
HMSTRT: CALL MSBGN ;[7.1120](RB)Parse the beginning
TMNN HNCIP,(HN) ;If the START message template is locked
SKIPN MSGSID ;or source's message handle is 0
RET ; ignore since server will persist.
LOAD T1,HNLAS,(HN) ;[7.1039]If LAT access state is not ON, ignore
CAIE T1,LS.ON ;[7.1039] the START message.
RET ;[7.1039] ...
LOAD T1,HNNAC,(HN) ;If the addition of this circuit brings total
OPSTR <CAML T1,>,HNMAC,(HN); over the maximum number of active circuits
JSP T2,NOCRE0 ;[7234] then reject it.
CALL HSTRCB ;(RB/CB)Find CB associated with this circuit.
RET ;None. Error action already taken.
LOAD T1,CBSTA,(CB) ;Get the current circuit state
CAIE T1,CS.RUN ;[7.1039]If the state is running,
IFSKP. ;[7.1039]
CALL RELSBS ;[7.1039](CB)Release all current slots
CALL RFXBFS ;[7.1039](CB)Release all buffers on free queue
CALL MDLXBF ;[7.1039](CB)Make all buffers on ACK queue for later release
ENDIF. ;[7.1039]
CALL GETXBH ;(CB)Get necessary number of transmit buffer
SKIPA ; headers (+MSD pointers)
CALL GETRBF ;(HN)Go see if we need more receive buffers
JSP T2,NOCRES ;Could not get the necessary buffer quota
CALL CBINIT ;(CB,RB)Initialize all host CB parameters
RET ;START message format bad. Error action done.
CALL MTTSTR ;()Send a START message
MOVEI T1,CS.STA ;Put the circuit into the
STOR T1,CBSTA,(CB) ; STARTING state.
IFN FTOPS10,<
MOVEI T1,MAXXBF+1 ;New circuit, add some buffers
CAMLE T1,LATNFB ;Are there already enough free buffers?
ADDM T1,LATWFB ;No, ask for some more
>;END IFN FTOPS10
RET
SUBTTL HSTRCB
;HSTRCB - Find the circuit block for a received START msg on a LAT host.
;Call: RB/ address of received message block
; CALL HSTRCB
; Error Return - CB not found
; Normal Return
; CB/ Circuit Block address
HSTRCB: XMOVEI T1,HN.QIC(HN) ;Search the inactive CB queue first
CALL CMNIAD ;(T1,RB/CB)Look for NI address match
SKIPA ;Not found on the inactive CB queue
JRST CBIFND ;Correct CB found on inactive CB queue
NFND1: XMOVEI T1,HN.QAC(HN) ;Not on inactive Q, try active Q
CALL CMNIAD ;(T1,RB/CB)Look for NI address match
SKIPA ;Not on active queue either
JRST CBAFND ;Active CB has been found
NFND2: LOAD T2,HNNAC,(HN) ;Get number of currently active CBs
OPSTR <CAML T2,>,HNMXC,(HN) ;Compare with maximum allowed
IFSKP. ;Not at maximum number of CBs allowed
MOVEI T1,CC.LST ;The number of words to get for a CB
CALL MMGTZW ;(T1/T1)Go get them
JSP T2,NOCRES ;Failed
MOVE CB,T1 ;This is the new CB address
MOVEI T1,CS.HLT ;Don't assume that the halted state
STOR T1,CBSTA,(CB) ; is zero.
OPSTRM <AOS>,HNNCC,(HN);Increment number of allocated CBs.
JRST CBALNW ;Allocated new CB successfully
ENDIF.
OPSTR <SKIPN CB,>,QLBWD,+HN.QIC(HN);Check inactive Q for free CB
JSP T2,NOCRES ;None, so can't reuse an inactive CB
CBIFND: MOVE T2,CB ;Remove from inactive CB queue
CALL LAUNQ ;(T1,T2)
CBALNW: CALL CBGNIX ;(CB)Get next assignable index for the CB
XMOVEI T1,HN.QAC(HN) ;Put at the front of the active
MOVE T2,CB ; CB
CALL LAQUE ;(T1,T2) queue
OPSTRM <AOS>,HNNAC,(HN) ;New active circuit. Count it.
SETONE CBSTA,(CB) ;Set state to non-HALTED since now active
OPSTRM <AOS>,CCRCV,(CB) ;Increment per server count
OPSTR <DMOVE T1,>,UNSAD,+UNB.OF(RB);Move the source NI address from
OPSTRM <DMOVEM T1,>,CBDNI,(CB) ; message to the CB
CBAFND: RETSKP ;Return success
SUBTTL CBINIT - Circuit Block Initialization
;CBINIT - Initialize a Circuit Block from the Contents of a START Message
;Call: CB/ Address of Circuit Block
; RB/ Address of Message Block
; CALL CBINIT
; Error Return - START Message content in error.
; Normal Return
CBINIT: MOVEI T1,MSTMSI ;Check to see if the message is at least
OPSTR <CAMLE T1,>,UNBSZ,+UNB.OF(RB); the minimum size for a START msg
JSP T2,ILLMES ;No, too short.
SETZM CLRBEG(CB) ;Clear the region which must be initialized
MOVEI T1,<CLREND-CLRBEG>; to zero when a circuit block is
XMOVEI T2,CLRBEG(CB) ; re-used.
XMOVEI T3,CLRBEG+1(CB) ; ...
XBLT. T1 ; ...
MOVE T1,MSGSID ;Move source's circuit ID from message
STOR T1,CBRID,(CB) ; to circuit block
CALL LAG2BY ;(MA/T1)Get maximum transmit frame size which
STOR T1,CBMTF,(CB) ; the remote will allow
OPSTR <ILDB T1,>,UNBFA,+UNB.OF(RB);LAT protocol version used by remote
CAIL T1,LALPV ;Check if in the range of version supported
CAILE T1,LAHPV ; by this node
JSP T2,LVSKEW ;Out of range, return error
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB);Remote's protocol ECO level
LSH T2,^D9 ;Shift protocol version
IOR T1,T2 ;OR version and ECO level
STOR T1,CBRPV,(CB) ; and store as single unit
OPSTR <ILDB T1,>,UNBFA,+UNB.OF(RB);Maximum number of slots in VC message
STOR T1,CBMSL,(CB) ; permitted by remote
OPSTR <ILDB T1,>,UNBFA,+UNB.OF(RB);Number of additional receive buffers
STOR T1,CBNBF,(CB) ; queued by remote for this circuit
OPSTR <ILDB T1,>,UNBFA,+UNB.OF(RB);Remote's circuit timer value
STOR T1,CBCTI,(CB) ;
OPSTR <ILDB T1,>,UNBFA,+UNB.OF(RB);Remote's keep-alive timer value
STOR T1,CBKTI,(CB) ;
IMULI T1,^D2000 ;[7.xxxx]Convert to ms and multiply by 2 (fudge factor)
STOR T1,CBKAV,(CB) ; and store in keep alive value field.
MOVX T1,-^D6 ;Decrement residual message count by what we
OPSTRM <ADDM T1,>,UNBSZ,+UNB.OF(RB); have read so far.
CALL LAG2BY ;(MA/T1)Get the "facility number"
STOR T1,CBNUM,(CB)
CALL LAG2BY ;(MA/T1)Get the product type code
STOR T1,CBPTC,(CB)
MOVEI T1,0 ;Skip the circuit name
CALL GTCSTR ;(T1,T2,RB)
JSP T2,ILLMES ;Illegally formatted message
MOVEI T1,ML.SYS ;Maximum length of system's name string
XMOVEI T2,CB.SNM(CB) ;Where copy the name string
TXO T2,<OWGP. 7,0>
CALL GTCSTR ;(T1,T2,RB)
JSP T2,ILLMES ;Illegally formatted message
STOR T1,CBRSC,(CB) ;Save the length of the name string
MOVEI T1,ML.LOC ;Maximum length of the system's location string
XMOVEI T2,CB.LOC(CB) ;Where to copy the location string
TXO T2,<OWGP. 7,0>
CALL GTCSTR ;(T1,T2,RB)
JSP T2,ILLMES ;Illegally formatted message
STOR T1,CBRLC,(CB) ;Save the length of the location string
RETSKP
SUBTTL CMNIAD - Find CB base on NI address
;CMNIAD - search the CBs on a CB queue looking for one which has the same
; NI address as the source NI address in the incoming message.
;Call: T1/ Queue header of CB queue to search
; RB/ Address of the circuit message
; CALL CMNIAD
; Not found return
; Success return
; T1/ unchanged
; CB/ circuit block address if found, 0 otherwise
CMNIAD: LOAD CB,QLFWD,(T1) ;Get the first queue entry
CMLOOP: JUMPE CB,RTN ;Is this last entry?
LOAD T3,CBDNI,(CB) ;First 4 bytes of remote NI address from CB
LOAD T4,CBDNI,+1(CB) ;Last 2 bytes
OPSTR <CAMN T3,>,UNSAD,+UNB.OF(RB);Compare with message destination adr
OPSTR <CAME T4,>,UNSAD,+<UNB.OF+1>(RB) ;...
IFNSK.
LOAD CB,QLFWD,+CB.LNK(CB); Get next forward CB
JRST CMLOOP ;Try again
ENDIF.
RETSKP ;Return success
;CBGNIX - Get the next assignable index for a CB
;Call: CB/ address of circuit block
; CALL CBGNIX
; Normal Return
;
; This routine is called each time a CB is to be used for a new LAT
; virtual circuit. The old index vector (CBVECT) pointer to the CB
; is deleted and a new index is generated.
CBGNIX: MOVE W1,CBVECT ;Get the address of the CB index vector
OPSTR <SKIPN T2,>,CBLID,(CB);Get the old circuit index, if any.
IFSKP.
ADD T2,W1 ;Get the address of the pointer to this CB
SETZM (T2) ; in the CB index vector and clear it.
ENDIF.
LOAD T2,HNNXI,(HN) ;Get the next available index to assign
STOR T2,CBLID,(CB) ;Set the new index in the CB
MOVE T1,W1 ;Address of teh CB index vector
ADD T1,T2 ;Offset into this vector for new index
MOVEM CB,(T1) ;Set the new pointer to point to new CB
CBGNX0: AOS T2 ;Increment the next available index
AOS T1 ; and the corresponding index vector pointer
CAIG T2,CBMAXI ;Time to wrap around?
IFSKP. ;Yes
MOVEI T2,1 ;Always start at 1
MOVE T1,W1
ENDIF.
SKIPE (T1) ;Is this vector entry free?
JRST CBGNX0 ;No, try next
STOR T2,HNNXI,(HN) ;Store new "next assignable index"
RET
SUBTTL HMRUN
;HMRUN - Process a Host RUN Message
;
; RB/ Address of receive buffer
; CB/ Address of circuit block
; HN/ Address of host node data base
; CALL HMRUN
; Return+1: Always
HMRUN: CALL MSBGN ;[7.1120](RB)Parse the beginning
CALL HRUNCB ;(RB/CB)Get the circuit block address
RET ;None, error action already comleted
SKIPE T2,MSGDID ;Destination and source circuit IDs from
SKIPN T1,MSGSID ; the message may not be zero
JSP T2,ILLMES ;If so, it is illegal
LOAD T3,CBRID,(CB) ;Get the remote's circuit index from the CB
LOAD T4,CBLID,(CB) ; and our circuit index from the CB must match
CAMN T1,T3 ; the source id and
CAME T2,T4 ; the destination id from the msg.
JSP T2,INVRUN ;Invalid RUN msg, go terminate the circuit.
MOVE T1,TODCLK ;Get current time
STOR T1,CBKAT,(CB) ;Save time for keep-alive process
MOVEI T1,CS.RUN ;Put in RUNNING state if not there already
STOR T1,CBSTA,(CB) ;Store state in CB
MOVE T1,MSGACK ;Get the SEQ/ACK number
MOVE W1,T1 ;
ANDI T1,377 ;Received message sequence number
LSH W1,-^D8 ;Last message ack'd by remote
LOAD T3,CBRSQ,(CB) ;Previous recv SEQ number
AOS T3 ;Increment
ANDI T3,377 ;Modulo 256
CAME T1,T3 ;Is is the expected sequence number
IFSKP.
STOR T1,CBRSQ,(CB) ;Update expected sequence number for next time
ELSE.
SETZM NSLOTS ;No, ignore any slots in this message
OPSTRM <AOS>,HCSEQ,(HN);Increment Host's count
OPSTRM <AOS>,CCSEQ,(CB);Increment per-server count
ENDIF.
LOAD T3,CBLRA,(CB) ;Previous "last ACK from remote"
STOR W1,CBLRA,(CB) ;New "last ACK from remote"
CAMGE W1,T3 ;Is new ACK less than old ACK?
ADDI W1,^D256 ;Yes, new ACK has wrapped around
SUB W1,T3 ;Number of messages ACK'd by this msg
CAILE W1,MAXXBF ;Range check it and if out of range
JSP T2,ILLMES ; treat as an illegal message
SKIPN W1 ;If anything got ACK'd
IFSKP.
SETZRO CBRTC,(CB)
ENDIF.
NXTACK: JUMPE W1,ACKDON ;No new messages ACK'd
MOVE XB,CB.AKQ(CB) ;Sneak look at buffer at head of Q
CALL RELXBF ;(XB)Free large MSD buffer.
XMOVEI T1,CB.AKQ(CB) ;Unqueue the now acknowledged buffers
CALL UNQ1WF ;(T1/T2) from the ACK wait queue
JSP T2,ILLMES ;Should not happen
XMOVEI T1,CB.XBQ(CB) ;Queue them back to the transmit buffer
CALL QUE1WB ;(T1,T2) queue.
SOJA W1,NXTACK
ACKDON: OPSTR <SKIPN>,CBAKQ,(CB);If all messages ack'd
SETZRO CBTIM,(CB) ; clear the circuit timer.
SETONE CBMRS,(CB) ;Indicate we must respond to this msg "soon"
CALL LSDMUX ;(RB)Go process all slots in the RUN message
IFNSK. ;Invalid slot type returned.
BUG. (INF,LATIST,LATSER,SOFT,<LAT Illegal Slot Type>,<<T2,SLTID>>,<
Cause: LAT Slot received with Slot type out of range.
Data: SLTID - Slot ID
>)
MOVEI T1,CE.ILL ;Set up stop reason code.
CALL MTTSTP ;(T1,XB,RB,CB)Illegal slot, kill the circuit
ENDIF.
RET ;All slots processed, return receive buffer
SUBTTL HSTRCB
;HRUNCB - Find the circuit block for a received RUN/STOP msg on a LAT host.
;Call: RB/ address of received message block
; CALL HRUNCB
; Error Return - CB not found
; Normal Return
; CB/ Circuit Block address
;
HRUNCB: SKIPN CB,MSGDID ;Index to CB from received message
JSP T2,ILLMS0 ;Zero message destination index is illegal
CAIG CB,CBMAXI ;If CB index is greater than our max
IFSKP.
SETZ CB, ;it's also illegal, so flag no circuit
JSP T2,ILLMS0 ;and go send a stop message
ENDIF.
ADD CB,CBVECT ;Add address of vector of pointers to CBs
SKIPN CB,(CB) ;The real circuit block address
JSP T2,INVRUN ;Circuit probably went away.
OPSTR <DMOVE T3,>,CBDNI,(CB);All 6 bytes of remote NI address from CB
OPSTR <CAMN T3,>,UNSAD,+UNB.OF(RB);Compare with message destination adr
OPSTR <CAME T4,>,UNSAD,+<UNB.OF+1>(RB)
SKIPA ;Not the right CB
JRST HRNFND ;Found the CB
XMOVEI T1,HN.QAC(HN) ;Try searching the active Q
CALL CMNIAD ;(T1,RB/CB)
SKIPA ;Not there either
JRST HRNFND ;Found the CB
XMOVEI T1,HN.QIC(HN) ;Try searching the inactive Q
CALL CMNIAD ;(T1,RB/CB)
JSP T2,ILLMES ;Non-existent CB. Treat as illegal message.
HRNFND: OPSTRM <AOS>,CCRCV,(CB) ;Increment per-server count
RETSKP ;Found the CB
SUBTTL HMSTOP
;HMSTOP - Process a Host STOP Message
;
; RB/ Address of receive buffer
; CB/ Address of circuit block
; HN/ Address of host node data base
; CALL HMSTOP
; Return+1: Always
HMSTOP: CALL MSBGN ;[7.1120](RB)Parse the beginning
CALL HRUNCB ;(RB/CB)Get the CB for this STOPS message
RET ;None, error action already done
SKIPE MSGSID ;Is the source ID in MSG non-zero?
JSP T2,ILLMES ;Yes, that's not legal
LOAD T1,CBLID,(CB) ;Get our remote ID for circuit. It must be
LOAD T2,CBSTA,(CB) ;Current circuit state
CAIE T2,CS.HLT ;[7481]Is it halted or
CAME T1,MSGDID ; an invalid STOP message?
RET ;[7481]Yes, just ignore it.
CALLRET CBKILL ;[7481](CB)Release all CB resources and
;[7481] put it on the inactive queue
; Routines to terminate a circuit because of some error. T1 contains
; the error to be entered into the STOP message.
ILLMES: OPSTRM <AOS>,CCIMR,(CB) ;Increment per-server count
ILLMS0: OPSTRM <AOS>,HCIMR,(HN) ;Increment host count
MOVEI T1,CE.ILL ;Illegally formatted message received
JRST INFSTP ;Join common code to kill off circuit
LVSKEW: MOVEI T1,CE.SKW ;Version skew between server and host,
JRST INFSTP ; cannot support connection.
NOCRES: OPSTRM <AOS>,CCIMR,(CB) ;Increment per-server count
NOCRE0: OPSTRM <AOS>,HCIMR,(HN) ;Increment host count
MOVEI T1,CE.RES ;Insufficient resources to support new circuit.
JRST INFSTP
XMTLIM: MOVEI T1,CE.LIM ;Retransmit limit exceeded. Server probably
JRST INFSTP ; has gone away.
IDLHLT: MOVEI T1,CE.NSL ;Circuit halted because there are no more slots
JRST MTTSTP
LCLHLT: MOVEI T1,CE.HLT ;Circuit halted by local system. Either stopped
JRST MTTSTP ; by operator or last slot has disconnected.
IFN FTOPS20,<
NIHALT: MOVEI T1,CE.NIH ;NI halted
SETZ T2,0 ;PC meaningless
JRST INFSTP
>;END IFN FTOPS20
INVRUN: MOVEI T1,CE.INV ;Invalid message
JRST INFSTP
INFSTP: OPSTR <DMOVE T3,>,CBDNI,(CB) ;[7369]GET ADDRESS IN T3 AND T4
BUG. (INF,LATNSC,LATSER,SOFT,<LAT Host node stopped circuit>,<<T1,CODE>,<T2,PC>,<T3,HIADDR>,<T4,LOADDR>>,<
Cause: LAT Host node stopped the circuit.
Action: Look at the Reason Code in T1 and the PC in T2. This error, if
relatively infrequent is nothing to be concerned about. If it occurs
frequently, use the CODE and PC to determine further action.
HIADDR and LOADDR specify the Ethernet address of the remote
server whose circuit has been stopped.
Data: CODE - Reason code
PC - PC
HIADDR - High order 32 bits of Ethernet address
LOADDR - Low order 16 bits of Ethernet address
>) ;[7369]
JRST MTTSTP
SUBTTL HMSTAT -- Receive Status Message
;[7.1120]
;HMSTAT - Receive a Status Message
;
; RB/ Address of message block
; CALL HMSTAT
; Return+1: Always
HMSTAT: STKVAR <NENTRY> ;
LOAD W1,UNBSZ,+UNB.OF(RB) ;Get the length of the message
CAIGE W1,^D12 ;Is it at least this big?
RET ;No, invalid message
LOAD W2,UNBFA,+UNB.OF(RB) ;Get the byte pointer for the message
MOVEI T4,3 ;Point to the current protocol version
ADJBP T4,W2 ;
ILDB T1,T4 ;Get the current protocol version
ILDB T2,T4 ;Get the current protocol ECO
CAXL T1,PROVER ;
CAXGE T2,PROECO ;Is it what we expect?
RET ;No, invalid message
ADDI T4,1 ;Point to the number of entries
ILDB T1,T4 ;Get the number of entries
JUMPE T1,RTN ;No entries: nothing to be done
MOVEM T1,NENTRY ;
ILDB W2,T4 ;Get the length of the subject name
TRNE W2,1 ;Is it an even number?
ADDI W2,1 ;No, it has a pad character
ADJBP W2,T4 ;Build a byte pointer to the entry
HMSTA1: ILDB W1,W2 ;Get the length of the entry
CAIL W1,^D14 ;Is it at least this big?
CALL RDSTA ;(W1,W2)Yes, handle this status entry
SOSGE NENTRY ;Is there another entry?
RET ;No, finished
ADJBP W1,W2 ;Point to the next entry
MOVEM W1,W2 ;
JRST HMSTA1 ;Parse the next entry
;[7.1120]
;RDSTA - Handle an entry for a Status message
;
; W1/ Length of this entry
; W2/ Byte pointer to this entry
; RB/ Address of message block
; CALL RDSTA
; Return+1: Always
RDSTA: SAVEAC <W2> ;Don't trash W2...
ILDB T3,W2 ;Get the entry status
ILDB T4,W2 ;Get the entry error
IBP W2 ;
ILDB SB,W2 ;Get the LO byte of the request id
ILDB T1,W2 ;Get the HO byte of the request id
LSH T1,^D8 ;Assemble the request id
ADD SB,T1 ;
MOVEM SB,T1 ;Save a copy for later
ANDI SB,PR.NDX ;Throw away the random portion
SKIPE SB ;
CAILE SB,PRMAXI ;Is it a valid request id?
RET ;No, invalid message
ADD SB,PRVECT ;Calculate address of PRVECT entry
SKIPN SB,(SB) ;Is this pending request block in use?
RET ;No, invalid request id
OPSTR <CAME T1,>,PRCID,(SB) ;Does it match this connect id?
RET ;No, invalid request id
ILDB T1,W2 ;Get the LO byte of the entry id
ILDB T2,W2 ;Get the HO byte of the entry id
LSH T2,^D8 ;Assemble the entry id
ADD T1,T2 ;
SKIPE T1 ;Is there an entry id?
STOR T1,PREID,(SB) ;Yes, save it
TXNE T3,1_7 ;Is the request rejected?
JRST RDSTA1 ;Yes, special handling
; ..
; ..
; Come here when the request is accepted: save the queue depth.
;
LOAD T1,PRSTA,(SB) ;Get the current (internal) state
CAXE T1,SS.SAC ;Solicit Access state
CAXN T1,SS.QUE ; or Queued state?
TRNA ;Yes, save the queue depth
RET ;No, ignore this message
IBP W2 ;Skip past the queue timer
IBP W2 ;
ILDB T1,W2 ;Get the LO byte of the queue position
ILDB T2,W2 ;Get the HO byte of the queue position
LSH T2,^D8 ;Assemble the queue position
ADD T1,T2 ;
STOR T1,PRQDP,(SB) ;Save the queue depth
MOVX T1,SS.QUE ;
LOAD T2,PRSTA,(SB) ;Get the current (internal) state
CAXE T2,SS.SAC ;Is this the Soliciting Access state?
RET ;No, return (do not change state)
STOR T1,PRSTA,(SB) ;Yes, change to Queued state
MOVX T1,.LAQUE ;[7.1155]Set the external status to queued
STOR T1,PRSTS,(SB) ;
HRLOI T1,377777 ;Set the retransmit timer so large
STOR T1,PRCMT,(SB) ; that LATXPR will never see it
SETZRO PRCMC,(SB) ;
RET ;
; ..
;..
; Come here for a rejection code.
;
RDSTA1: MOVX T1,SS.REJ ;
LOAD T2,PRSTA,(SB) ;Get the current (internal) state
CALLRET @REJDSP(T2) ;Change state to Reject or delete entry
RDSTA2: STOR T1,PRSTA,(SB) ;Change to Reject state
STOR T4,PRSTS,(SB) ;Return the rejection code
MOVE T1,SB ;
CALLRET PRWAKE ;(T1)Wake the job
RDSTA3: MOVE T1,SB ;
CALLRET PRDEL ;(T1)Delete this PRVECT entry
; Table of states for the PRVECT entries
;
REJDSP: XADDR. RTN ;(0) Halt
XADDR. RTN ;(1) Run
XADDR. RTN ;(2) Solicit Information
XADDR. RTN ;(3) Solicit Access (initialize first)
XADDR. RDSTA2 ;(4) Solicit Access
XADDR. RDSTA2 ;(5) Queued
XADDR. RTN ;(6) Rejected
XADDR. RTN ;(7) Timed Out
XADDR. RDSTA3 ;(8) Cancel (initialize first)
XADDR. RDSTA3 ;(9) Cancel
REJMAX==.-REJDSP-1
IF1,<IFL <REJMAX-SS.MAX>,<PRINTX ?Entries missing in REJDSP>>
SUBTTL HMINFO -- Receive Response Information Message
;[7.1120]
;HMINFO - Receive a Response Information Message
;
; RB/ Address of message block
; CALL HMINFO
; Return+1: Always
HMINFO: LOAD W1,UNBSZ,+UNB.OF(RB) ;Get the length of the message
CAIGE W1,^D20 ;Is it at least this long?
RET ;No, invalid message
LOAD W2,UNBFA,+UNB.OF(RB) ;Get the byte pointer for the message
MOVEI T4,3 ;Point to the current protcol version
ADJBP T4,W2 ;
ILDB T1,T4 ;Get the current protcol version
ILDB T2,T4 ;Get the current protocol ECO
CAXL T1,PROVER ;
CAXGE T2,PROECO ;Is it what we expect?
RET ;No, invalid message
IBP T4 ;Skip data link frame size
IBP T4 ;...
ILDB SB,T4 ;Get the LO byte of the solicit id
ILDB T1,T4 ;Get the HO byte of the solicit id
LSH T1,^D8 ;Assemble the solicit id
ADD SB,T1 ;
MOVE T1,SB ;Save a copy of it.
ANDI SB,PR.NDX ;Throw away the random portion
SKIPE SB ;
CAILE SB,PRMAXI ;Is it a valid solicit id?
RET ;No, invalid message
ADD SB,PRVECT ;Calculate address of PRVECT entry
SKIPN SB,(SB) ;Is this pending request block in use?
RET ;No, invalid solicit id
OPSTR <CAME T1,>,PRCID,(SB) ;Is it this one?
RET ;No, invalid solicit id
ILDB T2,T4 ;Get LO byte of the Response Status
ILDB T1,T4 ;Get HI byte of the Response Status
LSH T1,^D8 ;Assemble the response status
ADD T1,T2 ;
TXNE T1,RI%NSS ;Does the node offer the requested service?
JRST HMIRJ1 ;No. Go reject this request
ILDB T2,T4 ;Get LO byte of Source Node Status
ILDB T1,T4 ;Get HI byte of Source Node Status
LSH T1,^D8 ;Assemble the source node status
ADD T1,T2 ;
TXNN T1,RI%NDS ;Is the node disabled?
TXNN T1,RI%CMD ;No, Can we send a command message?
JRST HMIRJ2 ;No. Go reject this request
;
;
; The message has been verified. Save the Ethernet address and set up
; to transmit the Solicit Access message.
;
MOVEI T1,6 ;Get the length of the Ethernet address
MOVE T2,T4 ;Get the source byte pointer
XMOVEI T4,PR.DNI(SB) ;Get address of destination
TXO T4,<OWGP. 8,0> ;Make it a global byte pointer
CALL MVSTR ;(T1-T4/T3,T4)Move the Ethernet address
MOVX T1,SS.SAI ;
LOAD T2,PRSTA,(SB) ;Get the current (internal) state
CAXE T2,SS.SIN ;Is this the Solicit Information state?
RET ;No, return
STOR T1,PRSTA,(SB) ;Yes, change to Solicit Access (init first)
SETZRO PRCMT,(SB) ;Clear the command message timer
SETZRO PRCMC,(SB) ; and the retry count
RET ;
HMIRJ1: MOVX T1,.LANSS ;Frump up a "No such service" response
TRNA ;skip
HMIRJ2: MOVX T1,.LASCS ;Frump up a "Start slot can not be sent"
STOR T1,PRSTS,(SB) ;Store this in the status field
MOVX T1,SS.REJ ;Reject the request
STOR T1,PRSTA,(SB) ;Change state
HRLOI T2,377777 ;[7.1120]Set the timer to infinity
STOR T2,PRCMT,(SB) ;[7.xxxx][7.1120] so that LATXPR won't see it
SETZRO PRCMC,(SB) ;[7.xxxx][7.1120]Clear the command message count
MOVE T1,SB ;[7.xxxx]
CALLRET PRWAKE ;[7.1120](T1)Wake the job
SUBTTL Message Transmit Routines
;MTTSTR - transmit a START message
;Call: CALL MTTSTR
; Normal Return
;
; This routine builds the START message header in the template from the host
; node data base and transmits it. It sets the interlock so that the template
; cannot be changed at process level by the LATOP% JSYS. The message count
; is not changed since it is already correct (hence LAP2B0 is called instead of
; LAP2BY). Cannot fail after this point since sending a STOP will clobber
; the START msg template.
MTTSTR: SETONE HNCIP,(HN) ;Set interlock on the msg template
XMOVEI XB,HN.SMT(HN) ;Address of start message template
MOVX T1,<POINT 8,<SBF.OF>(XB)>;Set pointer to the message header
STOR T1,UNBFA,+UNB.OF(XB); for BMSGHD.
MOVEI T1,<MT.STA_2> ;Build a START
CALL BMSGHD ;(T1,XB,CB) message header
XMOVEI T1,<SBF.OF>(XB) ;Build the one word global
TLO T1,(<OWGP. 8,0>) ;[7.1039] byte pointer.
STOR T1,UNBFA,+UNB.OF(XB);
OPSTR <DMOVE T1,>,CBDNI,(CB);
OPSTRM <DMOVEM T1,>,UNDAD,+UNB.OF(XB);
LOAD T1,HNPID,(HN) ;Get the Portal ID for NISRV
STOR T1,UNPID,+UNB.OF(XB)
MOVX T1,NU.XMT ;Go transmit but don't
XMOVEI T2,UNB.OF(XB) ; use the usual routine
IFN FTOPS20,<
CALL DLLUNI##
>
IFN FTOPS10,<
SNCALL (DLLUNI##,MCSEC1)
>
IFSKP.
OPSTRM <AOS>,HCXMT,(HN);Increment host count
OPSTRM <AOS>,CCXMT,(CB);Increment per-server count
ELSE.
SETZRO HNCIP,(HN) ;Release the lock
ENDIF.
RET
;[7481]
;CBKILL - Kill a circuit by releasing all slots and buffers
;
;Call: CB/ address of the circuit block
; CALL CBKILL
; Normal return
CBKILL: CALL RELSBS ;(CB/)Release all slots for this CB
CALL RFXBFS ;(CB/)Release all buffers on
CALL MDLXBF ;(CB/)free queue and mark all those in DLL
; CALLRET CBDACT ; and move CB to the inactive queue
;CBDACT - Deactivate CB by moving to inactive queue
;
;Call: CB/ address of the circuit block
; CALL CBDACT
; Normal return
CBDACT: JUMPE CB,RTN ;If there is no CB, don't do the following
SETZRO CBRID,(CB) ;Clear remote circuit index
MOVEI T1,CS.HLT ;If the current circuit state is not halted
OPSTR <CAMN T1,>,CBSTA,(CB); move CB from active to inactive queue
RET ; otherwise CB is already on inactive queue
STOR T1,CBSTA,(CB) ;Set the state to halted now
XMOVEI T1,HN.QAC(HN) ;Remove
MOVE T2,CB ; the circuit block
CALL LAUNQ ;(T1,T2) from the active queue
XMOVEI T1,HN.QIC(HN) ; and queue to
MOVE T2,CB ;Need the CB address again.
CALL LAQUE ;(T1,T2) the inactive queue
OPSTRM <SOS>,HNNAC,(HN) ;Reduce the number of active circuits
RET
;MDLXBF - Remove all buffers from ACK Wait queue, and mark them
; for deletion at transmit complete.
;Call: CB/ circuit block address
; CALL MDLXBF
; Normal return
MDLXBF: SETZRO CBDLL,(CB) ;No buffers in DLL now
MDLXB1: XMOVEI T1,CB.AKQ(CB) ;Address of the ACK wait queue
CALL UNQ1WF ;(T1/T2)Unqueue next buffer on Q
RET ;Done
MOVEI T1,0 ;Mark buffer for freeing at xmit done
EXCH T1,UN.UID+UNB.OF(T2) ;and get current "DLL" flag
JUMPL T1,MDLXB1 ;If in DLL, it will be freed at XMTDON
MOVE XB,T2 ; else we have to free it now.
CALL RELXBH ;(XB)
JRST MDLXB1
;MTTSTP - transmit a STOP message
;Call: T1/ stop reason code
; XB/ address of transmit buffer
; RB/ address of recieve buffer
; CB/ address of circuit block (may be 0)
; CALL MTTSTP
; Normal return
MTTSTP: MOVEM T1,STPCOD ;Save the stop reason.
JUMPE CB,MTTSP0 ;If there is not CB, just send stop msg.
STOR T1,CBERR,(CB) ;Store reason for the stop in the CB
LOAD T1,CBRID,(CB) ;Get the id to which to send the STOP
SKIPE T1 ;[7.1039]If it is zero, assume MSGSID already
MOVEM T1,MSGSID ;[7.1155][7.1039] has the correct ID. This may
;[7.1039] prevent sending an illegal STOP with
;[7.1039] zero in the destination ID field.
CALL CBKILL ;[7481](CB/)Release all CB resources and
;[7481] put it on the inactive queue
;
; Here to actually send a stop message
; Always get a temp xmit buffer.
; Then send the message with a 0 in UNUID so that
; XMTDON will always just release the buffer.
;
MTTSP0: MOVX T1,HNRUN ;If the NI
TDNE T1,HN.FLG(HN) ; is no longer running
RET ;We're done.
MOVEI T1,SZMSTP ;There will be no buffers so get one
CALL MMGTZW ;(T1/T1)
RET ;Couldn't. Assume we did.
MOVE XB,T1 ;Transmit buffer for STOP message
MOVX T1,<POINT 8,<XBF.OF>(XB)>;Byte pointer to start of msg
STOR T1,UNBFA,+UNB.OF(XB);Store byte ptr to use building STOP msg
MOVEI T1,MT.STP_2 ;Message type (STOP) and number of slots (=0)
CALL LAP2B0 ;(XB,T1) to message
MOVE T1,MSGSID ;Get the source ID from the received message
CALL LAP2B0 ;(XB,T1) and enter as dest. ID to msg to send.
MOVEI T1,0 ;Get a 0 source ID
CALL LAP2B0 ;(XB,T1) and enter into msg to send
CALL LAP2B0 ;(XB,T1)Ack and sequence number must be zero.
MOVE T1,STPCOD ;Enter Disconnect reason and Reason text byte
CALL LAP2B0 ;(XB,T1) (=0 since text field not used) to msg.
XMOVEI T1,<XBF.OF>(XB) ;Set up 1 word global byte pointer
TLO T1,(<OWGP. 8,0>) ; to the transmit data for NISRV
STOR T1,UNBFA,+UNB.OF(XB); and store in UN block
MOVEI T1,MINXBF ;Initialize to zero
STOR T1,UNBSZ,+UNB.OF(XB); the message count
CALLRET XMTMSN ;(CB,XB,RB)Go give the message to the DLL.
; It will be freed at XMTDON
;MTTRUN - transmit a RUN message
;Call: XB/ address of the transmit buffer
; CALL MTTRUN
; Normal return
MTTRUN: JUMPE XB,RTN ;No message to transmit
XMOVEI T1,CB.XBQ(CB) ;Unqueue the transmit buffer
CALL UNQ1WF ;(T1/T2) from the free Q
NOP ;Would not be here if queue empty.
OPSTR <SKIPE>,CBXBQ,(CB);Is this our last transmit buffer?
IFSKP.
SETONE CBRRF,(CB) ;Yes, set the reply requested flag
LOAD T1,HNTIM,(HN) ;[7.xxxx][7.1120]Value for circuit timer (jiffies)
ADD T1,TODCLK ;Plus current time
STOR T1,CBTIM,(CB) ;Store in circuit timer
ENDIF.
XMOVEI T1,CB.AKQ(CB) ; and queue to the end
CALL QUE1WB ;(T1,T2) of the ACK queue
LOAD T1,CBTSQ,(CB) ;Get the transmit sequence number
AOJ T1, ; and increment it by one before
STOR T1,CBTSQ,(CB) ; using it in the next transmitted msg.
MOVX T1,<POINT 8,<XBF.OF>(XB)>;Set message pointer to point to
STOR T1,UNBFA,+UNB.OF(XB); the RUN message header.
MOVEI T1,MT.RUN_2 ;Message type for the header.
CALL BMSGHD ;(T1,XB,CB)Build the message header
MOVEI T1,SZ.MHD ;Store the message header length
OPSTR <SKIPN>,MDNXT,+MDB.OF(XB); which if there is no slot data
MOVEI T1,MINXBF ; must be the minimum NI datagram size.
STOR T1,MDBYT,+MDB.OF(XB); in the appropriate place
SETZRO UNBSZ,+UNB.OF(XB);MBZ for MSD type transmits
XMOVEI T1,<MDB.OF>(XB) ;Address of the first MSD block
STOR T1,UNBFA,+UNB.OF(XB);stored where usually byte pointer goes.
CALL XMTMSG ;(CB,XB,RB)No, go transmit a single buffer XB
RET
;TMRCHK - Host circuit timer check routine. This routine performs actions
; base on the state of the circuit timer.
;Call: CB/ circuit block address
;Return:
; RET - no further action required for this circuit
; RESKSP - continue processing
TMRCHK: OPSTR <SKIPN T1,>,CBTIM,(CB);Is the circuit timer running?
RETSKP ;No, continue processing circuit
SUB T1,TODCLK ;Account for current time
SKIPL T1 ;Any time still left?
IFSKP. ;Circuit timer has expired.
LOAD T1,HNRLI,(HN) ;Get the retransmit limit.
OPSTR <CAMG T1,>,CBRTC,(CB);Have we reached the limit?
IFSKP. ;No, so
CALL XUNAKQ ;(CB,HN) retransmit the unack queue
LOAD T1,HNTIM,(HN) ;[7.xxxx][7.1120] and reset the timer from now.
ADD T1,TODCLK ;
STOR T1,CBTIM,(CB) ;Restore reset timer to CB
ELSE.
JSP T2,XMTLIM ; otherwise, terminate the circuit
ENDIF. ; cause communication broken with remote.
RET
ENDIF.
RETSKP
;XUNAKQ - Transmit all messages on the unacknowledged queue
XUNAKQ: OPSTR <SKIPN>,CBDLL,(CB);Don't retransmit if already transmitting
OPSTR <SKIPN XB,>,QLFWD,+CB.AKQ(CB) ;First msg to retransmit
RET ;Should be
OPSTRM <AOS>,HCRTR,(HN) ;Increment host count
OPSTRM <AOS>,CCRTR,(CB) ; and per-server count
OPSTRM <AOS>,CBRTC,(CB) ;Increment retransmit count
XMTALL: OPSTRM <AOS>,CBDLL,(CB) ;Increment buffers in DLL
LOAD T1,HNPID,(HN) ;Reset the portal ID
STOR T1,UNPID,+UNB.OF(XB)
MOVX T1,NU.XMT ;Transmit function
XMOVEI T2,UNB.OF(XB) ;UN block
IFN FTOPS20,<
CALL DLLUNI##
>
IFN FTOPS10,<
SNCALL (DLLUNI##,MCSEC1)
>
IFNSK.
OPSTRM <SOS>,CBDLL,(CB)
ENDIF.
SKIPE XB,UE.LW0(XB) ;Next XB on queue to (re)transmit
JRST XMTALL ;Still more, continue to give buffers to DLL
RET
; BMSGHD - Build a LAT Virtual Circuit Message Header
;Call: T1/ <Message type>_2
; XB/ Message buffer address
; CB/ Address of the Circuit Block
BMSGHD: MOVE T2,NSLOTS ;Number of slots in message
LSH T2,^D8 ;Shift to left byte position
IOR T1,T2 ;Or in message type (shifted)
OPSTR <SKIPE>,CBRRF,(CB);If the Reply Request Flag is set
IORI T1,1 ; set it in message header
CALL LAP2B0 ;(XB,T1)Enter as 1st 2 bytes of header
LOAD T1,CBRID,(CB) ;Get the remote's circuit index
CALL LAP2B0 ;(XB,T1) and enter as 2 byte field
LOAD T1,CBLID,(CB) ;Get our circuit index
CALL LAP2B0 ;(XB,T1) and enter as 2 byte field
LOAD T1,CBRSQ,(CB) ;ACK number
LSH T1,^D8 ;Shift to left byte position
LOAD T2,CBTSQ,(CB) ;Send Seq Number
ANDI T2,377 ;Modulo 256
IOR T1,T2
CALL LAP2B0 ;(XB,T1)
RET
SUBTTL Message Transmitter -- XMTMSG
;XMTMSG - Transmit a LAT Message
;Call: CB/ 0 or Circuit Block Address
; XB/ Address of the UN block/Transmit Buffer
; RB/ Address of Receive Buffer if XB/0
; UNBSZ/ Message byte count
; CALL XMTMSG
; Normal Return
;
; This routine sets up the UN block for NISRV and issues the transmit
; function. Only UNBSZ must be set by the caller. If there is no CB,
; the information is taken from the receive buffer, otherwise from the
; circuit block.
;
; If there is no possibility of an ACK (such as sending a STOP message),
; then call XMTMSN, which will set UNUID to 0 so that the buffer will
; just be returned to free memory after NISRV has sent it.
;
XMTMSN: TDZA T1,T1 ;Enter here if you just want to free the buffer
; when transmit is done.
XMTMSG: MOVE T1,CB
TXO T1,DLL.FL ;Set "buffer-in-DLL" flag
STOR T1,UNUID,+UNB.OF(XB) ;Save the CB address for completion action
JUMPE CB,XMNOCB ;Case with no assigned circuit block
LOAD T1,HNPID,(HN) ;Portal ID
OPSTR <DMOVE T2,>,CBDNI,(CB) ;Get destination NI adr from CB
OPSTRM <AOS>,CBDLL,(CB) ;Increment # buffers in the DLL
JRST XMTMS0 ;Go do common code
XMNOCB: LOAD T1,UNPID,+UNB.OF(RB);Get the portal ID
OPSTR <DMOVE T2,>,UNSAD,+UNB.OF(RB) ;Source NI address from recvd msg
XMTMS0: STOR T1,UNPID,+UNB.OF(XB);Store in xmit buffer
OPSTRM <DMOVEM T2,>,UNDAD,+UNB.OF(XB) ; to the xmit buffer
STOR XB,UNRID,+UNB.OF(XB);Remember the buffer address
MOVEI T1,UNA.EV
STOR T1,UNADS,+UNB.OF(XB);Tell NISRV we are using EXEC virtual memory
MOVX T1,NU.XMT ;NI transmit function code
XMOVEI T2,UNB.OF(XB) ;UN block address
IFN FTOPS20,<
CALL DLLUNI##
>
IFN FTOPS10,<
SNCALL (DLLUNI##,MCSEC1)
>
IFSKP.
OPSTRM <AOS>,HCXMT,(HN)
JUMPE CB,RTN
OPSTRM <AOS>,CCXMT,(CB)
ELSE.
MOVX T1,DLL.FL ;Get "buffer-in-DLL" flag
ANDCAB T1,UN.UID+UNB.OF(XB) ;clear it in message
SKIPN T1
CALL RELXBH ;(XB)
JUMPN CB,RTN
OPSTRM <SOS>,CBDLL,(CB);Failed so put back count where is was
ENDIF.
RET
SUBTTL Message Transmitter -- XMTDON
;XMTDON - Message Transmitter Transmit Done Scheduler Level Routine
;Call: T1/ NU.XMT
; T2/ UN block address
; CALL XMTDON
; Normal return
;
; If the UNRID is zero, there is no longer a CB for this buffer because the
; circuit went away and we don't care what happens at transmit complete. Just
; release the buffer. If the CB state is stopping, complete the stopping of
; the circuit which could not be done earlier because all xmit buffers were in
; the DLL.
XMTDON: SAVEAC <CB>
MOVE XB,T2 ;Move transmit buffer adr to conventional AC.
LOAD CB,UNUID,+UNB.OF(T2) ;Get the CB address
TXZ CB,DLL.FL ;Clear the "buffer-in-DLL" flag
STOR CB,UNUID,+UNB.OF(T2) ; and store back this way
TXNE CB,SAV.FL ;[7.1120]Keep this buffer?
RET ;[7.1120]Yes, return
JUMPE CB,RELXBH ;If there is no CB, release buffer and header and return
OPSTRM <SOS>,CBDLL,(CB) ;One less buffer in the DLL
RET
SUBTTL Receive Message Handling Routines
;LAG2BY - obtains two bytes from the message which is assumed to be a 16-bit
; quantity.
;Call: MA/ Message base address
; CALL LAG2BY
; Normal Return
;Changes T2
; T1/ 16-bit quantity
LAG2BY: MOVX T1,-2 ;Amount to decrement the count by
OPSTRM <ADDM T1,>,UNBSZ,+UNB.OF(RB);Update message count
OPSTR <ILDB T1,>,UNBFA,+UNB.OF(RB);Get low order byte
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB);Get high order byte
LSH T2,^D8 ;Shift high order byte left
IOR T1,T2 ;Make a 16-bit quantity
RET ;Return with result
;GTCSTR - Move Counted String from a Message
;Call: T1/ Maximum count to move
; T2/ Destination byte pointer for string
; RB/ Message base address
;Changes T1,T2,T3,T4
IGCSTR: SETZ T1, ;[7.1039]Here to ignore a counter string
GTCSTR: SAVEAC <W1,W2> ;Get two work registers
OPSTR <SKIPN T3,>,UNBSZ,+UNB.OF(RB);Byte count left in message
RET ;Return error. Message unexpectedly truncated
OPSTR <ILDB W1,>,UNBFA,+UNB.OF(RB);Count of the counted string
SUBI T3,1(W1) ;Calculate new residual message count
JUMPL T3,RTN ;Message truncated
STOR T3,UNBSZ,+UNB.OF(RB);Store back into message header
SKIPE W1 ;A null string?
IFSKP.
MOVEI T1,0 ;Yes, return zero count
RETSKP ; successfully
ENDIF.
MOVE T3,W1 ;Copy of the actual string count
CAMLE T3,T1 ;Get the minimum of (actual string count,
MOVE T3,T1 ; maximum string count) for copy loop index
MOVEM T3,T1 ; and store as actual count copied
LOAD T4,UNBFA,+UNB.OF(RB);Save initial value of byte pointer
JUMPE T1,GTCDON ;Skipping over this field
GTCSLP: OPSTR <ILDB W2,>,UNBFA,+UNB.OF(RB);Fetch a source byte
IDPB W2,T2 ;Store as destination byte
SOJN T3,GTCSLP ;Loop till all bytes copied
GTCDON: ADJBP W1,T4 ;Adjust byte pointer properly in case less than
STOR W1,UNBFA,+UNB.OF(RB); the full string was copied
RETSKP ;Return success, T1/ count of string fetched
SUBTTL Transmit Message Handling Routines
;LAP2BY - Put 2 bytes to message
;Call: XB/ Address of the transmit buffer
; T1/ 16-bit quantity to ouput
; CALL LAP2BY or CALL LAP2B0
; Normal return
;T1 perserved, T2 used
;
; This routine enters a 16-bit quantity as two bytes from T1 into the transmit
; buffer with the least significant entered first. It assumes that UNBFA is
; set up with the proper byte pointer to the message buffer. The alternate
; entry LAP2B0 differs from LAP2BY in that LAP2B0 does not increment the
; message byte count whereas LAP2BY does.
LAP2BY: MOVEI T2,2 ;Amount to increment the message count by
OPSTRM <ADDM T2,>,UNBSZ,+UNB.OF(XB);Update the count in message header
LAP2B0: MOVE T2,T1 ;In order to return T1 preserved.
OPSTR <IDPB T2,>,UNBFA,+UNB.OF(XB);Low order byte entered first
LSH T2,-^D8 ;Shift hi byte into position
OPSTR <IDPB T2,>,UNBFA,+UNB.OF(XB);High order byte goes to b buffer
RET
;PTCSTR - put counted string to message buffer
;Call: XB/ Address of the transmit buffer
; T1/ Count to enter into buffer
; T2/ Source string byte pointer
PTCSTR: MOVEI T3,1(T1) ;Increment to include count byte
OPSTRM <ADDM T3,>,UNBSZ,+UNB.OF(XB);Increment count in buffer
PTCST0: OPSTR <IDPB T1,>,UNBFA,+UNB.OF(XB);Put the string count to buffer
MOVE T3,T1 ;Save copy of count for decrementing
PTCSTL: JUMPE T3,RTN ;If count exhausted, done with copying
ILDB T4,T2 ;Get the next source string byte
OPSTR <IDPB T4,>,UNBFA,+UNB.OF(XB);Put it to buffer
SOJA T3,PTCSTL ;Continue til string count zero
;PTUSTR - put uncounted string to message buffer
;Call: XB/ Address of the transmit buffer
; T1/ Count to enter into buffer
; T2/ Source string byte pointer
PTUSTR: OPSTRM <ADDM T1,>,UNBSZ,+UNB.OF(XB);Increment count in buffer
MOVE T3,T1 ;Save copy of count for decrementing
PTUSTL: JUMPE T3,RTN ;If count exhausted, done with copying
ILDB T4,T2 ;Get the next source string byte
OPSTR <IDPB T4,>,UNBFA,+UNB.OF(XB);Put it to buffer
SOJA T3,PTUSTL ;Continue til string count zero
;RBPOST - Return Receive Buffer to DLL
;Call: T1/ Message block address
; CALL RBPOST
; Normal Return
;
RBPOSS: SAVEAC <T1,T2,T3,T4> ;[7.1039]Preserve T1-T4
RBPOST: MOVEI T2,LMRFSI ;Size of the buffer
STOR T2,UNBSZ,+UNB.OF(T1);Store in UN block for NISRV
XMOVEI T2,<SBF.OF>(T1) ;Set up 1 word global byte pointer
TLO T2,(<OWGP. 8,0>) ;[7.1039] to the transmit data for NISRV
STOR T1,UNRID,+UNB.OF(T1);Store the buffer address for callback
STOR T2,UNBFA,+UNB.OF(T1); and store in UN block
LOAD T2,HNPID,(HN) ;Get the Portal ID for NISRV
STOR T2,UNPID,+UNB.OF(T1)
MOVEI T2,UNA.EV
STOR T2,UNADS,+UNB.OF(T1);Tell NISRV we are using EXEC virtual memory
XMOVEI T2,UNB.OF(T1) ;UN block address
MOVX T1,NU.RCV ;Post receive buffer function code
IFN FTOPS20,<
CALL DLLUNI##
>
IFN FTOPS10,<
SNCALL (DLLUNI##,MCSEC1)
>
IFNSK.
IFN FTOPS20,<
BUG. (CHK,LAPRBF,LATSER,SOFT,<Specify Receive Buffer Failure>,<<T1,DLLERC>>,<
Cause: LATSER received an error from NISRV while attempting to post a
receive buffer.
Data: DLLERC - Error code returned by NISRV
>)
>;END IFN FTOPS20
RET
ENDIF.
RETSKP
SUBTTL Slot Demultiplexor - LSDMUX
;LSDMUX - Process all slots in a received RUN message
;
;Call: RB/ Address of RUN message
; CALL LSDMUX
; Error return - illegal slot encountered
; Normal return
MIN. (MINSTY,<ST.DTA,ST.STA,ST.STP,ST.DTB,ST.ATT,ST.REJ>) ;Minimum slot type code
MAX. (MAXSTY,<ST.DTA,ST.STA,ST.STP,ST.DTB,ST.ATT,ST.REJ>) ;Maximum slot type code
LSDMUX: TRVAR <SLTDID,SLTSID,SLTCNT,SLTTYP,SLTEPT> ;Assign some variables on stack
SKIPN T1,NSLOTS ;Any slots left to process?
RETSKP ;No, return successfully
NXTSLT: OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB);Get the destination id
MOVEM T2,SLTDID
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB);Get the source id
MOVEM T2,SLTSID
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB);Get the slot data count
LOAD T3,UNBSZ,+UNB.OF(RB);Get the current message count
STOR T2,UNBSZ,+UNB.OF(RB) ;[7.1120]Save the slot data count
AOS T1,T2 ;Round up to the nearest even number
TRZ T1,1 ; since they may be 1 pad byte in slot
SUBI T3,SLHDSZ(T1) ;Subtract the total slot size
MOVEM T3,SLTCNT ;[7.1120]Save the byte count left in message
JUMPL T3,ILLSLT ;Error if message has ended prematurely
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB);Get the slot type/credits/reason
MOVEM T2,SLTTYP
ADJBP T1,UN.BFA+UNB.OF(RB);Point to next slot
MOVEM T1,SLTEPT ;in case we need to skip later
LSH T2,-4 ;Shift off the credits field
CAIL T2,MINSTY ;Range check slot type
CAILE T2,MAXSTY
CALLRET ILLSLT ;Slot ID out of range, illegal slot
CALL @SLTDSP-MINSTY(T2) ;Dispatch to proper routine
JRST ILLSLT
SOSG NSLOTS ;Indicate one less slot to process
RETSKP ;Count went to zero, so done.
MOVE T1,SLTCNT ;[7.1120]Restore the byte count
STOR T1,UNBSZ,+UNB.OF(RB) ;[7.1120] left in this message
MOVE T1,SLTEPT ;Get pointer to next slot's data
MOVEM T1,UN.BFA+UNB.OF(RB);and force pointer to there
JRST NXTSLT ;Still some left, go do next
SLTDSP: XADDR. HSDATA ;[7.1052]Data A slot
XADDR. RTN ;[7.1052]Undefined
XADDR. RTN ;[7.1052] "
XADDR. RTN ;[7.1052] "
XADDR. RTN ;[7.1052] "
XADDR. RTN ;[7.1052] "
XADDR. RTN ;[7.1052] "
XADDR. RTN ;[7.1052] "
XADDR. RTN ;[7.1052] "
XADDR. HSSTRT ;[7.1052]Start Slot
XADDR. HDRDAT ;[7.1052]Data B Slot
XADDR. IGNSLT ;[7.1052]Attention Slot
XADDR. RTN ;[7.1052]Reject Slot
XADDR. HSSTOP ;[7.1052]Stop Slot
SUBTTL HSSTRT - Process a START SLOT Message
;HSSTRT - Process a START SLOT message.
;
; HN/ Address of host node data base
; CB/ Address of circuit block
; RB/ Address of receive buffer
; CALL HSSTRT
; Return+1: Failure, invalid slot (cease parsing RUN message)
; Return+1: Success, SB/ Address of slot block (or zero)
HSSTRT: SKIPE SLTSID ;Source ID 0 is illegal
SKIPE SLTDID ;Destination ID of non-0 is illegal
CALLRET ILLSLT ;Report an illegal slot received
MOVNI T1,3 ;[7.1120]Number of bytes to be read
ADDB T1,UN.BSZ+UNB.OF(RB) ;[7.1120]Update the byte count
JUMPL T1,ILLSLT ;[7.1120]Negative: illegal slot
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB);Get the service class requested
CAIE T2,SCITTY ;Only interactive terminal class permitted
CALLRET ILLSLT ;If not, slot is illegal.
CALL SBALOC ;(CB/SB)Allocate a slot block
RETSKP ;Ignore since server should persist and we
; assume we should almost always get an SB
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB)
STOR T2,SBATS,(SB) ;Attention slot size maximum
OPSTR <ILDB T2,>,UNBFA,+UNB.OF(RB)
STOR T2,SBMDS,(SB) ;Data slot size maximum
LOAD T1,CBRSC,(CB) ;[7.1120]Get the server name count
CAILE T1,ML.SRN ;[7.1120]Is it too big for a slot block?
MOVEI T1,ML.SRN ;[7.1120]Yes, this is the maximum length
STOR T1,SBSRC,(SB) ;[7.1120]Save the server name count
ADDI T1,4 ;[7.1120]Convert fro bytes to words
IDIVI T1,5 ;[7.1120]
XMOVEI T2,CB.SNM(CB) ;[7.1120]Get address of source
XMOVEI T3,SB.SRN(SB) ;[7.1120]Get address of descriptor
XBLT. T1 ;[7.1120]Copy the string
MOVEI T1,ML.SVN ;[7.1120]Max length of service name
MOVX T2,<POINT 7,<SB.SVN>(SB)> ;[7.1120]Point to slot name string
CALL GTCSTR ;[7.1039](T1,T2,RB)Get a counted string
SETZ T1, ;[7.1039]Ran out of message
STOR T1,SBSVC,(SB) ;[7.1120]Store actual length of name
CALL IGCSTR ;[7.1039](T1,T2,RB)Ignore subject service name
JRST HSSTR2 ;[7.1039]No more data in message
; Now we are into the variable parameter part of the START SLOT message.
; Loop and record whatever fields we think are important.
;
HSSTR1: SOSL T1,UN.BSZ+UNB.OF(RB) ;[7.1039]Count down bytes in slot
ILDB T1,UN.BFA+UNB.OF(RB) ;[7.1039]Get Parameter number
JUMPLE T1,HSSTR2 ;[7.1039]Ran out of bytes, or hit end of parms
CAILE T1,SBPRMX ;[7.1039]Greater than max parm we know about?
SETZ T1, ;[7.1039]Yes, we will just ignore it.
CALL @SBPRTB(T1) ;[7.1039]Call routine to deal with parameter
JRST HSSTR2 ;[7.1039]Ran out of message
JRST HSSTR1 ;[7.1039]Get next parameter from slot
; Come here when the START SLOT has been parsed. Check to see whether
; or not the values are correct and the resources are available.
;
HSSTR2: OPSTRM <AOS>,HNCON,(HN) ;[7.1120]Increment the number of connects
LOAD T2,SBREA,(SB) ;[7.1120]Get a reject code (if any)
JUMPN T2,SLREJ0 ;[7.1120]Got one: reject this connection
OPSTR <SKIPN T1,>,SBPRA,(SB) ;[7.1120]Host initiated connect?
IFSKP. ;[7.1120]
SKIPG T1 ;[7.1120]Is this a duplicate?
IFSKP. ;[7.1120]No:
LOAD T2,PRSTA,(T1) ;[7.1120]Get the (internal) state
CALLRET @HSSDSP(T2) ;[7.1120]Accept if in SAC or QUE state
ELSE. ;[7.1120]
OPSTRM <SOS>,HNCON,(HN) ;[7.1120]
CALL RELSB ;[7.1120](SB,CB)Release this slot block
RETSKP ;[7.1120] (it is a dulplicate)
ENDIF. ;[7.1120]
ENDIF. ;[7.1120]
HSSTR3: LOAD T1,HNCON,(HN) ;[7.1120]Get the number of connects.
OPSTR <CAMLE T1,>,HNMCO,(HN);Check if maximum exceeded.
JRST SLRESF ;No additional sessions permitted.
IFN FTOPS10,<
MOVE T1,STATES## ;Get system states word
TRNE T1,ST.NRT ;Are remote TTYs allowed?
JRST SLSHUT ;Nope, reject the connection
> ;End IFN FTOPS10
CALL GETTDB ;(SB)Get a terminal data block and start a job
JRST SLRESF ;No terminal data blocks available
OPSTR <SKIPN T1,>,SBPRA,(SB) ;[7.1120]Host initiated connect?
IFSKP. ;[7.1120]
MOVX T2,SS.RUN ;[7.1120]Change to the RUN state
STOR T2,PRSTA,(T1) ;[7.1120]
MOVX T2,377777 ;[7.1120]Set the timer to infinity
STOR T2,PRCMT,(T1) ;[7.1120] so that LATXPR won't see it
SETZRO PRCMC,(T1) ;[7.1120]Clear the command message count
CALL PRWAKE ;[7.1120](T1)Wake the job
ENDIF. ;[7.1120]
MOVX T1,SBSTR!SBFCC ;Flag this slot as waiting to send a START
CALL SSBDAV ;(T1/SB) and a DATA_B slot when MUX runs.
RETSKP ;Return success
; Table of states for the PRVECT entries
;
HSSDSP: XADDR. SLCSRF ;(0) Halt
XADDR. SLCSRF ;(1) Run
XADDR. SLCSRF ;(2) Solicit Information
XADDR. SLCSRF ;(3) Solicit Access (initialize first)
XADDR. HSSTR3 ;(4) Solicit Access
XADDR. HSSTR3 ;(5) Queued
XADDR. SLCSRF ;(6) Rejected
XADDR. SLCSRF ;(7) Timed out
XADDR. SLUSRF ;(8) Cancel (initialize first)
XADDR. SLUSRF ;(9) Cancel
HSSMAX==.-HSSDSP-1
IF1,<IFL <HSSMAX-SS.MAX>,<PRINTX ?Entries missing in HSSDSP>>
; Come here to reject the START SLOT for various reasons.
;
SLUSRF: SKIPA T2,[SE.USR] ;[7.1120]User requested disconnect
SLSHUT: MOVX T2,SE.SHU ;[7.1120]System shutdown in progress
JRST SLREJ0 ;[7.1120]
SLRESF: SKIPA T2,[SE.RES] ;[7.1120]Insufficient resources
SLCSRF: MOVX T2,SE.CSR ;[7.1120]Corrupted solicit request
SLREJ0: STOR T2,SBREA,(SB) ;[7.1120]Save the rejection code
OPSTR <SKIPG T1,>,SBPRA,(SB) ;[7.1120]Get address of PR block
IFSKP. ;[7.1120]
STOR T2,PRSTS,(T1) ;[7.1120]Save the rejection code
MOVX T2,SS.REJ ;[7.1120]
STOR T2,PRSTA,(T1) ;[7.1120]Change state to Rejected
HRLOI T2,377777 ;[7.1120]Set the timer to infinity
STOR T2,PRCMT,(T1) ;[7.1120] so that LATXPR won't see it
SETZRO SBPRA,(SB) ;[7.1120]Clear the SB's pointer to the PR
SETZRO PRSBA,(T1) ;[7.1120]Clear the PR's pointer to the SB
SETZRO PRCMC,(T1) ;[7.1120]Clear the command message count
CALL PRWAKE ;[7.1120](T1)Wake the job
ENDIF. ;[7.1120]
MOVX T1,SBREJ ;[7.1120]Make this slot waiting to send
CALL SSBDAV ;[7.1120](T1,SB) a REJECT SLOT
RETSKP ;[7.1120]
;[7.1039]
; Dispatch table of routines to deal with parameters from start slot
;
SBPRTB: XADDR. IGCSTR ;[7.1039](0)Ignore ones we don't know about
XADDR. GETFLG ;[7.1120](1)Flag word
XADDR. LINKPR ;[7.1120](2)Queue entry
XADDR. IGCSTR ;[7.1039](3)Reserved
XADDR. IGCSTR ;[7.1120](4)Server name
XADDR. GETPRN ;[7.1039](5)Port name
SBPRMX=.-SBPRTB-1
;[7.1120]
;GETFLG - Get pertinent START SLOT flags.
;
; SB/ Address of slot block
; RB/ Address of receive buffer
; CALL GETFLG
; Return+2: Always
GETFLG: SOS UN.BSZ+UNB.OF(RB) ;Ignore the byte count
IBP UN.BFA+UNB.OF(RB) ;
CALL LAG2BY ;(RB/T1)Get 2 bytes (unsigned)
TRNN T1,1 ;Is this a dial-up line?
RETSKP ;No, return
SETONE SBDLP,(SB) ;Yes, set the bit in the SB
RETSKP ;
;[7.1120]
;LINKPR - Link this start slot to a pending request block.
;
; SB/ Address of slot block
; CALL LINKPR
; Return+2: Always, SBPRA/ Address of PR block (or minus one)
; or SBREA/ Reject code SE.ENQ (entry not in queue)
LINKPR: SOS UN.BSZ+UNB.OF(RB) ;Ignore the byte count
IBP UN.BFA+UNB.OF(RB) ;
CALL LAG2BY ;(RB/T1)Get two bytes (unsigned)
MOVEM T1,T2 ;Save the connect id
ANDI T1,PR.NDX ;Throw away the random portion
ADD T1,PRVECT ;Get address of PRVECT entry
SKIPN T1,(T1) ;Get address of pending request block
JRST LINKP1 ;None: invalid connect id
LOAD T3,PRCID,(T1) ;Get the connect id
CAME T3,T2 ;Is it what we expected?
JRST LINKP1 ;No, invalid connect id
LOAD T2,PRSBA,(T1) ;Is there already a slot block?
JUMPN T2,LINKP2 ;Yes: ignore this duplicate
STOR SB,PRSBA,(T1) ;Save address of slot block
STOR T1,SBPRA,(SB) ;Save address of pending request block
RETSKP ;
LINKP1: MOVX T1,SE.ENQ ;Reject code: entry not in queue
STOR T1,SBREA,(SB) ;
RETSKP ;
LINKP2: SETONE SBPRA,(SB) ;Invalid connect id: return with
RETSKP ; minus one as the address
REPEAT 0,<
;[7.1120]Delete this routine
;GETSRN - Get server name.
;
; SB/ Address of slot block
; CALL GETSRN
; Return+1: Error, couldn't get counted string
; Return+2: Success, T1/ character count
GETSRN: MOVE T2,[POINT 7,SB.SRN(SB)] ;Get server name
MOVEI T1,ML.SRN ;Set up max length of server name
CALL GTCSTR ;(T1,T2,RB)Go get the string
IFSKP.
STOR T1,SBSRC,(SB) ;Save the server name count
RETSKP ;Skip return
ENDIF.
SETZ T1, ;Error: return with character count zero
RET ;
> ;End REPEAT 0
;[7.1120]
;GETPRN - Get object port name.
; SB/ Address of slot block
; CALL GETPRN
; Return+1: Error, couldn't get counted string
; Return+2: Success, T1/ character count
GETPRN: MOVE T2,[POINT 7,SB.PRN(SB)] ;Get object port name
MOVEI T1,ML.PRN ;Set up max length of port name
CALL GTCSTR ;(T1,T2,RB)Go get the string
IFSKP.
STOR T1,SBPRC,(SB) ;Save the port name count
RETSKP ;Skip return
ENDIF.
SETZ T1, ;Error: return with character count zero
RET ;
SUBTTL Slot Processing Routines - STOP Slots
;HSSTOP - Process a STOP Slot.
;
;Call: SB/ Slot block address
; CALL HSSTOP
; Error return -
; Normal return
HSSTOP: SKIPN T2,SLTDID ;Destination ID cannot be zero
CALLRET IGNSLT ; but if it is zero, just ignore it.
SKIPN SLTSID ;Source ID must be zero
CAILE T2,NTTLAH ;Is the SBVECT index in range?
CALLRET ILLSLT ;No. Slot is illegal
MOVE T1,SBVECT ;Get the slot block address from
ADD T1,T2 ; the destination slot id
SKIPE SB,(T1) ;If the SB address is zero
OPSTR <CAME CB,>,SBCBA,(SB); or CB address has changed then
JRST IGNSLT ; ignore the slot since already gone.
CALL RELSB ;(CB,SB)Release all slot resources
RETSKP ;Return success
SUBTTL Slot Processing Routines - DATA_A,DATA_B Slots
;HSDATA - Process a DATA_A Slot
;
;Call: SB/ Slot block address
; CALL HSDATA
; Error return - illegal slot
; Normal return
HSDATA: CALL HDRDAT ;Go process data slot header
RET ;Illegal slot, error return
SKIPN W1,UN.BSZ+UNB.OF(RB) ;[7.1120]Get the number of characters in the slot
RETSKP ;None, return
IFN FTOPS20,<
LOAD T2,SBTDB,(SB) ;Terminal dynamic data base
DYNST ;Get the line number
NXSLCH: OPSTR <ILDB T1,>,UNBFA,+UNB.OF(RB);Get a character.
CALLX (MSEC1,TTCHI) ;[7.1024]Call TTYSRV to enter into input buffer
TRN ;Ignore error
>;end IFN FTOPS20
IFN FTOPS10,<
LOAD U,SBTDB,(SB) ;Get line data block address
NXSLCH: OPSTR <ILDB T3,>,UNBFA,+UNB.OF(RB);Get a character.
SNCALL (RECPTY##,MCSEC1);Call SCNSER to enter into input buffer
>;end IFN FTOPS10
SOJG W1,NXSLCH ;If still more, continue
RETSKP ;Otherwise return success
HSDATB: ;Process received DATA_B slot (NOP)
HDRDAT: SKIPE T2,SLTDID ;Destination ID cannot be zero
CAILE T2,NTTLAH ; or greater than maximum slot index
CALLRET ILLSLT ;Illegal slot
MOVE T3,SLTSID ;Source ID from the slot
MOVE T1,SBVECT ;Get the address of the SB
ADD T1,T2 ; based on the remote slot id from
SKIPN SB,(T1) ; the message
CALLRET IGNSLT ;No slot block.
OPSTR <CAME T3,>,SBRID,(SB) ;Is slot source ID equal to SB remote ID?
CALLRET IGNSLT ;No, ignore the slot
LOAD T3,SBSTA,(SB) ;Get the slot state
CAIN T3,SS.RUN ;If the slot state is not running or
OPSTR <CAME CB,>,SBCBA,(SB) ; the circuit block address has changed
CALLRET IGNSLT ; then slot disappeared already so ignore.
MOVE T3,SLTTYP ;See if remote extended us any transmit
ANDI T3,17 ; credits. If so, add them to what we already
OPSTRM <ADDM T3,>,SBXCR,(SB); have.
SKIPN UN.BSZ+UNB.OF(RB) ;[7.1120]Do remote credit check only if there was
RETSKP ; data in the slot.
OPSTR <SOSGE T3,>,SBRCR,(SB) ;Decrement the receive credits
JRST ILLSLT ;Illegal, server sent data with no credits
STOR T3,SBRCR,(SB) ;Store back updated credits count
SKIPE T3 ;If receive credits have gone to zero,
IFSKP. ; then indicate we need to grant more credits
MOVX T1,SBOUT ; by setting setting data available
CALL SSBDAV ; for MUX when it runs next time.
ENDIF.
RETSKP
SUBTTL Slot Block Allocation and Deallocation Routines
;SBALOC - Slot Block Allocation Routine
;
;Call: CB/ circuit block address
; CALL SBALOC
; Error Return
; Normal Return
; SB/ Address of allocated slot block
;
; This routine allocates and initializes a new slot block.
SBALOC: MOVEI T1,SB.LEN ;Number of words to allocate for a slot blk
CALL MMGTZW ;Try to get them
RET ;Can't
MOVE SB,T1 ;Put address in proper AC
MOVSI T4,-SBBWDS ;Look for a free slot block index
SBANXT: SKIPE T1,SBBITS(T4) ; by examining the free slot block words
JFFO T1,SBAGO ; for the first 1 bit. This represents
AOBJN T4,SBANXT ; the first free slot block index
RET ;No slot block available
SBAGO: HRRZS T4 ;Clear out left half
MOVE T3,BITS(T2) ;Clear the bit since the index is
ANDCAM T3,SBBITS(T4) ; no longer free
IMULI T4,^D36 ;Compute the slot block index
ADDI T2,1(T4) ;Cannot be zero
STOR T2,SBLID,(SB) ;Store in SB as local slot index
MOVE T1,SBVECT ;Now store the address of the slot block
ADD T1,T2 ; in the vector of slot block address, which
MOVEM SB,(T1) ; is indexed by slot block index
XMOVEI T1,CB.SBQ(CB) ;Queue the SB to the circuit block's
MOVE T2,SB ; queue of slot blocks.
CALL LAQUE ;
MOVEI T1,CS.STA ;Set the slot state
STOR T1,SBSTA,(SB) ; to starting.
STOR CB,SBCBA,(SB) ;Store the circuit block address in SB
MOVE T1,SLTSID ;Get the remote's slot id
STOR T1,SBRID,(SB) ;Store as our remote id
MOVE T1,SLTTYP ;Get the Slot type/credits from recv's slot
ANDI T1,17 ;Keep only the number of credits extended to us
STOR T1,SBXCR,(SB) ;Store is slot block as our transmit credits
MOVEI T1,MAXCRE ;Maximum credits to extend to remote
STOR T1,SBRCR,(SB) ; to current number of remote credits
RETSKP ;Return successfully
;SSBDAV - Set Slot BLock Data Available
;
;Call: T1/ Bit to set in SB.FLG
; SB/ Slot block address
; CALL SSBDAV
; Normal Return
SSBDAV: SKIPGE T2,SB.FLG(SB) ;Is there already data available?
IFSKP. ;No, so set it now
OPSTRM <AOS>,CBSDC,(CB);Increment number of slots waiting
TLO T2,400000 ; and indicate this slot now waiting
ENDIF.
IOR T2,T1 ;OR in new reason for waiting
MOVEM T2,SB.FLG(SB) ; and store back
RET ;Return
;CSBDAV - Clear Slot BLock Data Available
;
;Call: T1/ Bit to clear in SB.FLG
; SB/ Slot block address
; CALL SSBDAV
; Normal Return
CSBDAV: SKIPL T2,SB.FLG(SB) ;Is "data available" already clear?
RET ;Yes
ANDCM T2,T1 ;Clear the desired bit
TXNE T2,SBSMSK ;Are all bits off now?
IFSKP.
OPSTRM <SOS>,CBSDC,(CB)
MOVEI T2,0
ENDIF.
HLLM T2,SB.FLG(SB)
RET
;RELSBS - Release all Slot Blocks and their Resources for a virtual circuit
;
;Call: CB/ Address of the circuit block
; CALL RELSBS
; Normal Return
RELSBS: JUMPE CB,RTN ;No slots to release if no circuit block
OPSTR <SKIPN SB,>,QLFWD,+CB.SBQ(CB);Get the address of first SB on Q
RET ;If zero, there are no more on the queue
CALL RELSB ;Release the slot block
JRST RELSBS ;Go do the next
RET
;RELSB - Release a Slot Block and its Resources
;
;Call: CB/ Address of the circuit block for slot
; SB/ Address of the slot block to release
; CALL RELSB
; Normal Return
; SB/ address of previous slot or listhead
RELSB:
IFN FTOPS20,<
OPSTR <SKIPN T2,>,SBTDB,(SB) ;Is there a terminal data base
JRST RELSB0 ;No, go just release the SB resources
SETZM TTDEV(T2) ;Clear the slot block address in the TDB.
SETZRO TTPRM,(T2) ;TDB no longer permanent
SETZRO TTOTP,(T2) ;Clear output in progress so sched tests work.
OPSTR <SKIPE T1,>,SBPRA,(SB) ;[7.1120]Was this "host initiated"?
IFSKP. ;[7.1120]-No
DYNST ;Get the static line number
CALLX (MSEC1,NTYCOF) ;[7.1024]Go detach the job
LOAD T2,SBTDB,(SB) ;Get the TDB address again.
LOAD T1,TCJOB,(T2) ;If there is a controlling job, don't release
CAIE T1,-1 ; the TDB since this will be done
JRST RELSB0 ; later by JOBCOF.
ELSE.
LOAD T3,PRSTS,(T1) ;[7.1120]Get the status
TRZN T3,.TTDES ;[7.1120]Do we have a tty-designator?
JRST RELTT ;[7.1120]No. (That's odd...)
ADDI T3,DVXTT0 ;[7.1120]Get the device index
MOVX T1,DV%ASN ;[7.1120]Indicate device is
ANDCAM T1,DEVCHR(T3) ;[7.1120] no longer assigned.
MOVEI T1,-1 ;[7.1120]Mark the device as free.
HRLM T1,DEVUNT(T3) ;[7.1120]
ENDIF. ;[7.1120]
RELTT: DYNST ;No controlling job so we must release the
CALLX (MSEC1,TTYDE0) ;[7.1024] the dynamic data base here.
TRN ;TTYSRV already reports this.
>;end IFN FTOPS20
IFN FTOPS10,<
OPSTR <SKIPN U,>,SBTDB,(SB) ;Is there a terminal data base
JRST RELSB0 ;No, go just release the SB resources
PUSH P,J ;NGVLDB blows J (our W2)
CALL NGVLDB ;Give the LDB back to SCNSER
POP P,J ;Get our AC back
>;end IFN FTOPS10
RELSB0: OPSTR <SKIPN T1,>,SBPRA,(SB) ;[7.1120]Is there a pending request block?
IFSKP. ;[7.1120]
SETZRO PRSBA,(T1) ;[7.1120]Yes, clear its slot block address
CALL PRDEL ;[7.1120](T1)Delete the pending request block
ENDIF. ;[7.1120]
OPSTR <XMOVEI T1,>,CBSBQ,(CB) ;Point to the CB SBQ header
MOVE T2,SB ; and
CALL LAUNQ ; release the SB from this queue
SKIPL SB.FLG(SB) ;Did this SB have any data waiting?
IFSKP. ;Yes
OPSTRM <SOS>,CBSDC,(CB) ;Reduce number of slots with data waiting
ENDIF.
OPSTRM <SOS>,HNCON,(HN) ;Reduce number of active connects.
CALL RLSBID ;Release the SB local id.
MOVE T1,SB
OPSTR <SKIPN SB,>,QLBWD,(SB);Set up so the slot mux gets the correct
XMOVEI SB,CB.SBQ(CB) ; next slot.
CALL MMFREE ;Free the memory
RET
;RLSBID - Release a Slot Block's local id.
;
;Call: SB/ Address of the SB
; CALL RLSBID
; Normal Return
RLSBID: OPSTR <SKIPN T1,>,SBLID,(SB);Get the SB local index
RET ;Already zero. Nothing to do.
MOVE T2,SBVECT ;Clear the pointer to SB
ADD T2,T1 ; in the vector of SB addresses
SETZM (T2) ; ...
SOS T1 ;Normalize to zero
IDIVI T1,^D36 ;Now clear the bit to indicate that the
MOVE T3,BITS(T2) ; slot block index is now free
IORM T3,SBBITS(T1) ; ...
SETZ T1, ;Clear the local
STOR T1,SBLID,(SB) ; SB ID.
RET
;GETTDB - get terminal dynamic data base
;
;Call: SB/ slot block address
; CALL GETTDB
; Error return
; Normal return
IFN FTOPS20,<
GETTDB: SAVEAC <W1,W2>
MOVE W1,TT1LIN+TT.LAH
GTTDB0: LOAD T1,TTSTY,(W1) ;Get the line type
CAIE T1,TT.LAH
RET
MOVE T2,W1
CALLX (MSEC1,STADYN) ;[7.1024]
JUMPE T2,GTTDB2
GTTDB1: AOJA W1,GTTDB0 ;Try next line
GTTDB2: MOVE T2,W1
CALLX (MSEC1,TTYASC) ;[7.1024]
JRST GTTDB1
CALLX (MSEC1,STADYN) ;[7.1024]
JRST GTTDB1
STOR T2,SBTDB,(SB)
MOVEM SB,TTDEV(T2)
SETONE TCJOB,(T2)
SETONE TTPRM,(T2)
OPSTR <SKIPE W2,>,SBPRA,(SB) ;[7.1120]
IFSKP. ;[7.1120]
MOVEI T1,.CHCNC
MOVE T2,W1
CALLX (MSEC1,TTCHI) ;[7.1024]
NOP
ELSE. ;[7.1120]
MOVEI T1,.TTDES(W1) ;[7.1120]Make a TTY Designator
STOR T1,PRSTS,(W2) ;[7.1120]Stash it away
ADDI W1,DVXTT0 ;[7.1120]DVXTT0 + TTY Number = device index
LOAD T1,PRJOB,(W2) ;[7.1120]Get the real controlling job number
STOR T1,TCJOB,(T2) ;[7.1120]Set it in the TDB...
HRLM T1,DEVUNT(W1) ;[7.1120]...And here too
MOVX T1,DV%ASN ;[7.1120]Mark it as assigned
IORM T1,DEVCHR(W1) ;[7.1120]
MOVE T1,W2 ;[7.1120]PR address in T1
CALL PRWAKE ;[7.1120]Tell the user
ENDIF. ;[7.1120]
RETSKP
>;END IFN FTOPS20
; Get a remote LDB and make it mine
;
; Return:
; RET ;FAILED
; RETSKP ;SUCCESS
IFN FTOPS10,<
GETTDB: SAVEAC <W> ;SCNSER/NETSER WILL USE THIS
;Allocate an LDB
;
MOVSI T1,LTLLAT## ;FLAG A NEW LAT TERMINAL
MOVEI T3,LATDSP ;LAT'S ISR DISPATCH TABLE
SNCALL (GETLDB##,MCSEC1) ;(T1,T3/U)GET A REMOTE TTY LDB
RET ;GO ANNOUNCE THE FAILURE
;Finish making this a LAT LDB
;
MOVEI T1,LATRTQ ;GET POINTER TO OUTPUT Q HEADER
HRLZM T1,LDBQUH##(U) ;STORE FOR SCNSER (TOPOKE/TOTAKE)
STOR U,SBTDB,(SB) ;REMEMBER OUR LDB
MOVEM SB,LDBLAT##(U) ;STORE SB PTR IN LDB TOO
MOVEI T1,APCLAT## ;GET LATSRV CODE
DPB T1,@[IW MCSEC1,LDPAPC##] ;SET ASYNC PORT CHARACTERISTIC
MOVEI T1,M.LIDL## ;GET MAX. IDLE TIME FOR LAT LINES
SNCALL (SCNADT##,MCSEC1) ;(T1,U)SET THE TIMER GOING
LDB T1,@[IW MCSEC1,LDPXNF##] ;Find out our XON/XOF setting
STOR T1,SBXNF,(SB) ;And make LAT's setting agree (we will also
; send a DATA_B slot to inform LATbox).
;If not a host-initiated connect, run INITIA on the TTY.
;
OPSTR <SKIPE T1,>,SBPRA,(SB) ;Host-initiated connect?
JRST GETTD1 ;No, return TTY number
SNCALL (TTFGRT##,MCSEC1) ;Yes, use the .HELLO force command
RETSKP ;Success return
GETTD1: LDB T2,@[IW MCSEC1,LDPLNO##] ;(U)Get the TTY number
ADDI T2,.UXTRM ;
STOR T2,PRSTS,(T1) ;Copy it in the status field
RETSKP ;Success (do not run INITIA)
SUBTTL Subroutines -- NGVLDB - Give an LDB back to SCNSER
;Still in IFN FTOPS10
;NGVLDB - Give an LDB back to SCNSER
;
; Call: U/ Pointer to LDB
;
; Return:
; RET ;ALWAYS
NGVLDB: SETZM LDBLAT##(U) ;CLEAR OUT BY-NOW-STALE POINTER
MOVEI T1,IONND% ;"NODE DOWN" (PATH LOST/ETC) ERROR
SNCALL (DETLDB##,MCSEC1) ;DETACH THE LDB/DDB
XJRST [MCSEC1+FRELDB##] ;RETURN LDB TO SCNSER FREE POOL
>;END IFN FTOPS10
;LHRRH - LAT device dependent "return remote host" code
;
; Given the line #, returns the originating hostname, line and
; network type. Places this info in the users NTINF% .NWRRH
; argument block. NTINF has already checked the user arguments
; for validity.
;
; Call with T1/ address of internal arg block
;
; ARG+.NWABC/ # of bytes available for host name
; ARG+.NWFNC/ not used
; ARG+.NWNNP/ byte pointer to store hostname string
; ARG+.NWLIN/ address of dynamic data for line
; ARG+.NWTTF/ flags, and network and terminal types
; ARG+.NWNNU/ node # word 1
; ARG+.NWNU1/ node # word 2
;
; Returns + 1 on error with T1/ error code
; + 2 on success
IFN FTOPS20,<
XRENT (LHRRH,G) ;[7.1024]LHRRH::, XLHRR::
SASUBR <UAB>
MOVEM T1,UAB ;SAVE OUTPUT POINTER
MOVX T4,NW%LAT ;SET NETWORK TYPE
DPB T4,[POINT 9,.NWTTF(T1),17] ;STORE NETWORK TYPE
MOVE T2,.NWLIN(T1) ;GET DYNAMIC DATA ADR
NOSKED ;PROTECT SB/CB FROM CHANGING BENEATH US
MOVE T2,TTDEV(T2) ;GET SB ADDRESS
JUMPE T2,LHRRH3
LOAD T3,SBCBA,(T2) ;GET CB ADDRESS
JUMPE T3,LHRRH3
LOAD T4,CBDNI,(T3) ;GET NI ADDRESS (WORD 1)
MOVEM T4,.NWNNU(T1)
LOAD T4,CBDNI,+1(T3) ;GET NI ADDRESS (WORD 2)
MOVEM T4,.NWNNU+1(T1)
MOVE T2,T3 ;SAVE CB ADDRESS IN T2
LOAD T3,CBRSC,(T3) ;GET COUNT OF CHARACTERS
JUMPE T3,LHRRH3 ;IF ZERO - NO HOST NAME
CAML T3,.NWABC(T1) ;MAKE SURE NO MORE THAN MAX
MOVE T3,.NWABC(T1) ;ENFORCE IT
MOVE T1,.NWNNP(T1) ;GET POINTER TO OUTPUT STRING
OPSTR <XMOVEI T2,>,CBSNM,(T2) ;GET ADR OF REMOTE NAME STRING
TXO T2,<OWGP. 7,> ;FORM BYTE POINTER TO BUFFER
EXCH T1,T2 ;PUT POINTER WHERE MMVAZS WANTS THEM
CALL MMVAZS ;COPY THE STRING
LHRRH2: SETZ T1,
IDPB T1,T2 ;DEPOSIT A NULL
MOVE T1,UAB ;GET POINTER TO USER ARG BLOCK
MOVX T2,NW%NNN ;GET "NO NODE NAME KNOWN" FLAG
SKIPN T3 ;GOT A NODE NAME ?
IORM T2,.NWTTF(T1) ;NO - SET THE "NO NODE NAME KNOWN" FLAG
OKSKED ;DONE WITH SB/CB
RETSKP
LHRRH3: MOVE T2,.NWNNP(T1) ;GET POINTER TO OUTPUT STRING
SETZ T3, ;NO NODE NAME
CALLRET LHRRH2 ;UPDATE HOSTNAME STRING, AND RETURN
>;END IFN FTOPS20
SUBTTL Slot Multiplexor - Main Loop
;LAMUX Slot Multiplexor Main Loop
;
;Call: CALL LAMUX
; Normal return
LAMUX:
IFN FTOPS10,<
CALL LATSCN ;Scan active LDBs
LOAD CB,QLFWD,+HN.QAC(HN) ;Get the first CB on the active queue
LANXCB: JUMPE CB,CHKWFB ;All CBs processed, check if we need buffers
>;end IFN FTOPS10
IFN FTOPS20,<
LOAD CB,QLFWD,+HN.QAC(HN) ;Get the first CB on the active queue
LANXCB: JUMPE CB,RTN ;All CBs processed, return
TMNN HNRUN,(HN) ;[7.1039]Is the NI still running?
IFSKP. ;[7.1039]
CALL NIHALT ;[7.1039]()No, so deallocate all resources
JRST MXNXCB ;[7.1039]
ENDIF. ;[7.1039]
>
SETZM NSLOTS ;Initialize number of slots in this msg
LOAD T1,CBSTA,(CB) ;Consider only those circuits which are
CAIE T1,CS.RUN ; in the running state
JRST MXNXCB ; ...
OPSTR <SKIPE>,CBSBQ,(CB);[7.1039]If there are no slots for this circuit
IFSKP. ;[7.1039] kill it and look at the next one
CALL IDLHLT ;[7.1039]()
JRST MXNXCB ;[7.1039]
ENDIF. ;[7.1039]
LOAD T1,HNLAS,(HN) ;Get the current access state.
CAIN T1,LS.OFF ;If the access state is now off,
JRST MXNXC2 ; kill this circuit and look at next.
SETZRO CBRRF,(CB) ;No RRF set yet
CALL TMRCHK ;Check for circuit timer related functions.
JRST MXNXCB ;Continue with next circuit.
TMNN CBMRN,(CB) ;Must we go balanced (reply to server) now?
JRST LMNMRN ;No
; We have received a message from the server and must respond message now. If
; there is a free transmit buffer and there is slot data waiting to be sent,
; then build the slots in a large MSD transmit buffer and send it. If the MSD
; buffer is not available or there is no slot data waiting, just send a RUN
; message header. If there are no free transmit buffers, retransmit the queue
; of unacknowledged messages.
MOVX T1,CBMRS!CBMRN!CBRRF;Clear all flags
ANDCAM T1,CB.FLG(CB) ; since we will reply now.
SETZRO CBCSB,(CB) ;Clear count since balanced
SKIPN XB,CB.XBQ(CB) ;Is there a transmit buffer header free?
JRST LMNOXB ;No, go transmit unACK'd Q
OPSTR <SKIPE >,CBSDC,(CB);There is a buffer, is there data waiting?
CALL BLDMSL ;Everything there so build slots in buffer
NOP ;No slots, but don't care
CALL MTTRUN ;Transmit either hdr only or full message
JRST MXNXCB ;Go to next circuit block
LMNOXB: CALL XUNAKQ ;Transmit all messages on the unack'd Q
JRST MXNXCB
; Check to see if we just received a message from the server. If so,
; flag to force a reply at the next sheduler cycle. We wait one cycle in
; case user programs are controlling echoing in the hopes that response
; will be smoother.
LMNMRN: TMNN CBMRS,(CB) ;Must reply soon?
JRST LMUNSL
SETONE CBMRN,(CB) ;Yes, set to force reply on next cycle
JRST MXNXCB
; We are in balanced mode, i.e. the response to the latest server message
; has already been sent. Check here to see if we ought to send an unsolicited
; message. We are allowed one. We wait at least MXBALC scheduler cycles since
; last going balanced. If after that period there is slot data waiting, we
; send an unsolicited message to the server.
; If we have not data to send, wait another MXBALC cycles before trying again.
;
LMUNSL: LOAD T1,CBCSB,(CB) ;Number of cycles to wait before sending
CAIL T1,MXBALC ;Have we waited long enough?
IFSKP. ;No, so
AOJ T1, ; increment the count
STOR T1,CBCSB,(CB) ; and wait
JRST MXNXCB ; some more.
ENDIF.
; We have waited long enough. If there is slot data waiting and resouces
; available, send an unsolicited message to the server
;
SKIPN XB,CB.XBQ(CB) ;Is there a transmit buffer header free?
JRST MXNXCB ;No, so don't send anything
SETZRO CBCSB,(CB) ;We might send data, reset the ticker.
OPSTR <SKIPE >,CBSDC,(CB);Is there slot data waiting?
CALL BLDMSL ;Build a message full of slots
JRST MXNXC1 ; If no slots, do keep-alive timing.
CALL MTTRUN ;There are slots in the message so send it.
MXNXCB: LOAD CB,QLFWD,(CB) ;Index of the next CB on active queue
JRST LANXCB ;Continue looping
RET
; We don't have any unsolicited data to send, check if we have heard
; from the server within the last few SERVER_KEEP_ALIVE_TIMER seconds.
; If not, we will assume the server died, and we will kill the circuit.
;
MXNXC1: MOVE T1,TODCLK ;Get the current time
LOAD T2,CBKAT,(CB) ;Get the time last msg received
OPSTR <ADD T2,>,CBKAV,(CB) ;Add the keep-alive time
CAML T1,T2 ;Have we hit limit yet?
MXNXC2: CALL LCLHLT ;Yes, we have not heard from the server
JRST MXNXCB ;in a long time, so kill the circuit.
SUBTTL BLDMSL
;BLDMSL - Build RUN Message Slots
;
;Call: CB/ Address of Circuit Block
; CALL BLDMSL
; Normal return
;
; This routine scans through all slots associated with a LAT virtual circuit
; and builds RUN message slots for those which have data waiting to be sent
; to the remote node. SBFLGS contains a bits mask which indicates which
; type of slot must be built for the slot block. More than one bit may be set.
BLDMSL: OPSTR <SKIPN SB,>,QLFWD,+CB.SBQ(CB);Get addr of first slot for this CB
RET ;There are none
SETZRO UNBSZ,+UNB.OF(XB); and message count
SETZM MD.NXT+MDB.OF(XB) ;[7.1039]No transmit buffer yet.
BLSLOP: SKIPL W1,SB.FLG(SB) ;Does this slot have data waiting?
JRST MXNXSL ;No, loop to next slot
ANDX W1,SBSMSK ;[7.1120]Clear all but the flags
BLNXSL: JFFO W1,BLSDSP ;Find first flags bit which is lit.
MXNXSL: OPSTR<SKIPE SB,>,QLFWD,(SB);Get next slot's index and
JRST BLSLOP ; continue with the next slot
BLSLCP: SKIPN NSLOTS ;Check to see if any slots entered at all
RET ;None.
;If we couldn't get through all slots, rotate this circuit's slot queue so
;that we resume next time with the slot we did not complete this time.
SKIPN SB ;Did we get through the whole queue?
IFSKP. ;NO
OPSTR <CAMN SB,>,QLFWD,+CB.SBQ(CB);Is slot already at the Q head?
IFSKP. ;NO
LOAD T3,QLFWD,+CB.SBQ(CB);Get old queue head
LOAD T4,QLBWD,+CB.SBQ(CB);Get old queue tail
STOR T3,QLFWD,(T4) ;Joint them together
STOR T4,QLBWD,(T3) ; ...
LOAD T3,QLBWD,(SB) ;Get new Q tail from new Q head
SETZRO QLFWD,(T3) ;Clear new tail's forward ptr
SETZRO QLBWD,(SB) ;Clear new head's backward ptr
STOR SB,QLFWD,+CB.SBQ(CB);New head
STOR T3,QLBWD,+CB.SBQ(CB);New tail
ENDIF.
ENDIF.
;Compute final byte count padding to minimum NI datagram size if necessary.
LOAD T1,UNBSZ,+UNB.OF(XB);Store the larger of the final real message
CAIG T1,MINXBF-MMHDSI ; count and the minimum count as the message
MOVEI T1,MINXBF-MMHDSI ; count.
MOVE T3,MD.NXT+MDB.OF(XB) ;[7.1039]Get MSD address
STOR T1,MDBYT,(T3) ;[7.1039]and store count in MSD
RETSKP
; Check first to see if adding a new slot causes the number of slots in a
; message to exceed the maximum permitted by remote.
BLSDSP: LOAD T3,CBMSL,(CB) ;Get the maximum permitted by remote
CAMG T3,NSLOTS ; and compare with number of slots so far.
JRST BLSLCP ;At maximum, stop processing this circuit.
; Check to see if there is enough room remaining in the transmit buffer to
; include this slot.
HLRZ T1,SLLNTB-1(W2) ;Minimum bytes required for this slot type.
LOAD T3,UNBSZ,+UNB.OF(XB);Current number of bytes in the buffer.
ADD T1,T3 ;Count if we include this new slot.
CAILE T1,SZ.XBF ;Compare with total transmit buffer capacity.
JRST BLSLCP ;Will not fit so stop processing this circuit.
; Call the routine to build the slot. It may or may not be entered into the
; message. At this point however it is always marked as having been processed.
MOVE T1,BITS(W2) ;Get the mask for the bit
ANDCM W1,T1 ;Indicate that this slot has been processed.
CALL @SLBDSP-1(W2) ;Build the slot.
JRST BLNXSL ;Slot not entered. Try next.
; Slot successfully entered into the transmit buffer. Update the buffer counts.
; Terminal character count has already been added.
HRRZ T1,SLLNTB-1(W2) ;Get the count for the slot header.
OPSTR <ADD T1,>,UNBSZ,+UNB.OF(XB);Get the message count so far
TRNN T1,1 ;Is the count even?
IFSKP. ;No, must pad to even number
OPSTR <IDPB T1,>,UNBFA,+UNB.OF(XB);Put fill byte into message
AOS T1 ;Increment total in message
ENDIF.
STOR T1,UNBSZ,+UNB.OF(XB);
AOS NSLOTS ;Increment number of slots in the message.
JRST BLNXSL ;Get next slot request.
MIN. (MINSFL,<^L<SBREJ>,^L<SBSTR>,^L<SBSTO>,^L<SBOUT>,^L<SBFOU>,^L<SBFCC>>)
MAX. (MAXSFL,<^L<SBREJ>,^L<SBSTR>,^L<SBSTO>,^L<SBOUT>,^L<SBFOU>,^L<SBFCC>>)
SLBDSP: XADDR. XSLREJ ;[7.1052]Reject
XADDR. XSLSTA ;[7.1052]Start
XADDR. XSLATT ;[7.1052]Attention
XADDR. XSLDTA ;[7.1052]Data A
XADDR. XSLDTB ;[7.1052]Data B
XADDR. XSLSTP ;[7.1052]Stop
SLLNTB: EXP <SZ.SHD+SZ.REJ,,SZ.SHD+SZ.REJ> ;[7.1052]Reject
EXP <SZ.SHD+SZ.SST,,SZ.SHD+SZ.SST> ;[7.1052]Start
EXP <SZ.SHD+SZ.ATT,,SZ.SHD+SZ.ATT> ;[7.1052]Attention
EXP <SZ.SHD,,SZ.SHD> ;[7.1052]Data A
EXP <SZ.SHD+SZ.SDB,,SZ.SHD+SZ.SDB> ;[7.1052]Data B
EXP <SZ.SHD+SZ.SSP,,SZ.SHD+SZ.SSP> ;[7.1052]Stop
SUBTTL Slot Formatting Routines
;XSLSTA - Format a START Slot in the Transmit Buffer
;
;Call: SB/ Slot Block Address
; CB/ Circuit Block Address
; XB/ Transmit Buffer Address
; CALL XSLSTA
; Normal Return
XSLSTA: CALL XBFCHK ;Do we have a transmit buffer yet?
RET ;No, and can't get any.
MOVEI T1,SS.RUN ;Put the slot in the
STOR T1,SBSTA,(SB) ; RUNNING state.
MOVEI T1,<<ST.STA_^D12>!<MAXCRE_^D8>!SZ.SST>;COUNT/TYPE/CREDITS fields
CALL BSLTHD ;Build the slot header
MOVEI T1,SCITTY ;Only available service class currently
OPSTR <IDPB T1,>,UNBFA,+UNB.OF(XB)
MOVEI T1,MXSLSI ;Maximum slot size for all slot types
OPSTR <IDPB T1,>,UNBFA,+UNB.OF(XB);As maximum attention slot size
OPSTR <IDPB T1,>,UNBFA,+UNB.OF(XB);As maximum data slot size
MOVEI T1,0
CALL LAP2B0 ;Zero slot names
OPSTR <IDPB T1,>,UNBFA,+UNB.OF(XB);No parameters either
MOVX T1,SBSTR ;Indicate that this slot request successfully
CALL CSBDAV ; and entirely completed.
RETSKP
;XSLREJ - Format a REJECT Slot in the Transmit Buffer
;
;Call: SB/ Slot Block Address
; CB/ Circuit Block Address
; XB/ Transmit Buffer Address
; CALL XSLREJ
; Normal Return
XSLREJ: CALL XBFCHK ;Do we have a transmit buffer yet?
RET ;No, and can't get any.
LOAD T1,SBREA,(SB) ;Get the reject reason code
LSH T1,^D8
MOVEI T1,<ST.REJ_^D12!SZ.REJ>(T1) ;COUNT/TYPE/REASON fields
CALL BSLTHD ;Go build the slot header
MOVX T1,SBREJ ;Indicate that this slot request successfully
CALL CSBDAV ; and entirely completed.
CALL RELSB ;Release the slot.
RETSKP ;That's all there is to a REJECT slot.
SUBTTL Slot Formatting Routines
;XSLSTP - Format a STOP Slot in the Transmit Buffer
;
;Call: SB/ Slot Block Address
; CB/ Circuit Block Address
; XB/ Transmit Buffer Address
; CALL XSLSTP
; Normal Return
XSLSTP: CALL XBFCHK ;Do we have a transmit buffer yet?
RET ;No, and can't get any.
CALL RLSBID ;Release the local slot block ID.
LOAD T1,SBREA,(SB) ;Get the stop reason code
LSH T1,^D8
MOVEI T1,<ST.STP_^D12!SZ.SSP>(T1) ;COUNT/TYPE/REASON fields
CALL BSLTHD ;Go build the slot header
MOVX T1,SBSTO ;Indicate that this slot request successfully
CALL CSBDAV ; and entirely completed.
CALL RELSB ;Now go release the slot
RETSKP
;XSLATT - Format a ATTENTION Slot in the Transmit Buffer
;
;Call: SB/ Slot Block Address
; CB/ Circuit Block Address
; XB/ Transmit Buffer Address
; CALL XSLATT
; Normal Return
XSLATT: CALL XBFCHK ;Do we have a transmit buffer yet?
RET ;No, and can't get any.
MOVEI T1,<ST.ATT_^D12!SZ.ATT>;COUNT/TYPE fields
CALL BSLTHD ;Go build the slot header
MOVEI T1,1B30
OPSTRM <IDPB T1,>,UNBFA,+UNB.OF(XB);Deposit control flags
MOVX T1,SBFOU ;Indicate that this slot request successfully
CALL CSBDAV ; and entirely completed.
RETSKP
SUBTTL Slot Formatting Routines
;XSLDTA - Format a DATA_A Slot in the Transmit Buffer
;
;Call: W1/ Slot Block Flags
; SB/ Slot Block Address
; CB/ Circuit Block Address
; XB/ Transmit Buffer Address
; CALL XSLDTA
; Normal Return
; If we have transmit credit available, compute the maximum number of terminal
; output characters which may be entered into the slot. If we no longer have
; credit, set the character count to zero.
XSLDTA: SAVEAC <W1,W2>
IFN FTOPS20,<
SETZ W1, ;Assume character count is zero.
OPSTR <SKIPN>,SBXCR,(SB);Do we still have any transmit credit?
IFSKP.
LOAD T2,SBTDB,(SB) ;Get address of TDB
TMNE <TTSFG,TTRXF>,(T2);Check if at a page stop. If so, character
IFSKP. ; stays 0 (cannot call TTSND).
MOVEI W1,SZ.XBF-SZ.SHD;Get the residual buffer (minus slot header)
OPSTR <SUB W1,>,UNBSZ,+UNB.OF(XB); count.
CALL GTCHCT ;(T2/T1)Get total character count
CAMLE W1,T1 ;Smaller of residual count - 4 and TTOCT+TSALC
MOVE W1,T1 ;TTOCT+TSALC was smaller
OPSTR <CAMLE W1,>,SBMDS,(SB) ;Compare with maximum DATA_A slot size
LOAD W1,SBMDS,(SB) ;Maximum allowed by remote is less.
ENDIF.
ENDIF.
; Determine if the remote needs more credits and if we can give him any. If
; he doesn't or we can't and there is no terminal output data to be sent(count
; from above is 0) , exit without building the slot since there is no need to
; send one. Otherwise at least a DATA_A slot header will be sent. If it is
; extending credit, there may or may not be output data.
CALL CRECHK ;Check if we can grant more credit remote
SKIPE W1 ;Can't or don't need to so if there is no data
SKIPA ; either, no need to send a slot. Otherwise,
JRST XSLDA3 ; send at least empty slot granting new credit.
MOVE W2,T1 ;Save CRECHK result
CALL XBFCHK ;Do we have a transmit buffer yet?
JRST XSLDA3 ;No, and can't get any.
MOVE T1,W2 ;Retrieve CHECHK results
LSH T1,^D8 ;Shift into proper position
IORI T1,<ST.DTA_^D12>(W1);Fill in the rest of last 2 slot header bytes.
CALL BSLTHD ;Go build the slot header
JUMPE W1,XSLDA2 ;No slot data and no credits used.
MOVNS W1 ;Set up to be used in an AOBJN
HRLZS W1 ;... [-count,,0]
XSLDA0: LOAD T2,SBTDB,(SB) ;Dynamic TT data base
CALLX (MSEC1,TTSND) ;[7.1024]Get a character from the buffer
JRST [ HRRZS W1
MOVEI T1,1(W1)
MOVNS T1
OPSTR <ADJBP T1,>,UNBFA,+UNB.OF(XB)
DPB W1,T1
JRST XSLDA1]
OPSTR <IDPB T1,>,UNBFA,+UNB.OF(XB) ;[7.1039]Enter character into buffer
AOBJN W1,XSLDA0 ;Continue if more characters
XSLDA1: LOAD T1,SBXCR,(SB) ;Get our transmit credit count
SOS T1 ;Decrement since we may consume one credit now.
STOR T1,SBXCR,(SB) ; send data so store decremented credit count.
;Still in IFN FTOPS20
; Determine whether to slot request was FULLY completed. If not, don't
; clear the request bit since it will have to be completed next time around.
XSLDA2: OPSTRM <ADDM W1,>,UNBSZ,+UNB.OF(XB);Update the total message count.
OPSTRM <ADDM W2,>,SBRCR,(SB);Update his credit count.
LOAD T2,SBTDB,(SB) ;Get the TDB address back
CALL GTCHCT ;(T2/T1)Get remaining character count. If more,
JUMPN T1,RSKP ; return and do not clear request bit.
SETZRO TTOTP,(T2) ;Clear TTY output active if not more data.
OPSTR <SKIPN>,SBRCR,(SB);If remote has zero credit for transmits
RETSKP ; return successfully without clearint request.
MOVX T1,SBOUT ; Otherwise mark this request as complete.
CALL CSBDAV
RETSKP
XSLDA3: LOAD T2,SBTDB,(SB) ;Get the TDB address
CALL GTCHCT ;(T2/T1)Get remaining character count.
JUMPN T1,RTN
SETZRO TTOTP,(T2) ;There is no more terminal output, clear
RET ; the TTOTP bit and return.
>;end ifn ftops20
IFN FTOPS10,<
LOAD U,SBTDB,(SB) ;Get address of LDB.
;We will carry this in U for a while
SETZ W1, ;Assume character count is zero.
OPSTR <SKIPN>,SBXCR,(SB);Do we still have any transmit credit?
IFSKP.
MOVEI W1,SZ.XBF-SZ.SHD;Get the residual buffer (minus slot header)
OPSTR <SUB W1,>,UNBSZ,+UNB.OF(XB); count.
OPSTR <CAMLE W1,>,SBMDS,(SB) ;Compare with maximum DATA_A slot size
LOAD W1,SBMDS,(SB) ;Maximum allowed by remote is less.
ENDIF.
; Determine if the remote needs more credits and if we can give him any.
; If he doesn't or we can't and there is no terminal output data to be
; sent, exit without building the slot since there is no need to send
; one. Otherwise at least a DATA_A slot header will be sent. If it is
; extending credit, there may or may not be output data. We don't know
; at this point how many characters SCNSER has for us to send, so just
; keep trying to get chars until we fill the slot or run out of
; characters
;
; at this point:
; W1/ max characters we can send
;
MOVNS W1 ;Make into
HRLZS W1 ;AOBJN word
;
; now:
; W1/ -max,,0
;
JUMPE W1,NOCHR ;We don't have credit to send. Don't get a char
SKIPGE SB.TTO(SB) ;Is there saved character? (SBTTO is sign bit)
JRST GOTCHR ;Yes
SNCALL (XMTCHR##,MCSEC1) ;No, try to get a character from SCNSER
JRST NOCHR ;SCNSER doesn't have any for us.
SETONE SBTTO,(SB) ;SCNSER does have one, remember we got it
STOR T3,SBCHR,(SB) ;and save it away
GOTCHR: AOBJN W1,.+1 ;Got a char, count it
NOCHR: CALL CRECHK ;Check if we can grant more credit remote
TRNE W1,777777 ;Can't or don't need to. See if any data?
SKIPA ;Got data or can grant credit, send a slot
RET ;No slot to send, just return
MOVE W2,T1 ;Save CRECHK result
CALL XBFCHK ;Do we have a transmit buffer yet?
RET ;No, and can't get any.
LOAD T1,SBXCR,(SB) ;Get our transmit credit count
SOS T1 ;Decrement since we may consume one credit now
TRNE W1,777777 ;If data count is not zero, we will definitely
STOR T1,SBXCR,(SB) ;Store updated credit count
;Can't build slot header yet, since we don't know how many characters
; we will send. Save a pointer to the slot character count, and
; call BSLTHD anyway. We will stuff the char count later.
;
;At this point, the slot byte pointer points to the DST_SLOT_ID
;
MOVEI T1,3 ;the byte count is the 3rd byte of the slot
OPSTR <ADJBP T1,>,UNBFA,+UNB.OF(XB) ;so make a DPB pointer to it
PUSH P,T1 ;save first word of byte pointer
PUSH P,T2 ;and possible second word
;Still in IFN FTOPS10
;Now build the slot header
;
MOVE T1,W2 ;get CRECHK results
LSH T1,^D8 ;Shift to proper position
IORI T1,<ST.DTA_^D12> ;fill in the flag
CALL BSLTHD ;build the slot header (with bad char count)
TRNN W1,777777 ;Is there some data?
JRST XSLDA2 ;No, no characters to move
LOAD T3,SBCHR,(SB) ;Yes, get saved character.
SETZRO SBTTO,(SB) ;And remember we got it.
OPSTR <IDPB T3,>,UNBFA,+UNB.OF(XB) ;Stuff first character into buffer
JUMPGE W1,XSLDA2 ;if (heaven help us) there was only space for
;one character, stop now.
XSLDA0: SNCALL (XMTCHR##,MCSEC1) ;Get a character from SCNSER
JRST XSLDA2 ;None left
OPSTR <IDPB T3,>,UNBFA,+UNB.OF(XB) ;Stuff a character into buffer
AOBJN W1,XSLDA0 ;Count characters done
; Here we have either filled up the slot or run out of characters.
; Stuff the actual character count into the slot header.
;
XSLDA2: POP P,T2 ;retrieve pointer to slot header
POP P,T1 ; byte count
DPB W1,T1 ;and stuff actual character count
HRRZ T1,W1 ;get character count by itself
OPSTRM <ADDM T1,>,UNBSZ,+UNB.OF(XB) ;and update total message count.
OPSTRM <ADDB W2,>,SBRCR,(SB) ;Update his credit count. (remember total)
JUMPE W1,RSKP ;If we don't have any transmit credits, or
SKIPE W2 ;If the remote has zero credits for transmits
SKIPL LDBDCH##(U) ;Or if SCNSER doesn't think line is idle
.CREF LDLIDL ;(really checking this bit)
RETSKP ;Return successfully without clearing request
MOVX T1,SBOUT ;Otherwise, mark this request as complete.
CALL CSBDAV
RETSKP
>;END IFN FTOPS10
SUBTTL Slot Formatting Routines
;XSLDTB - Format a DATA_B Slot in the Transmit Buffer
;
;Call: SB/ Slot Block Address
; CB/ Circuit Block Address
; XB/ Transmit Buffer Address
; CALL XSLDTB
; Normal Return
;
XSLDTB: OPSTR <SKIPE>,SBXCR,(SB);Do we still have any transmit credit?
CALL XBFCHK ;Check if we have a transmit buffer yet.
RET ; Didn't and can't get one.
LOAD T1,SBXCR,(SB) ;Current number of transmit credits available
SOS T1 ;Decrement since this slot will consume one.
STOR T1,SBXCR,(SB) ;Store updated credit count
IFN FTOPS10,<
LOAD U,SBTDB,(SB) ;Point to LDB
>;end IFN FTOPS10
CALL CRECHK ;Does remote need credits?
NOP ;Dont't care if he did and we can't provide
OPSTRM <ADDM T1,>,SBRCR,(SB) ;[7275] Update remote credit count
LSH T1,^D8 ;Shift to proper position.
IORI T1,<ST.DTB_^D12>!SZ.SDB;Fill in rest of last 2 header bytes.
CALL BSLTHD ;Go build the slot header
MOVEI T1,SL.DXF ;Assume disabling XOFF recognition
IFN FTOPS20,<
LOAD T2,SBTDB,(SB) ;Get the terminal data base address
TMNE TT%PGM,TTFLGS(T2)
>;end IFN FTOPS20
IFN FTOPS10,<
LOAD U,SBTDB,(SB) ;Get LDB address
LDB T2,@[IW MCSEC1,LDPXNF##] ;Get XON/XOF flag
SKIPE T2 ;disabling XON/XOF recognition?
>;end IFN FTOPS10
MOVEI T1,SL.EXF ;No, enabling
OPSTR <IDPB T1,>,UNBFA,+UNB.OF(XB);Enter control flags to buffer
MOVEI T1,<XONC_^D8!XOFFC> ;XON and XOFF characters
CALL LAP2B0 ;Enter them into buffer
CALL LAP2B0 ;Also input XON/XOFF characters
MOVX T1,SBFCC
CALL CSBDAV
RETSKP
BSLTHD: MOVE T3,T1 ;Save input arg
LOAD T1,SBLID,(SB) ;Remote slot ID
LSH T1,^D8 ;Shift to second byte
OPSTR <IOR T1,>,SBRID,(SB) ;Local slot ID into first byte
CALL LAP2B0 ;(Clobbers T2 only.)
MOVE T1,T3 ;Get original argument back
CALL LAP2B0 ;Enter count/slot type/credits
RET
;CRECHK - Remote Credit Check Routine
;
;Call: SB/ Slot Block Address
; CALL CRECHK
; No-Grant return
; Grant return
; T1/ <Number to grant>
; If the remote has less than the maximum number of transmit credits, try to
; compute the number of additional credits to grant him and return in T1,
; shifted by one byte (for convenience of caller). We can only grant credit
; if there is room for a non-zero integral number of full slot buffers (of
; length MXSLSI).
;[7469] If terminal has pause at end of page enabled always be sure to
;[7469] grant at least 1 credit. If zero credits are granted and the
;[7469] user hits end of page they will not be able to resume type out
;[7469] by pressing the unpause character, since the LAT box will not
;[7469] be able to send it.
CRECHK: MOVEI T1,MAXCRE ;Maximum number of credits remote may have.
OPSTR <SUB T1,>,SBRCR,(SB);His deficiency.
JUMPE T1,RTN ;Can't grant him more-- he already has limit.
MOVE T3,T1 ;Save remote's credit deficiency.
IFN FTOPS20,<
LOAD T4,SBTDB,(SB) ;Get the terminal dynamic pointer
LOAD T1,TIMAX,(T4) ;Maximum that will fit in an input buffer
SUB T1,TTICT(T4) ;Subtract current input count to get whats left
IDIVI T1,MXSLSI ;Compute number of slot buffer that would fit
IFE. T1
SETONE TTFWK,(T4) ;[7469] Hopefully start the process running
JE TT%PGM,TTFLGS(T4),RTN ;[7469] Jump if not in page mode
TMNE TTNXO,(T4) ;[7469] Pause at end of page?
MOVEI T1,1 ;[7469] Yes, always grant 1 credit
ENDIF.
JUMPE T1,[SETONE TTFWK,(T4);None, so can't grant more so force
JRST RTN] ; the process to wake.
>;end IFN FTOPS20
IFN FTOPS10,<
MOVEI T1,TTIWRN## ;Get max characters for an input buffer
SUB T1,LDBTIC##(U) ;Minus number that have been echoed
SUB T1,LDBECC##(U) ;Also minus number that have not yet echoed
IDIVI T1,MXSLSI ;Compute number of slot buffer that would fit
JUMPE T1,RTN ;None, so can't grant more.
>;end IFN FTOPS10
CAMLE T1,T3 ;Make sure he never gets a total of more than
MOVE T1,T3 ; the maximum allowed.
RETSKP
IGNSLT: SETZM UN.BSZ+UNB.OF(RB) ;[7.1120]Force data to be ignored.
RETSKP ;This is a good return.
ILLSLT: OPSTRM <AOS>,HCISR,(HN) ;Increment host count
OPSTRM <AOS>,CCISR,(CB) ; and the per-server count
ILLSLX: RET ;Give a bad return
SUBTTL - Queue Handling Routines
;LAQUE - Add an element to the front of a queue
;
;Call: T1/ Address of Queue Header
; T2/ Address of Element to Add
; CALL LAQUE
; Normal Return
; This routine is used to queue either CBs or SBs. The queue headers
; and link words are always two words, and are described by the BEGSTR QL.
; All elements are linked in both forward and backward directions.
LAQUE: MOVE T4,T1 ;Save queue header address
OPSTR <SKIPE T3,>,QLFWD,(T1) ;Get old first queue element if any.
MOVE T1,T3 ; Old first element or Q header backward
STOR T2,QLBWD,(T1) ; pointer points to new element
STOR T2,QLFWD,(T4) ;Store new first queue element
SETZRO QLBWD,(T2) ;Zero its backward pointer
STOR T3,QLFWD,(T2) ;Set up its forward pointer
RET
;LAUNQ - Dequeue a queue element
;
;Call: T1/ Address of queue header
; T2/ Address of queue element to be unqueued
; CALL LAUNQ
; Normal return
;
;Uses: T3,T4
LAUNQ: LOAD T3,QLBWD,(T2) ;Get elements backward pointer
LOAD T4,QLFWD,(T2) ;Get its forward ptr also.
SKIPN T2,T4 ;Remove the element from the backward list
XMOVEI T2,QL.FWD(T1) ; by updating the backward
STOR T3,QLBWD,(T2) ; ptr of either next Q element or Q head
SKIPE T3 ;If backward ptr 0 update Q head forward ptr
XMOVEI T1,QL.FWD(T3) ; otherwise update that of the previous Q
STOR T4,QLFWD,(T1) ; element
RET
;QUE1WB - Routine to queue and element to the back of a 1 directional queue.
;
;Call: T1/ address of Q header block
; T2/ address of queue element to add to queue
; CALL QUE1WB
; Normal return
QUE1WB: OPSTR <SKIPN T3,>,QLBWD,(T1);Address of first element on Q
MOVE T3,T1 ;Zero, Q header fwd ptr points to new element
STOR T2,QLFWD,(T3) ;Update forward ptr of Q hdr or old Q tail
SETZRO QLFWD,(T2) ;Zero new elements forward ptr
STOR T2,QLBWD,(T1) ;New tail ptr
RET
;UNQ1WF - Routine to remove an element from the front of a 1 directional queue.
;
;Call: T1/ address of the Q header block
; CALL UNQ1WF
; Error return - queue emtpy
; Normal return
; T2/ address of element
UNQ1WF: OPSTR <SKIPN T2,>,QLFWD,(T1);Address of first element on Q
RET ;Zero, so queue is empty
OPSTR <SKIPN T3,>,QLFWD,(T2);If only 1 element on Q then update
STOR T3,QLBWD,(T1) ; the Q headers tail ptr (set to 0)
STOR T3,QLFWD,(T1) ;There is a new head of the Q (or 0)
RETSKP ;Return with the Q element in T2
SUBTTL - Buffer Handling Routines - Transmit Buffers
;GETXBH - Get the necessary number of transmit buffer headers
;
;Call: CB/ Address of the circuit block
; CALL GETXBH
; Error return - insufficient resources
; Normal return
GETXBH: MOVSI W1,-MAXXBF ;Number of buffers to get
GTXNXT: MOVEI T1,<<MINXBF+3>/4+XBF.OF>;Buffer length to get
CALL MMGTZW ;Go get the storage
JRST GTXFL ;Failed to get all that are needed
MOVX T2,<POINT 8,0>
STOR T2, MDAUX,+MDB.OF(T1);
MOVEI T2,SZ.MHD ;The message header always has
STOR T2,MDBYT,+MDB.OF(T1); 8 bytes.
MOVEI T2,VMC.XC ;Always use exec virtual paging
STOR T2,MDVMC,+MDB.OF(T1); ...
XMOVEI T2,<XBF.OF>(T1) ;
STOR T2,MDALA,+MDB.OF(T1);Address of start of header
MOVE T2,T1 ;Now queue to circuit blocks queue of free
XMOVEI T1,CB.XBQ(CB) ; transmit buffers
CALL QUE1WB ; ...
AOBJN W1,GTXNXT ;Get as many as required
RETSKP
; Failed to get the nececessary number of buffers. Must free those
; which we did get.
GTXFL: XMOVEI T1,CB.XBQ(CB) ;Unqueu each from the transmit free Q
CALL UNQ1WF ; ...
RET ;No more there so return with error
MOVE T1,T2 ;Give back the buffer to the memory
CALL MMFREE ; manager
JRST GTXFL ; and continue looping til all returned
;GETXBF - Get one long transmit buffer for real data
;
;Call: CB/ Address of the circuit block
; XB/ Address of the 1st MSD (header)
; CALL GETXBH
; Error return - insufficient resources
; Normal return
; T3/ MSD address (also saved in MD.NXT+MDB.OF(XB))
GETXBF: MOVEI T1,<MD.LEN+SZ.XBF>;Buffer length to get
IFN FTOPS20,<
CALL MMGTZW ;Go get the storage
>
IFN FTOPS10,<
CALL GETZBF ;Go get the storage
>
RET ;No luck!
MOVE T3,T1
SETZ T1,
MOVX T2,<POINT 8,0>
STOR T2,MDAUX,(T3);Byte pointer to message
MOVEI T1,SZ.XBF
STOR T1,MDBYT,(T3);Zero length
MOVEI T1,VMC.XC ;Always use exec virtual paging
STOR T1,MDVMC,(T3); ...
XMOVEI T1,<MD.LEN>(T3) ;
MOVEM T3,MD.NXT+MDB.OF(XB) ;Link header MSD to this
STOR T1,MDALA,(T3) ;Message address
RETSKP
;XBFCHK - Check for Transmit buffer
;
;Call: XB/
; CALL XBFCHK
; Error Return
; Normal Return
XBFCHK: SKIPE T3,MD.NXT+MDB.OF(XB) ;[7.1039]If we already have one,
RETSKP ;return
CALL GETXBF ;Get an MSD transmit buffer
RET ;None available, return failure
XMOVEI T1,<MD.LEN>(T3) ;[7.1039]Make a one word 8 bit
TLO T1,(<OWGP. 8,0>) ;[7.1039] global byte pointer and save as
STOR T1,UNBFA,+UNB.OF(XB); message byte pointer.
RETSKP
;RFXBFS - Release all free transmit buffers
;
;Call: CB/ circuit block address
; CALL RFXBFS
; Normal return
;
RFXBFS: XMOVEI T1,CB.XBQ(CB) ;Address of the free xmit buffer queue
CALL UNQ1WF ;Unqueue the head of the Q
RET
MOVE XB,T2 ;Put buffer address where RELXBH wants it
CALL RELXBH ;Go release it
JRST RFXBFS ;Get next
;RELXBF - Release Transmit Buffer
;
;Call: XB/ Address of buffer header
; CALL RELXBF
; Normal return
RELXBF: MOVEI T1,0 ;[7.1039]
EXCH T1,MD.NXT+MDB.OF(XB) ;[7.1039]If there is no MSD style buffer
JUMPE T1,RTN ;[7.1039] then just return
IFN FTOPS20,<
CALLRET MMFREE ;[7.1039] and free the MSD's storage.
>
IFN FTOPS10,<
CALLRET GIVBF ; and free the MSD's storage.
>
;RELXBH - Release Transmit Buffer Header and Buffer
;
;Call: XB/ Address of buffer header
; CALL RELXBH
; Normal return
RELXBH: CALL RELXBF ;Release the buffer first
MOVE T1,XB ;Now the header
CALL MMFREE
RET
SUBTTL - Buffer Handling Routines - Receive Buffers
;GETRBF - Get a Receive buffer
;
;Call: CALL GETRBF
; Error return - no receive buffers
; Normal Return
;
; This routine checks to see if enough receive buffers have been posted
; to the NI DLL to support the number of currently active circuits plus
; a new one. If buffers are needed and can be obtained, they are posted
; directly to the NI DLL. If some are needed, and cannot be obtained,
; the error return is taken.
GETRBF: STKVAR <BUFADR>
LOAD T1,HNNRB,(HN) ;Do check to see if we need more buffers.
LOAD T2,HNNAC,(HN)
CAIL T1,1(T2)
RETSKP ;No additional are needed. Return success.
MOVEI T1,<<LMRFSI+3>/4+UN.LEN+UE.LEN> ;Receive buffer size
IFN FTOPS20,<
CALL MMGTZW ;Get the number of required buffers
>
IFN FTOPS10,<
CALL GETZBF ;Get the number of required buffers
>
RET ;Can't, return error.
MOVEM T1,BUFADR ;Save address in case we can't post buffer
CALL RBPOST ;Post the receive buffer to NISRV
IFSKP.
OPSTRM <AOS>,HNNRB,(HN);Increment the number of receive buffers
RETSKP ;Return success
ENDIF.
MOVE T1,BUFADR ;Get address of buffer
IFN FTOPS20,<
CALLRET MMFREE ;Free the memory
>
IFN FTOPS10,<
CALLRET GIVBF ;Free the memory
>
ENDSV.
;RELRBF - Release a Receive buffer
;
;Call: RB/ Address of the buffer to release
; CALL RELRBF
; Normal Return
;
; This routine frees a receive buffer if there is already a sufficient number
; posted to the NI DLL otherwise the buffer is re-posted to the NI DLL.
RELRBF: LOAD T1,HNNRB,(HN) ;Do we still need this buffer?
LOAD T2,HNNAC,(HN)
CAILE T1,1(T2)
JRST RELRB0 ;No, so free it
MOVE T1,RB ;Yes, so
CALL RBPOST ; re-post it to NISRV
JRST RELRB0 ;NISRV could not accept it?! Release it.
RET ;Successfully re-posted. Return.
RELRB0: MOVE T1,RB ;Here to free the buffer.
IFN FTOPS10,<
CALL GIVBF
>
IFN FTOPS20,<
CALL MMFREE
>
OPSTRM <SOS>,HNNRB,(HN) ;Reduce the number of receive buffers
RET
IFN FTOPS10,<
SUBTTL SCNSER DEVICE DEPENDANT ROUTINES
;
; TOPS10 does not call a device dependant routine for each output
; character. Nor does it call a routine to change TTY PAGE.
; At each scheduler interval, we scan all LDBs in LATSER's queue
; to see what must be done with each one.
;
LATSCN: MOVEI T1,LATRTQ ;Get SCNSER's queue header
SNCALL (TOTAKE##,MCSEC1) ;Get next active LDB on the chain
RET ;None. Just return.
SKIPN SB,LDBLAT##(U) ;Get slot block address
RET ;None. This guy's a loser so punt.
MOVEI T1,0 ;T1 will get Slot flags
MOVEI T3,L1RCHP##
TDNE T3,LDBBYT##(U) ;Need to change parameters?
CALL LATCHP ;Yes. See what needs change and set T1
TXO T1,SBOUT ;Always set flag for output. Check later anyway
;
; Here if we MIGHT have characters to output, or need to change TTY PAGE
;
MOVE CB,SB.CBA(SB) ;And associated circuit block address
CALL SSBDAV ;And set this slot's flags
JRST LATSCN ;Look at next LDB in the queue
;
;Routine to see if we need to change recognition of XON/XOFF
;
;Call: U/ LDB address
;
;Return: Flag SBFCC set in T1 if we need to change
;
LATCHP: ANDCAM T3,LDBBYT##(U) ;Turn off CHP bit to show we checked
LDB T2,@[IW MCSEC1,LDPXNF##] ;Get XON/XOF flag
LOAD T3,SBXNF,(SB) ;Get bit that says what the LAT knows
CAMN T2,T3 ;Are they already the same?
RET ;Yes, no need to send a message, then
TXO T1,SBFCC ;Different. Need to send a message
STOR T2,SBXNF,(SB) ;AND remember what we are now.
RET
>;end IFN FTOPS10
ENDAV.
IFN FTOPS20,<
SUBTTL TTYSRV DEVICE DEPENDENT ROUTINES
XRENT (LTSTRO,G) ;[7.1024]LTSTRO::, XLTSTR::
MOVX T1,SBOUT
SETONE TTOTP,(T2) ;Set output active
JRST LTSSDC
XRENT (LTCOBF,G) ;[7.1024]LTCOBF::, XLTCOB::
MOVX T1,SBFOU
JRST LTSSDC
XRENT (LTEXF,G) ;[7.1024]LTEXF::, XLTEXF::
MOVX T1,SBFCC
LTSSDC: ACVAR <HN,XB,RB,CB,SB,W1,W2>
NOSKD1
CHNOFF DLSCHN
SKIPN SB,TTDEV(T2) ;Get the slot data base from TDB if not 0
JRST LTSSD0
MOVE CB,SB.CBA(SB) ;Get the circuit data base from slot block.
SAVEAC <T2> ;TTYSRV needs T2 returned intact
CALL SSBDAV
LTSSD0: CHNON DLSCHN
OKSKD1
RET
; TTYSRV Device Dependent Routine to see if SENDAL should be done on this
; line.
; Call: T2/ Line Number
; Non-skip Return/ Skip SENDALL to this Line
; Skip Return / Do SENDALL to this Line
XRENT (LTSALL,G) ;[7.1024]LTSALL::, XLTSAL::
SKIPG TTACTL(T2) ;Is line fully active?
RET ;No, don't do SENDALL
RETSKP ;Yes, do the SENDALL
; TTYSRV device dependent routine to perform hang-up action
;
;Call: T2/ Line Number
XRENT (LTHNGU,G) ;[7.1024]LTHNGU::, XLTHNG:
SAVEAC <T2> ;Caller wants this back intact
CALLX (MSEC1,STADYN) ;[7.1024]Get the dynamic data base
RET ;There is none
MOVX T1,SBSTO ;Mark to send STOP slot if necessary
CALL LTSSDC ;(CALLRET won't work here)
RET
; TTYSRV device dependent routine to see if output is possible on a line
;
; Call: T2/ TDB Address
; Non-skip Return/ Output not possible
; Skip Return / Output possible
XRENT (LTTCOU,G) ;[7.1024]LTTCOU::, XLTTCO::
RETSKP
; TTYSRV device dependent routine to set LAT Host terminal lines as
; high speed lines.
;
;RETSKP always with:
; T3/ ^D9600 to simulate high speed output
; T4/ IBFRC1 the high speed terminal characteristics word
XRENT (LTSOF,G) ;[7.1024]LTSOF::, XLTSOF::
MOVEI T3,^D9600 ;Fake 9600 baud
MOVE T4,IBFRC1 ;High speed buffer word
RETSKP ;Always
>;end IFN FTOPS20
IFN FTOPS10,<
SUBTTL More SCNSER device dependant routines
;Routine LTHNGU - LAT "disconnect" function
;Called by SCNSER thru ISRREM entry point in dispatch vector with
; a function code if IRRDSC in T3
;
; U/ LDB address
; T3/IRRDSC
; CALL LTHNGU
; Returns +2 always (note: there is no "error" return)
;
LTHNGU: MOVX T1,SBSTO ;Yes, we want to stop this slot
CALL LTSSDC ;SO do it
RETSKP ;And indicate success to SCNSER
;
;Routine LATREM
;Called from SCNSER through dispatch vector element ISRREM (7)
;
; U/ LDB address
; T3/ Function code
; Possible values are:
; (1) Input buffer low (ignored)
; (2) Input character not stored (ignored)
; (IRRSCG) Eat all output characters
; (IRRDSC) Disconnect LAT terminal
; (IRRTMO) Disconnect idle terminal
;
LATREM: CAIN T3,IRRDSC ;Is the the "disconnect" function?
CALLRET LTHNGU ;Yes, do it.
CAIN T3,IRRTMO ;Is it the "timeout" function?
CALLRET LTHNGU ;Yes, do it.
CAIE T3,IRRSCG ;Is it "send character gobbler"?
RET ;No, those are all we know about
LTCOBF: MOVX T1,SBFOU ;User hit ^O, tell remote to gobble output
LTSSDC: ACVAR <HN,XB,RB,CB,SB,W1,W2>
ETHLOK ;Interlock against races
SKIPN SB,LDBLAT##(U) ;Get slot data base from LDB
JRST LTSSD0 ;Not there any more, ignore
MOVE CB,SB.CBA(SB) ;Get circuit data base from slot block.
CALL SSBDAV
LTSSD0: ETHULK ;Release interlock
RET
>;end IFN FTOPS10
SUBTTL General Untility Routines
;
;RANDOM - get a "random" number
;
;Call: T1/ Maximum number allowed
; CALL RANDOM
; Normal Return
; T1/ Random Number
RANDOM: MOVE T4,T1 ;Save for modulo
IFN FTOPS20,<
CALLX (MSEC1,LGTAD) ;[7.1024]Get internal time and date
>;end IFN FTOPS20
IFN FTOPS10,<
MOVE T1,DATE## ;get TOPS-10 time and date
>;end IFN FTOPS10
ANDI T1,777777 ;Time only
IDIV T1,T4 ;MODULO max, (which is the remainder in T2)
SKIPN T1,T2 ;GET remainder
MOVEI T1,1 ;But if it's zero, make it 1
RET
;GTCHCT - Get character count for terminal output.
;Call: T2/ TDB address
;Return:
; T1/ Total character count
IFN FTOPS20,<
GTCHCT: SETZ T1,0
TMNN TTSAL,(T2) ;Is there a send all in progress?
IFSKP. ;Yes, must include count of the
LOAD T1,TSALC,(T2) ; send all buffer.
ENDIF.
ADD T1,TTOCT(T2) ;Add the terminal buffer count.
RET
>;END IFN FTOPS20
ENDAV.
SUBTTL LAGTCR - LAT memory management routines
;
; Subroutine to tell COMMON how much core LAT needs at ONCE time
;
;Call: CALL LAGTCR
;
;Return: +1 always with T1/ size of memory LAT needs, which is:
;
; Space for 1 outstanding receive buffer +
; for each possible open circuit: MAXXBF transmit buffers
; + 1 receive buffer
IFN FTOPS10,<
; MAX.(BUFSIZ,<RBFSIZ,XBFSIZ>) ;BUFSIZ is size of largest buffer
; BUFSIZ==BUFSIZ+QL.LEN ;we need + 2 words for linking list
BUFSIZ==PAGSIZ ;Oh, the hell with it! receive buffers have
;to be contiguous, so don't bother to
;split a buffer across a page boundary.
;Luckily, the actual size of a buffer
;is slightly smaller than a page.
NBUFS==<1+<MAXXBF+1>> ;
;
$CSUB
LAGTCR::
MOVEI T1,<BUFSIZ*NBUFS>
RET
XRESCD
;
; Routine to ask for more memory from user free core
; We should get it a tick or two later.
;
CHKWFB: SKIPE T1,LATWFB ;Do we want any more buffers?
SKIPE LATRFB ;And have we not yet aksed for them?
RET ;No to either, don't get memory now.
;
; Here we have finally decided it's our turn to ask for some memory
;
IMULI T1,BUFSIZ ;Calculate how many words
TRZE T1,PG.BDY ;Round up to page bound
ADDI T1,PAGSIZ
MOVEM T1,LATRFB ;Remember how many words we asked for.
LSH T1,W2PLSH ;Convert to pages
HRLI T1,(MS.DCN) ;Section to allocate from
XMOVEI T2,CHKRFB ;Callback routine address
XJRST [MCSEC1+GETCLP##] ;Ask for the space
;
; CHKRFB - Routine called when VMSER gave us memory
; If so, link it into free buffer list
;
CHKRFB: MOVE T4,T1 ;Get address of start
SETZ T1, ;Get a zero
EXCH T1,LATRFB ;Get number of pages we wanted (and clear it)
IDIVI T1,BUFSIZ ;Convert to number of buffers
ADDM T1,LATNFB ;Indicate that we've got more
MOVE T2,T4 ;Get address of first buffer
MOVE T4,T1 ;save buffer count
ALCBUF: MOVEI T1,LATFRE ;QUEUE header for LAT free core
CALL QUE1WB ;Link this buffer to the list.
ADDI T2,BUFSIZ ;Point to next one.
SOJG T4,ALCBUF ;Until all buffers have been allocated.
RET
;
; GETZBF - Routine to get a receive or transmit buffer and zero it.
;
;Call: T1/ required size
;Return: +1 failure
; +2 success T1/ address of buffer
;
GETZBF: PUSH P,T1 ;Save size wanted
MOVEI T1,LATFRE ;Address of queue header for free pool
CALL UNQ1WF ;Get a buffer
JRST TPOPJ ;Couldn't, restore T1 and return.
SOS LATNFB ;One less free buffer
PUSH P,T2 ;SAVE ADDRESS OF BUFFER
XMOVEI T3,1(T2) ;POINT TO SECOND WORD
SETZM (T2) ;ZERO FIRST WORD
MOVEI T1,BUFSIZ-1 ;SET UP TO ZERO THE WHOLE BLOCK
XBLT. T1 ;DO IT
POP P,T2 ;RESTORE ADDRESS
POP P,T1 ;Restore size
HRLI T1,'LAT' ;check word
MOVEM T1,(T2) ;save <'LAT',,size> as first word
HRRZ T3,T1 ;Isolate size
ADD T3,T2 ;Point to end of buffer
HRLI T1,'END'
MOVEM T1,1(T3)
XMOVEI T1,1(T2) ;POINT to address of data portion
RETSKP
;
; GIVBF - Routine to give back a buffer to free pool
;
;Call: T1/ address of data portion of buffer
;Return: +1 always
;
GIVBF: SUBI T1,1 ;Point to size word
HLRZ T2,(T1) ;Get check code
HRRZ T3,(T1) ;Get size
ADD T3,T1 ;Point to near end of buffer
HLRZ T3,1(T3) ;Get ending check code
CAIN T3,'END' ;See if either end has been wiped out
CAIE T2,'LAT' ;Is it still there?
BUG. (CHK,LATMEM,LATSER,SOFT,<LAT buffer overwritten>,<<T1,ADDRESS>>,<
While trying to return a buffer, LATSER discovered it had been overwritten.>)
MOVE T2,T1 ;Now return the buffer
MOVEI T1,LATFRE ;To the queue of free buffers
AOS LATNFB ;Count one more buffer available
CALLRET QUE1WB ;For re-use
> ;END IFN FTOPS10
MMGTZW:
IFN FTOPS20,<
CALLRET DNGWDZ ;[7.1024]
>;END IFN FTOPS20
IFN FTOPS10,<
MOVEI T2,1(T1) ;Going to ask for 1 more word for check
PUSH P,T2 ;save requested size
SNCALL (GETEWZ##,MCSEC1) ;Get zeroed core from ethernet free pool
JRST TPOPJ ;No luck
POP P,T2 ;Get back requested size
ADDI T1,1 ;Point to data portion of block
MOVEM T2,-1(T1) ;save length as first word of block
RETSKP ;And return it to caller
>;END IFN FTOPS10
MMFREE:
IFN FTOPS20,<
CALLRET DNFWDS ;[7.1024]
>
IFN FTOPS10,<
XMOVEI T2,-1(T1) ;Point to block-1
HRRZ T1,(T2) ;Which contains length of block
XJRST [MCSEC1+GIVEWS##] ;and give it back to ethernet free pool.
;
; Subroutine to convert SIXBIT nodename to ASCII
;
;Call: T1/ SIXBIT node name
;
;Return: +1 always with ASCII in OURNAM, OURNAM+1
; and character in OURCNT
;
CVTNOD: SETZM OURCNT ;No characters yet
SETZM OURNAM ;Or name
SETZM OURNAM+1 ; ...
JUMPE T1,RTN ;Done if no characters left
MOVE T3,[POINT 7,OURNAM] ;Where to put node name
CVTNO1: SETZ T2, ;Zap the temp AC
ROTC T1,6 ;Get next character into T2
ADDI T2,40 ;Convert to ASCII
AOS OURCNT ;Count characters done
IDPB T2,T3 ;Put the character into the name
JUMPN T1,CVTNO1 ;Continue
RET ;Done
>;END IFN FTOPS10
XLIST
LIT
IFN FTOPS10,<
define .xcrf1(syms),<
irp syms,<purge syms>>
.xcmsy ;Purge some stupid MACSYM symbols
PRGALL ;Purge all ..nnnn symbols
>;end IFN FTOPS10
END