Google
 

Trailing-Edge - PDP-10 Archives - BB-P363B-SM_1985 - mcb/nml/nmldtl.bli
There are 2 other files named nmldtl.bli in the archive. Click here to see a list.
! RATS:<BANKS.MCB.NMLMCB>NMLDTL.BLI.2 30-Oct-84 08:41:05, Edit by BANKS
!
! Ident 52.
!  Re-enable acceptance of the following parameters for dump:
!   135   Dump Address
!   136   Dump Count
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.3 30-Aug-82 10:17:57, Edit by PECKHAM
!
! Ident 51.
!  Disable acceptance of following parameters for load/dump:
!   126   Software Identification
!   135   Dump Address
!   136   Dump Count
!
! <BRANDT.DEVELOPMENT>NMLDTL.BLI.1 27-Aug-82 10:20:22, Edit by BRANDT
!
!   Ident 50.
!    In routine DUMP_NODE, make secondary dumper optional.  Therefore,
!    if none is specified, a secondary dumper will not be required.
!    The DN200 does not require a secondary dumper.
!
! <BRANDT.DEVELOPMENT>NMLDTL.BLI.1 25-Aug-82 11:20:36, Edit by BRANDT
!
!   Ident 49.
!    In routine DUMP_NODE, change CASE statement so that it has an
!    OUTRANGE branch to prevent an infinite loop in case of error.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.2 27-Jun-82 01:20:36, Edit by PECKHAM
!
! Ident 48.
! Should not have used NML$GET_PARAMETER to place substate directly into
! the parameter block, as it overwrote the full word.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.2 26-Jun-82 17:03:33, Edit by PECKHAM
!
! Ident 47.
! Allow service operations with substate FAILED in CIRCUIT_OPEN.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.2 23-Jun-82 11:32:56, Edit by PECKHAM
!
! Ident 46.
! Check RB_PRV_* bits in request block before performing requests.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.4 21-Jun-82 22:06:08, Edit by PECKHAM
!
! Ident 45.
! Handle the MOP prompt message (ENTER MOP MODE) as a one byte message.
! This conforms to the VMS/RSX agreed-upon protocol.
! Change MOP buffer size from 512 to 522 to accomodate 512 data bytes
! plus MOP protocol overhead (bug found by DON BRANDT).
! Add support for SERVICE DEVICE checking during load/dump.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.SOURCES>NMLDTL.BLI.34 28-May-82 21:48:00, Edit by PECKHAM
!
! Ident 44.
! Enable the NML$TRIGGER function.
! The TRIGGER_NODE routine does produce the right message.
! At some later point, TRIGGER_NODE should be used from LOAD_NODE
! and DUMP_NODE as per the NM spec.
! Condition out for $TOPS20.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.7 26-May-82 12:14:52, Edit by PECKHAM
!
! Ident 43.
! The FETCH_PARAMETERS routine was reading the HOST parameter onto
! the stack and passing the stack address back to the caller!
! Change LB_HOST to be a NODE_ID_BLOCK instead of pointer to one.
! Change FETCH_PARAMETERS to store into this block.
! Change IMAGE_LOAD to fill in missing data and use this block.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.15 21-May-82 18:28:51, Edit by PECKHAM
!
! Ident 42.
! Attack problems of service function interlocks and link state maintenance.
! This involves changes in CIRCUIT_OPEN to verify the circuit
! STATE / SERVICE / SUBSTATE for permission and set SUBSTATE,
! and changes to CIRCUIT_CLOSE to reset SUBSTATE.
! Move link initialization to CIRCUIT_CLOSE and initialize only if STATE ON.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.6 28-Apr-82 13:47:31, Edit by PECKHAM
!
! Ident 41.
! Change NMU$DLX_* routine references to $NMU_DLX_* macro references.
! Add receive timeout values where needed.
! Make sure all $NMU_DLX_WRITE function requests expect a $true/$false return.
! Check status of NMU$FILE_WRITE.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.3 28-Apr-82 10:31:26, Edit by PECKHAM
!
! Ident 40.
! FETCH_PARAMETERS should not put NICE$_SUC in the response buffer.
! DTL_SETUP sould not clear the response buffer before allocating it.
! Check SERVICE parameter for ENABLED before allowing circuit activity
! in DLX_OPEN.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.2 27-Apr-82 14:13:45, Edit by PECKHAM
!
! Ident 39.
! De-support TRIGGER function.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.3  2-Mar-82 11:57:52, Edit by PECKHAM
! NET:<DECNET20-V3P1.BASELEVEL-2.SOURCES>NMLDTL.BLI.24  1-Mar-82 17:23:28, Edit by WEBBER
!
! Ident 38.
! Fix DUMP_NODE and IMAGE_LOAD to retransmit on timeout.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.2 25-Feb-82 12:54:29, Edit by PECKHAM
!
! Ident 37.
! Fix success return length in DTL_CLEANUP.
! General handling of NMU$MEMORY_GET failures.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.2 25-Feb-82 08:46:47, Edit by PECKHAM
!
! Ident 36.
! Fix LOAD_NODE to report missing SECONDARY LOADER correctly.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.7 24-Feb-82 17:31:50, Edit by PECKHAM
!
! Ident 35.
! Initialize return code of response buffer to 0 in DTL_SETUP.
! Add DTL_CLEANUP which returns service buffer and sets up response message.
! Call this from NML$DUMP, NML$LOAD and NML$TRIGGER.
!
! NET:<PECKHAM.DEVELOPMENT>NMLDTL.BLI.4 23-Feb-82 08:35:48, Edit by PECKHAM
!
! Ident 34.
! Avoid creating pointers using SB_RESPONSE_PTR - screws up responses.
!
! NET:<DECNET20-V3P0.XPT>NMLDTL.BLI.36 20-Jan-82 19:54:18, Edit by WEBBER
!
! Ident 33.
! Change the name MEMSIZE to something else; it's now a macro name.
!
! NET:<DECNET20-V3P0.XPT>NMLDTL.BLI.34 14-Jan-82 13:24:19, Edit by WEBBER
!
! Ident 32.
! Fix numerous load & dump bugs.  E.g., pass a response pointer to
! NMU$FILE_CLOSE.
!
! NET:<DECNET20-V3P0.XPT>NMLDTL.BLI.28 10-Dec-81 10:26:10, Edit by WEBBER
!
! Ident 31.
! Fix numerous load bugs.
! Fix DUMP_NODE to add a DUMPER_READY state, which performs the functions
! that DUMPER_RUNNING used to.  The DUMPER_RUNNING state now is used to
! read the MOP MODE RUNNING message right after the secondary dumper is
! loaded.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NMLDTL.BLI.94 11-Nov-81 14:50:35, Edit by WEBBER
!
! Ident 30.		Lee Webber, 11-Nov-81
! Take common setup code out of NML$LOAD, DUMP and TRIGGER and put it into
! a separate routine DTL_SETUP.  Call the setup routine from the three main
! routines.
! Modifications to the SERVICE_DATA_BLOCK and REQUEST_BLOCK structures (the
! latter only has some fields renamed).
!
! Ident 29.
! Fill in TRIGGER_NODE routine.
! Rewrite all routines so that parameter defaulting and missing parameters
! are handled at the low level service routines.
! Add new FILE_DATA_BLOCK structure for file handling.
! Rename READ_PARAMETERS to FILE_READ_LABEL.  Add FILE_OPEN and FILE_CLOSE.
! TRANSFER_IMAGE integrated into IMAGE_LOAD.
! Re-organize data bases to support this and make names correspond to
! NCP parameter names.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NMLDTL.BLI.16 19-Oct-81 08:05:37, Edit by PECKHAM
!
! Ident 28.
! Rewrite DUMP_NODE routine to avoid loading secondary dumper
! unless needed.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NMLDTL.BLI.8 13-Oct-81 20:44:47, Edit by PECKHAM
!
! Ident 27.
! Fix IMAGE_LOAD computation in READ_PARAMETERS to use %asli32.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NMLDTL.BLI.7  9-Oct-81 14:35:11, Edit by GUNN
!
! Ident 26.
! Fix IMAGE_LOAD to only build target and host node id's in PARAMETER LOAD
! message if available in load data block.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.MCB>NMLDTL.BLI.6 20-Aug-81 10:21:36, Edit by GUNN
!
! Ident 25.
! Fix code in LOAD_NODE to handle receipt of DECnet-10/20 System Specific
! MOP ASCII Text Message returned by TERDMC.SYS the tertiary loader for
! the DMC device. This message contains the output produced by CHK11.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.SOURCES>NMLDTL.BLI.14 18-Aug-81 20:11:00, Edit by GUNN
!
! Ident 24.
! Change calls to 32 bit manipulation macros to conform to
! the new consistent definitions.
! Fix TRANSFER_IMAGE, and  SECONDARY_LOAD to build response message 
! if call to NMU$FILE_READ returns zero bytes.
! Fix up text of some of the NICE response messages.
!
! NET:<DECNET20-V3P1.BASELEVEL-2.SOURCES>NMLDTL.BLI.11 12-Aug-81 14:27:38, Edit by JENNESS
!
! Ident 23.
! Fix Parameters and Transfer message to put in parameter code 4 (instead of
! 2) for the host node number.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.4  8-Aug-81 11:56:37, Edit by GUNN
!
! Ident 22.
! Add error codes in response message for MCB environment.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.10  5-Aug-81 18:52:45, Edit by GUNN
!
! Ident 21.
! Add code to map HOST node id to both address and name in NML$LOAD.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.5 30-Jul-81 09:34:06, Edit by JENNESS
!
! Ident 20.
! Fix SECONDARY_LOAD to output the correct detail if the file access
! to the secondary dumper fails (instead of secondary loader detail all
! the time).
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.5 30-Jul-81 09:32:54, Edit by JENNESS
!
! Ident 19.
! Fix DUMP_NODE to open image dump file after closing secondary dumper.
! Only one file link (FAL/DAP) has to be open at a time to do a dump.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.3 29-Jul-81 09:45:36, Edit by GUNN
!
! Ident 18.
! Fix NML$TRIGGER to return a value from RTN_COD.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.2 29-Jul-81 08:08:33, Edit by GUNN
!
! Ident 17.
! Increased response buffer allocation to 256 characters to handle long
! text created by addition of JSYS error output in NMUDLX.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.4 30-Jun-81 11:48:39, Edit by JENNESS
!
! Ident 16.
! Fix NML$DUMP and NML$LOAD to set the ENTITY_PTR if a LOAD VIA circuit
! command is being processed.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.2 18-Jun-81 15:46:06, Edit by GUNN
!
! Ident 15.
! Change use of DLX_TRANSFER in IMAGE_LOAD to DLX_DATA in call to
! NMU$DLX_WRITE.
!
! NET:<DECNET20-V3P1.NMU>NMLDTL.BLI.46  1-Jun-81 08:18:13, Edit by JENNESS
!
! Insert the NML$DUMP and NML$TRIGGER routines.
!
! NET:<DECNET20-V3P1.NMU>NMLDTL.BLI.12 28-May-81 14:12:06, Edit by JENNESS
!
! Move LOAD_DATA_BLOCK, DUMP_DATA_BLOCK and TRIGGER_DATA_BLOCK into
! this module from NMLCOM.REQ.  Finish in DUMP_NODE routine.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.93 17-Apr-81 09:49:48, Edit by JENNESS
!
! Fill in READ_PARAMETERS routine.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.86 13-Apr-81 20:57:48, Edit by GUNN
!
! Save and restore real entity type in RB_NICE_ENTITY_TYPE across calls
! to GET_NEXT_PARAMETER.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.85 10-Apr-81 16:43:38, Edit by GUNN
!
! Don't try to map the HOST node id. Use just as given.
! Move initialization of LB_RESPONSE_PTR to beginning of NML$LOAD routine.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.83 10-Apr-81 16:10:42, Edit by GUNN
!
! Fix call to macro PUTB in NML$LOAD to use value not address as PUTW does.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.80 10-Apr-81 13:43:17, Edit by GUNN
!
! Call NML$REQUEST_FINISH on success.
! Use $RESPONSE macro in NML$LOAD to build error repsonses.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.76 10-Apr-81 08:58:50, Edit by JENNESS
!
! On return from LOAD_NODE, make sure the RB_RESPONSE_LENGTH field is
! set correctly.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.74  9-Apr-81 18:14:50, Edit by GUNN
!
! Steve changed formal REQ definition in NML$LOAD to be 'ref'.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.70  8-Apr-81 18:30:04, Edit by GUNN
!
! Fixed? various compile errors in LOAD_NODE code.
! Declared LB within context of block that calls LOAD_NODE.
! Added local LOAD_ADDRESS variable in routine TRANSFER_IMAGE.
! Deleted local variable FILE_ID in routine SECONDARY_LOAD.
! Added a dummy routine for READ_PARAMETERS.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.67  8-Apr-81 16:56:32, Edit by GUNN
!
! Change code which handles ADDRESS and NAME parameters to work
! properly.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.21  8-Apr-81 11:02:16, Edit by JENNESS
!
! Fill in LOAD_NODE routine.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.19  7-Apr-81 15:02:06, Edit by GUNN
!
! Fix bind of load block.
! Add code to allocate NICE response buffer in RB.
!
! NET:<DECNET20-V3P1.NML>NMLDTL.BLI.11  2-Apr-81 20:40:20, Edit by GUNN
!
! Add some common code to NML$DUMP and NML$TRIGGER.
! Add code to get parameters from volatile data base for NML$LOAD.
! Add low level function routine interface calls
! to do DUMP, TRIGGER, and LOAD.
! Add skeleton routines for LOAD_NODE, DUMP_NODE, and TRIGGER_NODE.
!
! Update copyright date.
!
module NMLDTL	(
		ident = 'X03.52'
		) =
begin

!
!                    COPYRIGHT (c) 1980, 1981, 1982, 1985
!                    DIGITAL EQUIPMENT CORPORATION
!                        Maynard, Massachusetts
!
!     This software is furnished under a license and may  be  used
!     and copied only in accordance with the terms of such license
!     and with the inclusion of the above copyright notice.   This
!     software  or any other copies thereof may not be provided or
!     otherwise made available to any other person.  No  title  to
!     and ownership of the software is hereby transferred.
!
!     The information  in  this  software  is  subject  to  change
!     without  notice  and should not be construed as a commitment
!     by DIGITAL EQUIPMENT CORPORATION.
!
!     DIGITAL assumes no responsibility for the use or reliability
!     of  its  software  on  equipment  which  is  not supplied by
!     DIGITAL.
!

!++
! FACILITY:	DECnet-10/20 V3.0 Network Management Layer (NML)
!
! ABSTRACT:
!
!	Performs remote node dump, trigger boot, and load.
!
! ENVIRONMENT:	TOPS-10/20 & MCB/RSX11 User mode under NML
!
! AUTHOR: Dale C. Gunn & Steven Jenness , CREATION DATE: 12-Nov-80
!
! MODIFIED BY:
!
!	, : VERSION
! 01	-
!--
!
! INCLUDE FILES:
!

library 'NMLLIB';                       ! All required definitions

require 'NMLEXT';                       ! External routine declarations

!
! TABLE OF CONTENTS
!

%if %bliss (bliss16)
%then linkage NML_LKG_DB = jsr (register = 5);
%else macro NML_LKG_DB = bliss36c %;
%fi

forward routine
        NML$DUMP,
        NML$LOAD,
        NML$TRIGGER,
        DTL_SETUP,
        DTL_CLEANUP,
        CIRCUIT_CLOSE : NML_LKG_DB,
        CIRCUIT_OPEN : NML_LKG_DB,
        CIRCUIT_PROMPT : NML_LKG_DB,
        CPU_IS_PDP11 : NML_LKG_DB,
        DUMP_NODE : NML_LKG_DB,
        FETCH_PARAMETERS,
        FILE_CLOSE : NML_LKG_DB,
        FILE_OPEN : NML_LKG_DB,
        FILE_READ_LABEL : NML_LKG_DB,
        GET_NEXT_PARAMETER,
        IMAGE_LOAD : NML_LKG_DB,
        LOAD_NODE : NML_LKG_DB novalue,
        SECONDARY_LOAD : NML_LKG_DB,
        SET_SUBSTATE : NML_LKG_DB novalue,
        TRIGGER_NODE : NML_LKG_DB;


!
! LOAD, DUMP & TRIGGER data block structure definitions
!
$show (fields) $show (literals)

$field
      SERVICE_DATA_FIELDS =
      set

! Common data for LOAD, DUMP and TRIGGER

      SB_CIRCUIT_HANDLE = [$integer],      ! Link handle for circuit
      SB_RESPONSE_PTR = [$pointer],        ! Pointer to response buffer
      SB_BUFFER = [$address],      	   ! Address of MOP buffer
      SB_BUFFER_PTR = [$pointer],          ! Pointer to MOP buffer
      SB_NODE_DATA = [$pointer],           ! Pointer to node entity ID
      SB_SERVICE_CIRCUIT = [$pointer],     ! 110 Pointer to service circuit-id
      SB_SERVICE_PASSWORD = [$pointer],    ! 111 Pointer to hexadecimal passwd
      LB_LOAD_FILE = [$pointer],           ! 120 Pointer to system image
      LB_SECONDARY_LOADER = [$pointer],    ! 121 Pointer to secondary loader
      LB_TERTIARY_LOADER = [$pointer],     ! 122 Pointer to tertiary loader
      LB_SOFTWARE_IDENTIFICATION = [$pointer], ! 126 Pointer to id string
      DB_DUMP_FILE = [$pointer],           ! 130 Pointer to dump image file 
      DB_SECONDARY_DUMPER = [$pointer],    ! 131 Pointer to secondary dumper
      LB_NAME = [$pointer],                ! 500 Pointer to node name block
      LB_ADDRESS = [$pointer],             ! 502 Pointer to node address block
      DB_DUMP_ADDRESS = [$bytes(4)],       ! 135 4 byte dump address
      DB_DUMP_COUNT = [$bytes(4)],         ! 136 4 byte dump count
      LB_HOST = [$bytes (NODE_ID_BUFFER_LENGTH)],
                                           ! 140 HOST node id block
      LB_SERVICE_DEVICE = [$tiny_integer], ! 112 Device type
      LB_CPU = [$tiny_integer],            ! 113 CPU type
      LB_SOFTWARE_TYPE = [$tiny_integer],  ! 125 Software type
      SB_USAGE = [$tiny_integer],          ! Function being performed
      SB_SUBSTATE = [$tiny_integer],       ! Current substate
      SB_AUTOSERVICE = [$bit]              ! True if auto-service
      tes;

literal
       SERVICE_DATA_BLOCK_SIZE = $field_set_size,
       SERVICE_DATA_BLOCK_ALLOCATION = $field_set_units ;

macro
     SERVICE_DATA_BLOCK = block [SERVICE_DATA_BLOCK_SIZE]
                       field (SERVICE_DATA_FIELDS) %;

! End of service structure definition

!%( *** TEMPORARY - until NMLLIB is modified			!***
macro RB_DTL_DATA = RB_LOAD_DATA%;				!***
macro RB_DTL_DATA_ALLOCATION = RB_LOAD_DATA_ALLOCATION%;	!***


!
! File handling structure definition
!

$field
      FILE_DATA_FIELDS =
      set
      FB_FILE_HANDLE = [$integer],
      FB_RESPONSE_PTR = [$pointer],
      FB_FILE = [$pointer],
      FB_CURRENT_ADDRESS = [$bytes (4)],
      FB_BYTES_LEFT = [$bytes (4)],
      FB_TRANSFER_ADDRESS = [$bytes (4)],
      FB_FILE_TYPE = [$byte]
      tes;

literal
       FILE_DATA_BLOCK_SIZE = $field_set_size,
       FILE_DATA_BLOCK_ALLOCATION = $field_set_units ;

macro
     FILE_DATA_BLOCK = block [FILE_DATA_BLOCK_SIZE]
                       field (FILE_DATA_FIELDS) %;

! End of file structure definition

$show (none)
!
! Macros:
!

!
! Equated symbols:
!

literal
       RESPONSE_BUFFER_LENGTH = 256,    ! NICE response buffer in bytes
       RESPONSE_BUFFER_SIZE = ch$allocation (RESPONSE_BUFFER_LENGTH,8),
       RESPONSE_BUFFER_ALLOCATION = RESPONSE_BUFFER_SIZE * %upval,

       MOP_BUFFER_LENGTH = 522,         ! MOP message buffer in bytes
       MOP_BUFFER_SIZE = ch$allocation (MOP_BUFFER_LENGTH, 8),
       MOP_BUFFER_ALLOCATION = MOP_BUFFER_SIZE * %upval,

       MOP_LOAD_DATA_LENGTH = (254 - 6),! Max bytes in image in load message
       MOP_RESPONSE_LENGTH = 32;        ! Max bytes in ACK to load

!
! RSX .SYS file label definitions
!

literal
    L$BSA = %o'10',                 ! Base address of image
    L$BLDZ = %o'16',                ! Load size of image
    L$BFLG = %o'30',                ! Header flags word
    L$BXFR = %o'350',               ! Transfer address
    L$BHRB = %o'356';               ! Starting block of image (0 relative)

!
! STATE/SUBSTATE/SERVICE definitions
!

literal
    CPARM_STATE = 0,
    CPARM_SUBSTATE = 1,
    CPARM_SERVICE = 100,

    LINK_ON = 0,
    LINK_OFF = 1,
    LINK_SERVICE = 2,
    LINK_CLEARED = 3,

    LINK_NO_SUBSTATE = -1,
    LINK_STARTING = 0,
    LINK_REFLECTING = 1,
    LINK_LOOPING = 2,
    LINK_LOADING = 3,
    LINK_DUMPING = 4,
    LINK_TRIGGERING = 5,
    LINK_AUTOSERVICE = 6,
    LINK_AUTOLOADING = 7,
    LINK_AUTODUMPING = 8,
    LINK_AUTOTRIGGERING = 9,
    LINK_SYNCHRONIZING = 10,
    LINK_FAILED = 11,

    LINK_ENABLED = 0,
    LINK_DISABLED = 1;

!
! External references:
!

external routine
         NML$FIND_NDB,                  ! Find node entity for circuit
         NML$PARAMETER_DATA,            ! Get NICE parameter data
         NML$CLR_VDB_PARAMETER,         ! Clear parameter in VDB
         NML$GET_VDB_PARAMETER,         ! Obtain parameter data from VDB
         NML$SET_VDB_PARAMETER,         ! Set parameter in VDB
         NMU$NETWORK_LOCAL,             ! Get local node number/name
         NMU$FILE_ROUTINES;             ! File access routines
%global_routine ('NML$DUMP', REQ : ref REQUEST_BLOCK) =

!++
! Functional description:
!
!	This routine performs the NICE dump request function.
!       It is responsible for extracting the parameter data,
!       required for the dump function, from the volatile data
!       base and merging this data with any parameter data
!       supplied with the dump request. It calls DUMP_NODE to
!       actually perform the function.
!
! Formal parameters:
!
!	.REQ	NML Request Block address
!
! Implicit inputs: none
!
! Routine value:
!
!	NICE return code.
!
! Side effects: none
!
!--

    begin
    bind
        ACCEPTABLE_PARAMETERS = plit (110, 111, 130, 131, 135, 136);

    macro                               ! Synonym for response buffer pointer
         RESPONSE_PTR = ch$ptr (.REQ [RB_RESPONSE],, 8) %;

    local
         RTN_COD;

    if not .REQ[RB_PRV_SERVICE] then return NICE$_PRV;

    !
    ! Set up the dump service block
    !

    if DTL_SETUP (.REQ, ACCEPTABLE_PARAMETERS) lss 0
    then
        return (ch$rchar(RESPONSE_PTR));

    !
    ! Access service block
    !

    begin

    local
         DB : ref SERVICE_DATA_BLOCK;

    DB = .REQ[RB_DTL_DATA];
    DB [SB_USAGE] = DLX_DUMP;
    RTN_COD = NICE$_SUC;

    !
    ! Open the link if we can
    !

    if not CIRCUIT_OPEN (.DB)
    then
        RTN_COD = ch$rchar (RESPONSE_PTR);

    !
    ! Execute the dump.
    !

    if .RTN_COD eql NICE$_SUC
    then
	begin
	DUMP_NODE (.DB);
        RTN_COD = ch$rchar (RESPONSE_PTR);
        CIRCUIT_CLOSE (.DB);
	end;

    end;
    DTL_CLEANUP (.REQ, .RTN_COD)
    end;				!End of NML$DUMP
%global_routine ('NML$LOAD', REQ : ref REQUEST_BLOCK) =

!++
! Functional description:
!
!	This routine performs the NICE load request function.
!       It is responsible for extracting the parameter data,
!       required for the load function, from the volatile data
!       base and merging this data with any parameter data
!       supplied with the load request. It calls LOAD_NODE to
!       actually perform the function.
!
! Formal parameters:
!
!	.REQ	NML Request Block address.
!
! Implicit inputs: none
!
! Routine value:
!
!	NICE return code.
!
! Side effects: none
!
!--

    begin
    bind
        ACCEPTABLE_PARAMETERS = plit (110, 111, 112, 113, 120, 121, 122, 125 %(, 126)% , 141, 500, 502);

    macro                               ! Synonym for response buffer pointer
         RESPONSE_PTR = ch$ptr (.REQ [RB_RESPONSE],, 8) %;

    local
         RTN_COD;

    if not .REQ[RB_PRV_SERVICE] then return NICE$_PRV;

    !
    ! Set up the load service block.
    !

    if DTL_SETUP (.REQ, ACCEPTABLE_PARAMETERS) lss 0
    then
        return (ch$rchar(RESPONSE_PTR));

    !
    ! Access service block
    !

    begin

    local
         LB : ref SERVICE_DATA_BLOCK;

    RTN_COD = NICE$_SUC;
    LB = .REQ[RB_DTL_DATA];
    LB [SB_USAGE] = DLX_LOAD;

    !
    ! Open the link if we can
    !

    if not CIRCUIT_OPEN (.LB)
    then
        RTN_COD = ch$rchar (.LB [SB_RESPONSE_PTR]);

    !
    ! Execute the load.
    ! Deallocate the buffers.
    !

    if .RTN_COD eql NICE$_SUC
    then
	begin
	LOAD_NODE (.LB);
        RTN_COD = ch$rchar (RESPONSE_PTR);
        CIRCUIT_CLOSE (.LB);
	end;

    end;
    DTL_CLEANUP (.REQ, .RTN_COD)
    end;				!End of NML$LOAD
%global_routine ('NML$TRIGGER', REQ : ref REQUEST_BLOCK) =

!++
! Functional description:
!
!	This routine performs the NICE trigger request function.
!       It is responsible for extracting the parameter data,
!       required for the trigger function, from the volatile data
!       base and merging this data with any parameter data
!       supplied with the trigger request. It calls TRIGGER_NODE to
!       actually perform the function.
!
! Formal parameters:
!
!	.REQ	NML Request Block address.
!
! Implicit inputs: none
!
! Routine value:
!
!	NICE return code.
!
! Side effects: none
!
!--

    begin
    bind
        ACCEPTABLE_PARAMETERS = plit (110, 111);

    macro                               ! Synonym for response buffer pointer
         RESPONSE_PTR = ch$ptr (.REQ [RB_RESPONSE],, 8) %;

    local
         RTN_COD;

    if not .REQ[RB_PRV_SERVICE] then return NICE$_PRV;

    !
    ! Set up the trigger service block.
    !

    if DTL_SETUP (.REQ, ACCEPTABLE_PARAMETERS) lss 0
    then
        return (ch$rchar(RESPONSE_PTR));

%if $MCB
%then

    !
    ! Access service block
    !

    begin

    local
         TB : ref SERVICE_DATA_BLOCK;

    RTN_COD = NICE$_SUC;
    TB = .REQ[RB_DTL_DATA];
    TB [SB_USAGE] = DLX_OTHER;

    !
    ! Open the link if we can
    !

    if not CIRCUIT_OPEN (.TB)
    then
        RTN_COD = ch$rchar (.TB [SB_RESPONSE_PTR]);

    !
    ! Execute the load.
    ! Deallocate the buffers.
    !

    if .RTN_COD eql NICE$_SUC
    then
	begin
	TRIGGER_NODE (.TB);
        RTN_COD = ch$rchar (RESPONSE_PTR);
        CIRCUIT_CLOSE (.TB);
	end;

    end;
%else
    RTN_COD = NICE$_UFO;
    $RESPONSE (RESPONSE_PTR, .RTN_COD);
%fi

    DTL_CLEANUP (.REQ, .RTN_COD)
    end;				!End of NML$TRIGGER
%routine ('DTL_SETUP', REQ: ref REQUEST_BLOCK, ACCEPTABLE_PARAMETERS: VECTOR) =

!++
! Functional description:
!
!	This routine does setup for LOAD, DUMP and TRIGGER.  It allocates
!	the service block that is used to control the process and sets up
!	its parameters.  All parameters that have no default value and that
!	have not been specified will be given "NA" values: -1 for $integer's
!	and the null pointer for pointers.
!
!
! Formal parameters:
!
!	.REQ			NML Request Block address.
!	.ACCEPTABLE_PARAMETERS	A list of the acceptable parameters for
!				the request type being done.
!
! Implicit inputs: none
!
! Routine value:
!
!	 1	Success: setup done
!	-1	Failure: one or more essential parameters are missing, or an
!			 specified parameter was invalid.  The MOP buffer,
!			 the service block and the NICE response buffer have
!			 been allocated.
!	-3	Failure: the routine was not able to allocate a service block
!			 plus a MOP buffer.  The NICE response buffer has been
!			 allocated.
!	-4	Failure: the routine was not able to allocate a NICE response
!			 buffer.  The service block and the MOP buffer were
!			 not allocated.
!
! Side effects: none.
!
!--

    begin

    label
        CHECK_PARAMETERS;

    local
	RET,
	BUFFER,
	SB: ref SERVICE_DATA_BLOCK;

    macro                               ! Synonym for response buffer pointer
         RESPONSE_PTR = ch$ptr (.REQ [RB_RESPONSE],, 8) %;

    REQ[RB_DTL_DATA] = 0;
    RET = 1;

    !
    ! Allocate NICE response buffer.
    !

    REQ[RB_RESPONSE_ALLOCATION] = RESPONSE_BUFFER_ALLOCATION ;
    if (REQ[RB_RESPONSE] = NMU$MEMORY_GET (.REQ[RB_RESPONSE_ALLOCATION])) eql 0
    then begin                          ! Allocation failure
	REQ[RB_RETURN_CODE] = NICE$_REE;
	return -4
	end;

    !
    ! Allocate a SERVICE_DATA_BLOCK plus transmit and receive MOP buffers
    !

    REQ[RB_DTL_DATA_ALLOCATION] = SERVICE_DATA_BLOCK_ALLOCATION
        + MOP_BUFFER_ALLOCATION;

    if (SB = NMU$MEMORY_GET (.REQ[RB_DTL_DATA_ALLOCATION])) eql 0
    then                                ! Allocation failure
        begin
        $RESPONSE (RESPONSE_PTR,NICE$_REE,0);
	return -3;
        end;

CHECK_PARAMETERS:
    begin                               ! CHECK_PARAMETERS
    REQ[RB_DTL_DATA] = .SB;
    SB[SB_BUFFER] = vector [.SB, SERVICE_DATA_BLOCK_SIZE];
    SB[SB_BUFFER_PTR] = ch$ptr (.SB [SB_BUFFER],, 8);

    !
    ! Merge information in SERVICE_DATA_BLOCK from NML volatile data base
    ! for this node, and any parameters supplied on the dump request.
    !

    SB [SB_RESPONSE_PTR] = RESPONSE_PTR;

    selectone .REQ[RB_NICE_ENTITY_TYPE] of
        set
        [NODE_E]:                   ! NODE entity
            begin
            SB[SB_NODE_DATA] = .REQ[RB_NICE_ENTITY] ; ! NODE for this load
            SB[SB_SERVICE_CIRCUIT] = 0;
            end;
        [CIRCUIT_]:                 ! CIRCUIT entity
            begin
            SB[SB_SERVICE_CIRCUIT] = .REQ[RB_NICE_ENTITY] ; ! CIRCUIT for this load
            !
            ! Scan through the VDB looking for the circuit specified.
            ! Set the corresponding NODE ID.
            !
            SB[SB_NODE_DATA] = NML$FIND_NDB (.REQ[RB_NICE_ENTITY]) ;
            end;
        tes;

    !
    ! Set default (NA) values for all parameter fields.
    !

        begin
        SB[SB_SERVICE_PASSWORD] = 0;
        SB[LB_LOAD_FILE] = 0;
        SB[LB_SECONDARY_LOADER] = 0;		! Set all pointer
        SB[LB_TERTIARY_LOADER] = 0;		! fields to the
        SB[LB_SOFTWARE_IDENTIFICATION] = 0;	! null pointer
        SB[DB_DUMP_FILE] = 0;
        SB[DB_SECONDARY_DUMPER] = 0;
        begin
        local PTR;
        PTR = ch$ptr (SB[LB_HOST],, 8);
        ch$wchar_a (0, PTR);            ! Node number = 0
        ch$wchar_a (0, PTR);
        ch$wchar_a (0, PTR);            ! Node name = ''
        end;
        SB[LB_NAME] = 0;
        SB[LB_ADDRESS] = 0;

        SB[LB_SERVICE_DEVICE] = -1;
        SB[LB_CPU] = -1;
        SB[LB_SOFTWARE_TYPE] = -1;		! Set all
        %movi32 (0, SB[DB_DUMP_ADDRESS]);	! numeric fields
        %subi32 (1, SB[DB_DUMP_ADDRESS]);	! to -1
        %movi32 (0, SB[DB_DUMP_COUNT]);
        %subi32 (1, SB[DB_DUMP_COUNT]);
        end;

    !
    ! Merge any parameters specified in the NICE request message.
    !

    if FETCH_PARAMETERS (.REQ, .SB, .ACCEPTABLE_PARAMETERS) lss 0
    then leave CHECK_PARAMETERS with RET = -1; ! Problem with a parameter

    end;                                ! CHECK_PARAMETERS
    !
    ! If there was an error, release everything we got (except the
    ! response buffer).
    !

    if .RET lss 0
    then begin
         NMU$MEMORY_RELEASE (.REQ[RB_DTL_DATA], .REQ[RB_DTL_DATA_ALLOCATION]);
         REQ[RB_DTL_DATA] = 0;
         end;

    .RET

    end;			! End of DTL_SETUP
%routine ('DTL_CLEANUP', REQ: ref REQUEST_BLOCK, RTN_COD) =

!++
! Functional description:
!
!	None
!
! Formal parameters:
!
!	.REQ			NML Request Block address.
!       RTN_COD                 Current NICE return code
!
! Implicit inputs: none
!
! Routine value:
!
!	return code
! 
! Side effects: none.
!
!--

    begin

    macro                               ! Synonym for response buffer pointer
         RESPONSE_PTR = ch$ptr (.REQ [RB_RESPONSE],, 8) %;

    !
    ! Deallocate service blocks
    !

    if .REQ[RB_DTL_DATA] neqa 0
    then NMU$MEMORY_RELEASE (.REQ[RB_DTL_DATA],.REQ[RB_DTL_DATA_ALLOCATION]) ;

    !
    ! If successful, build NICE repsonse message with success code.
    !

    if .RTN_COD eql NICE$_SUC
    then begin
         REQ [RB_RESPONSE_LENGTH] = $RESPONSE (RESPONSE_PTR, NICE$_SUC, 0) ;
         NML$REQUEST_FINISH (.REQ) ;
         end
    else if ch$rchar (RESPONSE_PTR) neq 0
         then
             REQ [RB_RESPONSE_LENGTH] = $RESPONSE_LENGTH (RESPONSE_PTR);

    .RTN_COD 
    end;			! End of DTL_CLEANUP
%routine ('CIRCUIT_CLOSE', DB : ref SERVICE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description
!
!        This routine closes the circuit.
!
! Formal parameters
!
!    .DB      Address of the service data block
!
! Implicit inputs: none
!
! Routine value:
!
!    $true    Circuit successfully closed
!
! Side effects: none
!
!--

    begin

    !
    ! Set the substate back to something reasonable
    !

    if .DB[SB_AUTOSERVICE]
    then DB[SB_SUBSTATE] = LINK_AUTOSERVICE
    else DB[SB_SUBSTATE] = LINK_NO_SUBSTATE;

    SET_SUBSTATE (.DB);
    $NMU_DLX_CLOSE (.DB[SB_CIRCUIT_HANDLE]);

%if $TOPS20
%then
    !
    ! If circuit state is ON then initialize the circuit
    !

    if (.DB [SB_USAGE] eql DLX_LOAD) and
       (ch$rchar (.DB[SB_RESPONSE_PTR]) eql NICE$_SUC)
    then begin

         local
             CIRCUIT_STATE;

         if not NML$GET_VDB_PARAMETER (CIRCUIT_, .DB [SB_SERVICE_CIRCUIT],
                                       CPARM_STATE, CIRCUIT_STATE)
         then CIRCUIT_STATE = LINK_ON;

         selectoneu .CIRCUIT_STATE of
             set
             [LINK_ON]:
                 $NMU_DLX_INITIALIZE (.DB[SB_CIRCUIT_HANDLE],
                                      .DB[SB_RESPONSE_PTR]);
             [otherwise]:
                 ;
             tes;

         end;
%fi

    $true
    end;				!End of CIRCUIT_CLOSE
%routine ('CIRCUIT_OPEN', DB : ref SERVICE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description
!
!        This routine opens the service circuit.
!
! Formal parameters
!
!    .DB      Address of the service data block
!
! Implicit inputs: none
!
! Routine value:
!
!    $true    Service circuit successfully opened
!    $false   Error in opening circuit - response set
!
! Side effects: none
!
!--

    begin
    local
         CIRCUIT_HANDLE,
         SERVICE_CIRCUIT;

    if .DB [SB_SERVICE_CIRCUIT] eqla 0
    then
        if not NML$GET_VDB_PARAMETER (NODE_E, ! CIRCUIT for this load
                                      .DB[SB_NODE_DATA],
                                      110,     ! SERVICE CIRCUIT
                                      DB [SB_SERVICE_CIRCUIT])
        then
            begin
            $RESPONSE_X (.DB[SB_RESPONSE_PTR],NICE$_PAM,110);
            return $false;
            end;

    !
    ! Check the circuit state for ON or SERVICE
    !

    begin

    local
        CIRCUIT_STATE;

    if not NML$GET_VDB_PARAMETER (CIRCUIT_, .DB [SB_SERVICE_CIRCUIT],
                                  CPARM_STATE, CIRCUIT_STATE)
    then CIRCUIT_STATE = LINK_ON;

    selectoneu .CIRCUIT_STATE of
        set
        [LINK_ON, LINK_SERVICE]:
            ;
        [otherwise]:
            begin
            $RESPONSE (.DB[SB_RESPONSE_PTR],NICE$_CWS,CIRCUIT_);
            return $false;
            end;
        tes;

    end;

    !
    ! Check the service state for ENABLED
    !

    begin

    local
        CIRCUIT_SERVICE;

    if not NML$GET_VDB_PARAMETER (CIRCUIT_, .DB [SB_SERVICE_CIRCUIT],
                                  CPARM_SERVICE, CIRCUIT_SERVICE)
    then CIRCUIT_SERVICE = LINK_DISABLED;

    selectoneu .CIRCUIT_SERVICE of
        set
        [LINK_ENABLED]:
            ;
        [otherwise]:
            begin
            $RESPONSE (.DB[SB_RESPONSE_PTR],NICE$_CWS,CIRCUIT_);
            return $false;
            end;
        tes;

    end;

    !
    ! Check the circuit substate.
    ! If no substate, then we can go ahead.
    ! If autoservice, remember the fact.
    ! Otherwise abort the request.
    !

    begin

    local
        CIRCUIT_SUBSTATE;

    if not NML$GET_VDB_PARAMETER (CIRCUIT_, .DB [SB_SERVICE_CIRCUIT],
                                  CPARM_SUBSTATE, CIRCUIT_SUBSTATE)
    then CIRCUIT_SUBSTATE = LINK_NO_SUBSTATE;

    DB[SB_SUBSTATE] = .CIRCUIT_SUBSTATE;

    selectoneu .CIRCUIT_SUBSTATE of
        set
        [LINK_NO_SUBSTATE, LINK_FAILED]:
            DB[SB_AUTOSERVICE] = $false;
        [LINK_AUTOSERVICE]:
            DB[SB_AUTOSERVICE] = $true;
        [otherwise]:
            begin
            $RESPONSE (.DB[SB_RESPONSE_PTR],NICE$_CWS,CIRCUIT_);
            return $false;
            end;
        tes;

    end;
    CIRCUIT_HANDLE = $NMU_DLX_OPEN (.DB [SB_USAGE], .DB [SB_SERVICE_CIRCUIT],
                                   .DB [SB_RESPONSE_PTR]);

    if .CIRCUIT_HANDLE leq 0 then return $false;

    DB [SB_CIRCUIT_HANDLE] = .CIRCUIT_HANDLE;

    !
    ! Set the substate for the requested operation
    !

    selectone .DB [SB_USAGE] of
        set
        [DLX_LOAD]:
            if .DB[SB_AUTOSERVICE]
            then DB[SB_SUBSTATE] = LINK_AUTOLOADING
            else DB[SB_SUBSTATE] = LINK_LOADING;
        [DLX_DUMP]:
            if .DB[SB_AUTOSERVICE]
            then DB[SB_SUBSTATE] = LINK_AUTODUMPING
            else DB[SB_SUBSTATE] = LINK_DUMPING;
        [otherwise]:
            if .DB[SB_AUTOSERVICE]
            then DB[SB_SUBSTATE] = LINK_AUTOTRIGGERING
            else DB[SB_SUBSTATE] = LINK_TRIGGERING;
        tes;

    SET_SUBSTATE (.DB);
    $true
    end;				!End of CIRCUIT_OPEN
%routine ('CIRCUIT_PROMPT', DB : ref SERVICE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description
!
!        This routine prompts for a message retransmission over the circuit
!        by sending a truncated MOP_MODE_RUNNING message.
!
! Formal parameters
!
!    .DB      Address of the service data block
!
! Implicit inputs: none
!
! Routine value:
!
!    $true    Prompted successfully
!    $false   Error in transmission - response set
!
! Side effects: none
!
!--

    begin
    $NMU_DLX_WRITE (.DB[SB_CIRCUIT_HANDLE], DLX_OTHER,
                    ch$ptr (uplit (%char(MOP_MODE_RUNNING)),, 8), 1,
                    .DB [SB_RESPONSE_PTR])
    end;				!End of CIRCUIT_PROMPT
%routine ('CPU_IS_PDP11', DB : ref SERVICE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description
!
!        This routine checks that the CPU parameter is PDP11.
!
! Formal parameters
!
!    .DB      Address of the service data block
!
! Implicit inputs: none
!
! Routine value:
!
!    $true    CPU parameter is PDP11
!    $false   Not PDP11 - response set
!
! Side effects: none
!
!--

    begin
    local
         CPU;

    if (CPU = .DB [LB_CPU]) eql -1
    then
        if not NML$GET_VDB_PARAMETER (NODE_E,
                                      .DB [SB_NODE_DATA],
                                       113,
                                       CPU)
        then
            begin
            $RESPONSE_X (.DB [SB_RESPONSE_PTR], NICE$_PAM, 113);
            return $false;
            end;

    if .CPU neq CPU_PDP11
    then
        begin
        $RESPONSE_X (.DB [SB_RESPONSE_PTR], NICE$_IPV, 113);
        return $false;
        end;

    $true
    end;				!End of CPU_IS_PDP11
%routine ('DUMP_NODE', DATA : ref SERVICE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description:
!
!        This routine is called after the NICE request message has been
!        decomposed.  It performs the actual dump of a target node
!        connected to this (EXECUTOR) node by some circuit.
!
! Formal parameters:
!
!    .DATA    Address of dump data block
!
!             Necessary parameters (must be specified in request or in VDB):
!
!	      Parameter		Name
!	      ---------		----
!
!		130	Dump Image File ID
!		131	Secondary Dumper ID
!
!	      Parameters that may be defaulted:
!
!	      Parameter		Name		Default Value
!	      ---------		----		-------------
!
!		135	Dump Beginning Address		0
!		136	Dump Count			gotten from target
!
! Implicit inputs: none
!
! Routine value: none
! Side effects: none
!
!--

    begin
    label
         DUMP_REQUEST;
    literal
           DUMPER_ASSUMED = 0,			! We hope the target can dump
           DUMPER_NEEDED = DUMPER_ASSUMED + 1,	! We need to load a secondary dumper
           DUMPER_RUNNING = DUMPER_NEEDED + 1,	! Secondary dumper is loaded
           DUMPER_READY = DUMPER_RUNNING + 1,	! Secondary dumper accepting dump requests
           DUMPER_BROKEN = DUMPER_READY + 1;	! Target can't be dumped
    local
         DUMP_COUNT_DEFAULTED,
         DUMPER_STATE,
         FB : FILE_DATA_BLOCK,
         SECONDARY_DUMPER,
         SERVICE_DEVICE;

    FB[FB_RESPONSE_PTR] = .DATA[SB_RESPONSE_PTR];
    FB[FB_FILE_TYPE] = FILE_DUMP_IMAGE;

    if not CPU_IS_PDP11 (.DATA) then return $false;

    if (SERVICE_DEVICE = .DATA [LB_SERVICE_DEVICE]) lss 0
    then
        if not NML$GET_VDB_PARAMETER (NODE_E,
                                      .DATA [SB_NODE_DATA],
                                      112,
                                      SERVICE_DEVICE)
        then
            SERVICE_DEVICE = -1;

    if (FB[FB_FILE] = .DATA [DB_DUMP_FILE]) eql 0
    then
        if not NML$GET_VDB_PARAMETER (NODE_E,
                                      .DATA [SB_NODE_DATA],
                                       130,
                                       FB[FB_FILE])
        then
	    begin
	    $RESPONSE_X (.DATA[SB_RESPONSE_PTR], NICE$_PAM, 130);
	    return $false
	    end;

    if (SECONDARY_DUMPER = .DATA [DB_SECONDARY_DUMPER]) eql 0
    then
        if not NML$GET_VDB_PARAMETER (NODE_E,
                                      .DATA [SB_NODE_DATA],
                                       131,
                                       SECONDARY_DUMPER)
        then
            SECONDARY_DUMPER = 0;

!
! Set dump limits.
!

    begin
    local
         PTR;
    own NEG1: THIRTY_TWO_BIT;
    %movi32 (0, NEG1);
    %subi32 (1, NEG1);

    %mov32 (DATA[DB_DUMP_ADDRESS], FB[FB_CURRENT_ADDRESS]);

    if %cmp32 (DATA[DB_DUMP_ADDRESS], eql, NEG1)
    then
        if not NML$GET_VDB_PARAMETER (NODE_E,
                                  .DATA [SB_NODE_DATA],
                                  135,
                                  FB[FB_CURRENT_ADDRESS])
        then %movi32 (0, FB[FB_CURRENT_ADDRESS]);

    DUMP_COUNT_DEFAULTED = $true;

    %mov32 (DATA[DB_DUMP_COUNT], FB[FB_BYTES_LEFT]);

    if %cmp32 (DATA[DB_DUMP_COUNT], eql, NEG1)
    then
        if NML$GET_VDB_PARAMETER (NODE_E,
                                  .DATA [SB_NODE_DATA],
                                  136,
                                  FB[FB_BYTES_LEFT])
        then
            DUMP_COUNT_DEFAULTED = $false
        else
            begin
            %movi32 (%o'76000', FB[FB_BYTES_LEFT]);
            %asli32 (3, FB[FB_BYTES_LEFT]);
            DUMP_COUNT_DEFAULTED = $true;
            end
    else
        DUMP_COUNT_DEFAULTED = $false;

    end;

!
! Open the file if we can.....
!

    if not FILE_OPEN (FB) then return $false;

!
! Until all bytes have been dumped
!    Send a dump request for the next block of memory
!    Receive the dump data
!    Validate the dump data response
!    Put data into dump image file
!
!

    $RESPONSE (.DATA [SB_RESPONSE_PTR], NICE$_SUC);

    DUMPER_STATE = DUMPER_ASSUMED;

    while %cmpi32 (FB[FB_BYTES_LEFT], gtr, 0)
    do
      case .DUMPER_STATE from 0 to 3 of
          set
          !
          ! If we need to load the secondary dumper and there is one,
          ! then do so.  Otherwise give up.
          !
          [DUMPER_NEEDED] :

	      begin
	      if .SECONDARY_DUMPER eqla 0
	      then
		  begin
		  $RESPONSE_X (.DATA[SB_RESPONSE_PTR], NICE$_PAM, 131);
		  exitloop;
		  end;

              if SECONDARY_LOAD (.DATA, FILE_SECONDARY_DUMPER,
                                 .SECONDARY_DUMPER)
              then
                  begin
                  $RESPONSE (.DATA[SB_RESPONSE_PTR], NICE$_SUC);
                  DUMPER_STATE = .DUMPER_STATE + 1
                  end
              else
                  exitloop;
	      end;

          !
          ! Construct and send the REQUEST DUMP message
          !
          [DUMPER_ASSUMED, DUMPER_RUNNING, DUMPER_READY] :
              DUMP_REQUEST:begin
              local
                   BUF_PTR,
                   DUMP_LENGTH,
                   RESULT;
      
              BUF_PTR = .DATA [SB_BUFFER_PTR];
              PUTB (REQUEST_DUMP, BUF_PTR);
              PUT32 (FB[FB_CURRENT_ADDRESS], BUF_PTR);

              %mov32 (FB[FB_BYTES_LEFT], DUMP_LENGTH);

              if %cmpi32 (DUMP_LENGTH, gtr, (MOP_BUFFER_LENGTH - 6))
              then %movi32 ((MOP_BUFFER_LENGTH - 6), DUMP_LENGTH);

              PUTW (DUMP_LENGTH, BUF_PTR);

              %(do a $NMU_DLX_WRITE_READ)%

              decru TIMES from NMU$K_MOP_RETRY_LIMIT to 1 do begin
                  if .DUMPER_STATE neq DUMPER_RUNNING
                  then
                      begin
                      if not $NMU_DLX_WRITE (.DATA [SB_CIRCUIT_HANDLE], DLX_DATA,
                                      .DATA [SB_BUFFER_PTR], 7,
                                      .DATA [SB_RESPONSE_PTR])

                      then exitloop RESULT = -1;
                      end
                  else
                      DUMPER_STATE = .DUMPER_STATE + 1;

                  RESULT = $NMU_DLX_READ (.DATA [SB_CIRCUIT_HANDLE], DLX_DATA,
                                     .DATA [SB_BUFFER_PTR], MOP_BUFFER_LENGTH,,
                                     .DATA [SB_RESPONSE_PTR]);

                  if .RESULT neq -2 then exitloop;
                  end;

              if .RESULT leq 0
              then
                  leave DUMP_REQUEST with DUMPER_STATE = .DUMPER_STATE + 1;

              begin
              local
                  BUF_PTR;

              BUF_PTR = .DATA [SB_BUFFER_PTR];

              selectone GETB (BUF_PTR) of
                  set
                  [MOP_MODE_RUNNING] :
                      if .RESULT geq 8
                      then
                          begin
                          local
                              MEMZISE : THIRTY_TWO_BIT,
                              TEMP;
                          bind
                              DEVTYPE = TEMP,
                              MOPVER = TEMP,
                              FEATURES = TEMP;

                          DEVTYPE = GETB (BUF_PTR);

                          if (.SERVICE_DEVICE geq 0) and
                             (.SERVICE_DEVICE neq .DEVTYPE)
                          then
                              begin
                              $RESPONSE (.DATA [SB_RESPONSE_PTR], NICE$_LPE);
                              exitloop;
                              end;

                          if GETB (BUF_PTR) neq 1
                          then
                              begin
                              $RESPONSE (.DATA [SB_RESPONSE_PTR], NICE$_LPE);
                              exitloop;
                              end;

                          GET32 (BUF_PTR, MEMZISE);
                          FEATURES = GETB (BUF_PTR);

                          if not .FEATURES <1, 1>
                          then
                              leave DUMP_REQUEST with DUMPER_STATE = .DUMPER_STATE + 1;

                          if .DUMP_COUNT_DEFAULTED
                          then
                              begin
                              %mov32 (MEMZISE, FB[FB_BYTES_LEFT]);
                              %sub32 (FB[FB_CURRENT_ADDRESS], FB[FB_BYTES_LEFT]);
                              end;

                          end;
                  [MEMORY_DUMP_DATA] :
                      begin
                      local
                           DUMPED_ADDRESS : THIRTY_TWO_BIT;

                      RESULT = .RESULT - 5;

                      if .RESULT lss 0 then exitloop;

                      !
                      ! Check for the correct dump address
                      ! Adjust dump address for next dump request
                      !
                      GET32 (BUF_PTR, DUMPED_ADDRESS);

                      if %cmp32 (DUMPED_ADDRESS, neq, FB[FB_CURRENT_ADDRESS])
                      then
                          begin
                          $RESPONSE_X (.DATA [SB_RESPONSE_PTR], NICE$_LPE, 0,
                                       'Address received in MEMORY DUMP DATA is incorrect', 117);
                          exitloop;
                          end;

                      %addi32 (.RESULT, FB[FB_CURRENT_ADDRESS]);
                      %subi32 (.RESULT, FB[FB_BYTES_LEFT]);

                      !
                      ! Write data to image file
                      !
                      if not NMU$FILE_WRITE (.FB[FB_FILE_HANDLE], .BUF_PTR, .RESULT, .FB[FB_RESPONSE_PTR])
                      then leave DUMP_REQUEST with DUMPER_STATE = .DUMPER_STATE + 1;
                      end;
                  [otherwise] :
                      leave DUMP_REQUEST with DUMPER_STATE = .DUMPER_STATE + 1;
                  tes;

              end;
              end;
          !
          ! The dumper is broken! Long live the dumper!
          !
          [inrange, outrange] :
              exitloop;
          tes;

!
! Close dump file
!

    FILE_CLOSE (FB);
    $true
    end;				!End of DUMP_NODE
%routine ('FETCH_PARAMETERS', REQ : ref REQUEST_BLOCK, DB : ref SERVICE_DATA_BLOCK, PRM : ref vector) =

!++
! Functional description:
!
!	This routine extracts the parameters supplied in the NICE request
!       message, checks to make sure they are applicable to the request,
!       and stores them in the service block.
!
! Formal parameters:
!
!	.REQ	NML Request Block address
!       .DB     dump/load/trigger block address
!       .PRM    address of plit vector with acceptable parameter numbers
!
! Implicit inputs: none
!
! Routine value:
!
!	NICE return code.
!
! Side effects: none
!
!--

    begin
    local
         ENTITY_TYPE,
         PARM_NO,
         PARM_DATA: THIRTY_TWO_BIT;

    ENTITY_TYPE =.REQ[RB_NICE_ENTITY_TYPE] ; ! Save real entity type
    REQ[RB_NICE_ENTITY_TYPE] = NODE_E ; ! Parameters are all NODE 

    while GET_NEXT_PARAMETER (.REQ, PARM_NO, PARM_DATA)
    do
       begin

       selectone
           begin
           local
                ADR : ref vector,
                CNT;
           ADR = .PRM;
           CNT = .ADR [-1];

           do
             begin
             local
                  VAL;

             VAL = .ADR [0];
             ADR = ADR [1];

             if .PARM_NO eql .VAL then exitloop .VAL;

             end
           while (CNT = .CNT - 1) neq 0

           end
       of
           set
           [110]:                  ! SERVICE CIRCUIT
               DB[SB_SERVICE_CIRCUIT] = .PARM_DATA ;
           [111]:                  ! SERVICE PASSWORD
               DB[SB_SERVICE_PASSWORD] = .PARM_DATA ;
           [112]:                  ! SERVICE DEVICE
               DB[LB_SERVICE_DEVICE] = .PARM_DATA ;
           [113]:                  ! CPU
               selectone ch$rchar (.PARM_DATA) of
                   set
                   [0 to 3] : DB[LB_CPU] = .PARM_DATA;
                   [otherwise] :
                       begin
                       $RESPONSE_X (.DB[SB_RESPONSE_PTR], NICE$_IPV, 113);
                       exitloop;
                       end;
                   tes;
           [120]:                  ! LOAD FILE
               DB[LB_LOAD_FILE] = .PARM_DATA ;
           [121]:                  ! SECONDARY LOADER
               DB[LB_SECONDARY_LOADER] = .PARM_DATA ;
           [122]:                  ! TERTIARY LOADER
               DB[LB_TERTIARY_LOADER] = .PARM_DATA ;
           [125]:                  ! SOFTWARE TYPE
                selectone .PARM_DATA of
                    set
                    [0 to 2] : DB[LB_SOFTWARE_TYPE] = .PARM_DATA;
                    [otherwise] :
                        begin
                        $RESPONSE_X (.DB[SB_RESPONSE_PTR], NICE$_IPV, 125);
                        exitloop;
                        end;
                    tes;
           [126]:                  ! SOFTWARE IDENTIFICATION
               DB[LB_SOFTWARE_IDENTIFICATION] = .PARM_DATA ;
           [130]:                  ! DUMP FILE
               DB[DB_DUMP_FILE] = .PARM_DATA ;
           [131]:                  ! SECONDARY DUMPER
               DB[DB_SECONDARY_DUMPER] = .PARM_DATA ;
           [135]:                  ! DUMP ADDRESS
               %mov32 (PARM_DATA, DB[DB_DUMP_ADDRESS]);
           [136]:                  ! DUMP COUNT
               %mov32 (PARM_DATA, DB[DB_DUMP_COUNT]);
           [141]:                  ! HOST
               begin
               local
                    FMT,
                    NOD_PTR;

               NOD_PTR = ch$ptr (DB[LB_HOST],,8) ;
               FMT = GETB (PARM_DATA); ! Get node id format byte

               selectoneu .FMT of
                   set
                   [0]:
                       begin            ! Node address
                       PUTB (GETB (PARM_DATA), NOD_PTR);
                       PUTB (GETB (PARM_DATA), NOD_PTR);
                       PUTB (0,NOD_PTR) ; ! Null node name
                       end;
                   [1 to 6]:
                       begin          ! Node name
                       PUTB (0,NOD_PTR); ! Node address of zero
                       PUTB (0,NOD_PTR);
                       PUTB (.FMT,NOD_PTR) ; ! Length of node name
                       ch$move (.FMT,.PARM_DATA,.NOD_PTR) ;
                       end;
                   [otherwise]:
                       begin
                       $RESPONSE_X (.DB[SB_RESPONSE_PTR],NICE$_IID,NODE_E,
                                    'HOST Node Id', 101) ;
                       exitloop;
                       end;
                   tes;

               end;
           [500]:                  ! NAME
               DB [LB_NAME] = .PARM_DATA;
           [502]:                  ! ADDRESS
               DB [LB_ADDRESS] = .PARM_DATA;
           [otherwise]:
               begin
               $RESPONSE_X (.DB[SB_RESPONSE_PTR],NICE$_PNA,.PARM_NO) ;
               exitloop;
               end;
           tes;

       end;

    REQ[RB_NICE_ENTITY_TYPE] = .ENTITY_TYPE ; ! Restore real entity type

    ch$rchar (.DB[SB_RESPONSE_PTR])
    end;				!End of FETCH_PARAMETERS
%routine ('FILE_CLOSE', FB : ref FILE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description
!
!        This routine closes the file.
!
! Formal parameters
!
!    .FB      Address of the file data block
!
! Implicit inputs: none
!
! Routine value:
!
!    $true    Parameters read from file and put in load data block
!    $false   Failure while reading parameters
!
! Side effects: none
!
!--

    begin
    NMU$FILE_CLOSE (.FB[FB_FILE_HANDLE], .FB[FB_RESPONSE_PTR]);
    $true
    end;				!End of FILE_CLOSE
%routine ('FILE_OPEN', FB : ref FILE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description
!
!        This routine opens the file.
!
! Formal parameters
!
!    .FB      Address of the file data block
!
! Implicit inputs: none
!
! Routine value:
!
!    $true    File opened
!    $false   Open failure - response set
!
! Side effects: none
!
!--

    begin
    local
         FILE_HANDLE;

    FILE_HANDLE = NMU$FILE_OPEN (.FB[FB_FILE_TYPE],
                                 0 %(not required)%,
                                 .FB[FB_FILE],
                                 .FB[FB_RESPONSE_PTR]);

    if .FILE_HANDLE eql 0 then return $false;

    FB[FB_FILE_HANDLE] = .FILE_HANDLE;
    $true
    end;				!End of FILE_OPEN
%routine ('FILE_READ_LABEL', FB : ref FILE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description
!
!        This routine reads the load parameters from a .SYS image
!        file.  When this routine completes (successfully) the
!        file pointer is positioned at the start of the load image.
!
!
! Formal parameters
!
!    .FB      Address of the load data block
!
! Implicit inputs: none
!
! Routine value:
!
!    $true    Parameters read from file and put in load data block
!    $false   Failure while reading parameters
!
! Side effects: none
!
!--

    begin

    local
         BYTE_BUFFER;

!
! Skip to and read the base address where image is to be loaded
!

    if not NMU$FILE_SEEK (.FB[FB_FILE_HANDLE], L$BSA, .FB[FB_RESPONSE_PTR])
    then return $false;

    begin
    local
         PTR;

    PTR = ch$ptr (BYTE_BUFFER,, 8);

    if 0 geq NMU$FILE_READ (.FB[FB_FILE_HANDLE], .PTR, 2, .FB[FB_RESPONSE_PTR])
    then
        begin
        $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_FIO, .FB[FB_FILE_TYPE],
                     'Could not read image file', 119);
        return $false;
        end;

    %movi32 (GETW (PTR), FB[FB_CURRENT_ADDRESS]);
    end;
!
! Skip to and read the number of bytes in the image
!
    if not NMU$FILE_SEEK (.FB[FB_FILE_HANDLE], L$BLDZ, .FB[FB_RESPONSE_PTR])
    then return $false;

    begin
    local
         PTR;

    PTR = ch$ptr (BYTE_BUFFER,, 8);

    if 0 geq NMU$FILE_READ (.FB[FB_FILE_HANDLE], .PTR, 2, .FB[FB_RESPONSE_PTR])
    then
        begin
        $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_FIO, .FB[FB_FILE_TYPE],
                     'Could not read image file', 119);
        return $false;
        end;

    %movi32 (GETW (PTR), FB[FB_BYTES_LEFT]);
    end;
    %asli32 (6, FB[FB_BYTES_LEFT]);
!
! Skip to and read the flags word in the header
!
    if not NMU$FILE_SEEK (.FB[FB_FILE_HANDLE], L$BFLG, .FB[FB_RESPONSE_PTR])
    then return $false;

    begin
    local
         PTR,
         VALUE;

    PTR = ch$ptr (BYTE_BUFFER,, 8);

    if 0 geq NMU$FILE_READ (.FB[FB_FILE_HANDLE], .PTR, 2, .FB[FB_RESPONSE_PTR])
    then
        begin
        $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_FIO, .FB[FB_FILE_TYPE],
                     'Could not read image file', 119);
        return $false;
        end;

    VALUE = GETW (PTR);

    if .VALUE <14, 1> eql 0
    then
        begin
        $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_IFC, .FB[FB_FILE_TYPE],
                   'Header found in image file', 111);
        return $false;
        end;

    end;
!
! Skip to and read the transfer address for the image
!
    if not NMU$FILE_SEEK (.FB[FB_FILE_HANDLE], L$BXFR, .FB[FB_RESPONSE_PTR])
    then return $false;

    begin
    local
         TEMP,
         PTR;

    PTR = ch$ptr (BYTE_BUFFER,, 8);

    if 0 geq NMU$FILE_READ (.FB[FB_FILE_HANDLE], .PTR, 2, .FB[FB_RESPONSE_PTR])
    then
        begin
        $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_FIO, .FB[FB_FILE_TYPE],
                     'Could not read image file', 119);
        return $false;
        end;

    TEMP = GETW (PTR);
    %movt32 (TEMP, FB[FB_TRANSFER_ADDRESS]);
    end;
!
! Skip to and read the block offset to the image in file (512 bytes
! per block).
!
    if not NMU$FILE_SEEK (.FB[FB_FILE_HANDLE], L$BHRB, .FB[FB_RESPONSE_PTR])
    then return $false;

    begin
    local
         PTR;

    PTR = ch$ptr (BYTE_BUFFER,, 8);

    if 0 geq NMU$FILE_READ (.FB[FB_FILE_HANDLE], .PTR, 2, .FB[FB_RESPONSE_PTR])
    then
        begin
        $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_FIO, .FB[FB_FILE_TYPE],
                     'Could not read image file', 119);
        return $false;
        end;

    BYTE_BUFFER = GETW (PTR) * 512;
    end;

    if not NMU$FILE_SEEK (.FB[FB_FILE_HANDLE], .BYTE_BUFFER, .FB[FB_RESPONSE_PTR])
    then return $false;

    $true
    end;				!End of FILE_READ_LABEL
%routine  ('GET_NEXT_PARAMETER', REQ : ref REQUEST_BLOCK, PARM_NO, PARM_DATA) =

!++
! Functional description:
!
!	Obtains the next parameter in the NICE request message.
!
! Formal parameters:
!
!	.REQ		The address of the NML Request Block for this request.
!       .PARM_NO	Address of variable to return parameter number.
!       .PARM_DATA	Address of variable in which to return parameter data.
!
! Implicit inputs:
!
!	.REQ [RB_NICE_PARAMETERS]	Contains a pointer to the previous
!				 	 parameter.
!       .REQ [RB_NICE_PARAMETER_LENGTH]	Contains the length of the previous
!					 parameter in bytes.
!
! Routine value:
!
!	$true, if the next parameter exists.
!       $false, otherwise.
!
! Side effects: none
!
!--

    begin

    local
         PARM_PTR ;                     ! Pointer to NICE parameter

    REQ[RB_NICE_PARAMETERS] = ch$plus (.REQ[RB_NICE_PARAMETERS],
                                       .REQ[RB_NICE_PARAMETER_LENGTH]) ;

    !
    ! Return false when all parameters have been processed.
    !

    if ch$diff (.REQ[RB_NICE_PARAMETERS],.REQ[RB_NICE_POINTER]) geq .REQ[RB_NICE_LENGTH]
    then begin
         REQ[RB_NICE_PARAMETER_LENGTH] = 0 ;
         return $false;
         end;

    !
    ! Get length of the parameter, to include the data portion plus
    ! two bytes for the DATA ID field.
    !

    PARM_PTR = .REQ[RB_NICE_PARAMETERS] ; ! Make copy of pointer
    .PARM_NO = GETW (PARM_PTR) ;         ! Get parameter number
    REQ[RB_NICE_PARAMETER_LENGTH] = NML$PARAMETER_DATA (.REQ[RB_NICE_ENTITY_TYPE],
                                                        ..PARM_NO,
                                                        PARM_PTR,
                                                        .PARM_DATA) + 2 ;

    !
    ! If this parameter is a qualifier, then call ourself recursively
    ! to skip over the qualifier to the next real parameter.
    !

    if .REQ[RB_NICE_PARAMETERS] eql .REQ[RB_NICE_QUALIFIER]
    then return GET_NEXT_PARAMETER (.REQ, .PARM_NO, .PARM_DATA);

    return $true

    end;				!End of GET_NEXT_PARAMETER
%routine ('IMAGE_LOAD', DATA : ref SERVICE_DATA_BLOCK, FILE_TYPE, FILE) : NML_LKG_DB =

!++
! Functional description:
!
!	This routine is called by the LOAD_NODE routine to perform
!	a core image transfer TO a target node.  The images that
!	this routine sends are for either a TERTIARY LOADER or
!	SYSTEM IMAGE.
!
! Formal parameters
!
!	.DATA           Address of load data block
!       .FILE_TYPE      Type of file for error response
!       .FILE           Pointer to ASCIZ file name
!
! Implicit inputs: none
!
! Routine value:
!
!	$true	image was sent to node successfully
!	$false	failure while sending image
!
! Side effects: none
!
!--

    begin
    macro
         ABORT (FB) =
             begin
             FILE_CLOSE (FB);
             return $false
             end %;

    local
         FB : FILE_DATA_BLOCK,
         TARGET_NAME,
         TARGET_NUMBER;

!
! Get the needed information for the load
!
    FB[FB_RESPONSE_PTR] = .DATA [SB_RESPONSE_PTR];
    FB[FB_FILE_TYPE] = .FILE_TYPE;
    FB[FB_FILE] = .FILE;

    if not CPU_IS_PDP11 (.DATA) then return $false;

    if (TARGET_NUMBER = .DATA [LB_ADDRESS]) eql 0
    then
        TARGET_NUMBER =  .DATA [SB_NODE_DATA];

    if (TARGET_NAME = .DATA [LB_NAME]) eql 0
    then
        TARGET_NAME = ch$plus (.DATA [SB_NODE_DATA],2)
    else
        TARGET_NAME = ch$plus (.TARGET_NAME,2);

    begin
    local PTR, TEMP;

    PTR = ch$ptr (DATA [LB_HOST],, 8);
    if (ch$rchar_a (PTR) eqlu 0) and
       (ch$rchar_a (PTR) eqlu 0) and
       (ch$rchar_a (PTR) eqlu 0)
    then
        if NML$GET_VDB_PARAMETER (NODE_E, .DATA [SB_NODE_DATA],
                                  140, TEMP)
        then
            begin
            PTR = .TEMP;                ! (for optimization)
            ch$move (ch$rchar (ch$plus (.PTR, 2)) + 3, .PTR, ch$ptr (DATA [LB_HOST],, 8));
            end;

    TEMP = NODE_ID_BUFFER_LENGTH;
    $NML$MAP_NODE_ID (TEMP, ch$ptr (DATA [LB_HOST],, 8));

    PTR = ch$ptr (DATA [LB_HOST],, 8);
    if (ch$rchar_a (PTR) eqlu 0) and
       (ch$rchar_a (PTR) eqlu 0)
    then
        begin
        PTR = NMU$NETWORK_LOCAL();
        ch$move (ch$rchar (ch$plus (.PTR, 2)) + 3, .PTR, ch$ptr (DATA [LB_HOST],, 8));
        end;

    end;

!
! Open the image file.
!

    if not FILE_OPEN (FB) then return $false;

!
! Read the image base address, size of image and transfer address.
! If anything looks wrong .. make the load fail.
!

    if not FILE_READ_LABEL (FB) then ABORT (FB);

    begin
    local
        LOAD_NUMBER;

!
! Send the image file to the target system.
! If no failure occured then start the program just
! loaded.
!

    begin
    local
        LENGTH;

!
! Start at the beginning of the load.
!
    LOAD_NUMBER = 0;
    LENGTH = 0;
!
! Loop reading from the image file and passing it on
! to the target system.
!
    until %cmpi32 (FB[FB_BYTES_LEFT], leq, 0) do
	begin

!
! Read in the next load message if the load number has
! been incremented.
!
	if .LENGTH eql 0
	then
	    begin
            local
                 BUFFER_PTR;

            BUFFER_PTR = .DATA [SB_BUFFER_PTR];
            PUTB (LOAD_WITHOUT_TRANSFER, BUFFER_PTR);
            PUTB (.LOAD_NUMBER, BUFFER_PTR);
            PUT32 (FB[FB_CURRENT_ADDRESS], BUFFER_PTR);
            LENGTH = MOP_LOAD_DATA_LENGTH;

            if %cmpi32 (FB[FB_BYTES_LEFT], leq, .LENGTH)
            then %movf32 (FB[FB_BYTES_LEFT], LENGTH);

	    if 0 geq NMU$FILE_READ (.FB[FB_FILE_HANDLE], .BUFFER_PTR,
                                    .LENGTH, .FB[FB_RESPONSE_PTR])
	    then begin
                 $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_FIO, .FB[FB_FILE_TYPE],
                              'Could not read image file', 119);
                 ABORT (FB);
                 end;

            %addi32 (.LENGTH, FB[FB_CURRENT_ADDRESS]);
            LENGTH = .LENGTH + 6;
	    end;

        %(do a $NMU_DLX_WRITE_READ)%
!
! Write the load memory message to the target node, and read the
! acknowledgement.  Retransmit until the proper message has been
! acknowledged.
!
        begin
        local RESULT;
        decru TIMES from NMU$K_MOP_RETRY_LIMIT to 1 do
            begin
	    if not $NMU_DLX_WRITE (.DATA [SB_CIRCUIT_HANDLE], DLX_DATA,
                                .DATA [SB_BUFFER_PTR], .LENGTH,
                                .DATA [SB_RESPONSE_PTR])
            then exitloop RESULT = -1;

            RESULT = $NMU_DLX_READ (.DATA [SB_CIRCUIT_HANDLE], DLX_DATA,
                               .DATA [SB_BUFFER_PTR], MOP_BUFFER_LENGTH,,
                               .DATA [SB_RESPONSE_PTR]);
            if .RESULT neq -2 then exitloop;
            end;

        if .RESULT lss 0
        then
            begin
            $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_LCE);
            ABORT (FB);
            end;
        end;
!
! If a request for the next memory load comes in, then setup
! the memory load number.  Otherwise make the load fail.
!
        begin
        local
             BUFFER_PTR;

	BUFFER_PTR = .DATA [SB_BUFFER_PTR];

	selectone GETB (BUFFER_PTR) of
	    set

	    [REQUEST_MEMORY_LOAD] :
                begin
                local
                     LOADNUM;

		LOADNUM = GETB (BUFFER_PTR);

                if .LOADNUM neq .LOAD_NUMBER
                then
                    begin
                    LOAD_NUMBER = (.LOAD_NUMBER + 1) and %o'377';

                    if .LOADNUM neq .LOAD_NUMBER
                    then
                        begin
                        $RESPONSE_X (.DATA [SB_RESPONSE_PTR], NICE$_LPE, 0,
                                     'Invalid load number requested', 108);
                        ABORT (FB);
                        end;

                    end;

                %subi32 ((.LENGTH-6), FB[FB_BYTES_LEFT]);
                LENGTH = 0;
                end;
	    [otherwise] :
		begin
		$RESPONSE_X (.DATA [SB_RESPONSE_PTR], NICE$_LPE, 0,
                           'Invalid MOP response to MEMORY LOAD', 109);
		ABORT (FB);
		end;
	    tes;

        end;
	end;

    end;
    FILE_CLOSE (FB);
!
! Okay, image loaded. Now give him the parameters and start him up.
!
    begin
    local
         BUFFER_PTR, LENGTH;

    BUFFER_PTR = .DATA [SB_BUFFER_PTR];
    !
    ! Put "parameters with transfer" MOP message code
    ! and the load number into MOP buffer.
    !
    PUTB (PARAMETERS_WITH_TRANSFER, BUFFER_PTR);

    PUTB (.LOAD_NUMBER, BUFFER_PTR);

    PUTB (2, BUFFER_PTR);           ! Target node number
    PUTB (2, BUFFER_PTR);
    PUTB (GETB (TARGET_NUMBER), BUFFER_PTR);
    PUTB (GETB (TARGET_NUMBER), BUFFER_PTR);

    if (LENGTH = GETB (TARGET_NAME)) neq 0
    then
        begin
        PUTB (1, BUFFER_PTR);       ! Target node name
        PUTB (.LENGTH, BUFFER_PTR);
        BUFFER_PTR = ch$move (.LENGTH, .TARGET_NAME, .BUFFER_PTR);
        end;

    if (LENGTH = ch$rchar (ch$ptr (DATA [LB_HOST], 2, 8))) neq 0
    then
        begin
        PUTB (3, BUFFER_PTR);       ! Host node name
        PUTB (.LENGTH, BUFFER_PTR);
        BUFFER_PTR = ch$move (.LENGTH, ch$ptr (DATA [LB_HOST], 3, 8), .BUFFER_PTR);
        end;

    PUTB (4, BUFFER_PTR);           ! Host node number
    PUTB (2, BUFFER_PTR);
    PUTB (ch$rchar (ch$ptr (DATA [LB_HOST], 0, 8)), BUFFER_PTR);
    PUTB (ch$rchar (ch$ptr (DATA [LB_HOST], 1, 8)), BUFFER_PTR);

    PUTB (0, BUFFER_PTR);           ! End of parameters

    PUT32 (FB[FB_TRANSFER_ADDRESS], BUFFER_PTR);

    BUFFER_PTR = ch$diff (.BUFFER_PTR, .DATA [SB_BUFFER_PTR]);

    if not $NMU_DLX_WRITE (.DATA [SB_CIRCUIT_HANDLE], DLX_DATA,
                            .DATA [SB_BUFFER_PTR], .BUFFER_PTR,
                            .DATA [SB_RESPONSE_PTR])
    then return $false;

    end;
    end;
    $true
    end;
%routine ('LOAD_NODE', LOAD_DATA : ref SERVICE_DATA_BLOCK) : NML_LKG_DB novalue =

!++
! Functional description:
!
!	This routine is called after the NICE request message
!	has been decomposed.  It performs the actual load
!	sequence by transferring MOP messages across the specified
!	circuit with the target node.
!
! Formal parameters:
!
!	.LOAD_DATA	Address of load data block
!
!		Necessary parameters (must be specified in request or on VDB):
!
!		Parameter	Name
!		---------	----
!
!			(one of):
!
!		121		Secondary Loader ID
!		122		Tertiary Loader ID
!		120		Load File ID
!
!		Parameters that may be defaulted:
!
!		Parameter	Name		Default Value
!		---------	----		-------------
!
!		125		Software Type	SECONDARY_LOADER
!
! Implicit inputs: none
!
! Routine value: none
! Side effects: none
!
!--

    begin
    local
        RETURN_CODE,
        CURRENT_LOAD;

!
! Setup the initial load file type. Default to secondary loader.
!

    begin
    local
         SOFTWARE_TYPE;
    bind
         PARAMETER_TO_GET = uplit (121,122,120): vector;
    local
         WHERE_TO_PUT_IT: vector[3];
    WHERE_TO_PUT_IT[0] = LOAD_DATA[LB_SECONDARY_LOADER];
    WHERE_TO_PUT_IT[1] = LOAD_DATA[LB_TERTIARY_LOADER];
    WHERE_TO_PUT_IT[2] = LOAD_DATA[LB_LOAD_FILE];

!
! If any important parameters haven't been specified in the request,
! try to obtain them from the data base.
!

    incr I from 0 to 2 do
        if ..WHERE_TO_PUT_IT[.I] eql 0
        then
            NML$GET_VDB_PARAMETER (NODE_E,
                                   .LOAD_DATA [SB_NODE_DATA],
                                   .PARAMETER_TO_GET[.I],
                                   .WHERE_TO_PUT_IT[.I]);

    if (SOFTWARE_TYPE = .LOAD_DATA [LB_SOFTWARE_TYPE]) eql -1
    then

        if not NML$GET_VDB_PARAMETER (NODE_E,
                                      .LOAD_DATA [SB_NODE_DATA],
                                       125,
                                       SOFTWARE_TYPE)
        then
            SOFTWARE_TYPE = SECONDARY_LOADER;


    CURRENT_LOAD = .SOFTWARE_TYPE;
    end;

!
! Load until one of the load routines indicates the loading
! has stopped. CURRENT_LOAD must never be -1 upon entry to this
! section of the code.
!

    RETURN_CODE = -1;

    while $true do
	begin

        !
        ! Convert from a MOP program type to a internal
        ! file type code
        !

        if not
           begin
           case .CURRENT_LOAD from -1 to 3 of
               set
               [-1] : ! Leave CURRENT_LOAD as is, allow loop on $NMU_DLX_READ
                   $true;
               [SECONDARY_LOADER] :
                   if .LOAD_DATA[LB_SECONDARY_LOADER] neq 0
                   then
                       SECONDARY_LOAD (.LOAD_DATA, FILE_SECONDARY_LOADER,
                                   .LOAD_DATA [LB_SECONDARY_LOADER])
                   else
                       (RETURN_CODE = .CURRENT_LOAD; $false);
               [TERTIARY_LOADER] :
                   if .LOAD_DATA[LB_TERTIARY_LOADER] neq 0
                   then
                       IMAGE_LOAD (.LOAD_DATA, FILE_TERTIARY_LOADER,
                               .LOAD_DATA [LB_TERTIARY_LOADER])
                   else
                       (RETURN_CODE = .CURRENT_LOAD; $false);
               [SYSTEM_IMAGE] :
                   if .LOAD_DATA[LB_LOAD_FILE] neq 0
                   then
                       IMAGE_LOAD (.LOAD_DATA, FILE_SYSTEM_IMAGE,
                               .LOAD_DATA [LB_LOAD_FILE])
                   else
                       (RETURN_CODE = .CURRENT_LOAD; $false);
               [inrange, outrange] :
                   begin
                   $RESPONSE_X (.LOAD_DATA [SB_RESPONSE_PTR], NICE$_MPE, 0,
                                'SOFTWARE TYPE parameter invalid', 105);
                   $false
                   end;
               tes
           end
        then
            exitloop;

        !
        ! Read the response from the load.
        !

	if $NMU_DLX_READ (.LOAD_DATA [SB_CIRCUIT_HANDLE], DLX_DATA,
                          .LOAD_DATA [SB_BUFFER_PTR], MOP_BUFFER_LENGTH,
                          60, %(give it 60 seconds)%
                          .LOAD_DATA [SB_RESPONSE_PTR]) leq 0
	then exitloop;

        !
        ! Get the function code from the response message.
        ! If it is a request program load .. go load the appropriate
        ! image.  If it is a request memory load .. it was a successful
        ! load.  If anything else .. who knows what happened (assume it
        ! was died).
        !

        begin
        local
             BUFFER_PTR,
             MOP_FUNCTION;

	BUFFER_PTR = .LOAD_DATA [SB_BUFFER_PTR];
	MOP_FUNCTION = GETB (BUFFER_PTR);

	selectone .MOP_FUNCTION of
	    set
	    [REQUEST_PROGRAM] :
		begin
		BUFFER_PTR = ch$plus (.BUFFER_PTR, 2);
		CURRENT_LOAD = GETB (BUFFER_PTR);
		end;
	    [REQUEST_MEMORY_LOAD] :
		begin
		$RESPONSE (.LOAD_DATA [SB_RESPONSE_PTR], NICE$_SUC);
                exitloop;
		end;
            [CHK11_ASCII_TEXT] :
                begin
                CURRENT_LOAD = -1;
                end;
	    [otherwise] :
		begin
		$RESPONSE_X (.LOAD_DATA [SB_RESPONSE_PTR], NICE$_LPE, 0,
                             'Unexpected MOP response, MOP function code = %D', .MOP_FUNCTION, .MOP_FUNCTION);
%(
  'Unexpected MOP response, expecting program request', 106);
)%
                exitloop;
		end;
	    tes;

        end;
	end;

!
! If we fell out due to a request for a software type we don't have
! a parameter for, record an error.
!

    if .RETURN_CODE geq 0 then
       $RESPONSE_X (.LOAD_DATA[SB_RESPONSE_PTR], NICE$_IPV,
           (case .RETURN_CODE from SECONDARY_LOADER to SYSTEM_IMAGE of
               set
               [SECONDARY_LOADER]:     121;
               [TERTIARY_LOADER]:      122;
               [SYSTEM_IMAGE]:         120;
           tes), 'File not specified');

    end;
%routine ('SECONDARY_LOAD', LOAD_DATA : ref SERVICE_DATA_BLOCK, FILE_TYPE, FILE) : NML_LKG_DB =

!++
! Functional description:
!
!	This routine sends a SECONDARY LOADER to the target node.
!	The whole loader is sent in one MEMORY LOAD WITH TRANSFER ADDRESS
!	MOP message.
!
! Formal parameters
!
!	.LOAD_DATA	Address of load data block
!       .FILE_TYPE      Type of file for error response
!       .FILE           Pointer to ASCIZ file name
!
! Implicit inputs: none
!
! Routine value:
!
!	$true	secondary boot was transmitted
!	$false	failure occured while sending boot
!
! Side effects: none
!
!--

    begin
    macro
         ABORT (FB) =
             begin
             FILE_CLOSE (FB);
             return $false
             end %;

    local
        FB : FILE_DATA_BLOCK;

    FB[FB_RESPONSE_PTR] = .LOAD_DATA [SB_RESPONSE_PTR];
    FB[FB_FILE_TYPE] = .FILE_TYPE;
    FB[FB_FILE] = .FILE;

    if not CPU_IS_PDP11 (.LOAD_DATA) then return $false;

!
! Open the secondary loader file.
!

    if not FILE_OPEN (FB) then return $false;

!
! Read the image base address, size of image and transfer address.
!

    if not FILE_READ_LABEL (FB) then ABORT (FB);

    if %cmpi32 (FB[FB_BYTES_LEFT], gtr, 512)
    then
        begin
        $RESPONSE_X (.LOAD_DATA [SB_RESPONSE_PTR], NICE$_IFC, .FB[FB_FILE_TYPE],
                   'Secondary image is too large, >512 bytes', 110);
        ABORT (FB);
        end;

    begin
    local
        BUFFER_PTR;

!
! Make a pointer to the buffer used to construct MOP messages.
!
    BUFFER_PTR = .LOAD_DATA [SB_BUFFER_PTR];
!
! Put in the header information for a "load memory with transfer address"
! Function, load number 0, load address
!
    PUTB (LOAD_WITH_TRANSFER, BUFFER_PTR);
    PUTB (0, BUFFER_PTR);
    PUT32 (FB[FB_CURRENT_ADDRESS], BUFFER_PTR);

!
! Put in the secondary image
!
    begin
    local
         LENGTH;

    %movf32 (FB[FB_BYTES_LEFT], LENGTH);

    if 0 geq (LENGTH = NMU$FILE_READ (.FB[FB_FILE_HANDLE], .BUFFER_PTR,
                                      .LENGTH, .FB[FB_RESPONSE_PTR]))
    then
        begin
        $RESPONSE_X (.FB[FB_RESPONSE_PTR], NICE$_FIO, .FB[FB_FILE_TYPE],
                     'Could not read image file', 119);
        ABORT (FB);
        end;

    BUFFER_PTR = ch$plus (.BUFFER_PTR, .LENGTH);
    end;
!
! Put in the transfer address of the secondary boot
!

    PUT32 (FB[FB_TRANSFER_ADDRESS], BUFFER_PTR);

!
! Send the boot to the target node.
!

    BUFFER_PTR = ch$diff (.BUFFER_PTR, .LOAD_DATA [SB_BUFFER_PTR]);

    if not $NMU_DLX_WRITE (.LOAD_DATA [SB_CIRCUIT_HANDLE], DLX_SECONDARY,
                            .LOAD_DATA [SB_BUFFER_PTR], .BUFFER_PTR,
                            .LOAD_DATA [SB_RESPONSE_PTR])
    then ABORT (FB);

    %(Should we do a read also ?)%
    end;
!
! Return indicating that the load has been sent.
!
    FILE_CLOSE (FB);
    $true
    end;
%routine ('SET_SUBSTATE', SB : ref SERVICE_DATA_BLOCK) : NML_LKG_DB novalue =

!++
! Functional description:
!
!        Set the substate for a given circuit.
!
! Formal parameters:
!
!    .DATA    Address of trigger data block
!
! Implicit inputs: none
!
! Routine value: none
! Side effects: none
!
!--

    begin

    if .SB[SB_SUBSTATE] geq 0
    then NML$SET_VDB_PARAMETER (CIRCUIT_, .SB[SB_SERVICE_CIRCUIT],
                                CPARM_SUBSTATE, %ref (.SB[SB_SUBSTATE]))
    else NML$CLR_VDB_PARAMETER (CIRCUIT_, .SB[SB_SERVICE_CIRCUIT],
                                CPARM_SUBSTATE);

    end;				!End of SET_SUBSTATE
%routine ('TRIGGER_NODE', DATA : ref SERVICE_DATA_BLOCK) : NML_LKG_DB =

!++
! Functional description:
!
!        This routine is called after the NICE request message has been
!        decomposed.  It performs the bootstrap ROM trigger function
!        on a target node.
!
! Formal parameters:
!
!    .DATA    Address of trigger data block
!
! Implicit inputs: none
!
! Routine value: none
! Side effects: none
!
!--

    begin
    local
         SERVICE_PASSWORD;

    if (SERVICE_PASSWORD = .DATA [SB_SERVICE_PASSWORD]) eql 0
    then
        begin
        SERVICE_PASSWORD = ch$plus (.DATA [SB_BUFFER_PTR], 5);
        if not NML$GET_VDB_PARAMETER (NODE_E,
                                      .DATA [SB_NODE_DATA],
                                       111,
                                       .SERVICE_PASSWORD)
        then
            begin
            $RESPONSE (.DATA [SB_RESPONSE_PTR], NICE$_PAM, 111);
            return $false;
            end;
        end;

    begin
    local
         PASSWORD_PTR,
         BUFFER_PTR;

    BUFFER_PTR = .DATA [SB_BUFFER_PTR];
    PASSWORD_PTR = .SERVICE_PASSWORD;

    PUTB (ENTER_MOP_MODE, BUFFER_PTR);

    decr COUNT from 4 to 1 do
        PUTB (GETB (PASSWORD_PTR), BUFFER_PTR);

    decr COUNT from 4 to 1 do
        if GETB (PASSWORD_PTR) neq 0
        then
            begin
            $RESPONSE (.DATA [SB_RESPONSE_PTR], NICE$_IPV, 111);
            return $false;
            end;

    end;

    if not $NMU_DLX_WRITE (.DATA [SB_CIRCUIT_HANDLE], DLX_DATA,
                      .DATA [SB_BUFFER_PTR], 5,
                      .DATA [SB_RESPONSE_PTR])
    then
        begin
        $RESPONSE (.DATA [SB_RESPONSE_PTR], NICE$_LCE);
        return $false;
        end;

    $RESPONSE (.DATA [SB_RESPONSE_PTR], NICE$_SUC);
    $true
    end;				!End of TRIGGER_NODE

end				!End of Module NMLDTL
eludom
! Local Modes:
! Mode:BLISS
! Auto Save Mode:2
! Comment Column:40
! Comment Rounding:+1
! End: