?? LEFT := 1, RIGHT := 110 ??
MODULE nam$independent_init_manager;

{ PURPOSE: This module implements the Independent Initialization Management
{          entity as defined by the CDNA GDS. It provides dumping and loading
{          support for network systems that are not capable of performing these
{          functions by themselves.
{
{ DESIGN:  The initialization protocol is processed using an event driven
{          finite state machine. Two kinds of events are defined: reception of
{          data units from remote systems and expired timers. When an event
{          occurs, it is examined to determine the condition that exists for
{          the specified remote system. A table indexed by this condition
{          and the current state of the remote system is then used to determine
{          the new state of the system and the processor that handles this
{          condition.
{
{          Timers are maintained internally by periodically interrogating the
{          system clock.
{
{          The following table defines the finite state machine:
{
{              |  UNKNOWN |  HELP    |   DUMP   |  DUMPING  |   DUMP    |  LOADING  |   LOAD    | INACTIVE |
{              |          | OFFERED  | INITIATED|           |  ABORTED  |           | COMPLETE  |          |
{              |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ CHECKSUM     |    LOG   |          |          |           |           |           |           |          |
{ ERROR        |AND DELETE|   LOG    |    LOG   |    LOG    |    LOG    |    LOG    |    LOG    |    LOG   |
{              |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ UNKNOWN OR   |    LOG   |          |          |           |           |           |           |          |
{ SHORT PDU    |AND DELETE|   LOG    |    LOG   |    LOG    |    LOG    |    LOG    |    LOG    |    LOG   |
{              |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ HELP REQUEST |    LOG   |   LOG    |    LOG   | TRUNCATE  | TRUNCATE  | TRUNCATE  | TRUNCATE  |    LOG   |
{ FROM EXCLUDED|AND DELETE|AND DELETE|AND DELETE|DUMP&DELETE|DUMP&DELETE|LOAD&DELETE|LOAD&DELETE|AND DELETE|
{ SYSTEM       |    (1)   |   (1)    |    (1)   |    (1)    |    (1)    |    (1)    |    (1)    |    (1)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ HELP REQUEST |    LOG   |   LOG    |    LOG   | TRUNCATE  | TRUNCATE  | TRUNCATE  | TRUNCATE  |    LOG   |
{ DEVICE NOT   |AND DELETE|AND DELETE|AND DELETE|DUMP&DELETE|DUMP&DELETE|LOAD&DELETE|LOAD&DELETE|AND DELETE|
{ SUPPORTED    |    (1)   |   (1)    |    (1)   |    (1)    |    (1)    |    (1)    |    (1)    |    (1)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ HELP REQUEST |          |          |          |TRUNC DUMP |TRUNC DUMP |TRUNC LOAD |TRUNC LOAD |          |
{ NO MORE      |  DELETE  |INACTIVATE|INACTIVATE|&INACTIVATE|&INACTIVATE|&INACTIVATE|&INACTIVATE|    LOG   |
{ RETRIES      |    (1)   |   (8)    |    (8)   |    (8)    |    (8)    |    (8)    |    (8)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ HELP REQUEST |  OFFER   |  OFFER   |  OFFER   | TRUNCATE  | TRUNCATE  | TRUNCATE  | TRUNCATE  |  OFFER   |
{ MORE RETRIES |   HELP   |   HELP   |   HELP   |DUMP & HELP|DUMP & HELP|LOAD & HELP|LOAD & HELP|   HELP   |
{              |    (2)   |   (2)    |    (2)   |    (2)    |    (2)    |    (2)    |    (2)    |    (2)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ HELP ACCEPT  |    LOG   | INITIATE |   START  |           |           |           |           |          |
{ WITH DUMP    |AND DELETE|   HELP   |   DUMP   |    LOG    |    LOG    |    LOG    |    LOG    |    LOG   |
{              |    (1)   |   (3)    |    (3)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ HELP ACCEPT  |    LOG   | INITIATE |          |           |           |   START   |   START   |          |
{ WITHOUT DUMP |AND DELETE|   HELP   |  IGNORE  |  IGNORE   |  IGNORE   |   LOAD    |   LOAD    |    LOG   |
{              |    (1)   |   (6)    |    (3)   |    (4)    |    (5)    |    (6)    |    (6)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ EXCESSIVE    |          |          |   ABORT  |   ABORT   |           |           |           |          |
{ DUMP DATA    |  DELETE  | IGNORE   |   DUMP   |   DUMP    |  IGNORE   |  IGNORE   |  IGNORE   |  IGNORE  |
{              |    (1)   |   (2)    |    (5)   |    (5)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ DUMP DATA IN |          |          | SAVE DUMP| SAVE DUMP |           |           |           |          |
{ SEQUENCE     |  DELETE  | IGNORE   |   DATA   |   DATA    |  IGNORE   |  IGNORE   |  IGNORE   |  IGNORE  |
{              |    (1)   |   (2)    |    (4)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ DUMP DATA LOW|          |          |          |           |           |           |           |          |
{ SEQUENCE     |  DELETE  | IGNORE   |  IGNORE  |  IGNORE   |  IGNORE   |  IGNORE   |  IGNORE   |  IGNORE  |
{              |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ DUMP DATA    |          |          |   START  |  RESYNC   |           |           |           |          |
{ HIGH SEQUENCE|  DELETE  | IGNORE   |   DUMP   |   DUMP    |  IGNORE   |  IGNORE   |  IGNORE   |  IGNORE  |
{ TRY RESYNC   |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ DUMP DATA    |          |          |          |           |           |           |           |          |
{ HIGH SEQUENCE|  DELETE  | IGNORE   |  IGNORE  |  IGNORE   |  IGNORE   |  IGNORE   |  IGNORE   |  IGNORE  |
{ RESYNC SENT  |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ TERM DUMP IN |          |          | END DUMP | END DUMP  | END DUMP  |           |           |          |
{ SEQUENCE OR  |  DELETE  | IGNORE   |START LOAD|START LOAD |START LOAD |  IGNORE   |START LOAD |  IGNORE  |
{ ABNORMAL     |    (1)   |   (2)    |    (6)   |    (6)    |    (6)    |    (6)    |    (6)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ TERM DUMP BAD|          |          |  START   |  RESYNC   | END DUMP  |           |           |          |
{ SEQUENCE TRY |  DELETE  | IGNORE   |   DUMP   |   DUMP    |START LOAD |  IGNORE   |START LOAD |  IGNORE  |
{ RESYNC       |    (1)   |   (2)    |    (3)   |    (4)    |    (6)    |    (6)    |    (6)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ TERM DUMP BAD|          |          |          |           | END DUMP  |           |           |          |
{ SEQUENCE     |  DELETE  | IGNORE   |  IGNORE  |  IGNORE   |START LOAD |  IGNORE   |START LOAD |  IGNORE  |
{ RESYNC SENT  |    (1)   |   (2)    |    (3)   |    (4)    |    (6)    |    (6)    |    (6)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ SYNC LOAD BAD|          |          |          |           |           |           |           |          |
{ SEQUENCE     |  DELETE  |   LOG    |    LOG   |    LOG    |    LOG    |    LOG    |    LOG    |    LOG   |
{              |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (6)    |    (7)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ SYNC LOAD    |          |          |          |           |           |  RESYNC   |  RESYNC   |          |
{ MORE RETRIES |  DELETE  |   LOG    |    LOG   |    LOG    |    LOG    |   LOAD    |   LOAD    |    LOG   |
{              |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (6)    |    (6)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ SYNC LOAD NO |          |          |          |           |           |           |           |          |
{ MORE RETRIES |  DELETE  |   LOG    |    LOG   |    LOG    |    LOG    |ABORT LOAD |ABORT LOAD |    LOG   |
{              |    (1)   |   (2)    |    (3)   |    (4)    |    (5)    |    (8)    |    (8)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ TIMER EXPIRED|          |          |  START   |  RESYNC   |   ABORT   | SEND LOAD |           |          |
{ MORE RETRIES |  DELETE  |INACTIVATE|   DUMP   |   DUMP    |   DUMP    |   DATA    | INACTIVATE|INACTIVATE|
{              |    (1)   |   (8)    |    (3)   |    (4)    |    (5)    |    (6)    |    (8)    |    (8)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+
{ TIMER EXPIRED|          |          |   ABORT  |   ABORT   |           | TERMINATE |           |          |
{ NO MORE      |  DELETE  |INACTIVATE|   DUMP   |   DUMP    |INACTIVATE |   LOAD    | INACTIVATE|  DELETE  |
{ RETRIES      |    (1)   |   (8)    |    (5)   |    (5)    |    (8)    |    (7)    |    (8)    |    (1)   |
{ -------------+----------+----------+----------+-----------+-----------+-----------+-----------+----------+

?? PUSH (LISTEXT := ON) ??
*copyc llt$transfer_symbol
*copyc llt$load_module
*copyc nae$initialization_me
*copyc nae$namve_conditions
*copyc nat$init_me_directives
*copyc nat$object_code_version
*copyc nat$data_fragments
*copyc nat$checksum
*copyc nat$network_address
*copyc nat$cn_interface
*copyc amt$file_identifier
*copyc ost$status
*copyc ost$status_message
*copyc ost$status_message_line_size
*copyc ost$status_message_line_count
*copyc ost$status_message_line
*copyc pmt$condition
*copyc pmt$established_handler
*copyc clt$value
?? POP ??
?? TITLE := 'Initialization protocol definitions' ??

  TYPE
    nit$system_type = 0 .. 0f(16);

  CONST
    di_system = 1,
    ica2_system = 2;

  CONST
    load_pdu_block_count = 2 {10} {count of load pdus sent per timer interval} ;

  TYPE
    nit$data_unit_id = 0 .. 0ff(16);

  CONST
    help_request_id = 11(16),
    help_offer_id = 12(16),
    help_accept_id = 13(16),
    begin_auto_dump_id = 20(16),
    dump_data_id = 22(16),
    synchronize_dump_id = 23(16),
    terminate_dump_id = 25(16),
    abort_dump_id = 26(16),
    load_data_id = 30(16),
    synchronize_load_id = 31(16);

  TYPE
    nit$request_flags = packed record
      system_type: nit$system_type,
      auto_dump: boolean,
      directed_dump: boolean,
      previous_load_specified: boolean,
      reserved: 0 .. 1,
    recend;

  TYPE
    nit$reset_code = packed record
      code: 0 .. nac$max_di_reset_code,
    recend;

  CONST
    power_up_reset = 0,
    manual_reset = 2,
    halt_memory_fault = 3,
    dead_man_timeout = 4,
    memory_too_small = 10(16),
    improper_first_module = 11(16),
    unsatisfied_external = 12(16),
    missing_module = 13(16),
    missing_configuration = 14(16);

  TYPE
    nit$board_definition = 0 .. 0ffffffff(16);

  TYPE
    nit$service_definition = packed record
      priority: nit$service_priority,
      reserved: 0 .. 3f(16),
    recend,
    nit$service_priority = 0 .. 3;

  TYPE
    nit$dump_flow_control = 0 .. 0ff(16);

  TYPE
    nit$sequence_number = 0 .. 0ffff(16);

  TYPE
    nit$resync_info = SEQ (REP 1 of integer);

  TYPE
    nit$dump_termination_code = 0 .. 0ff(16);

  CONST
    normal_dump_termination = 0,
    dump_abort_received = 1,
    dump_memory_error = 2;

  TYPE
    nit$load_flags = packed record
      last_data_unit: boolean,
      reserved: 0 .. 7f(16),
    recend;

  TYPE
    nit$synchronize_load_flags = packed record
      overflow: boolean,
      reserved: 0 .. 7f(16),
    recend;

  TYPE
    nit$pdu = ^SEQ ( * );

  TYPE
    nit$help_request_data_unit = record
      identifier: nit$data_unit_id,
      flags: nit$request_flags,
      requesting_system_id: nat$system_identifier,
      boot_card: nat$card_type,
      reset_code: nit$reset_code,
      last_version_number: nat$object_code_version,
      last_network_id: nat$network_identifier,
      last_system_id: nat$system_identifier,
      {board_definitions: array [ * ] of nit$board_definition,
    recend;

  TYPE
    nit$help_offer_data_unit = record
      identifier: nit$data_unit_id,
      service_definition: nit$service_definition,
      version_number: nat$object_code_version,
      network_id: nat$network_identifier,
      host_system_id: nat$system_identifier,
    recend;

  TYPE
    nit$help_accept_data_unit = record
      identifier: nit$data_unit_id,
      reserved: 0 .. 0ff(16),
    recend;

  TYPE
    nit$auto_dump_data_unit = record
      identifier: nit$data_unit_id,
      flow_control: nit$dump_flow_control,
      max_data_length: 0 .. 0ffff(16),
    recend;

  TYPE
    nit$dump_data_unit = record
      identifier: nit$data_unit_id,
      flags: 0 .. 0ff(16),
      sequence_number: nit$sequence_number,
      save_area: nit$resync_info,
      {data: SEQ ( * ),
    recend;

  TYPE
    nit$synchronize_dump_data_unit = record
      identifier: nit$data_unit_id,
      reserved: 0 .. 0ff(16),
      sequence_number: nit$sequence_number,
      save_area: nit$resync_info,
    recend;

  TYPE
    nit$term_dump_data_unit = record
      identifier: nit$data_unit_id,
      code: nit$dump_termination_code,
      sequence_number: nit$sequence_number,
      error_address: 0 .. 0ffffffff(16),
    recend;

  TYPE
    nit$abort_dump_data_unit = record
      identifier: nit$data_unit_id,
      reserved: 0 .. 0ff(16),
    recend;

  TYPE
    nit$load_data_unit = record
      identifier: nit$data_unit_id,
      flags: nit$load_flags,
      sequence_number: nit$sequence_number,
      save_area: nit$resync_info,
     {data: SEQ ( * ),
    recend;

  TYPE
    nit$synchronize_load_data_unit = record
      identifier: nit$data_unit_id,
      flags: nit$synchronize_load_flags,
      sequence_number: nit$sequence_number,
      save_area: nit$resync_info,
    recend;

?? TITLE := 'Dependent System Information', EJECT ??

  CONST
    default_flow_control = 2,   { 20 ms
    max_abort_dump_count = 3,
    max_dump_count = 3,
    max_dump_resync_count = 3,
    max_load_resync_count = 10, {3}
    max_initialize_attempts = 10;

  TYPE
    nit$dependent_system = record
      abort_dump_count: 0 .. max_abort_dump_count,
      boot_card: nat$card_type,
      device_id: nlt$device_identifier,
      condition: nit$condition_kind,
      dump_count: 0 .. max_dump_count,
      dump_data: ^SEQ ( * ),
      dump_file: amt$file_identifier,
      dump_file_opened: boolean,
      dump_overflow: boolean,
      dump_required: boolean,
      dump_resync_count: 0 .. max_dump_resync_count,
      last_dump_resync_info: nit$resync_info,
      load_data: ^SEQ ( * ),
      load_file: amt$file_identifier,
      load_file_opened: boolean,
      load_resync_count: 0 .. max_load_resync_count,
      load_timer: nit$timer_value,
      max_transmission_rate: nat$transmit_rate,
      more_retries: boolean,
      next_dump_sequence_number: nit$sequence_number,
      next_load_sequence_number: nit$sequence_number,
      next_system: ^nit$dependent_system,
      number_of_initialize_attempts: 0 .. max_initialize_attempts,
      object_code_version: nat$object_code_version,
      reset_code: nit$reset_code,
      state: nit$state,
      system_address: nat$system_address,
      system_type: nit$system_type,
      timer: integer,
    recend;

  TYPE
    nit$timer_value = 0 .. max_timer_value;

  CONST
    help_offered_timer = 30000,
    dump_timer = 10000,
    inactive_timer = 600000,
    loading_timer = 100 {50} ,
    load_complete_timer = 30000,
    max_wait_time = 86400000,
    max_timer_value = 86400000 {24 hours in milliseconds} ;

  TYPE
    nit$state = (unknown, help_offered, dump_initiated, dumping, dump_aborted, loading, load_complete,
          inactive),
    nit$condition_processor = ^procedure
           (VAR input_pdu: nit$pdu;
            VAR dependent_system: nit$dependent_system),
    nit$condition_kind = (checksum_error, unknown_or_short_pdu_kind, help_request_excluded_system,
          help_request_device_unsupported, help_request_no_retries, help_request_more_retries,
          help_accept_with_dump, help_accept_without_dump, excessive_dump_data, dump_data_in_sequence,
          dump_data_low_sequence, dump_data_high_seq_try_resync, dump_data_high_seq_resync_sent,
          term_dump_in_seq_or_abnormal, term_dump_bad_seq_try_resync, term_dump_bad_seq_resync_sent,
          sync_load_bad_seq, sync_load_more_retries, sync_load_no_more_retries, timer_expired_more_retries,
          timer_expired_no_more_retries);

?? TITLE := 'External References', EJECT ??
*copyc amp$return
*copyc amp$set_segment_eoi
*copyc baf$task_file_entry_p
*copyc clp$get_value
*copyc clp$scan_parameter_list
*copyc fsp$close_file
*copyc nap$xns_checksum
*copyc nap$cn_close_sap
*copyc nap$cn_open_sap
*copyc nap$cn_receive_datagram
*copyc nap$cn_send_datagram
*copyc nap$display_message
*copyc nap$process_init_directives
*copyc nap$open_di_dump_file
*copyc nap$open_di_load_file
*copyc nap$local_system_id
*copyc osp$append_status_integer
*copyc osp$format_message
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc pmp$abort
*copyc pmp$establish_condition_handler
*copyc pmp$get_compact_date_time
*copyc pmp$get_microsecond_clock
*copyc pmp$log
*copyc pmp$get_task_cp_time

?? TITLE := 'Module Level Variables', EJECT ??

  VAR
    state_table: [STATIC, READ] array [nit$condition_kind] of array [nit$state] of record
      condition_processor: nit$condition_processor,
      new_state: nit$state,
    recend := [

    {checksum_error} [[^log_and_delete, unknown], [^log, help_offered],
          [^log, dump_initiated], [^log, dumping], [^log, dump_aborted],
          [^log, loading], [^log, load_complete], [^log, inactive]],

    {unknown_or_short_pdu_kind} [[^log_and_delete, unknown], [^log, help_offered], [^log, dump_initiated],
          [^log, dumping], [^log, dump_aborted], [^log, loading], [^log, load_complete], [^log, inactive]],

    {help_request_excluded_system} [[^log_and_delete, unknown], [^log_and_delete, unknown],
          [^log_and_delete, unknown], [^truncate_dump_and_delete, unknown],
          [^truncate_dump_and_delete, unknown], [^truncate_load_and_delete, unknown],
          [^truncate_load_and_delete, unknown], [^log_and_delete, unknown]],

    {help_request_device_unsupported} [[^log_and_delete, unknown], [^log_and_delete, unknown],
          [^log_and_delete, unknown], [^truncate_dump_and_delete, unknown],
          [^truncate_dump_and_delete, unknown], [^truncate_load_and_delete, unknown],
          [^truncate_load_and_delete, unknown], [^log_and_delete, unknown]],

    {help_request_no_retries} [[^delete, unknown], [^inactivate, inactive], [^inactivate, inactive],
          [^truncate_dump_and_inactivate, inactive], [^truncate_dump_and_inactivate, inactive],
          [^truncate_load_and_inactivate, inactive], [^truncate_load_and_inactivate, inactive],
          [^log, inactive]],

    {help_request_more_retries} [[^offer_help, help_offered], [^offer_help, help_offered],
          [^offer_help, help_offered], [^truncate_dump_and_help, help_offered],
          [^truncate_dump_and_help, help_offered], [^truncate_load_and_help, help_offered],
          [^truncate_load_and_help, help_offered], [^offer_help, help_offered]],

    {help_accept_with_dump} [[^log_and_delete, unknown], [^initiate_help, dump_initiated],
          [^start_dump, dump_initiated], [^log, dumping], [^log, dump_aborted], [^log, loading],
          [^log, load_complete], [^log, inactive]],

    {help_accept_without_dump} [[^log_and_delete, unknown], [^initiate_help, loading],
          [^ignore, dump_initiated], [^ignore, dumping], [^ignore, dump_aborted], [^start_load, loading],
          [^start_load, loading], [^log, inactive]],

    {excessive_dump_data} [[^delete, unknown], [^ignore, help_offered], [^abort_dump, dump_aborted],
          [^abort_dump, dump_aborted], [^ignore, dump_aborted], [^ignore, loading], [^ignore, load_complete],
          [^ignore, inactive]],

    {dump_data_in_sequence} [[^delete, unknown], [^ignore, help_offered], [^save_dump_data, dumping],
          [^save_dump_data, dumping], [^ignore, dump_aborted], [^ignore, loading], [^ignore, load_complete],
          [^ignore, inactive]],

    {dump_data_low_sequence} [[^delete, unknown], [^ignore, help_offered], [^ignore, dump_initiated],
          [^ignore, dumping], [^ignore, dump_aborted], [^ignore, loading], [^ignore, load_complete],
          [^ignore, inactive]],

    {dump_data_high_seq_try_resync} [[^delete, unknown], [^ignore, help_offered],
          [^start_dump, dump_initiated], [^resync_dump, dumping], [^ignore, dump_aborted], [^ignore, loading],
          [^ignore, load_complete], [^ignore, inactive]],

    {dump_data_high_seq_resync_sent} [[^delete, unknown], [^ignore, help_offered], [^ignore, dump_initiated],
          [^ignore, dumping], [^ignore, dump_aborted], [^ignore, loading], [^ignore, load_complete],
          [^ignore, inactive]],

    {term_dump_in_seq_or_abnormal} [[^delete, unknown], [^ignore, help_offered],
          [^end_dump_start_load, loading], [^end_dump_start_load, loading], [^end_dump_start_load, loading],
          [^ignore, loading], [^start_load, loading], [^ignore, inactive]],

    {term_dump_bad_seq_try_resync} [[^delete, unknown], [^ignore, help_offered],[^start_dump, dump_initiated],
          [^resync_dump, dumping], [^end_dump_start_load, loading], [^ignore, loading],[^start_load, loading],
          [^ignore, inactive]],

    {term_dump_bad_seq_resync_sent} [[^delete, unknown], [^ignore, help_offered], [^ignore, dump_initiated],
          [^ignore, dumping], [^end_dump_start_load, loading], [^ignore, loading], [^start_load, loading],
          [^ignore, inactive]],

    {sync_load_bad_seq} [[^delete, unknown], [^log, help_offered], [^log, dump_initiated], [^log, dumping],
          [^log, dump_aborted], [^log, loading], [^log, load_complete], [^log, inactive]],

    {sync_load_more_retries} [[^delete, unknown], [^log, help_offered], [^log, dump_initiated],
          [^log, dumping], [^log, dump_aborted], [^resync_load, loading], [^resync_load, loading],
          [^log, inactive]],

    {sync_load_no_more_retries} [[^delete, unknown], [^log, help_offered], [^log, dump_initiated],
          [^log, dumping], [^log, dump_aborted], [^abort_load, inactive], [^abort_load, inactive],
          [^log, inactive]],

    {timer_expired_more_retries} [[^delete, unknown], [^inactivate, inactive], [^start_dump, dump_initiated],
          [^resync_dump, dumping], [^abort_dump, dump_aborted], [^send_load_data, loading],
          [^inactivate, inactive], [^inactivate, inactive]],

    {timer_expired_no_more_retries} [[^delete, unknown], [^inactivate, inactive], [^abort_dump, dump_aborted],
          [^abort_dump, dump_aborted], [^inactivate, inactive], [^terminate_load, load_complete],
          [^inactivate, inactive], [^delete, unknown]]

    ];

  VAR
    log_message: array [nit$condition_kind] of ost$status_condition_code := [nae$init_checksum_error,
          nae$unknown_or_short_pdu, nae$excluded_system, nae$unsupported_device,
          nae$too_many_load_requests, 0, nae$unexpected_help_accept, nae$unexpected_help_accept, 0, 0, 0, 0,
          0, 0, 0, 0, nae$invalid_load_resync_request, nae$invalid_load_resync_request,
          nae$invalid_load_resync_request, 0, 0];

  VAR
    cp_time: pmt$task_cp_time := [0, 0],
    service_priority: nit$service_priority,
    default_object_code_version: nat$object_code_version,
    device_name: [STATIC, READ] array [1 .. 2] of string (3) := ['DI', 'ICA'],
    dump_error_list: nat$di_dump_error_list,
    max_connections: 0 .. 1000,
    max_dumps: 0 .. 1000,
    max_dump_size: 0 .. amc$file_byte_limit,
    max_dump_block_size: nat$data_length,
    max_load_block_size: nat$data_length,
    start_of_system_chain: ^nit$dependent_system := NIL,
    system_exceptions: nat$init_exception_list := NIL;

?? TITLE := 'Initialization Management Executive' ??
?? NEWTITLE := '  exit_condition_handler', EJECT ??

  PROGRAM nap$independent_init_manager
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);


    PROCEDURE exit_condition_handler
      (    condition: pmt$condition;
           condition_descriptor: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status;

      local_status.normal := TRUE;
      nap$cn_close_sap (nac$cn_initialization_me_sap, local_status);
      IF (NOT local_status.normal) AND status.normal THEN
        status := local_status;
      IFEND;

    PROCEND exit_condition_handler;
?? OLDTITLE, EJECT ??

    VAR
      data_buffer: ^SEQ ( * ),
      datagram_length: integer,
      dependent_system_location: ^nit$dependent_system,
      device_id: nlt$device_identifier,
      exit_condition: [STATIC] pmt$condition := [pmc$block_exit_processing,
            [pmc$block_exit, pmc$program_termination, pmc$program_abort]],
      establish_descriptor: pmt$established_handler,
      received_datagram: array [1 .. 1] of nat$data_fragment,
      input_pdu: nit$pdu,
      max_datagram_size: nat$data_length,
      remaining_time: nit$timer_value,
      system_address: nat$system_address;

    process_parameters (parameter_list, service_priority, max_connections, max_dumps, max_dump_size, status);
    IF NOT status.normal THEN
      nap$display_message (status);
      RETURN;
    IFEND;

    nap$process_init_directives (system_exceptions, default_object_code_version, dump_error_list, status);
    IF NOT status.normal THEN
      nap$display_message (status);
      osp$set_status_condition (nae$errors_in_exception_list, status);
      RETURN;
    IFEND;

    pmp$establish_condition_handler (exit_condition, ^exit_condition_handler, ^establish_descriptor, status);
    IF NOT status.normal THEN
      nap$display_message (status);
      RETURN;
    IFEND;
    nap$cn_open_sap (nac$cn_initialization_me_sap, max_datagram_size, status);
    IF NOT status.normal THEN
      nap$display_message (status);
      RETURN;
    IFEND;
    PUSH data_buffer: [[REP max_datagram_size OF cell]];
    max_dump_block_size := max_datagram_size - #SIZE (nit$dump_data_unit) - #SIZE (nat$checksum_value);
    max_dump_block_size := max_dump_block_size - (max_dump_block_size MOD 2);
    max_load_block_size := max_datagram_size - #SIZE (nit$load_data_unit) - #SIZE (nat$checksum_value);
    max_load_block_size := max_load_block_size - (max_load_block_size MOD 2);

    remaining_time := 0;
    received_datagram [1].address := data_buffer;
    received_datagram [1].length := #SIZE (data_buffer^);

{   report_cp_time;

    WHILE TRUE DO
      nap$cn_receive_datagram (nac$cn_initialization_me_sap, received_datagram, remaining_time,
            device_id, system_address, datagram_length, status);
      IF status.normal THEN
        RESET data_buffer;
        NEXT input_pdu: [[REP datagram_length OF cell]] IN data_buffer;
        find_dependent_system (system_address, device_id, dependent_system_location);
        IF dependent_system_location = NIL THEN {nil only if memory allocation fails}
          osp$set_status_abnormal (nac$status_id, nae$allocation_failed, 'NETWORK INITIALIZER', status);
          nap$display_message (status);
        ELSE
          process_channelnet_input (input_pdu, dependent_system_location^);
        IFEND;

      ELSE

{       IF status.condition = nae$no_datagram_available THEN

        status.normal := TRUE;

{       ELSE

{         RETURN {SYSTEM ERROR ;

{       IFEND;

      IFEND;

      find_shortest_timer (dependent_system_location, remaining_time);
      IF (remaining_time = 0) THEN {a timer has expired}
        process_timer (dependent_system_location^);
        find_shortest_timer (dependent_system_location, remaining_time);
      IFEND;
    WHILEND;

  PROCEND nap$independent_init_manager;
?? TITLE := 'Initialization Parameter Processor', EJECT ??

  PROCEDURE process_parameters
    (    parameter_list: clt$parameter_list;
     VAR service_priority: nit$service_priority;
     VAR max_connections: 0 .. 1000;
     VAR max_dumps: 0 .. 1000;
     VAR max_dump_size: 0 .. amc$file_byte_limit;
     VAR status: ost$status);


{   PDT initialization_m_e_pdt (
{     priority,p : integer 0 .. 3 = 3
{     maximum_connections,mc : integer 0 .. 1000 = 1000
{     maximum_dumps,md : integer 0 .. 1000 = 10
{     maximum_dump_size,mds : integer 0 .. amc$file_byte_limit = 16000000
{     status)

?? PUSH (LISTEXT := ON) ??
?? FMT (FORMAT := OFF) ??

  VAR
    initialization_m_e_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [
  ^initialization_m_e_pdt_names, ^initialization_m_e_pdt_params];

  VAR
    initialization_m_e_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 9] of
  clt$parameter_name_descriptor := [['PRIORITY', 1], ['P', 1], ['MAXIMUM_CONNECTIONS', 2], ['MC', 2], [
  'MAXIMUM_DUMPS', 3], ['MD', 3], ['MAXIMUM_DUMP_SIZE', 4], ['MDS', 4], ['STATUS', 5]];

  VAR
    initialization_m_e_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 5] of
  clt$parameter_descriptor := [

{ PRIORITY P }
    [[clc$optional_with_default, ^initialization_m_e_pdt_dv1], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
  clc$integer_value, 0, 3]],

{ MAXIMUM_CONNECTIONS MC }
    [[clc$optional_with_default, ^initialization_m_e_pdt_dv2], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
  clc$integer_value, 0, 1000]],

{ MAXIMUM_DUMPS MD }
    [[clc$optional_with_default, ^initialization_m_e_pdt_dv3], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
  clc$integer_value, 0, 1000]],

{ MAXIMUM_DUMP_SIZE MDS }
    [[clc$optional_with_default, ^initialization_m_e_pdt_dv4], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
  clc$integer_value, 0, amc$file_byte_limit]],

{ STATUS }
    [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
  clc$array_not_allowed, clc$status_value]]];

  VAR
    initialization_m_e_pdt_dv1: [STATIC, READ, cls$pdt_names_and_defaults] string (1) := '3';

  VAR
    initialization_m_e_pdt_dv2: [STATIC, READ, cls$pdt_names_and_defaults] string (4) := '1000';

  VAR
    initialization_m_e_pdt_dv3: [STATIC, READ, cls$pdt_names_and_defaults] string (2) := '10';

  VAR
    initialization_m_e_pdt_dv4: [STATIC, READ, cls$pdt_names_and_defaults] string (8) := '16000000';

?? FMT (FORMAT := ON) ??
?? POP ??

    VAR
      value: clt$value;

    clp$scan_parameter_list (parameter_list, initialization_m_e_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$get_value ('PRIORITY', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    service_priority := value.int.value;

    clp$get_value ('MAXIMUM_CONNECTIONS', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    max_connections := value.int.value;

    clp$get_value ('MAXIMUM_DUMPS', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    max_dumps := value.int.value;

    clp$get_value ('MAXIMUM_DUMP_SIZE', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    max_dump_size := value.int.value;

  PROCEND process_parameters;

?? TITLE := 'Event Processors' ??
?? NEWTITLE := 'Process_channelnet_input', EJECT ??

  PROCEDURE process_channelnet_input
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    VAR
      condition: nit$condition_kind,
      current_state: nit$state,
      data_to_checksum: array [1 .. 1] of nat$data_fragment,
      data_unit_id: ^nit$data_unit_id,
      dump_data: ^nit$dump_data_unit,
      help_request: ^nit$help_request_data_unit,
      input_checksum: ^nat$checksum_value,
      input_data: ^SEQ ( * ),
      status: ost$status,
      synchronize_load: ^nit$synchronize_load_data_unit,
      system_address: nat$system_address,
      terminate_dump: ^nit$term_dump_data_unit;

    IF #SIZE (input_pdu^) >= (#SIZE (nat$checksum_value) + #SIZE (nit$data_unit_id)) THEN
      data_to_checksum [1].address := input_pdu;
      data_to_checksum [1].length := #SIZE (input_pdu^) - #SIZE (nat$checksum_value);
      RESET input_pdu;
      NEXT input_data: [[REP data_to_checksum [1].length OF cell]] IN input_pdu;
      NEXT input_checksum IN input_pdu;

      IF input_checksum^ = nap$xns_checksum (data_to_checksum) THEN
        RESET input_data;
        NEXT data_unit_id IN input_data;
        RESET input_data;

        CASE data_unit_id^ OF
        = help_request_id =
          status.normal := TRUE;
          nap$process_init_directives (system_exceptions, default_object_code_version, dump_error_list,
                status);
          IF NOT status.normal THEN { error processing exception file - use previous version }
            nap$display_message (status);
            osp$set_status_abnormal (nac$status_id, nae$errors_in_exception_list,
                  'Last valid exception list used.', status);
            nap$display_message (status);
          IFEND;

          NEXT help_request IN input_data;
          IF help_request = NIL THEN
            condition := unknown_or_short_pdu_kind;
          ELSEIF system_excluded (help_request^.requesting_system_id) THEN
            condition := help_request_excluded_system;
          ELSEIF (help_request^.flags.system_type <> di_system) AND
                (help_request^.flags.system_type <> ica2_system) THEN
            condition := help_request_device_unsupported;
          ELSEIF (help_request^.reset_code.code = power_up_reset) OR
                (help_request^.reset_code.code = manual_reset) THEN
            condition := help_request_more_retries;
          ELSEIF dependent_system.number_of_initialize_attempts >= max_initialize_attempts THEN
            condition := help_request_no_retries;
          ELSE
            condition := help_request_more_retries;
          IFEND;

        = help_accept_id =
          IF dependent_system.dump_required THEN
            condition := help_accept_with_dump;
          ELSE
            condition := help_accept_without_dump;
          IFEND;

        = dump_data_id =
          NEXT dump_data IN input_data;
          IF dump_data = NIL THEN
            condition := unknown_or_short_pdu_kind;
          ELSEIF dependent_system.dump_overflow THEN
            condition := excessive_dump_data;
          ELSEIF dump_data^.sequence_number = dependent_system.next_dump_sequence_number THEN
            condition := dump_data_in_sequence;
          ELSEIF dump_data^.sequence_number < dependent_system.next_dump_sequence_number THEN
            condition := dump_data_low_sequence;
          ELSEIF dependent_system.dump_resync_count = 0 THEN
            condition := dump_data_high_seq_try_resync;
          ELSE
            condition := dump_data_high_seq_resync_sent;
          IFEND;

        = terminate_dump_id =
          NEXT terminate_dump IN input_data;
          IF terminate_dump = NIL THEN
            condition := unknown_or_short_pdu_kind;
          ELSEIF (terminate_dump^.sequence_number = dependent_system.next_dump_sequence_number - 1) OR
                (terminate_dump^.code <> normal_dump_termination) THEN
            condition := term_dump_in_seq_or_abnormal;
          ELSEIF dependent_system.dump_resync_count = 0 THEN
            condition := term_dump_bad_seq_try_resync;
          ELSE
            condition := term_dump_bad_seq_resync_sent;
          IFEND;

        = synchronize_load_id =
          NEXT synchronize_load IN input_data;
          IF synchronize_load = NIL THEN
            condition := unknown_or_short_pdu_kind;
          ELSEIF synchronize_load^.sequence_number > dependent_system.next_load_sequence_number THEN
            condition := sync_load_bad_seq;
          ELSEIF dependent_system.load_resync_count < max_load_resync_count THEN
            condition := sync_load_more_retries;
          ELSE
            condition := sync_load_no_more_retries;
          IFEND;

        ELSE
          condition := unknown_or_short_pdu_kind;
        CASEND;
      ELSE
        condition := checksum_error;
      IFEND;
    ELSE
      condition := unknown_or_short_pdu_kind;
    IFEND;

    current_state := dependent_system.state;
    dependent_system.state := state_table [condition] [current_state].new_state;
    dependent_system.condition := condition;
    state_table [condition] [current_state].condition_processor^ (input_data, dependent_system);
  PROCEND process_channelnet_input;
?? TITLE := 'Process_timer', EJECT ??

  PROCEDURE process_timer
    (VAR dependent_system: nit$dependent_system);

    VAR
      condition: nit$condition_kind,
      current_state: nit$state,
      nil_input_pdu: [STATIC] nit$pdu := NIL;

    IF dependent_system.more_retries THEN
      condition := timer_expired_more_retries;
    ELSE
      condition := timer_expired_no_more_retries;
    IFEND;

    current_state := dependent_system.state;
    dependent_system.state := state_table [condition] [current_state].new_state;
    state_table [condition] [current_state].condition_processor^ (nil_input_pdu, dependent_system);
  PROCEND process_timer;
?? OLDTITLE ??
?? TITLE := 'Condition Processors' ??
?? NEWTITLE := 'abort_dump', EJECT ??

  PROCEDURE abort_dump
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    VAR
      abort: nit$abort_dump_data_unit,
      more_retries: boolean,
      output_data: array [1 .. 1] of nat$data_fragment;

{ This processor sends an abort dump pdu to the dependent system.

    dependent_system.abort_dump_count := dependent_system.abort_dump_count + 1;

    abort.identifier := abort_dump_id;
    output_data [1].address := ^abort;
    output_data [1].length := #SIZE (abort);
    send_pdu (output_data, dependent_system.device_id, dependent_system.system_address);

    more_retries := dependent_system.abort_dump_count < max_abort_dump_count;
    set_timer (dependent_system, dump_timer, more_retries);
  PROCEND abort_dump;
?? TITLE := 'abort_load', EJECT ??

  PROCEDURE abort_load
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor logs the load failure and inactivates the dependent system.
{ Only a help request from the dependent system will be honored.

    VAR
      status: ost$status;

    osp$set_status_abnormal (nac$status_id, nae$excessive_resyncs, '', status);
    osp$append_status_integer (osc$status_parameter_delimiter, dependent_system.system_address.system, 16,
          FALSE, status);
    nap$display_message (status);
    inactivate (input_pdu, dependent_system);
  PROCEND abort_load;
?? TITLE := 'delete', EJECT ??

  PROCEDURE delete
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor deletes all system specific information for a dependent system

    delete_dependent_system (dependent_system.system_address);
  PROCEND delete;
?? TITLE := 'end_dump_start_load', EJECT ??

  PROCEDURE end_dump_start_load
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor provides the transition from the dump phase to the load phase

    VAR
      terminate_dump: ^nit$term_dump_data_unit;

    RESET input_pdu;
    NEXT terminate_dump IN input_pdu;

{   IF terminate_dump^.code = dump_memory_error THEN
{     pmp$log ('dump_memory_error', status);
{   IFEND;

    close_dump_file (dependent_system);

{   report_cp_time;

    start_load (input_pdu, dependent_system);
  PROCEND end_dump_start_load;
?? TITLE := 'ignore', EJECT ??

  PROCEDURE ignore
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor is called when an unexpected condition arises that is not a
{ definite error indication. Also, any condition that does represent an error
{ but could occur many times in a row should be logged no more than once.
{ An example is a series of dump data units when the load phase has already
{ begun.

  PROCEND ignore;
?? TITLE := 'inactivate', EJECT ??

  PROCEDURE inactivate
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor closes any files still open for a system and establishes a long
{ timer. When this timer expires, the information for the system will be
{ deleted. However, if another help request is received before the timer expires,
{ it will be considered to be a continuation of the previous help attempt and
{ limits on help attempts and dumps will continue to be enforced.

    close_dump_file (dependent_system);
    close_load_file (dependent_system);
    set_timer (dependent_system, inactive_timer, {more retries =} FALSE);
  PROCEND inactivate;
?? TITLE := 'initiate_help', EJECT ??

  PROCEDURE initiate_help
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    VAR
      status: ost$status;

{ This processor counts the number of times help has been provided and starts
{ the dump or load as appropriate.

    IF dependent_system.number_of_initialize_attempts < max_initialize_attempts THEN
      dependent_system.number_of_initialize_attempts := dependent_system.number_of_initialize_attempts + 1;
    IFEND;
    osp$set_status_abnormal (nac$status_id, nae$di_reset, device_name [dependent_system.system_type], status);
    osp$append_status_integer (osc$status_parameter_delimiter, dependent_system.system_address.system, 16,
          FALSE, status);
    osp$append_status_integer (osc$status_parameter_delimiter, dependent_system.reset_code.code, 16, TRUE,
          status);
    nap$display_message (status);

{   report_cp_time;

    IF dependent_system.dump_required THEN
      dependent_system.dump_resync_count := 0;
      dependent_system.abort_dump_count := 0;
      start_dump (input_pdu, dependent_system);
      dependent_system.dump_resync_count := 0 {if first dump pdu is bad, restart dump immediately} ;
    ELSE
      start_load (input_pdu, dependent_system);
    IFEND;
  PROCEND initiate_help;
?? TITLE := 'logging processors', EJECT ??

  PROCEDURE log
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor is called when a condition arises that is an error
{ indication but no action is required in response to the condition.
{ These conditions are logged.

    VAR
      status: ost$status;

    IF log_message [dependent_system.condition] > 0 THEN
      osp$set_status_condition (log_message [dependent_system.condition], status);
      osp$append_status_integer (osc$status_parameter_delimiter, dependent_system.system_address.system, 16,
            FALSE, status);
      nap$display_message (status);
    IFEND;

  PROCEND log;


  PROCEDURE log_and_delete
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor logs the unexpected condition and deletes the system entry.

    log (input_pdu, dependent_system);
    delete (input_pdu, dependent_system);
  PROCEND log_and_delete;

?? TITLE := 'offer_help', EJECT ??

  PROCEDURE offer_help
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor sends a help offer pdu to a dependent system requesting help.
{ Pertinent information is saved from the help request pdu.

    VAR
      help_offer: nit$help_offer_data_unit,
      help_request: ^nit$help_request_data_unit,
      output_data: array [1 .. 1] of nat$data_fragment;

    RESET input_pdu;
    NEXT help_request IN input_pdu;

    get_system_init_values (help_request^.requesting_system_id, help_request^.reset_code.code,
          dependent_system.object_code_version, dependent_system.dump_required,
          dependent_system.max_transmission_rate);
    IF dependent_system.dump_required AND ((dependent_system.dump_count = max_dump_count) OR
          (NOT help_request^.flags.auto_dump)) THEN

{     pmp$log ('dump_suppressed', status);

      dependent_system.dump_required := FALSE;
    IFEND;

    dependent_system.boot_card := help_request^.boot_card;
    dependent_system.reset_code := help_request^.reset_code;
    dependent_system.system_type := help_request^.flags.system_type;

    dependent_system.load_timer := (max_load_block_size * 8000) DIV dependent_system.max_transmission_rate;
    IF dependent_system.load_timer < loading_timer THEN
      dependent_system.load_timer := loading_timer;
    IFEND;

    help_offer.identifier := help_offer_id;
    help_offer.service_definition.priority := service_priority;
    help_offer.service_definition.reserved := 0 {this field used by ESCI for debug} ;
    help_offer.version_number := dependent_system.object_code_version;
    help_offer.network_id := dependent_system.system_address.network;
    help_offer.host_system_id := nap$local_system_id ();

    output_data [1].address := ^help_offer;
    output_data [1].length := #SIZE (help_offer);
    send_pdu (output_data, dependent_system.device_id, dependent_system.system_address);

    set_timer (dependent_system, help_offered_timer, {more_retries =} FALSE);
  PROCEND offer_help;
?? TITLE := 'resync_dump', EJECT ??

  PROCEDURE resync_dump
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor sends a synchronize dump pdu and keeps count of the number of
{ such pdu's sent during this resynchronization attempt.

    VAR
      more_retries: boolean,
      output_data: array [1 .. 1] of nat$data_fragment,
      synchronize_dump: nit$synchronize_dump_data_unit;

    dependent_system.dump_resync_count := dependent_system.dump_resync_count + 1;

    synchronize_dump.identifier := synchronize_dump_id;
    synchronize_dump.sequence_number := dependent_system.next_dump_sequence_number;
    synchronize_dump.save_area := dependent_system.last_dump_resync_info;

    output_data [1].address := ^synchronize_dump;
    output_data [1].length := #SIZE (synchronize_dump);
    send_pdu (output_data, dependent_system.device_id, dependent_system.system_address);

    more_retries := dependent_system.dump_resync_count < max_dump_resync_count;
    set_timer (dependent_system, dump_timer, more_retries);
  PROCEND resync_dump;
?? TITLE := 'resync_load', EJECT ??

  PROCEDURE resync_load
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor resets the load process as requested in a synchronize load pdu

    VAR
      skipped_data: ^SEQ ( * ),
      synchronize_load: ^nit$synchronize_load_data_unit;

    RESET input_pdu;
    NEXT synchronize_load IN input_pdu;

    dependent_system.load_resync_count := dependent_system.load_resync_count + 1;
    dependent_system.next_load_sequence_number := synchronize_load^.sequence_number;
    RESET dependent_system.load_data;
    IF dependent_system.next_load_sequence_number > 0 THEN
      NEXT skipped_data: [[REP dependent_system.next_load_sequence_number * max_load_block_size OF cell]] IN
            dependent_system.load_data;
    IFEND;
    IF synchronize_load^.flags.overflow THEN
      dependent_system.load_timer := dependent_system.load_timer + loading_timer;

{
{  Make sure the load time delay never goes above 5000 milliseconds (5 seconds)
{

      IF dependent_system.load_timer > 5000 THEN
        dependent_system.load_timer := 5000;
      IFEND;
    IFEND;

    send_load_data (input_pdu, dependent_system);
  PROCEND resync_load;
?? TITLE := 'save_dump_data', EJECT ??

  PROCEDURE save_dump_data
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor adds a block of dump data to the dump file.

    VAR
      dump_block: ^SEQ ( * ),
      dump_data: ^nit$dump_data_unit,
      dump_byte_count: nat$data_length,
      dump_information: ^SEQ ( * );

    dump_byte_count := #SIZE (input_pdu^) - #SIZE (nit$dump_data_unit);
    RESET input_pdu;
    NEXT dump_data IN input_pdu;
    NEXT dump_information: [[REP dump_byte_count OF cell]] IN input_pdu;

    dependent_system.last_dump_resync_info := dump_data^.save_area;
    dependent_system.dump_resync_count := 0;
    dependent_system.next_dump_sequence_number := dependent_system.next_dump_sequence_number + 1;

    NEXT dump_block: [[REP dump_byte_count OF cell]] IN dependent_system.dump_data;
    IF dump_block = NIL THEN
      dependent_system.dump_overflow := TRUE;

{     pmp$log ('dump truncated - too long', status);

    ELSE
      dump_block^ := dump_information^;
    IFEND;

    set_timer (dependent_system, dump_timer, {more retries =} TRUE);
  PROCEND save_dump_data;
?? TITLE := 'send_load_data', EJECT ??

  PROCEDURE send_load_data
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor sends load data pdu's to the dependent system. Several load
{ pdu's are generated on each invocation. A short timer is used to interrupt
{ load pdu generation and allow other processing.

    VAR
      load_block_size: nat$data_length,
      load_data: nit$load_data_unit,
      load_data_pointer: ^SEQ ( * ),
      output_data: array [1 .. 3] of nat$data_fragment,
      pad_byte: [STATIC] 0 .. 0ff(16) := 0,
      pdu_count: 0 .. load_pdu_block_count;

    load_data.identifier := load_data_id;

  /send_load_pdu/
    FOR pdu_count := 1 TO load_pdu_block_count DO
      load_data.sequence_number := dependent_system.next_load_sequence_number;
      IF ((load_data.sequence_number + 1) * max_load_block_size) >= #SIZE (dependent_system.load_data^) THEN
        load_block_size := #SIZE (dependent_system.load_data^) -
              (load_data.sequence_number * max_load_block_size);

{ include pad byte if load block is odd number of bytes

        output_data [3].length := load_block_size MOD 2;
        load_data.flags.last_data_unit := TRUE;
      ELSE
        load_block_size := max_load_block_size;
        load_data.flags.last_data_unit := FALSE;
        output_data [3].length := 0 {no pad byte needed} ;
      IFEND;
      NEXT load_data_pointer: [[REP load_block_size OF cell]] IN dependent_system.load_data;

      output_data [1].address := ^load_data;
      output_data [1].length := #SIZE (load_data);
      output_data [2].address := load_data_pointer;
      output_data [2].length := load_block_size;
      output_data [3].address := ^pad_byte;
      send_pdu (output_data, dependent_system.device_id, dependent_system.system_address);
      IF load_data.flags.last_data_unit THEN
        EXIT /send_load_pdu/;
      IFEND;
      dependent_system.next_load_sequence_number := dependent_system.next_load_sequence_number + 1;
    FOREND /send_load_pdu/;

    set_timer (dependent_system, dependent_system.load_timer,
          {more retries =} NOT load_data.flags.last_data_unit);
  PROCEND send_load_data;
?? TITLE := 'start_dump', EJECT ??

  PROCEDURE start_dump
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor issues a begin auto dump pdu. The number of start dump attempts
{ is kept to allow the dump process to be abandoned if the dependent system does
{ not respond appropriately.

    VAR
      begin_auto_dump: nit$auto_dump_data_unit,
      converted_time: string (20),
      count: integer,
      date_time: ost$date_time,
      flow_control_rate: integer,
      index: integer,
      more_retries: boolean,
      output_data: array [1 .. 1] of nat$data_fragment,
      status: ost$status,
      system: string (12),
      system_id: string (15),
      timestamp: string (12);

    IF NOT dependent_system.dump_file_opened THEN
      STRINGREP (system_id, count, dependent_system.system_address.system: 13: #(16));
      system := system_id (2, 12);
      FOR index := 1 TO #SIZE (system) DO
        IF system (index) = ' ' THEN
          system (index) := '0';
        IFEND;
      FOREND;

      pmp$get_compact_date_time (date_time, {ignore} status);
      IF date_time.year > 99 THEN
         date_time.year := date_time.year - 100;
      IFEND;
      STRINGREP (converted_time, count, date_time.year: 3, date_time.month: 3, date_time.day: 3,
            date_time.hour: 3, date_time.minute: 3, date_time.second: 3);
      timestamp (1, 2) := converted_time (2, 2) {year} ;
      timestamp (3, 2) := converted_time (5, 2) {month} ;
      timestamp (5, 2) := converted_time (8, 2) {day} ;
      timestamp (7, 2) := converted_time (11, 2) {hour} ;
      timestamp (9, 2) := converted_time (14, 2) {minute} ;
      timestamp (11, 2) := converted_time (17, 2) {second} ;
      FOR index := 1 TO #SIZE (system) DO
        IF timestamp (index) = ' ' THEN
          timestamp (index) := '0';
        IFEND;
      FOREND;
      status.normal := TRUE;
      nap$open_di_dump_file (system, timestamp, 'FULL', max_dumps, max_dump_size, dependent_system.dump_file,
            dependent_system.dump_data, dependent_system.dump_file_opened, status);
      IF status.normal THEN

{       pmp$log ('dump_initiated', status);

        dependent_system.dump_count := dependent_system.dump_count + 1;
        dependent_system.dump_overflow := FALSE;
      ELSE {abort dump}
        nap$display_message (status);
        dependent_system.dump_overflow := TRUE;

{       pmp$log ('dump_suppressed', status);
{start the di dump - dump data unit will trigger transition to loading state.

      IFEND;
    IFEND;

    dependent_system.next_dump_sequence_number := 0;
    dependent_system.dump_resync_count := dependent_system.dump_resync_count + 1;

    begin_auto_dump.identifier := begin_auto_dump_id;

{   Calculate the speed at which the dump is to occur.
{
{   This value is calculated using the following formula:
{          ((max_dump_block_size  *  8 bits  *  1000 ms)  DIV  transmission_rate)  DIV  10 ms
{
{   NOTE: The dependent system expects the flow_control value to be in 10's of milliseconds.
{         That is why there is a division by 10 ms.

    flow_control_rate := (max_dump_block_size * 800) DIV dependent_system.max_transmission_rate;
    IF flow_control_rate > UPPERVALUE(nit$dump_flow_control) THEN
      begin_auto_dump.flow_control := UPPERVALUE(nit$dump_flow_control);
    ELSEIF flow_control_rate < default_flow_control THEN
      begin_auto_dump.flow_control := default_flow_control;
    ELSE
      begin_auto_dump.flow_control := flow_control_rate;
    IFEND;
    begin_auto_dump.max_data_length := max_dump_block_size;

    output_data [1].address := ^begin_auto_dump;
    output_data [1].length := #SIZE (begin_auto_dump);
    send_pdu (output_data, dependent_system.device_id, dependent_system.system_address);

    more_retries := dependent_system.dump_resync_count < max_dump_resync_count;
    set_timer (dependent_system, dump_timer, more_retries);
  PROCEND start_dump;
?? TITLE := 'start_load', EJECT ??

  PROCEDURE start_load
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{ This processor obtains the load file and initializes the loading process.
{ If the load file is not available, the load is marked complete and the timer
{ is set to zero to trigger an immediate state change. The reason for the
{ failure has already been logged by the load file open routine.

    VAR
      byte_count: ^1 .. llc$maximum_68000_address,
      count: integer,
      idr_header: ^llt$identification,
      index: integer,
      load_data: ^SEQ ( * ),
      m68000_text_descriptor: ^0 .. 0ffffffffff(16),
      status: ost$status,
      text_descriptor: ^llt$object_text_descriptor,
      version: string (5);

    IF dependent_system.load_file_opened THEN
      dependent_system.load_resync_count := dependent_system.load_resync_count + 1;
    ELSE
      dependent_system.load_resync_count := 0;
      STRINGREP (version, count, dependent_system.object_code_version: 5: #(16)); {allow room for leading 0}
      FOR index := 1 TO count DO
        IF version (index) = ' ' THEN
          version (index) := '0';
        IFEND;
      FOREND;
      status.normal := TRUE;
      nap$open_di_load_file (version (2, * ), dependent_system.boot_card, dependent_system.load_file,
            load_data, dependent_system.load_file_opened, status);
      IF NOT status.normal THEN {load file not available - mark load complete (no more retries)}
        nap$display_message (status);
        set_timer (dependent_system, 0, {more retries =} FALSE);
        RETURN;
      IFEND;

{     pmp$log ('load_initiated', status);

      RESET load_data;
      NEXT text_descriptor IN load_data;
      NEXT idr_header IN load_data;
      NEXT text_descriptor IN load_data;
      RESET load_data TO text_descriptor;
      NEXT m68000_text_descriptor IN load_data;
      NEXT byte_count IN load_data;
      byte_count^ := text_descriptor^.number_of_68000_bytes;
      RESET load_data TO byte_count;
      NEXT dependent_system.load_data: [[REP #SIZE (load_data^) - #SIZE (llt$object_text_descriptor) -
            #SIZE (llt$identification) - #SIZE (m68000_text_descriptor^) OF cell]] IN load_data;
    IFEND;
    dependent_system.next_load_sequence_number := 0;
    RESET dependent_system.load_data;
    send_load_data (input_pdu, dependent_system);
  PROCEND start_load;
?? TITLE := 'terminate_load', EJECT ??

  PROCEDURE terminate_load
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

{   VAR
{     status: ost$status;

{ This processor sets a timer at the end of the load process. During this timer
{ interval, synchronize load requests from the dependent system will be honored.
{ When the timer expires, the system will be changed to the inactive state and
{ only help requests will be processed. If the load file is not open at this
{ point, then a failure in the load process has occurred and a zero timer is
{ used to trigger an immediate state change.

    IF dependent_system.load_file_opened THEN
      set_timer (dependent_system, load_complete_timer, {more retries =} FALSE);

{     pmp$log ('load completed', status);
{     report_cp_time;

    ELSE
      set_timer (dependent_system, 0, {more retries =} FALSE);
    IFEND;
  PROCEND terminate_load;
?? TITLE := 'Truncate dump/load Processors', EJECT ??

{ The truncate... processors terminate a dump or load abnormally, log the
{ abnormality, and then continue with the wrapup process indicated by their
{ name.

  PROCEDURE truncate_dump_and_delete
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    truncate_dump (dependent_system);
    delete (input_pdu, dependent_system);
  PROCEND truncate_dump_and_delete;

  PROCEDURE truncate_dump_and_help
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    truncate_dump (dependent_system);
    offer_help (input_pdu, dependent_system);
  PROCEND truncate_dump_and_help;

  PROCEDURE truncate_dump_and_inactivate
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    truncate_dump (dependent_system);
    inactivate (input_pdu, dependent_system);
  PROCEND truncate_dump_and_inactivate;

  PROCEDURE truncate_load_and_delete
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    truncate_load (dependent_system);
    delete (input_pdu, dependent_system);
  PROCEND truncate_load_and_delete;

  PROCEDURE truncate_load_and_help
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    truncate_load (dependent_system);
    offer_help (input_pdu, dependent_system);
  PROCEND truncate_load_and_help;

  PROCEDURE truncate_load_and_inactivate
    (VAR input_pdu: nit$pdu;
     VAR dependent_system: nit$dependent_system);

    truncate_load (dependent_system);
    inactivate (input_pdu, dependent_system);
  PROCEND truncate_load_and_inactivate;
?? OLDTITLE ??

?? TITLE := 'Miscellaneous Routines' ??
?? NEWTITLE := 'close (dump/load) file', EJECT ??

  PROCEDURE close_dump_file
    (VAR dependent_system: nit$dependent_system);

    VAR
      file_name: amt$local_file_name,
      segment_pointer: amt$segment_pointer,
      status: ost$status;

    IF dependent_system.dump_file_opened THEN
      status.normal := TRUE;
      segment_pointer.kind := amc$sequence_pointer;
      segment_pointer.sequence_pointer := dependent_system.dump_data;
      amp$set_segment_eoi (dependent_system.dump_file, segment_pointer, status);
      status.normal := TRUE;
      file_name := baf$task_file_entry_p (dependent_system.dump_file)^.local_file_name;
      fsp$close_file (dependent_system.dump_file, status);
      amp$return (file_name, status);
      dependent_system.dump_file_opened := FALSE;

{     pmp$log ('dump_completed', status);

    IFEND;
  PROCEND close_dump_file;

  PROCEDURE close_load_file
    (VAR dependent_system: nit$dependent_system);

    VAR
      file_name: amt$local_file_name,
      status: ost$status;

    IF dependent_system.load_file_opened THEN
      status.normal := TRUE;
      file_name := baf$task_file_entry_p (dependent_system.load_file)^.local_file_name;
      fsp$close_file (dependent_system.load_file, status);
      amp$return (file_name, status);
      dependent_system.load_file_opened := FALSE;
    IFEND;
  PROCEND close_load_file;
?? TITLE := 'delete_dependent_system', EJECT ??

  PROCEDURE delete_dependent_system
    (    system_address: nat$system_address);

    VAR
      dependent_system_location: ^nit$dependent_system,
      previous_link: ^^nit$dependent_system;

    previous_link := ^start_of_system_chain;
    dependent_system_location := start_of_system_chain;
    WHILE dependent_system_location <> NIL DO
      IF dependent_system_location^.system_address = system_address THEN
        previous_link^ := dependent_system_location^.next_system;
        FREE dependent_system_location;
        RETURN;
      IFEND;
      previous_link := ^dependent_system_location^.next_system;
      dependent_system_location := dependent_system_location^.next_system;
    WHILEND;
  PROCEND delete_dependent_system;
?? TITLE := 'find_dependent_system', EJECT ??

  PROCEDURE find_dependent_system
    (    system_address: nat$system_address;
         device_id: nlt$device_identifier;
     VAR dependent_system_location: ^nit$dependent_system);

    dependent_system_location := start_of_system_chain;
    WHILE dependent_system_location <> NIL DO
      IF dependent_system_location^.system_address = system_address THEN

{ Update the device identifier field. This is done in case a DI is now
{ attempting to initialize across another device (i.e., using another
{ MCI within the same DI).

        dependent_system_location^.device_id := device_id;
        RETURN;
      IFEND;
      dependent_system_location := dependent_system_location^.next_system;
    WHILEND;

    ALLOCATE dependent_system_location;
    IF dependent_system_location <> NIL THEN
      dependent_system_location^.system_address := system_address;
      dependent_system_location^.device_id := device_id;
      dependent_system_location^.next_system := start_of_system_chain;
      start_of_system_chain := dependent_system_location;

      dependent_system_location^.abort_dump_count := 0;
      dependent_system_location^.dump_count := 0;
      dependent_system_location^.dump_data := NIL;
      dependent_system_location^.dump_file_opened := FALSE;
      dependent_system_location^.dump_overflow := FALSE;
      dependent_system_location^.dump_required := FALSE;
      dependent_system_location^.dump_resync_count := 0;
      dependent_system_location^.load_data := NIL;
      dependent_system_location^.load_file_opened := FALSE;
      dependent_system_location^.load_resync_count := 0;
      dependent_system_location^.more_retries := FALSE;
      dependent_system_location^.number_of_initialize_attempts := 0;
      dependent_system_location^.state := unknown;
    IFEND;

  PROCEND find_dependent_system;
?? TITLE := 'find_shortest_timer', EJECT ??

  PROCEDURE find_shortest_timer
    (VAR dependent_system_location: ^nit$dependent_system;
     VAR remaining_time {in milliseconds} : nit$timer_value);

    VAR
      current_microsecond_time: integer,
      current_millisecond_time: integer,
      millisecond_timer: integer,
      next_system: ^nit$dependent_system,
      next_timer_to_expire: ^nit$dependent_system,
      next_timer_value: integer,
      status: ost$status;

    status.normal := TRUE;
    current_millisecond_time := #FREE_RUNNING_CLOCK (0) DIV 1000;

    next_system := start_of_system_chain;
    next_timer_to_expire := start_of_system_chain;
    next_timer_value := current_millisecond_time + max_timer_value;

    WHILE next_system <> NIL DO
      IF next_system^.timer < next_timer_value THEN
        next_timer_value := next_system^.timer;
        next_timer_to_expire := next_system;
      IFEND;
      next_system := next_system^.next_system;
    WHILEND;

    dependent_system_location := next_timer_to_expire;
    millisecond_timer := next_timer_value - current_millisecond_time;
    IF millisecond_timer < 0 THEN
      remaining_time := 0;
    ELSEIF millisecond_timer > max_wait_time THEN
      remaining_time := max_wait_time;
    ELSE
      remaining_time := millisecond_timer;
    IFEND;

  PROCEND find_shortest_timer;
?? TITLE := 'get_system_init_values', EJECT ??

  PROCEDURE get_system_init_values
    (    system_id: nat$system_identifier;
         reset_code: 0 .. nac$max_di_reset_code;
     VAR object_code_version: nat$object_code_version;
     VAR dump_required: boolean;
     VAR transmit_rate: nat$transmit_rate);

    VAR
      index: integer;

    object_code_version := default_object_code_version;
    dump_required := reset_code IN dump_error_list;
    transmit_rate := nac$high_transmit_rate;

    IF system_exceptions <> NIL THEN
      FOR index := 1 TO UPPERBOUND (system_exceptions^) DO
        IF system_exceptions^ [index].system_id = system_id THEN
          IF system_exceptions^ [index].version_specified THEN
            object_code_version := system_exceptions^ [index].object_code_version;
          IFEND;
          dump_required := reset_code IN system_exceptions^ [index].dump_error_list;
          transmit_rate := system_exceptions^ [index].transmit_rate;
          RETURN;
        IFEND;
      FOREND;
    IFEND;
  PROCEND get_system_init_values;
?? TITLE := 'report_cp_time', EJECT ??
?? NOCOMPILE ??

  PROCEDURE report_cp_time;

    VAR
      local_status: ost$status,
      new_time: pmt$task_cp_time,
      report_line: string (40),
      length: integer;

    pmp$get_task_cp_time (new_time, local_status);

    STRINGREP (report_line, length, 'Job time=', new_time.task_time - cp_time.task_time, ', Monitor time=',
          new_time.monitor_time - cp_time.monitor_time);

    pmp$log (report_line (1, length), local_status);

    cp_time := new_time;

  PROCEND report_cp_time;
?? COMPILE ??
?? TITLE := 'send_pdu', EJECT ??

  PROCEDURE send_pdu
    (    output_data: nat$data_fragments;
         device_id: nlt$device_identifier;
         system_address: nat$system_address);

    VAR
      checksum: nat$checksum_value,
      index: integer,
      output_pdu: ^nat$data_fragments,
      status: ost$status;

    PUSH output_pdu: [1 .. UPPERBOUND (output_data) + 1];
    FOR index := 1 TO UPPERBOUND (output_data) DO
      output_pdu^ [index] := output_data [index];
    FOREND;
    output_pdu^ [UPPERBOUND (output_pdu^)].address := ^checksum;
    output_pdu^ [UPPERBOUND (output_pdu^)].length := #SIZE (checksum);
    checksum := nap$xns_checksum (output_data);

    status.normal := TRUE;
    nap$cn_send_datagram (nac$cn_initialization_me_sap, device_id, system_address,
          output_pdu^, status);
    IF NOT status.normal THEN

{ *** a distinction must be made between fatal errors (pmp$abort) and nonfatal ones
{     pmp$log ('error sending datagram', status);

      nap$display_message (status);
    IFEND;
  PROCEND send_pdu;
?? TITLE := 'set_timer', EJECT ??

  PROCEDURE set_timer
    (VAR dependent_system: nit$dependent_system;
         timer_value {in milliseconds} : nit$timer_value;
         more_retries: boolean);

    VAR
      current_microsecond_time: integer,
      ignore_status: ost$status;

    pmp$get_microsecond_clock (current_microsecond_time, ignore_status);
    dependent_system.timer := (current_microsecond_time DIV 1000) + timer_value;
    dependent_system.more_retries := more_retries;
  PROCEND set_timer;
?? TITLE := 'system_excluded', EJECT ??

  FUNCTION system_excluded
    (    system_id: nat$system_identifier): boolean;

    VAR
      index: integer;

    IF system_exceptions = NIL THEN
      system_excluded := FALSE;
    ELSE
      FOR index := 1 TO UPPERBOUND (system_exceptions^) DO
        IF system_exceptions^ [index].system_id = system_id THEN
          system_excluded := NOT system_exceptions^ [index].service_system;
          RETURN;
        IFEND;
      FOREND;
      system_excluded := FALSE;
    IFEND;
  FUNCEND system_excluded;
?? TITLE := 'truncate (dump/load)', EJECT ??

  PROCEDURE truncate_dump
    (VAR dependent_system: nit$dependent_system);

{   VAR
{     status: ost$status;

    close_dump_file (dependent_system);

{   pmp$log ('dump terminated by help request', status);

  PROCEND truncate_dump;


  PROCEDURE truncate_load
    (VAR dependent_system: nit$dependent_system);

    VAR
      status: ost$status;

    close_load_file (dependent_system);

{   pmp$log ('load terminated by help request', status);

  PROCEND truncate_load;

MODEND nam$independent_init_manager;
