?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Deadstart : Automatic PP Reload' ??
MODULE dsm$mtr_automatic_pp_reload;

{ PURPOSE:
{   This module contains the monitor procedures that support the automatic reload of a PP.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cml$pp_hung
*copyc cyd$cybil_structure_definitions
*copyc dst$automatic_pp_reload
*copyc dst$dft_pp_registers
*copyc dst$log_hung_pp_data
*copyc dst$mtr_dft_requests
*copyc dst$signal_contents
?? POP ??
*copyc dpp$display_error
*copyc dsp$mtr_dft_puf_request
*copyc dsp$mtr_dft_reload_sci
*copyc dsp$report_system_message
*copyc dsp$mtr_reserve_puf_memory_area
*copyc dsp$mtr_return_puf_memory_area
*copyc iop$reload_hung_disk_pp
*copyc mtp$error_stop
*copyc mtp$get_date_time_at_timestamp
*copyc mtp$step_unstep_system
*copyc tmp$send_signal
?? EJECT ??
*copyc cmv$logical_pp_table_p
*copyc dsv$cpu_pp_communication_block
*copyc dsv$dftb_data
*copyc tmv$system_job_monitor_gtid
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
  CONST
    c$driver_code_nil = 'It is too early in the deadstart process for the Automatic PP Reload ' CAT
          'process to successfully function.',
    c$pps_reconfigured = ', the Automatic PP Reload process is not allowed.  The PPs have been reconfigured.',
    c$process_is_disabled = 'The Automatic PP Reload process is disabled via the SETSA command.';

  VAR
    dsv$automatic_pp_reload: [XDCL, #GATE] dst$automatic_pp_reload :=
          [TRUE, FALSE, FALSE, [dsc$imn_null_model, dsc$imn_null_model]];
?? OLDTITLE ??
?? NEWTITLE := 'build_pp_address', EJECT ??

{ PURPOSE:
{   This procedure builds the PP address for a message string.

  PROCEDURE build_pp_address
    (    pp: dst$iou_resource;
         use_channel: boolean;
         channel: dst$iou_resource;
         driver_name: dst$driver_name;
     VAR message: ost$string);

    message.value := ' ';
    message.size := 1;

    message.value (message.size, 3) := 'IOU';
    message.size := message.size + 3;
    message.value (message.size, 1) := CHR ((pp.iou_number MOD 10) + ORD ('0'));
    message.size := message.size + 1;

    IF use_channel THEN
      IF channel.channel_protocol = dsc$cpt_nio THEN
        message.value (message.size, 3) := ' CH';
        message.size := message.size + 3;
      ELSE
        message.value (message.size, 4) := ' CCH';
        message.size := message.size + 4;
      IFEND;
      message.value (message.size, 1) := CHR ((channel.number DIV 8) + ORD ('0'));
      message.size := message.size + 1;
      message.value (message.size, 1) := CHR ((channel.number MOD 8) + ORD ('0'));
      message.size := message.size + 1;
      message.value (message.size, 4) := '(8) ';
      message.size := message.size + 4;
    IFEND;

    IF pp.channel_protocol = dsc$cpt_nio THEN
      message.value (message.size, 2) := 'PP';
      message.size := message.size + 2;
    ELSE
      message.value (message.size, 3) := 'CPP';
      message.size := message.size + 3;
    IFEND;
    message.value (message.size, 1) := CHR ((pp.number DIV 8) + ORD ('0'));
    message.size := message.size + 1;
    message.value (message.size, 1) := CHR ((pp.number MOD 8) + ORD ('0'));
    message.size := message.size + 1;
    message.value (message.size, 4) := '(8) ';
    message.size := message.size + 4;

    message.value (message.size, 1) := '(';
    message.size := message.size + 1;
    message.value (message.size, 7) := driver_name;
    message.size := message.size + 7;
    message.value (message.size, 9) := ') hung.  ';
    message.size := message.size + 9;

  PROCEND build_pp_address;
?? OLDTITLE ??
?? NEWTITLE := 'log_hung_pp_data', EJECT ??

{ PURPOSE:
{   This procedure retrieves the data from the hung PP for the statistic and sends the statistic to job mode
{   to be emitted.

  PROCEDURE log_hung_pp_data
    (    logical_pp: iot$pp_number);

    TYPE
      t$eng_log_msg = RECORD
        message_type: integer,
        hung_pp_data: dst$log_hung_pp_data,
      RECEND,

      t$pp_data = RECORD
        CASE 0 .. 2 OF
        = 0 =
          data: ARRAY [1 .. 2] OF integer,
        = 1 =
          pp_registers: dst$dft_pp_registers,
        = 2 =
          r_register: integer,
          unused: integer,
        CASEND,
      RECEND;

    VAR
      puf_memory_area_p: ^dst$mtr_dft_puf_memory_area,
      eng_log_msg: t$eng_log_msg,
      index: 1 .. 3,
      local_status: syt$monitor_status,
      msg_recorded: boolean,
      pp_data: ARRAY [1 .. 3] OF t$pp_data,
      seq_p: ^SEQ ( * );

    eng_log_msg.hung_pp_data.pp := cmv$logical_pp_table_p^ [logical_pp].pp_info.physical_pp;
    eng_log_msg.hung_pp_data.channel := cmv$logical_pp_table_p^ [logical_pp].pp_info.channel;
    eng_log_msg.hung_pp_data.driver_name := cmv$logical_pp_table_p^ [logical_pp].pp_info.driver_name;

    dsp$mtr_reserve_puf_memory_area (puf_memory_area_p);

    seq_p := #SEQ (puf_memory_area_p^);
    FOR index := 1 TO 3 DO
      puf_memory_area_p^.data [1] := 0;
      puf_memory_area_p^.data [2] := 0;
      dsp$mtr_dft_puf_request (dsc$dpuf_dump_pp_registers, logical_pp, 0, seq_p, local_status);
      IF NOT local_status.normal THEN
        mtp$error_stop ('Unable to perform dump_pp_registers DFT request.');
      IFEND;
      pp_data [index].data := puf_memory_area_p^.data;
    FOREND;
    eng_log_msg.hung_pp_data.pp_hung_on_one_instruction :=
          (pp_data [1].pp_registers.p_register = pp_data [2].pp_registers.p_register) AND
          (pp_data [1].pp_registers.p_register = pp_data [3].pp_registers.p_register);
    eng_log_msg.hung_pp_data.pp_registers := pp_data [3].pp_registers;

    seq_p := NIL;
    dsp$mtr_dft_puf_request (dsc$dpuf_idle_pp, logical_pp, 0, seq_p, local_status);
    IF NOT local_status.normal THEN
      mtp$error_stop ('Unable to perform idle_pp DFT request.');
    IFEND;

    seq_p := #SEQ (puf_memory_area_p^);
    puf_memory_area_p^.data [1] := 0;
    puf_memory_area_p^.data [2] := 0;
    dsp$mtr_dft_puf_request (dsc$dpuf_capture_r_register, logical_pp, 0, seq_p, local_status);
    IF NOT local_status.normal THEN
      mtp$error_stop ('Unable to perform capture_r_register DFT request.');
    IFEND;
    pp_data [1].data := puf_memory_area_p^.data;
    eng_log_msg.hung_pp_data.r_register := pp_data [1].r_register;

    { After DFT captures the R register it leaves the PP in an unknown state.  It is necessary to hardware
    { idle the PP again to assure that the PP is in a known state.

    seq_p := NIL;
    dsp$mtr_dft_puf_request (dsc$dpuf_idle_pp, logical_pp, 0, seq_p, local_status);
    IF NOT local_status.normal THEN
      mtp$error_stop ('Unable to perform idle_pp DFT request.');
    IFEND;

    dsp$mtr_return_puf_memory_area;

    eng_log_msg.message_type := cml$pp_hung;
    dsp$report_system_message (#SEQ (eng_log_msg), dsc$general_system_message, dsc$informative_message,
          msg_recorded);

  PROCEND log_hung_pp_data;
?? OLDTITLE ??
?? NEWTITLE := 'handle_hung_pp', EJECT ??

{ PURPOSE:
{   This procedure processes the hung PP.

  PROCEDURE handle_hung_pp
    (    pp: dst$iou_resource);

    VAR
      channel: dst$iou_resource,
      local_status: syt$monitor_status,
      logical_pp_index: iot$pp_number,
      message: ost$string,
      sci_pp: dst$iou_resource,
      signal: dst$signal_contents;

    retrieve_sci_pp_number (sci_pp);
    IF pp = sci_pp THEN
      IF NOT dsv$automatic_pp_reload.enabled THEN
        build_pp_address (pp, FALSE, channel, 'SCI    ', message);
        message.value (message.size, *) := c$process_is_disabled;
        step_system (message);
      IFEND;
      dsp$mtr_dft_reload_sci (pp, local_status);
      IF NOT local_status.normal THEN
        signal.identifier := dsc$deadstart_signal;
        signal.contents.kind := dsc$signal_hung_pp_process;
        mtp$get_date_time_at_timestamp (#FREE_RUNNING_CLOCK (0), signal.contents.hpp_data.date_time);
        signal.contents.hpp_data.sci_reload_failed := TRUE;
        signal.contents.hpp_data.check_entire_table := FALSE;
        signal.contents.hpp_data.logical_pp_index := 0;
        tmp$send_signal (tmv$system_job_monitor_gtid, signal.signal, local_status);
      IFEND;
      RETURN;
    IFEND;

    FOR logical_pp_index := LOWERBOUND (cmv$logical_pp_table_p^) TO UPPERBOUND (cmv$logical_pp_table_p^) DO
      IF cmv$logical_pp_table_p^ [logical_pp_index].flags.configured AND
            (cmv$logical_pp_table_p^ [logical_pp_index].pp_info.physical_pp = pp) THEN
        IF NOT dsv$automatic_pp_reload.enabled THEN
          build_pp_address (pp, TRUE, cmv$logical_pp_table_p^ [logical_pp_index].pp_info.channel,
                cmv$logical_pp_table_p^ [logical_pp_index].pp_info.driver_name, message);
          message.value (message.size, *) := c$process_is_disabled;
          step_system (message);
        IFEND;
        IF NOT cmv$logical_pp_table_p^ [logical_pp_index].flags.pp_handshaking_supported AND
              NOT cmv$logical_pp_table_p^ [logical_pp_index].flags.pp_hung THEN
          cmv$logical_pp_table_p^ [logical_pp_index].flags.pp_hung := TRUE;
          signal.identifier := dsc$deadstart_signal;
          signal.contents.kind := dsc$signal_hung_pp_process;
          mtp$get_date_time_at_timestamp (#FREE_RUNNING_CLOCK (0), signal.contents.hpp_data.date_time);
          signal.contents.hpp_data.sci_reload_failed := FALSE;
          signal.contents.hpp_data.check_entire_table := FALSE;
          signal.contents.hpp_data.logical_pp_index := logical_pp_index;
          tmp$send_signal (tmv$system_job_monitor_gtid, signal.signal, local_status);
        IFEND;
        RETURN;
      IFEND;
    FOREND;

    IF NOT dsv$automatic_pp_reload.enabled THEN
      build_pp_address (pp, FALSE, channel, 'unknown', message);
      message.value (message.size, *) := c$process_is_disabled;
      step_system (message);
    IFEND;

  PROCEND handle_hung_pp;
?? OLDTITLE ??
?? NEWTITLE := 'retrieve_sci_pp_number', EJECT ??

{ PURPOSE:
{   This procedure retrieves the PP number of the SCI PP.

  PROCEDURE retrieve_sci_pp_number
    (VAR sci_pp: dst$iou_resource);

    sci_pp.iou_number := 0;
    CASE dsv$automatic_pp_reload.iou_model_type [0] OF
    = dsc$imn_i4_44_model, dsc$imn_i4_46_model =
      sci_pp.channel_protocol := dsc$cpt_cio;
    ELSE
      sci_pp.channel_protocol := dsc$cpt_nio;
    CASEND;
    sci_pp.number := dsv$cpu_pp_communication_block.relocation.sci_pp_number;

  PROCEND retrieve_sci_pp_number;
?? OLDTITLE ??
?? NEWTITLE := 'step_system', EJECT ??

{ PURPOSE:
{   This procedure steps the system with the given message.

  PROCEDURE step_system
    (    message: ost$string);

    VAR
      step_message: string (71);

    dpp$display_error (message.value);

    step_message := 'Automatic PP Reload process detected fatal error, see critical window.';

    mtp$step_unstep_system (syc$ic_fatal_software_error, step_message);

  PROCEND step_system;
?? OLDTITLE ??
?? NEWTITLE := 'translate_fs1_bits', EJECT ??

{ PURPOSE:
{   This procedure scans the FS1 register to determine the PP number of the hung PP.

  PROCEDURE translate_fs1_bits
    (    maintenance_register: integer;
     VAR pp: dst$iou_resource);

    TYPE
      t$maintenance_register = PACKED RECORD
        CASE 0 .. 3 OF
        = 0 =
          integer_part: integer,
        = 1 =
          s0_part: t$mr_s0_part,
        = 2 =
          other_part: t$mr_other_part,
        = 3 =
          other_part_by_bit: PACKED ARRAY [0 .. 63] OF boolean,
        CASEND,
      RECEND,

      t$mr_other_part = PACKED RECORD
        unused_1: 0 .. 7,
        bits_3_7: 0 .. 1f(16),
        unused_2: 0 .. 7,
        bits_11_15: 0 .. 1f(16),
        unused_3: 0 .. 7,
        bits_19_23: 0 .. 1f(16),
        unused_4: 0 .. 7,
        bits_27_31: 0 .. 1f(16),
        unused_5: 0 .. 0ffffffff(16),
      RECEND,

      t$mr_s0_part = PACKED RECORD
        unused_1: 0 .. 3ffffffff(16),
        bit_34: boolean,
        unused_2: 0 .. 1fffffff(16),
      RECEND;

    VAR
      pp_found: boolean,
      register: t$maintenance_register;

    register.integer_part := maintenance_register;

    IF dsv$automatic_pp_reload.iou_model_type [pp.iou_number] = dsc$imn_i0_5x_model THEN
      IF register.s0_part.bit_34 THEN
        pp.channel_protocol := dsc$cpt_nio;
        handle_hung_pp (pp);
      IFEND;
      RETURN;
    IFEND;

    WHILE TRUE DO
      pp_found := FALSE;
      IF register.other_part.bits_3_7 <> 0 THEN
        IF register.other_part_by_bit [3] THEN
          register.other_part_by_bit [3] := FALSE;
          pp_found := TRUE;
          pp.number := 4(8);
        ELSEIF register.other_part_by_bit [4] THEN
          register.other_part_by_bit [4] := FALSE;
          pp_found := TRUE;
          pp.number := 3(8);
        ELSEIF register.other_part_by_bit [5] THEN
          register.other_part_by_bit [5] := FALSE;
          pp_found := TRUE;
          pp.number := 2(8);
        ELSEIF register.other_part_by_bit [6] THEN
          register.other_part_by_bit [6] := FALSE;
          pp_found := TRUE;
          pp.number := 1(8);
        ELSEIF register.other_part_by_bit [7] THEN
          register.other_part_by_bit [7] := FALSE;
          pp_found := TRUE;
          pp.number := 0(8);
        IFEND;
      ELSEIF register.other_part.bits_11_15 <> 0 THEN
        IF register.other_part_by_bit [11] THEN
          register.other_part_by_bit [11] := FALSE;
          pp_found := TRUE;
          pp.number := 11(8);
        ELSEIF register.other_part_by_bit [12] THEN
          register.other_part_by_bit [12] := FALSE;
          pp_found := TRUE;
          pp.number := 10(8);
        ELSEIF register.other_part_by_bit [13] THEN
          register.other_part_by_bit [13] := FALSE;
          pp_found := TRUE;
          pp.number := 7(8);
        ELSEIF register.other_part_by_bit [14] THEN
          register.other_part_by_bit [14] := FALSE;
          pp_found := TRUE;
          pp.number := 6(8);
        ELSEIF register.other_part_by_bit [15] THEN
          register.other_part_by_bit [15] := FALSE;
          pp_found := TRUE;
          pp.number := 5(8);
        IFEND;
      ELSEIF register.other_part.bits_19_23 <> 0 THEN
        IF register.other_part_by_bit [19] THEN
          register.other_part_by_bit [19] := FALSE;
          pp_found := TRUE;
          pp.number := 24(8);
        ELSEIF register.other_part_by_bit [20] THEN
          register.other_part_by_bit [20] := FALSE;
          pp_found := TRUE;
          pp.number := 23(8);
        ELSEIF register.other_part_by_bit [21] THEN
          register.other_part_by_bit [21] := FALSE;
          pp_found := TRUE;
          pp.number := 22(8);
        ELSEIF register.other_part_by_bit [22] THEN
          register.other_part_by_bit [22] := FALSE;
          pp_found := TRUE;
          pp.number := 21(8);
        ELSEIF register.other_part_by_bit [23] THEN
          register.other_part_by_bit [23] := FALSE;
          pp_found := TRUE;
          pp.number := 20(8);
        IFEND;
      ELSEIF register.other_part.bits_27_31 <> 0 THEN
        IF register.other_part_by_bit [27] THEN
          register.other_part_by_bit [27] := FALSE;
          pp_found := TRUE;
          pp.number := 31(8);
        ELSEIF register.other_part_by_bit [28] THEN
          register.other_part_by_bit [28] := FALSE;
          pp_found := TRUE;
          pp.number := 30(8);
        ELSEIF register.other_part_by_bit [29] THEN
          register.other_part_by_bit [29] := FALSE;
          pp_found := TRUE;
          pp.number := 27(8);
        ELSEIF register.other_part_by_bit [30] THEN
          register.other_part_by_bit [30] := FALSE;
          pp_found := TRUE;
          pp.number := 26(8);
        ELSEIF register.other_part_by_bit [31] THEN
          register.other_part_by_bit [31] := FALSE;
          pp_found := TRUE;
          pp.number := 25(8);
        IFEND;
      IFEND;

      IF NOT pp_found THEN
        RETURN;
      IFEND;

      CASE dsv$automatic_pp_reload.iou_model_type [pp.iou_number] OF
      = dsc$imn_i1_10_model, dsc$imn_i1_11_model, dsc$imn_i1_12_model, dsc$imn_i1_13_model,
            dsc$imn_i1_14_model, dsc$imn_i2_20_model =
        pp.channel_protocol := dsc$cpt_nio;
      = dsc$imn_i4_42_model =
        IF pp.number = 25(8) THEN
          pp.channel_protocol := dsc$cpt_cio;
          pp.number := 0;
        ELSEIF pp.number = 26(8) THEN
          pp.channel_protocol := dsc$cpt_cio;
          pp.number := 1;
        ELSEIF pp.number = 27(8) THEN
          pp.channel_protocol := dsc$cpt_cio;
          pp.number := 2;
        ELSEIF pp.number = 30(8) THEN
          pp.channel_protocol := dsc$cpt_cio;
          pp.number := 3;
        ELSEIF pp.number = 31(8) THEN
          pp.channel_protocol := dsc$cpt_cio;
          pp.number := 4;
        ELSE
          pp.channel_protocol := dsc$cpt_nio;
        IFEND;
      = dsc$imn_i4_44_model, dsc$imn_i4_46_model =
        pp.channel_protocol := dsc$cpt_cio;
      ELSE
      CASEND;

      handle_hung_pp (pp);
    WHILEND;

  PROCEND translate_fs1_bits;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$mtr_handle_bit_57', EJECT ??

{ PURPOSE:
{   This procedure processes the OS Action code that is sent by DFT when it detects a bit 57 condition.
{   The procedure reloads SCI and notes all of the PPs that do not support handshaking.  PPs that do
{   support handshaking will be detected by the handshaking process.

  PROCEDURE [XDCL] dsp$mtr_handle_bit_57
    (    element_number: dst$dftb_mrt_element_index);

    VAR
      index: iot$pp_number,
      iou_number: dst$iou_number,
      local_status: syt$monitor_status,
      message: ost$string,
      sci_pp: dst$iou_resource,
      signal: dst$signal_contents;

    IF dsv$automatic_pp_reload.turned_off THEN
      RETURN;
    IFEND;

    IF element_number = dsc$dftb_eid_iou0_element THEN
      message.value := 'Fatal IOU0 error - Bit 57 condition detected';
      iou_number := 0;
    ELSE
      message.value := 'Fatal IOU1 error - Bit 57 condition detected';
      iou_number := 1;
    IFEND;
    message.size := 44;

    IF dsv$automatic_pp_reload.pps_reconfigured THEN
      message.value (message.size + 1, *) := c$pps_reconfigured;
      step_system (message);
    IFEND;

    IF NOT dsv$automatic_pp_reload.enabled THEN
      message.value (message.size, *) := c$process_is_disabled;
      step_system (message);
    IFEND;

    FOR index := LOWERBOUND (cmv$logical_pp_table_p^) TO UPPERBOUND (cmv$logical_pp_table_p^) DO
      IF cmv$logical_pp_table_p^ [index].flags.configured AND
            cmv$logical_pp_table_p^ [index].flags.resources_acquired AND
            cmv$logical_pp_table_p^ [index].flags.pp_loaded AND
            NOT cmv$logical_pp_table_p^ [index].flags.pp_handshaking_supported AND
            NOT cmv$logical_pp_table_p^ [index].flags.pp_hung AND
            (cmv$logical_pp_table_p^ [index].pp_info.physical_pp.iou_number = iou_number) THEN
        cmv$logical_pp_table_p^ [index].flags.pp_hung := TRUE;
      IFEND;
    FOREND;

    retrieve_sci_pp_number (sci_pp);
    dsp$mtr_dft_reload_sci (sci_pp, local_status);
    IF NOT local_status.normal THEN
      signal.identifier := dsc$deadstart_signal;
      signal.contents.kind := dsc$signal_hung_pp_process;
      mtp$get_date_time_at_timestamp (#FREE_RUNNING_CLOCK (0), signal.contents.hpp_data.date_time);
      signal.contents.hpp_data.sci_reload_failed := TRUE;
      signal.contents.hpp_data.check_entire_table := FALSE;
      signal.contents.hpp_data.logical_pp_index := 0;
      tmp$send_signal (tmv$system_job_monitor_gtid, signal.signal, local_status);
    IFEND;

    signal.identifier := dsc$deadstart_signal;
    signal.contents.kind := dsc$signal_hung_pp_process;
    mtp$get_date_time_at_timestamp (#FREE_RUNNING_CLOCK (0), signal.contents.hpp_data.date_time);
    signal.contents.hpp_data.sci_reload_failed := FALSE;
    signal.contents.hpp_data.check_entire_table := TRUE;
    signal.contents.hpp_data.logical_pp_index := 0;
    tmp$send_signal (tmv$system_job_monitor_gtid, signal.signal, local_status);

  PROCEND dsp$mtr_handle_bit_57;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$mtr_handle_pp_hang', EJECT ??

{ PURPOSE:
{   This procedure processes the OS Action code that is sent by DFT when it detects a hung PP.

  PROCEDURE [XDCL] dsp$mtr_handle_pp_hang
    (    element_number: dst$dftb_mrt_element_index;
         data_from_mrb: boolean;
         data_p: ^cell);

    VAR
      buffer_seq_p: ^SEQ ( * ),
      data_length: integer,
      index: 1 .. dsc$dftb_mr_number_of_registers,
      maintenance_registers_p: ^dst$dftb_maintenance_registers,
      message: ost$string,
      nrb_internal_header_p: ^dst$dftb_nrb_internal_header,
      partial_nrb_record_p: ^ARRAY [1 .. 5] OF integer,
      pp: dst$iou_resource,
      register_data_p: ^SEQ ( * ),
      seq_entry_pp: ^^SEQ ( * ),
      seq_header: cyt$sequence_pointer,
      skip_data_p: ^SEQ ( * );

    IF dsv$automatic_pp_reload.turned_off THEN
      RETURN;
    IFEND;

    IF dsv$automatic_pp_reload.pps_reconfigured THEN
      message.value := 'Hung PP detected';
      message.size := 16;
      message.value (message.size + 1, *) := c$pps_reconfigured;
      step_system (message);
    IFEND;

    IF data_p = NIL THEN
      RETURN;
    IFEND;

    seq_entry_pp := #LOC(seq_header);
    seq_header.pva := data_p;
    IF data_from_mrb THEN
      seq_header.length := dsv$dftb_data.mrb_length * 8;
    ELSE
      seq_header.length := dsv$dftb_data.nrb_length * 8;
    IFEND;
    seq_header.nextt := 0;
    buffer_seq_p := seq_entry_pp^;
    IF buffer_seq_p = NIL THEN
      RETURN;
    IFEND;
    RESET buffer_seq_p;

   /find_register_data/
    BEGIN
      IF data_from_mrb THEN
        NEXT register_data_p: [[REP dsv$dftb_data.mrb_length OF integer]] IN buffer_seq_p;
      ELSE
        data_length := #SIZE (buffer_seq_p^);
        NEXT partial_nrb_record_p IN buffer_seq_p;
        data_length := data_length - #SIZE (partial_nrb_record_p^);
        WHILE data_length > 0 DO
          NEXT nrb_internal_header_p IN buffer_seq_p;
          IF nrb_internal_header_p^.type_code = dsc$dftb_nrb_ih_register_data THEN
            NEXT register_data_p: [[REP (nrb_internal_header_p^.length - 1) OF integer]] IN buffer_seq_p;
            EXIT /find_register_data/;
          IFEND;
          NEXT skip_data_p: [[REP (nrb_internal_header_p^.length - 1) OF integer]] IN buffer_seq_p;
          data_length := data_length - (nrb_internal_header_p^.length * 8);
        WHILEND;
        RETURN;
      IFEND;
    END /find_register_data/;

    IF element_number = dsc$dftb_eid_iou0_element THEN
      pp.iou_number := 0;
    ELSE
      pp.iou_number := 1;
    IFEND;

    RESET register_data_p;
    data_length := #SIZE (register_data_p^);
    WHILE data_length > 0 DO
      NEXT maintenance_registers_p IN register_data_p;
      data_length := data_length - #SIZE (maintenance_registers_p^);
      FOR index := 1 TO dsc$dftb_mr_number_of_registers DO

        CASE dsv$automatic_pp_reload.iou_model_type [pp.iou_number] OF
        = dsc$imn_i1_10_model, dsc$imn_i1_11_model, dsc$imn_i1_12_model, dsc$imn_i1_13_model,
              dsc$imn_i1_14_model, dsc$imn_i2_20_model, dsc$imn_i4_42_model, dsc$imn_i4_44_model,
              dsc$imn_i4_46_model =
          IF maintenance_registers_p^.register_header [index].register_number = 80(16) THEN
            translate_fs1_bits (maintenance_registers_p^.register_list [index], pp);
            RETURN;
          IFEND;

        = dsc$imn_i4_40_model =
          IF maintenance_registers_p^.register_header [index].register_number = 80(16) THEN
            pp.channel_protocol := dsc$cpt_nio;
            translate_fs1_bits (maintenance_registers_p^.register_list [index], pp);
          IFEND;
          IF maintenance_registers_p^.register_header [index].register_number = 84(16) THEN
            pp.channel_protocol := dsc$cpt_cio;
            translate_fs1_bits (maintenance_registers_p^.register_list [index], pp);
          IFEND;

        = dsc$imn_i0_5x_model =
          IF ((maintenance_registers_p^.register_header [index].register_number >= 90(16)) AND
                (maintenance_registers_p^.register_header [index].register_number <= 94(16))) THEN
            pp.number := maintenance_registers_p^.register_header [index].register_number - 90(16);
            translate_fs1_bits (maintenance_registers_p^.register_list [index], pp);
          ELSEIF ((maintenance_registers_p^.register_header [index].register_number >= 0A0(16)) AND
                (maintenance_registers_p^.register_header [index].register_number <= 0A4(16))) THEN
            pp.number := maintenance_registers_p^.register_header [index].register_number - 0A0(16);
            translate_fs1_bits (maintenance_registers_p^.register_list [index], pp);
          IFEND;

        ELSE
        CASEND;
      FOREND;
    WHILEND;

  PROCEND dsp$mtr_handle_pp_hang;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$mtr_process_hung_pp', EJECT ??

{ PURPOSE:
{   This procedure processes a hung PP that was detected by the CPU handshaking with the PP.

  PROCEDURE [XDCL] dsp$mtr_process_hung_pp
    (    logical_pp: iot$pp_number);

    VAR
      local_status: syt$monitor_status,
      message: ost$string,
      pp: dst$iou_resource,
      seq_p: ^SEQ ( * ),
      signal: dst$signal_contents;

    IF dsv$automatic_pp_reload.turned_off THEN
      RETURN;
    IFEND;

    cmv$logical_pp_table_p^ [logical_pp].flags.pp_hung := TRUE;

    pp := cmv$logical_pp_table_p^ [logical_pp].pp_info.physical_pp;

    build_pp_address (pp, TRUE, cmv$logical_pp_table_p^ [logical_pp].pp_info.channel,
          cmv$logical_pp_table_p^ [logical_pp].pp_info.driver_name, message);

    IF NOT dsv$automatic_pp_reload.enabled THEN
      message.value (message.size, *) := c$process_is_disabled;
      step_system (message);
    IFEND;

    log_hung_pp_data (logical_pp);

    { Determine if pointer to the driver code needed to reload the driver in monitor exists.
    { The pointer would not exist in the boot therefore reload is not available in the boot.

    CASE cmv$logical_pp_table_p^ [logical_pp].pp_info.pp_type OF
    = cmc$lpt_disk_pp_type, cmc$lpt_nad_pp_type =
      IF cmv$logical_pp_table_p^ [logical_pp].pp_info.driver_code_p = NIL THEN
        message.value (message.size + 1, *) := c$driver_code_nil;
        step_system (message);
      IFEND;
    ELSE
    CASEND;

    { Network channels are NOT master cleared.

    IF (cmv$logical_pp_table_p^ [logical_pp].pp_info.pp_type <> cmc$lpt_network_pp_type) AND
          (cmv$logical_pp_table_p^ [logical_pp].pp_info.pp_type <> cmc$lpt_nad_pp_type) THEN
      seq_p := NIL;
      dsp$mtr_dft_puf_request (dsc$dpuf_master_clear_channel, logical_pp, 0, seq_p, local_status);
      IF NOT local_status.normal THEN
        mtp$error_stop ('Unable to perform master_clear_channel DFT request.');
      IFEND;
    IFEND;

    IF cmv$logical_pp_table_p^ [logical_pp].flags.pp_reload_supported THEN
      CASE cmv$logical_pp_table_p^ [logical_pp].pp_info.pp_type OF
      = cmc$lpt_disk_pp_type =
        iop$reload_hung_disk_pp (logical_pp);
        RETURN;
      = cmc$lpt_nad_pp_type =
        seq_p := NIL;
        dsp$mtr_dft_puf_request (dsc$dpuf_load_pp, logical_pp, 0, seq_p, local_status);
        IF NOT local_status.normal THEN
          mtp$error_stop ('Unable to load the NAD driver via a DFT request.');
        IFEND;
        cmv$logical_pp_table_p^ [logical_pp].flags.pp_hung := FALSE;
        RETURN;
      ELSE
      CASEND;
    IFEND;

    signal.identifier := dsc$deadstart_signal;
    signal.contents.kind := dsc$signal_hung_pp_process;
    mtp$get_date_time_at_timestamp (#FREE_RUNNING_CLOCK (0), signal.contents.hpp_data.date_time);
    signal.contents.hpp_data.sci_reload_failed := FALSE;
    signal.contents.hpp_data.check_entire_table := FALSE;
    signal.contents.hpp_data.logical_pp_index := logical_pp;
    tmp$send_signal (tmv$system_job_monitor_gtid, signal.signal, local_status);

  PROCEND dsp$mtr_process_hung_pp;
?? OLDTITLE ??
MODEND dsm$mtr_automatic_pp_reload;
