Trailing-Edge
-
PDP-10 Archives
-
BB-X117B-SB_1986
-
10,7/nml/dtet10.b36
There are no other files named dtet10.b36 in the archive.
!DSKB:DTET10.B36[10,6062,NML] 1985-05-15 08:51:39, Edit by APPELLOF
!
! Complete Davenport's work adding routines to log CHK11
! output to ERROR.SYS.
! Add routines CHK11_TTY_PSI_INTERRUPT,
! OPEN_CHK11_TTY, CLOSE_CHK11_TTY, READ_CHK11_OUTPUT
!
! DSKT:DTET10.B36[10,6026,NML703] 19-Oct-84 14:50:11, Edit by DAVENPORT
!
! Remove calls to NMU$SCHED_PAUSE in routines TRIGGER_ROM and
! ROM_DUMP. NMLDLW and NMLDTL need these to be uninterruptable
! so as to interlock against each other.
!
! DSKT:DTET10.B36[10,6026,NML703] 16-Oct-84 09:37:32, Edit by DAVENPORT
!
! Added code to OPEN_DTE_DEVICE to check for CPU not running and give
! an appropriate error message. Changed START_PROTOCOL to clear the
! DTE before trying to start protocol. Also now tries four times
! before giving up.
!
%sbttl 'TOPS-10 Specific DTE Service Routines'
!
! External routines
!
external routine
NMU$MEMORY_GET,
NMU$MEMORY_RELEASE,
NMU$FILE_BUILD_BUFFERS,
NMU$FILE_KILL_BUFFERS: novalue;
!
! Forward routines
!
forward routine
CHK11_TTY_PSI_INTERRUPT: vanilla_interrupt_linkage novalue,
OPEN_CHK11_TTY: novalue,
CLOSE_CHK11_TTY: novalue,
READ_CHK11_OUTPUT: novalue,
READ_DTE_DATA_BUFFER,
WRITE_DTE_DATA_BUFFER,
DTE_PSI_INTERRUPT: vanilla_interrupt_linkage
novalue;
!
! Macros
!
macro
DTE_ARG_BLOCK = vector [10] volatile %, ! DTE. UUO argument block
FILOP_ARG_BLOCK = vector [10] volatile %, ! FILOP. UUO argument block
PSI_ARG_BLOCK = vector [3] volatile %, ! PISYS. UUO argument block
TRMOP_ARG_BLOCK = vector [2] volatile %; ! TRMOP. UUO argument block
!
! Items in CHK11 (222) entry in ERROR.SYS made by NML through DAEMON
! taken from SPEAR
! In the code, all offsets will be + 2 to account for arguments to
! The DAEMON UUO
LITERAL
NH_MID=%O'0', !TRANSMITTING NODE ID#,, DESTINATION NODE ID#
!contains 0 in NML entry
NH_XID=%O'1', !PNTR TO ASCIZ TRANSMITTING NODE NAME
!contains CIRCUIT_ID in NML entry
NH_RID=%O'2', !PNTR TO ASCIZ Destination NODE NAME
!contains 0 in NML entry
NH_ADN=%O'3', !PNTR TO ASCIZ Adjacent Node Name
!ie, the node at the other end of the line
!contains 0 in NML entry
NH_FUN=%O'4', !FUNCTION WORD AS DESCRIBED BELOW
!contains 0 in NML entry
NH_NUM=%O'5', !RIGHT JUSTIFIED NUMBER OF BYTES IN LOG
!DATA SECTION
NH_SEQ=%O'6', !HARDWARE ENTRY SEQ. NUMBER FROM THE XMIT NODE
!contains 0 in NML entry
NH_LID=%O'7', !CONTROLLER #,,LINE or unit #
!(-1 IS NULL indicating NO LINE or unit IS
!ASSOCIATED WITH THIS ENTRY, 0=single line unit ie. DL11)
NH_LI1=%O'10', !RESERVED,,STATION #
!(WORDS NH_LID %O'',& NH_LI1 %O''ARE USED TO MAKE UP AN
!ASCIZ LINE IDENTIFICATION )
!contains 0 in NML entry
NH_DAT=%O'11', !NODE UPTIME IN MILLISECS. WHEN
!THIS EVENT/ERROR WAS DETECTED.
!contains 0 in NML entry
NH_TRY=%O'12', !FLAGS AND RETRY COUNT
!contains 0 in NML entry
NH_RSM=%O'13', !REASON FOR ENTRY (OCTAL)
!contains 0 in NML entry
NH_PTR=%O'14', !PNTR TO START OF LOG DATA.
NH_LEN = NH_PTR + 1; !Length of entry header
%routine ('GET_DTE_SYSID', CD: ref CD_BLOCK) =
!++
! Function description:
!
! This routine returns the system specific identifier
! for the DTE described by the circuit data block.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
!
! Routine value:
!
! The system identifier for the DTE
!
!--
begin
!
! Create the id from the CPU and DTE numbers
!
.CD [CD_CONTROLLER]^18 + .CD [CD_DEVICE]
end; ! of GET_DTE_SYSID
%routine ('OPEN_DTE_DEVICE', CD: ref CD_BLOCK, RSP_POINTER) =
!++
! Functional description:
!
! This routine is called by NMU$DTE_OPEN to perform
! system specific operations for servicing a DTE.
!
! 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 DTE
!
!--
begin
builtin
UUO;
register
T1;
local
DTE_DEVICE_NAME,
BUFFER_SIZE,
FILOP_BLOCK: FILOP_ARG_BLOCK,
PSI_BLOCK: PSI_ARG_BLOCK;
bind
OBUF = CD [CD_DTE_OBUF]: vector [3],
IBUF = CD [CD_DTE_IBUF]: vector [3];
!
! First check if the DTE's CPU is running
!
T1 = _CCOKP + 2*(.CD [CD_CONTROLLER]);
if not UUO (1, GETTAB (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Unable to obtain CPU status for device %X',
ch$ptr (CD [CD_NAME],,8));
return $false;
end;
if .T1 gtr 0
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'CPU not running for device %X',
ch$ptr (CD [CD_NAME],,8));
return $false;
end;
!
! Create a SIXBIT device name for the specific DTE
!
DTE_DEVICE_NAME = %sixbit 'DTE000' or .CD [CD_CONTROLLER]^6 or .CD [CD_DEVICE];
!
! Open the DTE for I/O
!
FILOP_BLOCK [$FOFNC] = FO$PRV or FO$ASC or $FOSIO;
FILOP_BLOCK [$FOIOS] = UU$AIO or IO$MAI or $IOBYT;
FILOP_BLOCK [$FODEV] = .DTE_DEVICE_NAME;
FILOP_BLOCK [$FOBRH] = OBUF^18 + IBUF;
! T1 = ($FOBRH+1)^18 + FILOP_BLOCK;
!
! if not UUO (1, FILOP$ (T1))
! then
! begin
! $RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
! 'Unable to open %X for I/O. FILOP. error %O',
! ch$ptr (CD [CD_NAME],,8),
! .T1);
! return $false;
! end;
!
! CD [CD_DTE_CHAN] = (.FILOP_BLOCK [$FOFNC] and FO$CHN)^-18;
if not UUO (1, OPEN (1, FILOP_BLOCK [$FOIOS]))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Unable to open %X for I/O',
ch$ptr (CD [CD_NAME],,8));
return $false;
end;
CD [CD_DTE_CHAN] = 1;
!
! Get size of buffers to allocate
!
T1 = FILOP_BLOCK [$FOIOS];
if not UUO (1, DEVSIZ (T1))
then
begin
CLOSE_DTE_DEVICE (.CD);
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Unable to determine %X I/O buffer size',
ch$ptr (CD [CD_NAME],,8));
return $false;
end;
BUFFER_SIZE = .T1 <0,18,0>;
!
! Allocate I/O buffers for DTE device
!
if ((OBUF [$BFADR] = NMU$FILE_BUILD_BUFFERS (1, .BUFFER_SIZE)) eqla 0)
or
((IBUF [$BFADR] = NMU$FILE_BUILD_BUFFERS (1, .BUFFER_SIZE)) eqla 0)
then
begin
CLOSE_DTE_DEVICE (.CD);
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Unable to allocate I/O buffers for %X',
ch$ptr (CD [CD_NAME],,8));
return $false;
end;
!
! Set up for PSI interrupts for this DTE
!
NMU$SCHED_EVENT (CD [CD_DTE_EVB], $true);
CD [CD_DTE_PSI] = ALLOCATE_INTERRUPT_CHANNEL (DTE_PSI_INTERRUPT, .CD);
PSI_BLOCK [$PSECN] = .CD [CD_DTE_CHAN];
PSI_BLOCK [$PSEOR] = (.CD [CD_DTE_PSI]*4)^18 or PS$RID or PS$ROD or PS$RDO;
PSI_BLOCK [$PSEPR] = 0;
T1 = PS$FAC + PSI_BLOCK;
if not UUO (1, PISYS$ (T1))
then
begin
CLOSE_DTE_DEVICE (.CD);
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Unable to enable PSI system for %X',
ch$ptr (CD [CD_NAME],,8));
return $false;
end;
!
! Open CHK11 terminal
!
OPEN_CHK11_TTY (.CD);
$true
end; ! of OPEN_DTE_DEVICE
%routine ('CLOSE_DTE_DEVICE', CD: ref CD_BLOCK) =
!++
! Functional description:
!
! This routine is called by NMU$DTE_CLOSE to perform
! system specific operations for releasing a DTE.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
!
! Routine value:
!
! $true System specific release succeeded
! $false Error releasing DTE
!
!--
begin
builtin
UUO;
register
T1;
local
RETURN_VALUE,
FILOP_BLOCK: FILOP_ARG_BLOCK,
PSI_BLOCK: PSI_ARG_BLOCK;
bind
OBUF = CD [CD_DTE_OBUF]: vector [3],
IBUF = CD [CD_DTE_IBUF]: vector [3];
!
! Release CHK11 terminal and flush output
!
CLOSE_CHK11_TTY (.CD);
!
! Remove DTE from PSI system
!
PSI_BLOCK [$PSECN] = .CD [CD_DTE_CHAN];
PSI_BLOCK [$PSEOR] = (.CD [CD_DTE_PSI]*4)^18 or PS$RID or PS$ROD or PS$RDO;
PSI_BLOCK [$PSEPR] = 0;
T1 = PS$FRC + PSI_BLOCK;
UUO (1, PISYS$ (T1));
RELEASE_INTERRUPT_CHANNEL (.CD [CD_DTE_PSI]);
!
! Close the DTE device
!
FILOP_BLOCK [$FOFNC] = (.CD [CD_DTE_CHAN])^18 or $FOCLS;
! T1 = ($FOFNC+1)^18 + FILOP_BLOCK;
!
! RETURN_VALUE = UUO (1, FILOP$ (T1));
UUO (0, CLOSE (.CD [CD_DTE_CHAN], 0));
UUO (0, RELEAS (.CD [CD_DTE_CHAN], 0));
RETURN_VALUE = $true;
!
! Deallocate I/O buffers
!
if .OBUF [$BFADR] neqa 0
then
NMU$FILE_KILL_BUFFERS (.OBUF [$BFADR]);
if .IBUF [$BFADR] neqa 0
then
NMU$FILE_KILL_BUFFERS (.IBUF [$BFADR]);
OBUF [$BFADR] = 0;
IBUF [$BFADR] = 0;
.RETURN_VALUE
end; ! of CLOSE_DTE_DEVICE
%routine ('START_PROTOCOL', CD: ref CD_BLOCK, RSP_POINTER) =
!++
! Function description:
!
! This routine is used to initialize protocol on a
! DTE circuit.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true Protocol successfully initialized
! $false Error initializing protocol
!
!--
begin
builtin
UUO;
register
T1;
local
DTE_BLOCK: DTE_ARG_BLOCK; ! DTE. UUO argument block
incr COUNT from 1 to 4
do
begin
!
! First see if primary protocol is already running
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
T1 = $DTEGS ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Could not check status on %X. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
if ((.T1 and DT$RLD) eql 0)
and
((.T1 and DT$PPC) neq 0)
then
return $true;
!
! Clear the DTE to a known state
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
T1 = $DTECL ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Could not clear %X. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
!
! Set DTE line user to DECNET
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
DTE_BLOCK [1] = %sixbit 'DECNET';
T1 = $DTESU ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Could not set %X user to DECNET. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
!
! Try to start primary protocol
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
T1 = $DTEST ^ 18 + DTE_BLOCK;
if UUO (1, DTE$ (T1))
then
return $true;
NMU$SCHED_PAUSE ();
end;
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Could not start primary protocol on %X. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
$false
end; ! of START_PROTOCOL
%routine ('STOP_PROTOCOL', CD: ref CD_BLOCK, RSP_POINTER) =
!++
! Function description:
!
! This routine is used to terminate protocol on a
! DTE circuit.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true Protocol successfully terminated
! $false Error clearing protocol
!
!--
begin
builtin
UUO;
register
T1;
local
DTE_BLOCK: DTE_ARG_BLOCK; ! DTE. UUO argument block
!
! Set up argument block with DTE identifier
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
T1 = $DTECL ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_HWF, 0,
'Could not stop protocol on %X. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
$true
end; ! of STOP_PROTOCOL
%routine ('TRIGGER_ROM', CD: ref CD_BLOCK, RSP_POINTER) =
!++
! Function description:
!
! This routine is called to trigger the DN20 boot-
! strap ROM.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true Bootstrap ROM triggered successfully
! $false Error triggering bootstrap ROM
!
!--
begin
builtin
UUO;
register
T1;
local
DTE_BLOCK: DTE_ARG_BLOCK; ! DTE. UUO argument block
!
! Set DTE line user to 'PROGRA' so we can use it
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
DTE_BLOCK [1] = %sixbit 'PROGRA';
T1 = $DTESU ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_HWF, 0,
'Could not set %X user to NML. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
!
! Trigger DN20 ROM for LOAD and DUMP
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
T1 = $DTEPR ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_HWF, 0,
'Could not trigger ROM bootstrap on %X. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
! NMU$SCHED_PAUSE ();
$true
end; ! of TRIGGER_ROM
%routine ('ROM_DUMP', CD: ref CD_BLOCK, DUMP_PAGE, RSP_POINTER) =
!++
! Function description:
!
! This routine is called to dump 2K bytes from the DN20
! using the ROM.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .DUMP_PAGE Page number to store dump data
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true Dump successful
! $false Error during ROM assisted dump
!
!--
begin
builtin
UUO;
register
T1;
literal
MAX_ROM_DUMP_WORDS = %o'200';
local
COUNT,
DUMP_COUNT,
DUMP_POINTER,
DTE_BLOCK: DTE_ARG_BLOCK; ! DTE. UUO argument block
!
! Initialize count of words dumped and dump pointer
!
DUMP_COUNT = 0;
DUMP_POINTER = ch$ptr (.DUMP_PAGE^9,, 16);
!
! Loop until dump page is filled with dump data
!
while .DUMP_COUNT lss (2 * 512)
do
begin
!
! Setup argument block for next transfer of up
! to MAX_ROM_DUMP_WORDS of DN20 memory.
!
COUNT = min ((2*512 - .DUMP_COUNT), MAX_ROM_DUMP_WORDS);
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
DTE_BLOCK [1] = .DUMP_POINTER;
DTE_BLOCK [2] = .COUNT;
!
! Read dump data, assisted by primary boot ROM in DN20
!
T1 = $DTEDM ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_HWF, 0,
'ROM assisted dump failed on %X. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
! NMU$SCHED_PAUSE ();
!
! Update dump count and pointer
!
DUMP_COUNT = .DUMP_COUNT + .COUNT;
DUMP_POINTER = ch$plus (.DUMP_POINTER, .COUNT);
end;
$true
end; ! of ROM_DUMP
%routine ('READ_MOP_DATA', CD: ref CD_BLOCK, PTR, LEN, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$DTE_READ to read a MOP data
! messages from a DN20 front end.
!
! 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 (-1 if error)
!
!--
begin
bind
IBUF = CD [CD_DTE_IBUF]: vector [3] volatile;
if .IBUF [$BFCTR] eql 0
then
if not READ_DTE_DATA_BUFFER (.CD, .RSP_POINTER)
then
return $false;
NMU$SCHED_PAUSE ();
LEN = min (.IBUF [$BFCTR], .LEN);
decr COUNT from .LEN to 0
do
ch$wchar_a (ch$rchar_a (IBUF [$BFPTR]), PTR);
IBUF [$BFCTR] = .IBUF [$BFCTR] - .LEN;
.LEN
end; ! of READ_MOP_DATA
%routine ('READ_DTE_DATA_BUFFER', CD: ref CD_BLOCK, RSP_POINTER) =
!++
! Functional description:
!
! This routine is called by READ_MOP_DATA to read the
! next buffer of data from the DTE device.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true If successful
! $false If I/O error or timeout
!
!--
begin
builtin
UUO;
register
T1;
local
FILOP_BLOCK: FILOP_ARG_BLOCK;
while not
begin
FILOP_BLOCK [$FOFNC] = (.CD [CD_DTE_CHAN])^18 or $FOINP;
T1 = ($FOFNC+1)^18 + FILOP_BLOCK;
UUO (1, FILOP$ (T1))
end
do
begin
if (.T1 and IO$ERR) neq 0
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'I/O error reading %X MOP data. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
if not NMU$SCHED_WAIT (CD [CD_DTE_EVB], 120)
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Timeout reading %X MOP data',
ch$ptr (CD [CD_NAME],,8));
return $false;
end;
end;
$true
end; ! of READ_DTE_DATA_BUFFER
%routine ('WRITE_MOP_DATA', CD: ref CD_BLOCK, PTR, LEN, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$DTE_WRITE to send MOP data
! messages to a DN20 front end.
!
! 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
bind
OBUF = CD [CD_DTE_OBUF]: vector [3] volatile;
decr COUNT from .LEN to 1
do
begin
if .OBUF [$BFCTR] eql 0
then
if not WRITE_DTE_DATA_BUFFER (.CD, .RSP_POINTER)
then
return $false;
OBUF [$BFCTR] = .OBUF [$BFCTR] - 1;
ch$wchar_a (ch$rchar_a (PTR), OBUF [$BFPTR]);
end;
if not WRITE_DTE_DATA_BUFFER (.CD, .RSP_POINTER)
then
return $false;
$true
end; ! of WRITE_MOP_DATA
%routine ('WRITE_DTE_DATA_BUFFER', CD: ref CD_BLOCK, RSP_POINTER) =
!++
! Functional description:
!
! This routine is called by WRITE_MOP_DATA to write the
! next buffer of data to the DTE device.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true If successful
! $false If I/O error or timeout
!
!--
begin
builtin
UUO;
register
T1;
local
FILOP_BLOCK: FILOP_ARG_BLOCK;
while not
begin
FILOP_BLOCK [$FOFNC] = (.CD [CD_DTE_CHAN])^18 or $FOOUT;
T1 = ($FOFNC+1)^18 + FILOP_BLOCK;
UUO (1, FILOP$ (T1))
end
do
begin
if (.T1 and IO$ERR) neq 0
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'I/O error writing %X MOP data. Status = %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
if not NMU$SCHED_WAIT (CD [CD_DTE_EVB], 600)
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Timeout writing %X MOP data',
ch$ptr (CD [CD_NAME],,8));
return $false;
end;
end;
$true
end; ! of WRITE_DTE_DATA_BUFFER
%routine ('WRITE_SECONDARY_DATA', CD: ref CD_BLOCK, PTR, LEN, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$DTE_WRITE to load the second-
! ary bootstrap loader into a DN20 front end.
!
! 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
builtin
UUO;
register
T1;
local
LOADER_PAGE,
LOADER_POINTER,
MOP_POINTER,
DTE_BLOCK: DTE_ARG_BLOCK;
LOADER_PAGE = NMU$PAGE_GET ();
LOADER_POINTER = ch$ptr (.LOADER_PAGE^9,,16);
MOP_POINTER = ch$plus (.PTR, 6);
incr COUNT from 1 to (.LEN-8) by 2
do
ch$wchar_a (GETW (MOP_POINTER), LOADER_POINTER);
!
! Set up the DTE. UUO argument block
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
DTE_BLOCK [1] = ch$ptr (.LOADER_PAGE^9,,16);
DTE_BLOCK [2] = 256;
T1 = $DTELS ^ 18 + DTE_BLOCK;
!
! Load the secondary bootstrap into the DN20
!
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Failure loading secondary boot on %X. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
NMU$PAGE_RELEASE (.LOADER_PAGE);
return $false;
end;
NMU$PAGE_RELEASE (.LOADER_PAGE);
NMU$SCHED_PAUSE ();
$true
end; ! of WRITE_SECONDARY_DATA
%routine ('OWNER_IS_DECNET', CD: ref CD_BLOCK, RSP_POINTER) =
!++
! Functional description:
!
! This routine is used by NMU$DTE_OPEN is insure that the
! current user of a DTE is either DECNET or NML. This is
! to guarantee that NML doesn't interfere with ANF10 DTEs
! or DTEs currently running diagnostics.
!
! Formal parameters:
!
! .CD Pointer to circuit data block
! .RSP_POINTER Pointer to NICE response buffer
!
! Routine value:
!
! $true If DTE owner is DECNET or NML
! $false If DTE owner isn't DECNET or NML
!
!--
begin
builtin
UUO;
register
T1;
local
DTE_BLOCK: DTE_ARG_BLOCK;
!
! Set up argument block with DTE identifier
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
T1 = $DTERU ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
begin
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'Could not read %X line user. DTE. error %O',
ch$ptr (CD [CD_NAME],,8),
.T1);
return $false;
end;
!
! Return now if line user is DECNET or if line
! currently not in use
!
if (.DTE_BLOCK [1] eql %sixbit 'DECNET')
or
(.DTE_BLOCK [1] eql %sixbit 'NOBODY')
then
return $true;
!
! Last chance is line owner of NML
!
UUO (0, PJOB (T1));
if (.DTE_BLOCK [1] eql %sixbit 'PROGRA')
and
(.DTE_BLOCK [2] eql .T1)
then
return $true;
!
! Give reasonable explanation of problem
!
if .DTE_BLOCK [1] eql %sixbit 'PROGRA'
then
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'%X is in use by job %D',
ch$ptr (CD [CD_NAME],,8),
.DTE_BLOCK [2])
else
$RESPONSE (.RSP_POINTER, NICE$_OPF, 0,
'%X is in use by a protocol other than DECNET',
ch$ptr (CD [CD_NAME],,8));
$false
end; ! of OWNER_IS_DECNET
%routine ('DTE_PSI_INTERRUPT', CD: ref CD_BLOCK): vanilla_interrupt_linkage novalue =
!++
! Functional description:
!
! Routine called upon a DTE input/output done interrupt.
!
!--
begin
NMU$SCHED_FLAG (CD [CD_DTE_EVB])
end; ! of DTE_PSI_INTERRUPT
%routine ('OPEN_CHK11_TTY', CD: ref CD_BLOCK): novalue =
!++
! Functional description:
!
! Routine called when DTE device is opened to open the CHK11
! terminal so that CHK11 output can be logged.
!
!--
begin
builtin
UUO;
register
T1;
local
BUFFER_SIZE,
DTE_BLOCK: DTE_ARG_BLOCK,
FILOP_BLOCK: FILOP_ARG_BLOCK,
TRMOP_BLOCK: TRMOP_ARG_BLOCK,
PSI_BLOCK: PSI_ARG_BLOCK;
bind
IBUF = CD [CD_DTE_CHK11_IBUF]: vector [3];
CD [CD_DTE_CHK11_CHAN] = 0;
!
! Set up argument block with DTE identifier
!
DTE_BLOCK [0] = .CD [CD_DTE_SYSID];
T1 = $DTEDT ^ 18 + DTE_BLOCK;
if not UUO (1, DTE$ (T1))
then
return $false;
CD [CD_DTE_CHK11_TTY] = .T1;
!
! Open the CHK11 terminal for I/O
!
FILOP_BLOCK [$FOFNC] = FO$PRV or FO$ASC or $FORED;
FILOP_BLOCK [$FOIOS] = UU$AIO or IO$SUP or $IOASL;
FILOP_BLOCK [$FODEV] = .CD [CD_DTE_CHK11_TTY];
FILOP_BLOCK [$FOBRH] = IBUF;
T1 = ($FOBRH+1)^18 + FILOP_BLOCK;
if not UUO (1, FILOP$ (T1))
then
return $false;
CD [CD_DTE_CHK11_CHAN] = (.FILOP_BLOCK [$FOFNC] and FO$CHN)^-18;
!
! Get size of buffers to allocate
!
T1 = FILOP_BLOCK [$FOIOS];
if not UUO (1, DEVSIZ (T1))
then
begin
CLOSE_CHK11_TTY (.CD);
return $false;
end;
BUFFER_SIZE = .T1 <0,18,0>;
!
! Allocate I/O buffers for CHK11 terminal
!
if (IBUF [$BFADR] = NMU$FILE_BUILD_BUFFERS (1, .BUFFER_SIZE)) eqla 0
then
begin
CLOSE_CHK11_TTY (.CD);
return $false;
end;
!
! Set up terminal TTY NO DEFER
!
TRMOP_BLOCK [0] = $TOSET + $TODEM;
TRMOP_BLOCK [1] = .CD [CD_DTE_CHK11_TTY];
TRMOP_BLOCK [2] = 0;
T1 = 3 ^ 18 + TRMOP_BLOCK;
UUO (1, TRMOP$ (T1));
!
! Allocate memory for CHK11 buffer
!
if (CD [CD_DTE_CHK11_BUF_ADDR] = NMU$MEMORY_GET (500)) eqla 0
then
begin
CLOSE_CHK11_TTY (.CD);
return $false;
end;
begin
bind
DAEMON_BUFFER = .CD [CD_DTE_CHK11_BUF_ADDR]: vector [500];
CD [CD_DTE_CHK11_BUF_CTR] = (500-(2+NH_LEN))*5; !NH_LEN words for daemon header
CD [CD_DTE_CHK11_BUF_PTR] = ch$ptr (DAEMON_BUFFER [2+NH_LEN+4],,7);
incr I from 0 to 14 do DAEMON_BUFFER [.I] = 0;
DAEMON_BUFFER[0] = $DMERR; !Set up DAEMON Function code for later
DAEMON_BUFFER [1] = %o'222'; !check11 code
ch$move(ch$rchar(ch$ptr(CD[CD_NAME],,8)),
ch$ptr(CD[CD_NAME],1,8),ch$ptr(DAEMON_BUFFER[2+NH_LEN],,7));
DAEMON_BUFFER [2 + NH_XID] = NH_LEN; !Insert offset to circuit name
DAEMON_BUFFER [2 + NH_LID] = .CD [CD_DTE_SYSID]; !cpu,,dte#
DAEMON_BUFFER [2 + NH_PTR] = NH_LEN+4; !offset to log data
end;
!
! Set up for PSI interrupts for this terminal
!
CD [CD_DTE_CHK11_PSI] = ALLOCATE_INTERRUPT_CHANNEL (CHK11_TTY_PSI_INTERRUPT, .CD);
PSI_BLOCK [$PSECN] = .CD [CD_DTE_CHK11_CHAN];
PSI_BLOCK [$PSEOR] = (.CD [CD_DTE_CHK11_PSI]*4)^18 or PS$RID or PS$ROD or PS$RDO;
PSI_BLOCK [$PSEPR] = 0;
T1 = PS$FAC + PSI_BLOCK;
if not UUO (1, PISYS$ (T1))
then
begin
CLOSE_CHK11_TTY (.CD);
return $false;
end;
end; ! of OPEN_CHK11_TTY
%routine ('CLOSE_CHK11_TTY', CD: ref CD_BLOCK): novalue =
!++
! Functional description:
!
! Routine called when DTE device is closed to close the CHK11
! terminal and log its output to the system error file.
!
!--
begin
builtin
UUO;
register
T1;
local
FILOP_BLOCK: FILOP_ARG_BLOCK,
PSI_BLOCK: PSI_ARG_BLOCK;
bind
IBUF = CD [CD_DTE_CHK11_IBUF]: vector [3],
DAEMON_BUFFER = .CD [CD_DTE_CHK11_BUF_ADDR]: vector [500];
!
! If CHK11 terminal not open, just return
!
if .CD [CD_DTE_CHK11_CHAN] eql 0
then
return;
!
! Remove CHK11 terminal from PSI system
!
PSI_BLOCK [$PSECN] = .CD [CD_DTE_CHK11_CHAN];
PSI_BLOCK [$PSEOR] = (.CD [CD_DTE_CHK11_PSI]*4)^18 or PS$RID or PS$ROD or PS$RDO;
PSI_BLOCK [$PSEPR] = 0;
T1 = PS$FRC + PSI_BLOCK;
UUO (1, PISYS$ (T1));
RELEASE_INTERRUPT_CHANNEL (.CD [CD_DTE_CHK11_PSI]);
!
! Flush any CHK11 terminal output
!
READ_CHK11_OUTPUT (.CD);
!
! Close the CHK11 terminal
!
FILOP_BLOCK [$FOFNC] = (.CD [CD_DTE_CHK11_CHAN])^18 or $FOREL;
T1 = ($FOFNC+1)^18 + FILOP_BLOCK;
UUO (1, FILOP$ (T1));
if .IBUF [$BFADR] neqa 0
then
NMU$FILE_KILL_BUFFERS (.IBUF [$BFADR]);
IBUF [$BFADR] = 0;
if DAEMON_BUFFER neqa 0
then
begin
!
! Log accumulated CHK11 output to error file
!
T1 = ((.(DAEMON_BUFFER [2 + NH_NUM]) + 4)/5); !Calculate # words in CHK11 log
if .T1 gtr 0
then
begin
!
! Total length of arg block is
!(# of words)+(length of entry header)+(2 daemon args)+(4 wd circuit id)
!
T1 = (.T1 + NH_LEN + 2 + 4 )^18 + DAEMON_BUFFER;
UUO (1, DAEMON (T1));
end;
!
! Deallocate CHK11 buffer
!
NMU$MEMORY_RELEASE (DAEMON_BUFFER, 500);
CD [CD_DTE_CHK11_BUF_ADDR] = 0;
end;
end; ! of CLOSE_CHK11_TTY
%routine ('READ_CHK11_OUTPUT', CD: ref CD_BLOCK): novalue =
!++
! Functional description:
!
! Routine called upon CHK11 terminal PSI interrupt to read
! CHK11 output data into CHK11 buffer.
!
!--
begin
builtin
UUO;
register
T1;
local
COUNT,
CHAR,
FILOP_BLOCK: FILOP_ARG_BLOCK;
bind
IBUF = CD [CD_DTE_CHK11_IBUF]: vector [3] volatile,
DAEMON_BUFFER = .CD [CD_DTE_CHK11_BUF_ADDR]: vector [500];
!
! Loop while CHK11 output is available
!
while
begin
FILOP_BLOCK [$FOFNC] = (.CD [CD_DTE_CHK11_CHAN])^18 or $FOINP;
T1 = ($FOFNC+1)^18 + FILOP_BLOCK;
UUO (1, FILOP$ (T1))
end
do
begin
!
! Copy any characters read into CHK11 buffer
!
COUNT = .CD [CD_DTE_CHK11_BUF_CTR] - 1;
if .COUNT gtr .IBUF [$BFCTR]
then
COUNT = .IBUF [$BFCTR];
incr I from 1 to .COUNT
do
begin
CHAR = ch$rchar_a (IBUF [$BFPTR]);
if .CHAR neq 0 then
begin
DAEMON_BUFFER [2 + NH_NUM] = .DAEMON_BUFFER [2 + NH_NUM] + 1;
ch$wchar_a (.CHAR, CD [CD_DTE_CHK11_BUF_PTR]);
end
end
end;
end; ! of READ_CHK11_OUTPUT
%routine ('CHK11_TTY_PSI_INTERRUPT', CD: ref CD_BLOCK): vanilla_interrupt_linkage novalue =
!++
! Functional description:
!
! Routine called upon CHK11 terminal PSI interrupt to read any
! CHK11 output text.
!
!--
begin
READ_CHK11_OUTPUT (.CD);
end; ! of CHK11_TTY_PSI_INTERRUPT