Trailing-Edge
-
PDP-10 Archives
-
BB-P363B-SM_1985
-
t20/nmlt20/knit20.b36
There are no other files named knit20.b36 in the archive.
! UPD ID= 336, SNARK:<6.1.NML>KNIT20.B36.8, 23-Jul-85 14:22:46 by MCCOLLUM
! Set CD_MORE_MOP_RESPONSES in READ_MOP_LOOP if bit LM%MRF (LM_MRF) is set
! in word .LMCID ($LMCID) of the LLMOP% argument block on return from a
! .ELRPY ($ELRPY) function. LOOP_CIRCUIT in NMLLBK reads this flag.
!
! UPD ID= 275, SNARK:<6.1.NML>KNIT20.B36.7, 6-Mar-85 11:35:55 by GLINDELL
! Add typeout of ETHERNET address to TRACE of ETHERNET receive
!
! UPD ID= 182, SNARK:<6.1.NML>KNIT20.B36.6, 7-Dec-84 08:52:45 by HALPIN
! Change all DLX_LOAD and DLX_DUMP references to DLX_LDA. Only one
! Circuit Block for Load Dump Assistance.
! Rewrite READ_MOP_LOAD_DUMP routine to use non-blocking reads. Turn
! Receive PSI Interrupts in OPEN_KLNI_DEVICE.
! READ_MOP_LOAD_DUMP chacks for messages to the LOAD/DUMP ASSISTANCE
! MULTICAST ADDRESS, and sets flag in the circuit block.
! Store the Source ETHERNET Address in Circuit Block.
!
! UPD ID= 172, SNARK:<6.1.NML>KNIT20.B36.5, 19-Nov-84 10:20:25 by HALPIN
! Add NI% JSYS Interface routines for LOAD/DUMP and ENABLE MULTICAST
! MOP Functions.
!
! UPD ID= 147, SNARK:<6.1.NML>KNIT20.B36.4, 30-Oct-84 11:33:50 by GUNN
! Add BOOT_REMOTE routine.
!
! UPD ID= 141, SNARK:<6.1.NML>KNIT20.B36.3, 29-Oct-84 11:45:13 by GUNN
! Fix READ_MOP_LOOP to properly build Ethernet address of responding
! node in response message.
!
!
! UPD ID= 105, SLICE:<6.1.NML>KNIT20.B36.2, 18-Sep-84 16:22:01 by GUNN
%sbttl 'TOPS-20 Specific Ethernet KLNI LLMOP Routines'
!
! Definitions needed for debugging
!
external
%debug_data_base;
!
! Macros
!
macro
CH$HEX [ ] =
ch$ptr (uplit (X_CHAR(%explode(%remaining))),,8) %;
macro
X_CHAR [B1,B2,B3,B4,B5,B6,B7,B8] =
((%X B1 ^ (%bpval-4))
%if not %null(B2)
%then
or (%X B2 ^ (%bpval-8))
%if not %null(B3)
%then
or (%X B3 ^ (%bpval-12))
%if not %null(B4)
%then
or (%X B4 ^ (%bpval-16))
%if not %null(B5)
%then
or (%X B5 ^ (%bpval-20))
%if not %null(B6)
%then
or (%X B6 ^ (%bpval-24))
%if not %null(B7)
%then
or (%X B7 ^ (%bpval-28))
%if not %null(B8)
%then
or (%X B8 ^ (%bpval-32))
%fi %fi %fi %fi %fi %fi %fi) %;
macro
NI_ARG_BLOCK = monblock [$EIBMX] volatile %, ! NI JSYS argument block
BUFFER_DESCRIPTOR_BLOCK = monblock [$BXBMX] volatile %, ! Buffer Descriptor
LLMOP_ARG_BLOCK = monblock [10] volatile %; ! LLMOP JSYS argument block
literal
MOP_BUFFER_LENGTH = 1504, ! MOP message buffer in bytes
MOP_BUFFER_SIZE = ch$allocation (MOP_BUFFER_LENGTH, 8),
MOP_BUFFER_ALLOCATION = MOP_BUFFER_SIZE * %upval,
FWORD = %O'777777777777',
LHALF = %O'777777000000',
RHALF = %O'777777';
bind
LOAD_DUMP_ASST_MULTICAST = CH$HEX ('AB0000010000');
%routine ('OPEN_KLNI_DEVICE', CD: ref CD_BLOCK, RSP_POINTER) =
!++
! Functional description:
!
! This routine is called by NMU$KLNI_OPEN to perform
! system specific operations for servicing a KLNI.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true System specific open succeeded
! $false Error opening KLNI
!
!--
begin
literal
LOAD_DUMP_PROTOCOL = %X'6001';
if .CD [CD_USAGE] eql DLX_LDA
then begin
local
ERROR_CODE,
NI_BLOCK : NI_ARG_BLOCK;
DECLARE_JSYS (NI, GETER);
incr I from 0 to $EIBMX-1
do
NI_BLOCK[.I,FWORD] = 0;
NI_BLOCK [$EILEN,EILEN] = $EIBMX; ! Open Function takes 4 words
NI_BLOCK [$EIFCN,EIFCN] = $EIOPN;
NI_BLOCK [$EIFLG,EIPAD] = 1;
NI_BLOCK [$EICHN,EICHN] = .CD [CD_KLNI_CHAN];
NI_BLOCK [$EIPRO,EIPRO] = LOAD_DUMP_PROTOCOL;
NI_BLOCK [$EIPSI,EIRCH] = .CD [CD_KLNI_RCV_PSI];
NI_BLOCK [$EIPSI,EITCH] = .CD [CD_KLNI_XMT_PSI];
NI_BLOCK [$EIPSI,EISCH] = .CD [CD_KLNI_STS_PSI];
if not $$NI (NI_BLOCK)
then begin
$$GETER($FHSLF; ERROR_CODE);
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Open failure on %X. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.ERROR_CODE);
return $false;
end;
CD [CD_KLNI_PRTLID] = .NI_BLOCK [$EIPID,EIPID];
if (CD [CD_RCV_BID] = NMU$MEMORY_GET (MOP_BUFFER_ALLOCATION)) eql 0
then ! Allocation failure
begin
$RESPONSE (.RSP_POINTER,NICE$_REE,0);
CLOSE_KLNI_DEVICE (.CD);
return $false;
end;
if not POST_RECEIVE_BUFFER (.CD, .RSP_POINTER)
then return $false;
end;
return $true;
end; ! of OPEN_KLNI_DEVICE
%routine ('CLOSE_KLNI_DEVICE', CD: ref CD_BLOCK) =
!++
! Functional description:
!
! This routine is called by NMU$KLNI_CLOSE to perform
! system specific operations for releasing a KLNI.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
!
! Routine value:
!
! $true System specific release succeeded
! $false Error releasing KLNI
!
!--
begin
local
ERROR_CODE,
NI_BLOCK : NI_ARG_BLOCK;
DECLARE_JSYS (NI);
if .CD [CD_RCV_BID] neq 0
then NMU$MEMORY_RELEASE (.CD[CD_RCV_BID], MOP_BUFFER_ALLOCATION);
CD [CD_RCV_BID] = 0;
incr I from 0 to $EIBMX-1
do
NI_BLOCK[.I,FWORD] = 0;
NI_BLOCK [$EILEN,EILEN] = $EIBMX; ! Close Function takes 2 words
NI_BLOCK [$EIFCN,EIFCN] = $EICLO;
NI_BLOCK [$EIFLG,EIFLG] = 0;
NI_BLOCK [$EIPID,EIPID] = .CD [CD_KLNI_PRTLID];
if not $$NI (NI_BLOCK)
then return $false;
$true
end; ! of CLOSE_KLNI_DEVICE
%routine ('READ_MOP_LOOP', CD: ref CD_BLOCK, PTR, LEN, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$KLNI_READ to read a MOP loop
! reply message from a remote node on an Ethernet.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .PTR Pointer to message buffer
! .LEN Number of bytes in message buffer to write
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! Number of bytes read on circuit
!
! or
!
! -2 for read timeout
! -1 for any other error
!
!--
begin
forward routine
BUILD_PARAMETER_DATA;
routine BUILD_PARAMETER_DATA (ENTITY_TYPE, PARMNO, PVALU, LENGTH, POINTER) =
%( Nota Bene:
%routine ('BUILD_PARAMETER_DATA', ENTITY_TYPE, PARMNO, PVALU, LENGTH, POINTER) =
The code in this routine was lifted from NMLVDB 'READ_PARAMETER_DATA'.
It is here only temporarily. It should be moved to NMLPRM and made
to be a global routine. NMLEVD could be changed to make use of this.
)%
!++
! FUNCTIONAL DESCRIPTION:
!
! Builds the DATA ID, DATA TYPE and PARAMETER DATA fields of the
! NICE response message into the response message buffer.
!
! FORMAL PARAMETERS
!
! ENTITY_TYPE Entity type.
! PARMNO The architecturally defined parameter number
! for this parameter.
! PVALU The value for this parameter.
! LENGTH The length of the buffer remaining.
! POINTER The address of a character sequence pointer to the
! buffer.
!
! IMPLICIT INPUTS
!
! NONE.
!
! ROUTINE VALUE:
!
! The number of bytes for this parameter excluding data id
! and datatype bytes.
!
! SIDE EFFECTS:
!
! If the parameter will fit in the buffer, it is copied into
! the buffer.
!
!--
begin
external routine
NML$DATA_TYPE;
macro
PUTN (VALUE, PTR_ADR, N) =
begin
local L, X;
X = VALUE;
ch$wchar_a (.X, PTR_ADR);
incr L from 256 to ((N - 1) * 256) by 256
do begin
X = .X / .L;
ch$wchar_a (.X, PTR_ADR);
end;
.L / 256
end %;
local
BUF_PTR,
BUF_LEN,
DATA_ID: block [1] field (DATA_ID_FIELDS), ! Data ID
DATA_TYPE: block [1] field (DATA_TYPE_FIELDS);
BUF_PTR = ..POINTER;
DATA_ID = 0;
DATA_ID[DI_PARMNO] = .PARMNO; ! Get parameter number
DATA_ID[DI_TYPE] = 0; ! This is a parameter
DATA_TYPE = NML$DATA_TYPE (.ENTITY_TYPE, .PARMNO);
if .DATA_TYPE[DT_CODED] eql 0 ! Not coded
then begin
PUTW (DATA_ID, BUF_PTR); ! Write data id into buffer
PUTB (.DATA_TYPE, BUF_PTR); ! Write data type into buffer
if .DATA_TYPE[DT_FTYPE] eql 0 ! Binary number
then begin
if .DATA_TYPE[DT_LENGTH] eql 0
then begin ! Binary image field
BUF_LEN = ch$rchar (ch$ptr (.PVALU,,8)) + 1;
if .LENGTH geq .BUF_LEN
then BUF_PTR = ch$move (.BUF_LEN,
ch$ptr (.PVALU,,8),
.BUF_PTR);
end
else begin
BUF_LEN = .DATA_TYPE[DT_LENGTH];
if .DATA_TYPE[DT_LENGTH] leq %bpval/8
then begin ! Data stored in value
if .LENGTH geq .BUF_LEN
then PUTN (.PVALU,
BUF_PTR,
.DATA_TYPE[DT_LENGTH]);
end
else begin ! Data stored in buffer
BUF_LEN = .DATA_TYPE[DT_LENGTH];
if .LENGTH geq .BUF_LEN
then BUF_PTR = ch$move (.BUF_LEN,
ch$ptr (.PVALU,,8),
.BUF_PTR);
end;
end;
end
else begin ! ASCII image field
BUF_LEN = ch$rchar (ch$ptr (.PVALU,,8)) + 1;
if .LENGTH geq .BUF_LEN
then BUF_PTR = ch$move (.BUF_LEN,
ch$ptr (.PVALU,,8),
.BUF_PTR);
end;
end
else begin ! Coded
%( N.B. - We have to do special casing here for multiple coded
fields. )%
if .DATA_TYPE[DT_FTYPE] eql 0 ! Single field
then begin
PUTW (DATA_ID, BUF_PTR); ! Write data id into buffer
PUTB (.DATA_TYPE, BUF_PTR); ! Write data type into buffer
BUF_LEN = .DATA_TYPE[DT_NUMBER];
if .LENGTH geq .BUF_LEN
then PUTN (.PVALU, BUF_PTR, .DATA_TYPE[DT_NUMBER]);
end
else selectone .DATA_TYPE[DT_NUMBER] of
set ! Multiple field
[CMN] : ! Node format
begin
local PTR;
PTR = ch$ptr (.PVALU,,8);
begin
literal DATA_TYPE = 1^7 + 1^6 + 2;
PUTW (DATA_ID, BUF_PTR); ! Write data id
PUTB (DATA_TYPE, BUF_PTR); ! Write data type
end;
BUF_LEN = 6 + 5; ! Assume node name of 6 chars
if .LENGTH geq .BUF_LEN
then
begin
!
! Node address
!
begin
literal DATA_TYPE = 0^7 + 0^6 + 0^4 + 2;
local NODE_ADDRESS;
NODE_ADDRESS = GETW (PTR);
PUTB (DATA_TYPE, BUF_PTR); ! Write Data Type
PUTW (NODE_ADDRESS, BUF_PTR); ! Write address
end;
!
! Node name
!
begin
literal DATA_TYPE = 0^7 + 1^6;
local NODE_NAME_LENGTH;
PUTB (DATA_TYPE, BUF_PTR); ! Write Data Type
NODE_NAME_LENGTH = GETB (PTR); ! Get I-length
PUTB (.NODE_NAME_LENGTH, BUF_PTR);
BUF_PTR = ch$move (.NODE_NAME_LENGTH,
.PTR,
.BUF_PTR);
BUF_LEN = .NODE_NAME_LENGTH + 5; ! Real length
end;
end;
end;
[CMV] : ! Version format
begin
external ! Version numbers defined in NMUSKD
NMLVER, ! Major version
DECECO, ! Minor version
USRECO; ! Customer version
begin
literal DATA_TYPE = 1^7 + 1^6 + 3;
PUTW (DATA_ID, BUF_PTR); ! Write data id
PUTB (DATA_TYPE, BUF_PTR); ! Write data type
end;
BUF_LEN = 6; ! Six bytes to write excluding
! data id and data type bytes
if .LENGTH geq .BUF_LEN
then
begin
literal DATA_TYPE = 0^7 + 0^6 + 0^4 + 1;
PUTB (DATA_TYPE, BUF_PTR); ! Write Data Type
PUTB (.NMLVER, BUF_PTR); ! Write version byte
PUTB (DATA_TYPE, BUF_PTR); ! Write Data Type
PUTB (.DECECO, BUF_PTR); ! Write version byte
PUTB (DATA_TYPE, BUF_PTR); ! Write Data Type
PUTB (.USRECO, BUF_PTR); ! Write version byte
end;
end;
[otherwise] : ! Unknown multiple parameter
BUF_LEN = 0;
tes;
end;
.POINTER = .BUF_PTR;
return .BUF_LEN; ! Return number of bytes written
end; ! End of BUILD_PARAMETER_DATA
DECLARE_JSYS (LLMOP);
local
COUNT,
LLMOP_BLOCK: LLMOP_ARG_BLOCK; ! LLMOP JSYS argument block
LLMOP_BLOCK [$LMCID,FWORD] = 0; ! Clear LLMOP Arg Block
LLMOP_BLOCK [$LMDST,FWORD] = 0;
LLMOP_BLOCK [$LMDST+1,FWORD] = 0;
LLMOP_BLOCK [$LMREQ,FWORD] = 0;
LLMOP_BLOCK [$LMRBL,FWORD] = 0;
!
! First wait for reply message to arrive. Timeout after 'n' seconds
!
LLMOP_BLOCK [$LMCID,FWORD] = .CD[CD_KLNI_CHAN]; ! Pass channel id
LLMOP_BLOCK [$LMREQ,LM_REQ] = .CD[CD_KLNI_REQNO]; ! Pass request number
incr COUNT from 1 to 5 do
begin
if not $$LLMOP ($ELSTS, LLMOP_BLOCK)
then
begin
RSP_POINTER = ch$plus (.RSP_POINTER,
$RESPONSE (.RSP_POINTER,
NICE$_OPF,
0,
'LLMOP Failure',
ch$ptr (CD [CD_NAME],,
8)));
return -1;
end;
if .LLMOP_BLOCK [$LMSTF,LM_RTC] eql $LMSUC
then
begin
!
! Read MOP data message from KLNI
!
LLMOP_BLOCK [$LMRBL,LM_MBL] = .LEN; ! Pass length of reply buffer
LLMOP_BLOCK [$LMRBP,FWORD] = .PTR; ! Pass pointer to reply buffer
if not $$LLMOP ($ELRPY, LLMOP_BLOCK)
then
begin
RSP_POINTER = ch$plus (.RSP_POINTER,
$RESPONSE (.RSP_POINTER,
NICE$_OPF,
0,
'Failure reading MOP loop reply on %X. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.LLMOP_BLOCK [$LMSTF,LM_RTC]));
return -1;
end
else
begin
local ! Buffer for Ethernet reply address
RPYADR : vector [ch$allocation(7,8)*%upval];
%( Here put in the Data-Id and Data-Type bytes. See NMARCH and/or NMLPRM?)%
RSP_POINTER = ch$plus (.RSP_POINTER,
$RESPONSE (.RSP_POINTER,
NICE$_SUC,
0));
! Build ENTITY ID field in response message
RSP_POINTER = ch$move(ch$rchar(ch$ptr(CD[CD_NAME],,8))+1,
ch$ptr (CD [CD_NAME],,8),
.RSP_POINTER);
! Build TEST DATA field in response message
PUTB (0, RSP_POINTER);
PUTB (0, RSP_POINTER);
! Build DATA BLOCK field in response message
!
! Conjure up an HI-6 parameter field.
!
! Shuffle the 6 byte address forward to make room
! for the I field, then store the I-6 field.
!
ch$move (6,
ch$ptr(LLMOP_BLOCK [$LMSRC,FWORD],,8),
ch$ptr(RPYADR,1,8));
ch$wchar (6,ch$ptr(RPYADR,0,8));
BUILD_PARAMETER_DATA (ENTITY_NODE, ! NODE Entity
010, ! PHYSICAL ADDRESS Parameter
RPYADR,
12, ! Fake this for now
RSP_POINTER);
CD[CD_MORE_MOP_RESPONSES] = .LLMOP_BLOCK[$LMCID,LM_MRF];
return .LLMOP_BLOCK [$LMRBL,LM_RML];
end;
end
else
NMU$SCHED_SLEEP(1); ! Sleep a second before reading
end;
$$LLMOP ($ELABT, LLMOP_BLOCK); ! Timed Out, Abort Request
return -2 ! Indicate timeout to caller
end; ! of READ_MOP_LOOP
%routine ('WRITE_MOP_LOOP', CD: ref CD_BLOCK, PTR, LEN, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$KLNI_WRITE to send MOP data
! messages on the Ethernet using a KLNI.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .PTR Pointer to message buffer
! .LEN Number of bytes in message buffer to write
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true If successful
! $false If error
!
!--
begin
DECLARE_JSYS (LLMOP);
local
LLMOP_BLOCK: LLMOP_ARG_BLOCK; ! LLMOP JSYS argument block
!
! Set up the LLMOP JSYS argument block
!
LLMOP_BLOCK [$LMCID,FWORD] = 0; ! Clear LLMOP Arg Block
LLMOP_BLOCK [$LMDST,FWORD] = 0;
LLMOP_BLOCK [$LMDST+1,FWORD] = 0;
LLMOP_BLOCK [$LMREQ,FWORD] = 0;
LLMOP_BLOCK [$LMRBL,FWORD] = 0;
LLMOP_BLOCK [$LMCID,LM_CID] = .CD[CD_KLNI_CHAN]; ! Pass channel id
LLMOP_BLOCK [$LMRBL,LM_MBL] = .LEN; ! Pass length of data message
LLMOP_BLOCK [$LMRBP,FWORD] = .PTR; ! Pass pointer to data message
ch$move (6, .CD[CD_KLNI_PHYADR], ch$ptr(LLMOP_BLOCK[$LMDST,FWORD],,8));
!
! Send MOP loop message
!
if not $$LLMOP ($ELDIR, LLMOP_BLOCK)
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Failure sending MOP loop data on %X. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.LLMOP_BLOCK [$LMSTF,LM_RTC]);
return $false;
end;
CD[CD_KLNI_REQNO] = .LLMOP_BLOCK [$LMREQ,LM_REQ]; ! Return request number
$true
end; ! of WRITE_MOP_LOOP
%routine ('BOOT_REMOTE', CD: ref CD_BLOCK, PTR, LEN, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$KLNI_WRITE to send a MOP BOOT
! message on the Ethernet using a KLNI.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .PTR Pointer to message buffer
! .LEN Number of bytes in message buffer to write
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true If successful
! $false If error
!
!--
begin
DECLARE_JSYS (LLMOP);
local
L,
LLMOP_BLOCK: LLMOP_ARG_BLOCK; ! LLMOP JSYS argument block
if .LEN lss 12 ! Is it a V3.0 style BOOT message?
then
begin
$RESPONSE (.RSP_POINTER, NICE$_MPE, 0,
'Invalid BOOT message length');
return $false;
end;
!
! Set up the LLMOP JSYS argument block
!
LLMOP_BLOCK [$LMCID,FWORD] = 0; ! Clear Channel-Id
LLMOP_BLOCK [$LMDST,FWORD] = 0; ! Clear Destination Address
LLMOP_BLOCK [$LMDST+1,FWORD] = 0;
LLMOP_BLOCK [$LMPWD,FWORD] = 0; ! Clear Password Verification
LLMOP_BLOCK [$LMPWD+1,FWORD] = 0;
LLMOP_BLOCK [$LMCIF,FWORD] = 0; ! Clear Control Information
LLMOP_BLOCK [$LMDID,FWORD] = 0; ! Clear Device Id
LLMOP_BLOCK [$LMSID,FWORD] = 0; ! Clear Software Id
LLMOP_BLOCK [$LMCID,LM_CID] = .CD[CD_KLNI_CHAN]; ! Pass channel id
if GETB (PTR) neq ENTER_MOP_MODE ! Is it a BOOT message
then
begin
$RESPONSE (.RSP_POINTER, NICE$_MPE, 0,
'Invalid BOOT message function code');
return $false;
end;
PTR = ch$move (8, ! Move Password Verification
.PTR, ! From message
ch$ptr(LLMOP_BLOCK[$LMPWD,FWORD],,8)); ! To Arg Block
ch$move (6, ! Move Ethernet Destination Address
.CD[CD_KLNI_PHYADR], ! From Circuit Data Block
ch$ptr(LLMOP_BLOCK[$LMDST,FWORD],,8)); ! To Argument Block
LLMOP_BLOCK [$LMCIF,LM_PRO] = GETB (PTR); ! Set Processor
LLMOP_BLOCK [$LMCIF,(LM_BDV or LM_BSV)] = GETB (PTR); ! Set Control Info
if .LLMOP_BLOCK [$LMCIF,LM_BDV] ! Boot Device present?
then
begin
if (L = GETB (PTR)) lss (12 - .LEN)
then
begin
$RESPONSE (.RSP_POINTER, NICE$_MPE, 0,
'Invalid BOOT message - length');
return $false;
end;
LLMOP_BLOCK [$LMDID,FWORD] = .PTR; ! Get Device Id pointer
PTR = ch$plus (.PTR, .L); ! Update pointer
end
else L = 0;
if .LEN gtr .L + 11
then
LLMOP_BLOCK [$LMSID,FWORD] = .PTR; ! Set Software Id pointer
!
! Send MOP BOOT message
!
if not $$LLMOP ($RCRBT, LLMOP_BLOCK)
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Failure sending MOP message on %X. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.LLMOP_BLOCK [$LMSTF,LM_RTC]);
return $false;
end;
$true
end; ! of BOOT_REMOTE
%routine ('WRITE_MOP_LOAD_DUMP', CD: ref CD_BLOCK, PTR, LEN, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$KLNI_WRITE to send MOP data
! messages on the Ethernet using a KLNI.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .PTR Pointer to message buffer
! .LEN Number of bytes in message buffer to write
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true If successful
! $false If error
!
!--
begin
DECLARE_JSYS (NI, GETER);
local
ERROR_CODE,
BUFFER_DESCRIPTOR : BUFFER_DESCRIPTOR_BLOCK,
NI_BLOCK : NI_ARG_BLOCK;
%debug (NETWORK_TRACE,
(begin
local COUNT, POINTER, OUTCNT;
TRACE_INFO (
'Writing MOP message to Link %X, %D Bytes',
ch$ptr (CD[CD_NAME],,8),
.LEN);
TRACE_INFO ('address %6K', .CD [CD_KLNI_PHYADR]);
POINTER = .PTR;
COUNT = .LEN;
while .COUNT gtr 0 do
begin
OUTCNT = min (.COUNT, 8);
TRACE_INFO (' %#B', .OUTCNT, .POINTER);
POINTER = ch$plus (.POINTER, 8);
COUNT = .COUNT - 8;
end;
end));
incr I from 0 to $BXBMX-1
do
BUFFER_DESCRIPTOR [.I,FWORD] = 0;
BUFFER_DESCRIPTOR [$BXLEN,FWORD] = $BXBMX;
BUFFER_DESCRIPTOR [$BXNXT,BXNXT] = 0; ! No chain here.
BUFFER_DESCRIPTOR [$BXBSZ,BXBSZ] = .LEN; ! Length of Datagram in bytes
BUFFER_DESCRIPTOR [$BXBFA,BXBFA] = .PTR; ! Pointer to start of datagram
ch$move (6, .CD[CD_KLNI_PHYADR], ch$ptr(BUFFER_DESCRIPTOR [$BXDAD,BXDAD],,8));
incr I from 0 to $EIBMX-1
do
NI_BLOCK[.I,FWORD] = 0;
NI_BLOCK [$EILEN,EILEN] = $EIBMX; ! XMIT Function takes 3 words
NI_BLOCK [$EIFCN,EIFCN] = $EIXMT; ! Transmit a Datagram
NI_BLOCK [$EIPID,EIPID] = .CD [CD_KLNI_PRTLID]; ! We need the Portal ID
NI_BLOCK [$EIFLG,EIBLK] = 1; ! Blocking Transmits for now.
NI_BLOCK [$EIBCP,EIBCP] = BUFFER_DESCRIPTOR; !Address of Buffer descriptor
if not $$NI(NI_BLOCK)
then begin
$$GETER($FHSLF; ERROR_CODE);
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Failure sending MOP load/dump data on %X. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.ERROR_CODE);
return $false;
end;
return $true;
end; ! of WRITE_MOP_LOAD
%routine ('READ_MOP_LOAD_DUMP', CD: ref CD_BLOCK, PTR, LEN, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$KLNI_READ to read MOP data
! messages on the Ethernet using a KLNI.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .PTR Pointer to message buffer
! .LEN Size of the receive buffer
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! Number of bytes read on circuit
!
! or
!
! -2 for read timeout
! -1 for any other error
!
!--
begin
DECLARE_JSYS (NI, GETER);
local
ERROR_CODE,
BUFFER_DESCRIPTOR : BUFFER_DESCRIPTOR_BLOCK,
NI_BLOCK : NI_ARG_BLOCK,
LENGTH;
incr I from 0 to $BXBMX-1
do BUFFER_DESCRIPTOR [.I,FWORD] = 0;
BUFFER_DESCRIPTOR [$BXLEN,FWORD] = $BXBMX;
BUFFER_DESCRIPTOR [$BXNXT,BXNXT] = 0;
incr I from 0 to $EIBMX-1
do NI_BLOCK[.I,FWORD] = 0;
NI_BLOCK [$EILEN,EILEN] = $EIBMX;
NI_BLOCK [$EIFCN,EIFCN] = $EIRRQ;
NI_BLOCK [$EIFLG,EIFLG] = 0; ! Don't Block
NI_BLOCK [$EIPID,EIPID] = .CD [CD_KLNI_PRTLID]; ! We need the Portal ID
NI_BLOCK [$EIBCP,EIBCP] = BUFFER_DESCRIPTOR;
if not $$NI (NI_BLOCK)
then begin
$$GETER($FHSLF; ERROR_CODE);
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Failure reading MOP load/dump data on %X. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.ERROR_CODE);
return -1;
end;
if ((LENGTH = .BUFFER_DESCRIPTOR [$BXBSZ,BXBSZ]) gtr .LEN)
then return -1;
if .BUFFER_DESCRIPTOR [$BXSTA,BXVAL]
then begin
local
TMP_PTR;
TMP_PTR = ch$ptr (.CD[CD_RCV_BID],2,8); ! And point past it.
ch$move (.LENGTH, ! Copy data from KLNI
.TMP_PTR, ! Receive buffer to NML's
.PTR); ! MOP buffer
ch$move (6, ch$ptr (BUFFER_DESCRIPTOR [$BXSAD,BXSAD],,8),
.CD [CD_KLNI_HRDWADR]);
TMP_PTR = LOAD_DUMP_ASST_MULTICAST;
CD [CD_KLNI_MULTICAST] = ch$eql (6, .TMP_PTR,
6, ch$ptr ( BUFFER_DESCRIPTOR [$BXDAD,BXDAD],,8));
%debug (NETWORK_TRACE,
(if .LENGTH gtr 0
then
begin
local COUNT, PTR, OUTCNT;
TRACE_INFO ('Read MOP data on link %X, %D bytes read',
ch$ptr(CD[CD_NAME],,8),
.LENGTH,
);
TRACE_INFO ('address %6K, multicast: %D',
ch$ptr (BUFFER_DESCRIPTOR [$BXSAD,BXSAD],,8),
.CD [CD_KLNI_MULTICAST]
);
PTR = ch$ptr(.CD[CD_RCV_BID],2,8);
COUNT = .LENGTH;
while .COUNT gtr 0 do
begin
OUTCNT = min (.COUNT, 8);
TRACE_INFO (' %#B', .OUTCNT, .PTR);
PTR = ch$plus (.PTR, 8);
COUNT = .COUNT - 8;
end;
end
else TRACE_INFO ('Read MOP data failure on link %X, after interrupt',
ch$ptr(CD[CD_NAME],,8))));
if not POST_RECEIVE_BUFFER (.CD, .RSP_POINTER) ! Post the buffer again
then return -1;
return .BUFFER_DESCRIPTOR [$BXBSZ,BXBSZ];! And return the msg len
end;
return -1;
end;
%routine ('POST_RECEIVE_BUFFER', CD: ref CD_BLOCK, RSP_POINTER) =
begin
DECLARE_JSYS (NI, GETER);
local
ERROR_CODE,
BUFFER_DESCRIPTOR : BUFFER_DESCRIPTOR_BLOCK,
NI_BLOCK : NI_ARG_BLOCK;
incr I from 0 to $BXBMX-1
do
BUFFER_DESCRIPTOR [.I,FWORD] = 0;
BUFFER_DESCRIPTOR [$BXLEN,FWORD] = $BXBMX;
BUFFER_DESCRIPTOR [$BXNXT,BXNXT] = 0; ! No chain here.
BUFFER_DESCRIPTOR [$BXBSZ,BXBSZ] = MOP_BUFFER_LENGTH; ! Buffer size in bytes
BUFFER_DESCRIPTOR [$BXBFA,BXBFA] = ch$ptr (.CD [CD_RCV_BID],,8);
BUFFER_DESCRIPTOR [$BXBID,BXBID] = .CD [CD_RCV_BID]; ! Receive Buffer Id
incr I from 0 to $EIBMX-1
do
NI_BLOCK[.I,FWORD] = 0;
NI_BLOCK [$EILEN,EILEN] = $EIBMX;
NI_BLOCK [$EIFCN,EIFCN] = $EIRCV;
NI_BLOCK [$EIPID,EIPID] = .CD [CD_KLNI_PRTLID];
NI_BLOCK [$EIFLG,EIFLG] = 0;
NI_BLOCK [$EIBCP,EIBCP] = BUFFER_DESCRIPTOR; !Address of Buffer descriptor
if not $$NI (NI_BLOCK)
then begin
$$GETER($FHSLF; ERROR_CODE);
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Could not post a reveive buffer on %X. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.ERROR_CODE);
CLOSE_KLNI_DEVICE (.CD);
return $false;
end;
return $true;
end;
%routine ('ENABLE_MULTICAST_ADDRESS', CD: ref CD_BLOCK, RSP_POINTER) =
begin
DECLARE_JSYS (NI, GETER);
local
ERROR_CODE,
NI_BLOCK : NI_ARG_BLOCK,
TMP_PTR;
incr I from 0 to $EIBMX-1
do
NI_BLOCK[.I,FWORD] = 0;
TMP_PTR = LOAD_DUMP_ASST_MULTICAST;
NI_BLOCK [$EILEN,EILEN] = $EIBMX;
NI_BLOCK [$EIFCN,EIFCN] = $EIEMA;
NI_BLOCK [$EIFLG,EIFLG] = 0; ! Don't Block
NI_BLOCK [$EIPID,EIPID] = .CD [CD_KLNI_PRTLID]; ! We need the Portal ID
ch$move (6, .TMP_PTR, ch$ptr (NI_BLOCK [$EIAR1,EIAR1],,8));
if not $$NI (NI_BLOCK)
then begin
$$GETER($FHSLF; ERROR_CODE);
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Failure enabling load/dump assistance on %X. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.ERROR_CODE);
return $false;
end;
return $true;
end;
! Local Modes:
! Mode:BLISS
! Auto Save Mode:0
! Comment Column:40
! Comment Rounding:+1
! End: