?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Deadstart : Miscellaneous Procedures' ??
MODULE dsm$deadstart_services;

{ PURPOSE:
{   This module contains utility procedures used during and after the deadstart process.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cmt$channel_type
*copyc cyd$cybil_structure_definitions
*copyc dse$error_codes
*copyc dst$boot_data_kinds
*copyc dst$change_processor_state
*copyc dst$channel_state
*copyc dst$cpu_attributes
*copyc dst$dft_requests
*copyc dst$iou_information_table
*copyc osc$maximum_processors
*copyc oss$mainframe_pageable
*copyc ost$heap
*copyc ost$iou_model_number
*copyc ost$processor_id
?? POP ??
*copyc clp$convert_integer_to_string
*copy  dpp$put_critical_message
*copyc dsp$access_secure_mode
*copyc dsp$access_vcu_cda_data
*copyc dsp$change_cy2000_element
*copyc dsp$get_cy2000_element
*copyc dsp$get_data_from_ssr
*copyc dsp$get_entry_from_ssr
*copyc dsp$get_iou_status_register
*copyc dsp$manage_virtual_cpu
*copyc dsp$read_mrt_entry
*copyc dsp$start_additional_cpu
*copyc dsp$store_data_in_ssr
*copyc dsp$write_mrt_entry
*copyc osp$extend_heap
*copyc osp$fatal_system_error
*copyc osp$free_heap_pages
*copyc osp$set_status_abnormal
*copyc osp$system_error
*copyc pmp$zero_out_table
?? EJECT ??
*copyc avv$security_options
*copyc dsv$automatic_pp_reload
*copyc dsv$mainframe_type
*copyc dsv$mf_element_table_p
*copyc dsv$mtr_dft_requests
*copyc jmv$sdt
*copyc mmv$pft_p
*copyc mtv$cst0
*copyc mtv$scb
*copyc osv$mainframe_wired_heap
*copyc osv$mainframe_wired_cb_heap
*copyc osv$page_size
*copyc osv$boot_sdte
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
  CONST
    c$number_of_memory_elements = 1,
    c$number_of_page_map_elements = 1;

  TYPE
    t$boot_data_list = ARRAY [dst$boot_data_kinds] OF REL (SEQ ( * )) ^SEQ ( * );

  VAR
    mtv$recovery_lock1: [XREF] boolean;

  VAR
    dsv$boot_data_base_p: [XDCL] ^SEQ ( * ) := NIL,


    v$iou_information_table: [STATIC, oss$mainframe_pageable] dst$iou_information_table,
    v$mrt_channel_types: [STATIC, oss$mainframe_pageable]
          ARRAY [dst$iou_number] OF
          ARRAY [dst$channel_protocol_type] OF
          ARRAY [dst$physical_resource_number] OF RECORD
            known_channel_type: boolean,
            channel_type: cmt$channel_type,
          RECEND,
    v$number_of_ious: [STATIC, oss$mainframe_pageable] 0 .. dsc$max_number_of_ious;
?? OLDTITLE ??
?? NEWTITLE := 'build_channel_types_table', EJECT ??

{ PURPOSE:
{   This procedure builds the table containing channel types.

  PROCEDURE build_channel_types_table
    (    model_type: dst$iou_model_types;
         iou_number: dst$iou_number;
         mrt_entry: dst$mrt_entry);

?? NEWTITLE := 'retrieve_channel_types', EJECT ??

{ PURPOSE:
{   This procedure retrieves the channel types from the MRT.

    PROCEDURE retrieve_channel_types
      (    number_of_entries: 1 .. 12;
           iou_number: dst$iou_number;
           channel_protocol: dst$channel_protocol_type;
           mrt_channel_types: ARRAY [1 .. *] OF dst$mrt_two_channel_descriptor);

      VAR
        index: 1 .. 12,
        number: 0 .. 34(8);

      number := 0;
      FOR index := 1 TO number_of_entries DO

        { Retrieve the channel type from the 'a' channel entry in the two channel entry from the MRT.

        v$mrt_channel_types [iou_number] [channel_protocol] [number].known_channel_type := TRUE;
        CASE mrt_channel_types [index].a_channel_type OF
        = dsc$mrt_ct_cyber_170_channel, dsc$mrt_ct_170_dma_esm_enhanced =
          v$mrt_channel_types [iou_number] [channel_protocol] [number].channel_type := cmc$170_channel;
        = dsc$mrt_ct_ici_s0 =
          v$mrt_channel_types [iou_number] [channel_protocol] [number].channel_type := cmc$ici_channel;
        = dsc$mrt_ct_isi_channel, dsc$mrt_ct_isi_dma_channel =
          v$mrt_channel_types [iou_number] [channel_protocol] [number].channel_type := cmc$isi_channel;
        = dsc$mrt_ct_ipi_dma_enhanced, dsc$mrt_ct_ipi_s0, dsc$mrt_ct_ipi_dma_dual_port =
          v$mrt_channel_types [iou_number] [channel_protocol] [number].channel_type := cmc$ipi_channel;
        ELSE
          v$mrt_channel_types [iou_number] [channel_protocol] [number].known_channel_type := FALSE;
        CASEND;
        number := number + 1;

        { Retrieve the channel type from the 'b' channel entry in the two channel entry from the MRT.

        v$mrt_channel_types [iou_number] [channel_protocol] [number].known_channel_type := TRUE;
        CASE mrt_channel_types [index].b_channel_type OF
        = dsc$mrt_ct_cyber_170_channel, dsc$mrt_ct_170_dma_esm_enhanced =
          v$mrt_channel_types [iou_number] [channel_protocol] [number].channel_type := cmc$170_channel;
        = dsc$mrt_ct_ici_s0 =
          v$mrt_channel_types [iou_number] [channel_protocol] [number].channel_type := cmc$ici_channel;
        = dsc$mrt_ct_isi_channel, dsc$mrt_ct_isi_dma_channel =
          v$mrt_channel_types [iou_number] [channel_protocol] [number].channel_type := cmc$isi_channel;
        = dsc$mrt_ct_ipi_dma_enhanced, dsc$mrt_ct_ipi_s0, dsc$mrt_ct_ipi_dma_dual_port =
          v$mrt_channel_types [iou_number] [channel_protocol] [number].channel_type := cmc$ipi_channel;
        ELSE
          v$mrt_channel_types [iou_number] [channel_protocol] [number].known_channel_type := FALSE;
        CASEND;
        number := number + 1;
        IF number = 14(8) THEN
          number := 20(8);
        IFEND;
      FOREND;

    PROCEND retrieve_channel_types;

?? OLDTITLE, EJECT ??

    VAR
      mrt_channel_types: ARRAY [1 .. 12] OF dst$mrt_two_channel_descriptor;

    { Retrieve the NIO channel states.

    mrt_channel_types [1] := mrt_entry.iou.channel_00_01;
    mrt_channel_types [2] := mrt_entry.iou.channel_02_03;
    mrt_channel_types [3] := mrt_entry.iou.channel_04_05;
    mrt_channel_types [4] := mrt_entry.iou.channel_06_07;
    mrt_channel_types [5] := mrt_entry.iou.channel_10b_11b;
    mrt_channel_types [6] := mrt_entry.iou.channel_12b_13b;
    mrt_channel_types [7] := mrt_entry.iou.channel_20b_21b;
    mrt_channel_types [8] := mrt_entry.iou.channel_22b_23b;
    mrt_channel_types [9] := mrt_entry.iou.channel_24b_25b;
    mrt_channel_types [10] := mrt_entry.iou.channel_26b_27b;
    mrt_channel_types [11] := mrt_entry.iou.channel_30b_31b;
    mrt_channel_types [12] := mrt_entry.iou.channel_32b_33b;

    IF model_type = dsc$imn_i4_44_model THEN
      retrieve_channel_types (12, iou_number, dsc$cpt_cio, mrt_channel_types);
    ELSE
      retrieve_channel_types (12, iou_number, dsc$cpt_nio, mrt_channel_types);

      { Retrieve the CIO channel states.

      mrt_channel_types [1] := mrt_entry.iou.i4_cio_channel_00_01;
      mrt_channel_types [2] := mrt_entry.iou.i4_cio_channel_02_03;
      mrt_channel_types [3] := mrt_entry.iou.i4_cio_channel_04_05;
      mrt_channel_types [4] := mrt_entry.iou.i4_cio_channel_06_07;
      mrt_channel_types [5] := mrt_entry.iou.i4_cio_channel_10b_11b;

      retrieve_channel_types (5, iou_number, dsc$cpt_cio, mrt_channel_types);
    IFEND;

  PROCEND build_channel_types_table;
?? OLDTITLE ??
?? NEWTITLE := 'build_iou_table', EJECT ??

{ PURPOSE:
{   This procedure places iou information in the iou information table.

  PROCEDURE build_iou_table
    (    iou_index: dst$iou_number;
         model_number: 0 .. 0fff(16));

    v$number_of_ious := v$number_of_ious + 1;
    v$iou_information_table [v$number_of_ious].physical_iou_number := iou_index;

    { Setup the IOU MODEL TYPE from the model number in the MRT.

    CASE model_number OF
    = osc$imn_10 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i1_10_model;
    = osc$imn_11 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i1_11_model;
    = osc$imn_12 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i1_12_model;
    = osc$imn_13 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i1_13_model;
    = osc$imn_14 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i1_14_model;
    = osc$imn_20 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i2_20_model;
    = osc$imn_40 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i4_40_model;
    = osc$imn_42 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i4_42_model;
    = osc$imn_44 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i4_44_model;
    = osc$imn_46 =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i4_46_model;
    = osc$imn_50, osc$imn_51, osc$imn_52, osc$imn_53, osc$imn_54, osc$imn_55,
      osc$imn_5B, osc$imn_5C, osc$imn_5D, osc$imn_5E, osc$imn_5F =
      v$iou_information_table [v$number_of_ious].model_type := dsc$imn_i0_5x_model;
    ELSE
      osp$system_error ('Unrecognized IOU model number in the MRT', NIL);
    CASEND;

  PROCEND build_iou_table;
?? OLDTITLE ??
?? NEWTITLE := 'build_mainframe_element_entry', EJECT ??

{ PURPOSE:
{   This procedure builds a table entry from data in the element id from the MRT.
{   An output variable is used as an accumulator for the number of elements in the table.

  PROCEDURE build_mainframe_element_entry
    (    element_number: 0 .. 0ff(16);
         element_id: dst$dft_element_id;
     VAR actual_number_of_elements: ost$processor_element_number;
     VAR element_table_p: ^SEQ ( * ));

    VAR
      element_entry_p: ^dst$mf_element_table_entry,
      ignore_status: ost$status,
      number_string: ost$string;

    NEXT element_entry_p IN element_table_p;
    actual_number_of_elements := actual_number_of_elements + 1;
    element_entry_p^.element_id.element_number := element_number;
    element_entry_p^.element_id.dft_entry_id := element_id.element_number;
    element_entry_p^.model_number := element_id.model_number;
    element_entry_p^.serial_number := element_id.serial_number;

    clp$convert_integer_to_string (element_number, 16, FALSE, number_string, ignore_status);
    element_entry_p^.element_number_string.size := number_string.size;
    element_entry_p^.element_number_string.value := number_string.value;
    clp$convert_integer_to_string (element_entry_p^.model_number, 16, FALSE, number_string, ignore_status);
    element_entry_p^.model_number_string.size := number_string.size;
    element_entry_p^.model_number_string.value := number_string.value;
    clp$convert_integer_to_string (element_entry_p^.serial_number, 16, FALSE, number_string, ignore_status);
    element_entry_p^.serial_number_string.size := number_string.size;
    element_entry_p^.serial_number_string.value := number_string.value;

  PROCEND build_mainframe_element_entry;
?? OLDTITLE ??
?? NEWTITLE := 'cy2000_build_ch_types_table', EJECT ??

{ PURPOSE:
{   This procedure builds the table containing channel types for a Cyber 2000 mainframe.

  PROCEDURE cy2000_build_ch_types_table
    (    iou_number: dst$iou_number;
         element_id: 0 .. 0ff(16);
     VAR status: ost$status);

    VAR
      channel_element: dst$dft_get_channel_element,
      channel_element_seq_p: ^SEQ ( * ),
      channel_type: 0 .. 0ff(16),
      number: 0 .. 34(8);

    channel_element_seq_p := #SEQ (channel_element);
    RESET channel_element_seq_p;
    dsp$get_cy2000_element (element_id, dsc$dft_sub_channel, channel_element_seq_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    number := 0;
    WHILE number <= 33(8) DO
      IF number <= 13(8) THEN
        channel_type := channel_element.lower_channels [number].channel_type;
      ELSE
        channel_type := channel_element.upper_channels [number].channel_type;
      IFEND;
      CASE channel_type OF
      = dsc$mrt_ct_cyber_170_channel =
        v$mrt_channel_types [iou_number] [dsc$cpt_nio] [number].known_channel_type := TRUE;
        v$mrt_channel_types [iou_number] [dsc$cpt_nio] [number].channel_type := cmc$170_channel;
      = dsc$mrt_ct_170_dma_esm_enhanced =
        v$mrt_channel_types [iou_number] [dsc$cpt_cio] [number].known_channel_type := TRUE;
        v$mrt_channel_types [iou_number] [dsc$cpt_cio] [number].channel_type := cmc$170_channel;
      = dsc$mrt_ct_ici_s0 =
        v$mrt_channel_types [iou_number] [dsc$cpt_cio] [number].known_channel_type := TRUE;
        v$mrt_channel_types [iou_number] [dsc$cpt_cio] [number].channel_type := cmc$ici_channel;
      = dsc$mrt_ct_isi_channel, dsc$mrt_ct_isi_dma_channel =
        v$mrt_channel_types [iou_number] [dsc$cpt_cio] [number].known_channel_type := TRUE;
        v$mrt_channel_types [iou_number] [dsc$cpt_cio] [number].channel_type := cmc$isi_channel;
      = dsc$mrt_ct_ipi_dma_enhanced, dsc$mrt_ct_ipi_s0, dsc$mrt_ct_ipi_dma_dual_port =
        v$mrt_channel_types [iou_number] [dsc$cpt_cio] [number].known_channel_type := TRUE;
        v$mrt_channel_types [iou_number] [dsc$cpt_cio] [number].channel_type := cmc$ipi_channel;
      ELSE
      CASEND;
      number := number + 1;
      IF number = 14(8) THEN
        number := 20(8);
      IFEND;
    WHILEND;

  PROCEND cy2000_build_ch_types_table;
?? OLDTITLE ??
?? NEWTITLE := 'cy2000_build_mf_information', EJECT ??

{ PURPOSE:
{   This procedure builds the mainframe tables for a Cyber 2000 mainframe.

  PROCEDURE cy2000_build_mf_information;

    VAR
      actual_number_of_elements: ost$processor_element_number,
      cpu_element: dst$dft_get_cpu_element,
      cpu_index: ost$logical_processor_id,
      element_entry_p: ^dst$mf_element_table_entry,
      element_id: 0 .. 0ff(16),
      element_seq_p: ^SEQ ( * ),
      entry_index: ost$processor_element_number,
      iou_element: dst$dft_get_iou_element,
      iou_index: dst$iou_number,
      memory_element: dst$dft_get_memory_element,
      mode: 0 .. 0ffff(16),
      possible_number_of_elements: ost$processor_element_number,
      status: ost$status,
      temp_element_table_p: ^SEQ ( * );

    actual_number_of_elements := 0;
    possible_number_of_elements := osc$maximum_processors + c$number_of_memory_elements +
          dsc$max_number_of_ious;
    PUSH temp_element_table_p: [[REP possible_number_of_elements OF dst$mf_element_table_entry]];
    RESET temp_element_table_p;

    { Retrieve the CPU information from the MRT and build the CPU entry in the mainframe element table.

    element_id := dsc$dftb_eid_cpu0_element;
    element_seq_p := #SEQ (cpu_element);
    FOR cpu_index := LOWERVALUE (ost$logical_processor_id) TO UPPERVALUE (ost$logical_processor_id) DO
      RESET element_seq_p;
      dsp$get_cy2000_element (element_id, dsc$dft_sub_none, element_seq_p, status);
      IF status.normal AND (cpu_element.state <> dsc$dft_state_not_installed) THEN
        build_mainframe_element_entry (cpu_index, cpu_element.element_id, actual_number_of_elements,
              temp_element_table_p);
        IF cpu_element.vector_degrade = 0 THEN
          mtv$scb.vector_simulation_control.vector_divide_degraded :=
                mtv$scb.vector_simulation_control.vector_divide_degraded - $ost$processor_id_set [cpu_index];
        ELSE
          mtv$scb.vector_simulation_control.vector_divide_degraded :=
                mtv$scb.vector_simulation_control.vector_divide_degraded + $ost$processor_id_set [cpu_index];
        IFEND;
      IFEND;
      element_id := element_id + 10(16);
    FOREND;

    { Retrieve the MEMORY information from the MRT and build the MEMORY entry in the mainframe element table.

    element_seq_p := #SEQ (memory_element);
    RESET element_seq_p;
    dsp$get_cy2000_element (dsc$dftb_eid_memory_element, dsc$dft_sub_none, element_seq_p, status);
    IF NOT status.normal THEN
      osp$system_error ('ERROR, unable to find MEMORY information in the MRT.', NIL);
    IFEND;
    build_mainframe_element_entry (0, memory_element.element_id, actual_number_of_elements,
          temp_element_table_p);

    { Retrieve the IOU information from the MRT and build the IOU entry in the mainframe element table.

    element_id := dsc$dftb_eid_iou0_element;
    element_seq_p := #SEQ (iou_element);
    FOR iou_index := LOWERVALUE (dst$iou_number) TO UPPERVALUE (dst$iou_number) DO
      RESET element_seq_p;
      dsp$get_cy2000_element (element_id, dsc$dft_sub_none, element_seq_p, status);
      IF status.normal AND (iou_element.state <> dsc$dft_state_not_installed) THEN
        build_mainframe_element_entry (iou_index, iou_element.element_id, actual_number_of_elements,
            temp_element_table_p);
        IF iou_element.state = dsc$dft_state_on THEN
          build_iou_table (iou_index, iou_element.element_id.model_number);
          cy2000_build_ch_types_table (iou_index, element_id, status);
          IF NOT status.normal THEN
            osp$system_error ('ERROR, unable to determine channel type.', NIL);
          IFEND;
        IFEND;
      IFEND;
      element_id := element_id + 10(16);
    FOREND;

    IF v$number_of_ious = 0 THEN
      osp$system_error ('ERROR, unable to find IOU information in the MRT.', NIL);
    IFEND;

    { Store the element table in mainframe wired.

    ALLOCATE dsv$mf_element_table_p: [1 .. actual_number_of_elements] IN osv$mainframe_wired_heap^;
    RESET temp_element_table_p;
    FOR entry_index := 1 TO actual_number_of_elements DO
      NEXT element_entry_p IN temp_element_table_p;
      dsv$mf_element_table_p^ [entry_index] := element_entry_p^;
    FOREND;

    { Recover the secure analysis state.

    dsp$access_secure_mode (dsc$dft_return_secure_mode, mode, status);
    IF status.normal THEN
      avv$security_options [avc$vso_secure_analysis].active := (mode = dsc$dft_secure_mode_enabled);
    IFEND;

  PROCEND cy2000_build_mf_information;
?? OLDTITLE ??
?? NEWTITLE := 'cy2000_change_channel_states', EJECT ??

{ PURPOSE:
{   This procedure changes specific channel states in the MRT on a Cyber 2000 mainframe.

  PROCEDURE cy2000_change_channel_states
    (    channel_state_list: dst$partial_channel_state_list;
     VAR status: ost$status);

    VAR
      element_id: 0 .. 0ff(16),
      element_state: 0 .. 0ff(16),
      list_index: integer;

    status.normal := TRUE;

    FOR list_index := LOWERBOUND (channel_state_list) TO UPPERBOUND (channel_state_list) DO
      element_id := (channel_state_list [list_index].channel.iou_number * 10(16)) + dsc$dftb_eid_iou0_element;
      CASE channel_state_list [list_index].element_state OF
      = cmc$on =
        element_state := dsc$dft_state_on;
      = cmc$down =
        element_state := dsc$dft_state_down_by_operator;
      = cmc$off =
        element_state := dsc$dft_state_off;
      ELSE
        element_state := 0ff(16);
      CASEND;
      dsp$change_cy2000_element (element_id,
            (dsc$dft_sub_channel + channel_state_list [list_index].channel.number), element_state, status);
    FOREND;

  PROCEND cy2000_change_channel_states;
?? OLDTITLE ??
?? NEWTITLE := 'cy2000_read_channel_states', EJECT ??

{ PURPOSE:
{   This procedure reads the channel states from the MRT on Cyber 2000 mainframes.

  PROCEDURE cy2000_read_channel_states
    (VAR channel_state_list: dst$entire_channel_state_list;
     VAR status: ost$status);

    VAR
      channel_element: dst$dft_get_channel_element,
      channel_element_seq_p: ^SEQ ( * ),
      channel_protocol: dst$channel_protocol_type,
      channel_state: 0 .. 0ff(16),
      element_id: 0 .. 0ff(16),
      iou_index: dst$number_of_ious,
      iou_information_table: dst$iou_information_table,
      iou_number: dst$iou_number,
      number: 0 .. 34(8),
      number_of_ious: dst$number_of_ious,
      protocol_index: dst$channel_protocol_type;

    status.normal := TRUE;

    { Initialize the channel state list.

    FOR iou_number := LOWERVALUE (dst$iou_number) TO UPPERVALUE (dst$iou_number) DO
      FOR protocol_index := LOWERVALUE (dst$channel_protocol_type) TO
            UPPERVALUE (dst$channel_protocol_type) DO
        FOR number := LOWERVALUE (dst$physical_resource_number) TO
              UPPERVALUE (dst$physical_resource_number) DO
          channel_state_list [iou_number] [protocol_index] [number] := cmc$down;
        FOREND;
      FOREND;
    FOREND;

    dsp$retrieve_iou_information (number_of_ious, iou_information_table);
    channel_element_seq_p := #SEQ (channel_element);

    FOR iou_index := 1 TO number_of_ious DO
      iou_number := iou_information_table [iou_index].physical_iou_number;
      element_id := (iou_number * 10(16)) + dsc$dftb_eid_iou0_element;
      RESET channel_element_seq_p;
      dsp$get_cy2000_element (element_id, dsc$dft_sub_channel, channel_element_seq_p, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      number := 0;
      WHILE number <= 33(8) DO
        IF number <= 13(8) THEN
          channel_state := channel_element.lower_channels [number].state;
        ELSE
          channel_state := channel_element.upper_channels [number].state;
        IFEND;
        IF (number = 32(8)) OR (number = 33(8)) THEN
          channel_protocol := dsc$cpt_nio;
        ELSE
          channel_protocol := dsc$cpt_cio;
        IFEND;
        CASE channel_state OF
        = dsc$dft_state_on =
          channel_state_list [iou_number] [channel_protocol] [number] := cmc$on;
        = dsc$dft_state_down_by_system, dsc$dft_state_down_by_operator =
          channel_state_list [iou_number] [channel_protocol] [number] := cmc$down;
        ELSE
          channel_state_list [iou_number] [channel_protocol] [number] := cmc$off;
        CASEND;
        number := number + 1;
        IF number = 14(8) THEN
          number := 20(8);
        IFEND;
      WHILEND;
    FOREND;

  PROCEND cy2000_read_channel_states;
?? OLDTITLE ??
?? NEWTITLE := 'perform_miscellaneous_things', EJECT ??

{ PURPOSE:
{   This procedure performs several miscellaneous tasks early in deadstart.

  PROCEDURE perform_miscellaneous_things;

    TYPE
      t$iou_status = PACKED RECORD
        CASE 0 .. 2 OF
        = 0 =
          register: integer,
        = 1 =
          unused_1: 0 .. 0ffffffff(16),
          unused_2: 0 .. 07ffffff(16),
          bits_59_63: 0 .. 1f(16),
        = 2 =
          unused_a: 0 .. 0ffffffff(16),
          unused_b: 0 .. 01fffffff(16),
          bits_61_63: 0 .. 7,
        CASEND,
      RECEND;

    VAR
      iou: dst$iou_number,
      iou_status: t$iou_status,
      iou_status_register: integer,
      request_p: ^SEQ ( * ),
      status: ost$status;

    { Allocate space for the DFT requests issued from monitor.

    IF dsv$mtr_dft_requests.puf_p = NIL THEN
      dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap, #SIZE (dst$dft_process_pp_function),
            request_p);
      RESET request_p;
      NEXT dsv$mtr_dft_requests.puf_p IN request_p;
    IFEND;
    IF dsv$mtr_dft_requests.reload_sci_p = NIL THEN
      dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap, #SIZE (dst$dft_reload_sci),
            request_p);
      RESET request_p;
      NEXT dsv$mtr_dft_requests.reload_sci_p IN request_p;
    IFEND;
    IF dsv$mtr_dft_requests.puf_data_p = NIL THEN
      dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap, #SIZE (dst$mtr_dft_puf_memory_area),
            request_p);
      RESET request_p;
      NEXT dsv$mtr_dft_requests.puf_data_p IN request_p;
    IFEND;

    { Retrieve the IOU model type(s) for the automatic pp reload variable.

    FOR iou := 1 TO v$number_of_ious DO
      dsv$automatic_pp_reload.iou_model_type [v$iou_information_table [iou].physical_iou_number] :=
            v$iou_information_table [iou].model_type;
    FOREND;

    { Retrieves the IOU status register via DFT to and determine if the hardware physical PPs have
    { been reconfigured.  If reconfiguration has occurred, then the automatic reload of PPs will not
    { be allowed if DFT detects that a PP has hung.

   /search_ious/
    FOR iou := 0 TO (dsc$max_number_of_ious - 1) DO
      IF dsv$automatic_pp_reload.iou_model_type [iou] = dsc$imn_null_model THEN
        CYCLE /search_ious/;
      IFEND;

      dsp$get_iou_status_register (iou, iou_status_register, status);
      IF NOT status.normal THEN
        osp$system_error ('Unable to retrieve the IOU status register via DFT.', ^status);
      IFEND;
      iou_status.register := iou_status_register;

      CASE dsv$automatic_pp_reload.iou_model_type [iou] 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_40_model =
        dsv$automatic_pp_reload.pps_reconfigured := (iou_status.bits_59_63 <> 0);
        EXIT /search_ious/;
      = dsc$imn_i4_42_model, dsc$imn_i4_44_model, dsc$imn_i4_46_model =
        dsv$automatic_pp_reload.pps_reconfigured := (iou_status.bits_61_63 <> 0);
        EXIT /search_ious/;
      ELSE
      CASEND;
    FOREND /search_ious/;

  PROCEND perform_miscellaneous_things;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$allocate_continuous_memory', EJECT ??

{ PURPOSE:
{   This procedure returns a sequence pointer to an area of continuous memory.

  PROCEDURE [XDCL] dsp$allocate_continuous_memory
    (    heap_p: ^ost$heap;
         size: integer;
     VAR return_seq_p: ^SEQ ( * ));

    TYPE
      aligned_seq = RECORD
        seq_area: ALIGNED [0 MOD 65536] SEQ ( * ),
      RECEND,
      chain = RECORD
        seq_p: ^SEQ ( * ),
        chain_p: ^chain,
      RECEND;

    VAR
      aligned_seq_p: ^aligned_seq,
      area_index: integer,
      area_ok: boolean,
      area_p: ^ARRAY [1 .. *] OF cell,
      chain_p: ^chain,
      first_rma: integer,
      last_rma: integer,
      new_chain_p: ^chain,
      new_seq_p: ^SEQ ( * ),
      page_boundary_p: ^cell;

    area_ok := FALSE;
    chain_p := NIL;
    page_boundary_p := NIL;

    WHILE NOT area_ok DO
      osp$extend_heap (size, heap_p, page_boundary_p);
      ALLOCATE aligned_seq_p: [[REP size OF cell]] IN heap_p^;
      new_seq_p := ^aligned_seq_p^.seq_area;
      RESET new_seq_p;
      NEXT area_p: [1 .. size] IN new_seq_p;
      #real_memory_address (#LOC (area_p^ [1]), first_rma);

      { Make sure that the heap contains continuous memory.

      area_ok := TRUE;
      area_index := 1;
      WHILE (area_index < size) AND area_ok DO
        area_index := area_index + osv$page_size;
        IF area_index > size THEN
          area_index := size;
        IFEND;
        #real_memory_address (#LOC (area_p^[area_index]), last_rma);
        area_ok := (area_index - 1) = (last_rma - first_rma);
      WHILEND;

      IF area_ok THEN
        return_seq_p := new_seq_p;
      ELSE

        { Save a pointer to the unused meory area so that it can be freed later.

        PUSH new_chain_p;
        new_chain_p^.seq_p := new_seq_p;
        new_chain_p^.chain_p := chain_p;
        chain_p := new_chain_p;
      IFEND;
    WHILEND;

    { Free the unused memory areas.

    WHILE chain_p <> NIL DO
      new_seq_p := chain_p^.seq_p;
      chain_p := chain_p^.chain_p;
      FREE new_seq_p IN heap_p^;
    WHILEND;
    IF mmv$pft_p <> NIL THEN
      osp$free_heap_pages (heap_p);
    IFEND;

    { Zero out the return sequence.

    RESET return_seq_p;
    pmp$zero_out_table (return_seq_p, #SIZE (return_seq_p^));

  PROCEND dsp$allocate_continuous_memory;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$build_mainframe_information', EJECT ??

{ PURPOSE:
{   This procedure builds some tables from the MRT entries for IOU, CPU, MEMORY and PAGE_MAP.
{   The following variables are built by this procedure.
{       * A table is built which contains the element id, model number and serial number.  The
{         model and serial number are stored in string format because they are used numerous times
{         in the system in that format.
{       * A variable is built that contains the IOU model type.
{       * A variable is built that contains the number of IOUs and their names.

  PROCEDURE [XDCL] dsp$build_mainframe_information;

    VAR
      actual_number_of_elements: ost$processor_element_number,
      channel_index: dst$channel_protocol_type,
      cpu_index: ost$logical_processor_id,
      element_entry_p: ^dst$mf_element_table_entry,
      element_id: dst$dft_element_id,
      entry_index: ost$processor_element_number,
      iou_index: dst$iou_number,
      mrt_entry: dst$mrt_entry,
      number_index: dst$physical_resource_number,
      possible_number_of_elements: ost$processor_element_number,
      status: ost$status,
      temp_element_table_p: ^SEQ ( * );

    { Initialize the channel type array.

    FOR iou_index := LOWERVALUE (dst$iou_number) TO UPPERVALUE (dst$iou_number) DO
      FOR channel_index := LOWERVALUE (dst$channel_protocol_type) TO
            UPPERVALUE (dst$channel_protocol_type) DO
        FOR number_index := LOWERVALUE (dst$physical_resource_number) TO
              UPPERVALUE (dst$physical_resource_number) DO
          v$mrt_channel_types [iou_index] [channel_index] [number_index].known_channel_type := FALSE;
        FOREND;
      FOREND;
    FOREND;
    v$number_of_ious := 0;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      cy2000_build_mf_information;
      perform_miscellaneous_things;
      RETURN;
    IFEND;

    actual_number_of_elements := 0;
    possible_number_of_elements := osc$maximum_processors + c$number_of_memory_elements +
          dsc$max_number_of_ious + c$number_of_page_map_elements;
    PUSH temp_element_table_p: [[REP possible_number_of_elements OF dst$mf_element_table_entry]];
    RESET temp_element_table_p;

    { Retrieve the CPU information from the MRT and build the CPU entry in the mainframe element table.

    FOR cpu_index := LOWERVALUE (ost$logical_processor_id) TO UPPERVALUE (ost$logical_processor_id) DO
      dsp$read_mrt_entry (dsc$mrt_id_processor, cpu_index, mrt_entry, status);
      IF status.normal THEN
        element_id.element_number := dsc$dftb_eid_cpu0_element;
        element_id.model_number := mrt_entry.processor.element_id.model_number;
        element_id.serial_number := mrt_entry.processor.element_id.serial_number_upper * 10000(8) +
              mrt_entry.processor.element_id.serial_number_lower;
        build_mainframe_element_entry (cpu_index, element_id, actual_number_of_elements,
              temp_element_table_p);
        IF mrt_entry.processor.disable_maintenance_mode THEN
          mtv$scb.vector_simulation_control.vector_divide_degraded :=
                mtv$scb.vector_simulation_control.vector_divide_degraded - $ost$processor_id_set [cpu_index];
        ELSE
          mtv$scb.vector_simulation_control.vector_divide_degraded :=
                mtv$scb.vector_simulation_control.vector_divide_degraded + $ost$processor_id_set [cpu_index];
        IFEND;
      IFEND;
    FOREND;

    { Retrieve the MEMORY information from the MRT and build the MEMORY entry in the mainframe element table.

    dsp$read_mrt_entry (dsc$mrt_id_central_memory, 0, mrt_entry, status);
    IF NOT status.normal THEN
      osp$system_error ('ERROR, unable to find MEMORY information in the MRT.', NIL);
    IFEND;
    element_id.element_number := dsc$dftb_eid_memory_element;
    element_id.model_number := mrt_entry.memory.element_id.model_number;
    element_id.serial_number := mrt_entry.memory.element_id.serial_number_upper * 10000(8) +
          mrt_entry.memory.element_id.serial_number_lower;
    build_mainframe_element_entry (0, element_id, actual_number_of_elements, temp_element_table_p);

    { Retrieve the IOU information from the MRT and build the IOU entry in the mainframe element table.

    FOR iou_index := LOWERVALUE (dst$iou_number) TO UPPERVALUE (dst$iou_number) DO
      dsp$read_mrt_entry (dsc$mrt_id_iou, iou_index, mrt_entry, status);
      IF status.normal THEN
        element_id.element_number := dsc$dftb_eid_iou0_element;
        element_id.model_number := mrt_entry.iou.element_id.model_number;
        element_id.serial_number := mrt_entry.iou.element_id.serial_number_upper * 10000(8) +
              mrt_entry.iou.element_id.serial_number_lower;
        build_mainframe_element_entry (iou_index, element_id, actual_number_of_elements,
              temp_element_table_p);
        IF NOT ((iou_index <> LOWERVALUE (dst$iou_number)) AND mrt_entry.iou.iou_logically_off) THEN
          build_iou_table (iou_index, mrt_entry.iou.element_id.model_number);
          build_channel_types_table (v$iou_information_table [v$number_of_ious].model_type, iou_index,
                mrt_entry);
        IFEND;
      IFEND;
    FOREND;

    IF v$number_of_ious = 0 THEN
      osp$system_error ('ERROR, unable to find IOU information in the MRT.', NIL);
    IFEND;

    { Retrieve the PAGE_MAP information from the MRT and build the PAGE_MAP entry in the
    { mainframe element table.

    IF dsv$mainframe_type = dsc$mt_93x_mainframe THEN
      dsp$read_mrt_entry (dsc$mrt_id_page_map, 0, mrt_entry, status);
      IF NOT status.normal THEN
        osp$system_error ('ERROR, unable to find PAGE MAP information in the MRT.', NIL);
      IFEND;
      element_id.element_number := dsc$dftb_eid_page_map_element;
      element_id.model_number := mrt_entry.page_map.element_id.model_number;
      element_id.serial_number := mrt_entry.page_map.element_id.serial_number_upper * 10000(8) +
            mrt_entry.page_map.element_id.serial_number_lower;
      build_mainframe_element_entry (0, element_id, actual_number_of_elements, temp_element_table_p);
    IFEND;

    { Store the element table in mainframe wired.

    ALLOCATE dsv$mf_element_table_p: [1 .. actual_number_of_elements] IN osv$mainframe_wired_heap^;
    RESET temp_element_table_p;
    FOR entry_index := 1 TO actual_number_of_elements DO
      NEXT element_entry_p IN temp_element_table_p;
      dsv$mf_element_table_p^ [entry_index] := element_entry_p^;
    FOREND;

    { Recover the secure analysis state.

    dsp$read_mrt_entry (dsc$mrt_id_global_processor, 0, mrt_entry, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    avv$security_options [avc$vso_secure_analysis].active := mrt_entry.global_processor.secure_analysis;

    perform_miscellaneous_things;

  PROCEND dsp$build_mainframe_information;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$build_sequence_p', EJECT ??

{ PURPOSE:
{   This procedure builds a sequence pointer from a pointer to a cell.

  PROCEDURE [XDCL] dsp$build_sequence_p
    (    seq_pva_p: ^cell,
         limit: integer;
     VAR return_seq_p: ^SEQ ( * ));

    VAR
      seq_entry_pointer_p: ^^SEQ ( * ),
      seq_header: cyt$sequence_pointer;

    seq_entry_pointer_p := #LOC (seq_header);
    seq_header.pva := seq_pva_p;
    seq_header.length := limit;
    seq_header.nextt := 0;
    return_seq_p := seq_entry_pointer_p^;
    RESET return_seq_p;

  PROCEND dsp$build_sequence_p;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$change_channel_states', EJECT ??

{ PURPOSE:
{   This procedure changes specific channel states in the MRT.

  PROCEDURE [XDCL] dsp$change_channel_states
    (    channel_state_list: dst$partial_channel_state_list;
     VAR status: ost$status);

?? NEWTITLE := 'break_apart_channel_states', EJECT ??

{ PURPOSE:
{   This procedure breaks each two channel entry in the MRT down into individual entries.

    PROCEDURE break_apart_channel_states
      (    number_of_entries: 1 .. 12;
           channel_protocol: dst$channel_protocol_type;
           mrt_channel_states: ARRAY [1 .. *] OF dst$mrt_two_channel_descriptor;
       VAR split_channel_states: split_channel_states_type);

      VAR
        channel_number: 0 .. 34(8),
        index: 1 .. 12;

      channel_number := 0;
      FOR index := 1 TO number_of_entries DO

        { Retrieve the channel states from the 'a' channel entry in the two channel entry in the MRT.

        split_channel_states [channel_protocol] [channel_number].on_off_state :=
              mrt_channel_states [index].a_channel_on_off_status;
        split_channel_states [channel_protocol] [channel_number].up_down_state :=
              mrt_channel_states [index].a_channel_up_down_status;
        channel_number := channel_number + 1;

        { Retrieve the channel states from the 'b' channel entry in the two channel entry in the MRT.

        split_channel_states [channel_protocol] [channel_number].on_off_state :=
              mrt_channel_states [index].b_channel_on_off_status;
        split_channel_states [channel_protocol] [channel_number].up_down_state :=
              mrt_channel_states [index].b_channel_up_down_status;
        channel_number := channel_number + 1;
        IF channel_number = 14(8) THEN
          channel_number := 20(8);
        IFEND;
      FOREND;

    PROCEND break_apart_channel_states;
?? OLDTITLE ??
?? NEWTITLE := 'replace_channel_states', EJECT ??

{ PURPOSE:
{   This procedure puts the individual entries back into the two channel entries in the MRT.

    PROCEDURE replace_channel_states
      (    number_of_entries: 1 .. 12;
           channel_protocol: dst$channel_protocol_type;
           split_channel_states: split_channel_states_type;
       VAR mrt_channel_states: ARRAY [1 .. *] OF dst$mrt_two_channel_descriptor);

      VAR
        channel_number: 0 .. 34(8),
        index: 1 .. 12;

      channel_number := 0;
      FOR index := 1 TO number_of_entries DO

        { Replace the channel states for the 'a' channel entry in the two channel entry in the MRT.

        mrt_channel_states [index].a_channel_on_off_status :=
              split_channel_states [channel_protocol] [channel_number].on_off_state;
        mrt_channel_states [index].a_channel_up_down_status :=
              split_channel_states [channel_protocol] [channel_number].up_down_state;
        channel_number := channel_number + 1;

        { Replace the channel states for the 'b' channel entry in the two channel entry in the MRT.

        mrt_channel_states [index].b_channel_on_off_status :=
              split_channel_states [channel_protocol] [channel_number].on_off_state;
        mrt_channel_states [index].b_channel_up_down_status :=
              split_channel_states [channel_protocol] [channel_number].up_down_state;
        channel_number := channel_number + 1;
        IF channel_number = 14(8) THEN
          channel_number := 20(8);
        IFEND;
      FOREND;

    PROCEND replace_channel_states;
?? OLDTITLE, EJECT ??
    TYPE
      split_channel_states_record = RECORD
        on_off_state: boolean,
        up_down_state: boolean,
      RECEND,

      split_channel_states_type = ARRAY [dst$channel_protocol_type] OF
            ARRAY [dst$physical_resource_number] OF split_channel_states_record;

    VAR
      iou_index: dst$number_of_ious,
      iou_information_table: dst$iou_information_table,
      list_index: integer,
      mrt_cio_channel_states: ARRAY [1 .. 5] OF dst$mrt_two_channel_descriptor,
      mrt_nio_channel_states: ARRAY [1 .. 12] OF dst$mrt_two_channel_descriptor,
      mrt_entry: dst$mrt_entry,
      number_of_ious: dst$number_of_ious,
      split_channel_states: split_channel_states_type;

    status.normal := TRUE;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      cy2000_change_channel_states (channel_state_list, status);
      RETURN;
    IFEND;

    dsp$retrieve_iou_information (number_of_ious, iou_information_table);

    FOR iou_index := 1 TO number_of_ious DO

      { Read the IOU entry from the MRT.

      dsp$read_mrt_entry (dsc$mrt_id_iou, iou_information_table [iou_index].physical_iou_number,
            mrt_entry, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      { Split apart the two channel entry groups for the NIO channels.

      mrt_nio_channel_states [1] := mrt_entry.iou.channel_00_01;
      mrt_nio_channel_states [2] := mrt_entry.iou.channel_02_03;
      mrt_nio_channel_states [3] := mrt_entry.iou.channel_04_05;
      mrt_nio_channel_states [4] := mrt_entry.iou.channel_06_07;
      mrt_nio_channel_states [5] := mrt_entry.iou.channel_10b_11b;
      mrt_nio_channel_states [6] := mrt_entry.iou.channel_12b_13b;
      mrt_nio_channel_states [7] := mrt_entry.iou.channel_20b_21b;
      mrt_nio_channel_states [8] := mrt_entry.iou.channel_22b_23b;
      mrt_nio_channel_states [9] := mrt_entry.iou.channel_24b_25b;
      mrt_nio_channel_states [10] := mrt_entry.iou.channel_26b_27b;
      mrt_nio_channel_states [11] := mrt_entry.iou.channel_30b_31b;
      mrt_nio_channel_states [12] := mrt_entry.iou.channel_32b_33b;

      IF iou_information_table [iou_index].model_type = dsc$imn_i4_44_model THEN
        break_apart_channel_states (12, dsc$cpt_cio, mrt_nio_channel_states, split_channel_states);
      ELSE
        break_apart_channel_states (12, dsc$cpt_nio, mrt_nio_channel_states, split_channel_states);

        { Split apart the two channel entry groups for the CIO channels.

        mrt_cio_channel_states [1] := mrt_entry.iou.i4_cio_channel_00_01;
        mrt_cio_channel_states [2] := mrt_entry.iou.i4_cio_channel_02_03;
        mrt_cio_channel_states [3] := mrt_entry.iou.i4_cio_channel_04_05;
        mrt_cio_channel_states [4] := mrt_entry.iou.i4_cio_channel_06_07;
        mrt_cio_channel_states [5] := mrt_entry.iou.i4_cio_channel_10b_11b;

        break_apart_channel_states (5, dsc$cpt_cio, mrt_cio_channel_states, split_channel_states);
      IFEND;

      { Change the channel states.  NOS/VE has three channel states: ON, DOWN, OFF.  The
      { MRT has four channel states: ON-OFF, UP-DOWN.  The following chart shows how these
      { two groups relate to one another.
      {       NOS/VE       MRT                    MEANING
      {       ******   ***********   **********************************
      {        ON    =  ON & UP    =  available for overall use
      {        DOWN  =  ON & DOWN  =  available for use by maintenance
      {        OFF   =  OFF & UP   =  NOT available for ANY use
      {        OFF   =  OFF & DOWN =  treated the same as OFF & UP
      {       ******   ***********   **********************************

      FOR list_index := LOWERBOUND (channel_state_list) TO UPPERBOUND (channel_state_list) DO
        IF channel_state_list [list_index].channel.iou_number =
              iou_information_table [iou_index].physical_iou_number THEN
          CASE channel_state_list [list_index].element_state OF
          = cmc$on =
            split_channel_states [channel_state_list [list_index].channel.channel_protocol]
                  [channel_state_list [list_index].channel.number].on_off_state := FALSE;
            split_channel_states [channel_state_list [list_index].channel.channel_protocol]
                  [channel_state_list [list_index].channel.number].up_down_state := FALSE;
          = cmc$down =
            split_channel_states [channel_state_list [list_index].channel.channel_protocol]
                  [channel_state_list [list_index].channel.number].on_off_state := FALSE;
            split_channel_states [channel_state_list [list_index].channel.channel_protocol]
                  [channel_state_list [list_index].channel.number].up_down_state := TRUE;
          = cmc$off =
            split_channel_states [channel_state_list [list_index].channel.channel_protocol]
                  [channel_state_list [list_index].channel.number].on_off_state := TRUE;
            split_channel_states [channel_state_list [list_index].channel.channel_protocol]
                  [channel_state_list [list_index].channel.number].up_down_state := FALSE;
          ELSE
          CASEND;
        IFEND;
      FOREND;

      { Put the individual NIO channel states back into the two channel entry groups.

      IF iou_information_table [iou_index].model_type = dsc$imn_i4_44_model THEN
        replace_channel_states (12, dsc$cpt_cio, split_channel_states, mrt_nio_channel_states);
      ELSE
        replace_channel_states (12, dsc$cpt_nio, split_channel_states, mrt_nio_channel_states);
      IFEND;

      mrt_entry.iou.channel_00_01 := mrt_nio_channel_states [1];
      mrt_entry.iou.channel_02_03 := mrt_nio_channel_states [2];
      mrt_entry.iou.channel_04_05 := mrt_nio_channel_states [3];
      mrt_entry.iou.channel_06_07 := mrt_nio_channel_states [4];
      mrt_entry.iou.channel_10b_11b := mrt_nio_channel_states [5];
      mrt_entry.iou.channel_12b_13b := mrt_nio_channel_states [6];
      mrt_entry.iou.channel_20b_21b := mrt_nio_channel_states [7];
      mrt_entry.iou.channel_22b_23b := mrt_nio_channel_states [8];
      mrt_entry.iou.channel_24b_25b := mrt_nio_channel_states [9];
      mrt_entry.iou.channel_26b_27b := mrt_nio_channel_states [10];
      mrt_entry.iou.channel_30b_31b := mrt_nio_channel_states [11];
      mrt_entry.iou.channel_32b_33b := mrt_nio_channel_states [12];

      { Put the individual CIO channel states back into the two channel entry groups.

      IF iou_information_table [iou_index].model_type <> dsc$imn_i4_44_model THEN
        replace_channel_states (5, dsc$cpt_cio, split_channel_states, mrt_cio_channel_states);

        mrt_entry.iou.i4_cio_channel_00_01 := mrt_cio_channel_states [1];
        mrt_entry.iou.i4_cio_channel_02_03 := mrt_cio_channel_states [2];
        mrt_entry.iou.i4_cio_channel_04_05 := mrt_cio_channel_states [3];
        mrt_entry.iou.i4_cio_channel_06_07 := mrt_cio_channel_states [4];
        mrt_entry.iou.i4_cio_channel_10b_11b := mrt_cio_channel_states [5];
      IFEND;

      { Write the IOU entry to the MRT.

      dsp$write_mrt_entry (dsc$mrt_id_iou, iou_information_table [iou_index].physical_iou_number,
            mrt_entry, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    FOREND;

  PROCEND dsp$change_channel_states;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$change_processor_state', EJECT ??

{ PURPOSE:
{   This procedure changes the processor state in the processor entry in the MRT.
{ NOTE:
{   The following data applies to the non-cyber-2000 mainframes.
{     NOS/VE has three states: ON, DOWN, OFF.  The MRT has four states: ON-OFF, UP-DOWN.  The following chart
{     shows how these two groups relate to one another.
{           NOS/VE       MRT MEANING
{           ******   ************************************************
{            ON    = processor_down := FALSE, processor_off := FALSE
{            DOWN  = processor_down := TRUE , processor_off := FALSE
{            OFF   = processor_down := FALSE, processor_off := TRUE OR
{                    processor_down := TRUE , processor_off := TRUE
{           ******   ************************************************


  PROCEDURE [XDCL] dsp$change_processor_state
    (    processor_id: ost$processor_id;
         state_data: dst$change_processor_state;
         service_processor_recovery: boolean);

    VAR
      element_id: 0 .. 0ff(16),
      element_state: 0 .. 0ff(16),
      local_status: ost$status,
      mrt_entry: dst$mrt_entry;

    { If the state desired is DOWN and the CPU has not been halted via DFT then make the call to DFT to
    { halt the CPU BEFORE changing the MRT.  Otherwise DFT will incorrectly halt the CPU on its own.

    IF (state_data.state = cmc$down) AND state_data.halt_cpu_via_dft THEN
      dsp$manage_virtual_cpu (processor_id);
    IFEND;


    { Change the MRT to reflect the state change.

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      element_id := processor_id * 10(16);
      CASE state_data.state OF
      = cmc$on =
        element_state := dsc$dft_state_on;
      = cmc$down =

        { If DFT noticed the halt of the CPU, it has already changed the MRT on CYBER 2000 and halted the CPU.

        IF NOT state_data.halt_cpu_via_dft THEN
          RETURN;
        IFEND;
        IF state_data.down_reason = dsc$pdr_down_by_operator THEN
          element_state := dsc$dft_state_down_by_operator;
        ELSE
          element_state := dsc$dft_state_down_by_system;
        IFEND;
      = cmc$off =
        element_state := dsc$dft_state_off;
      ELSE
        element_state := dsc$dft_state_not_installed;
      CASEND;

      dsp$change_cy2000_element (element_id, dsc$dft_sub_none, element_state, local_status);
      IF NOT local_status.normal THEN
        IF NOT service_processor_recovery THEN

{ This flag set indicates that the Service Processor MRT already reflects the
{ fact that the processor is running. Attempting to modify the MRT will result
{ in the following error. Ignore it .

          dpp$put_critical_message ('Unable to change MRT data.', local_status);

{         osp$fatal_system_error ('Unable to change MRT data', ^local_status);
        IFEND;
      IFEND;

    ELSE { non CY2000

      dsp$read_mrt_entry (dsc$mrt_id_processor, processor_id, mrt_entry, local_status);
      IF NOT local_status.normal THEN
        dpp$put_critical_message ('Unable to read MRT data', local_status);

{       osp$fatal_system_error ('Unable to read MRT data', ^local_status);
      IFEND;
      CASE state_data.state OF
      = cmc$on =
        mrt_entry.processor.processor_down := FALSE;
        mrt_entry.processor.processor_off := FALSE;
        mrt_entry.processor.processor_down_by_operator := FALSE;
        mrt_entry.processor.processor_down_by_system := FALSE;
      = cmc$down =
        mrt_entry.processor.processor_down := TRUE;
        mrt_entry.processor.processor_off := FALSE;
        IF state_data.down_reason = dsc$pdr_down_by_operator THEN
          mrt_entry.processor.processor_down_by_operator := TRUE;
        ELSE
          mrt_entry.processor.processor_down_by_system := TRUE;
        IFEND;
      = cmc$off =
        mrt_entry.processor.processor_down := FALSE;
        mrt_entry.processor.processor_off := TRUE;
        mrt_entry.processor.processor_down_by_operator := FALSE;
        mrt_entry.processor.processor_down_by_system := FALSE;
      ELSE
      CASEND;
      dsp$write_mrt_entry (dsc$mrt_id_processor, processor_id, mrt_entry, local_status);
      IF NOT local_status.normal THEN
       IF state_data.state = cmc$down THEN
        dpp$put_critical_message ('CPU already at desired state in DFT', local_status);
        dpp$put_critical_message ('Continueing with processor Down', local_status);
       ELSE
        dpp$put_critical_message ('Unable to read MRT data.', local_status);
        dpp$put_critical_message ('Continueing - DFT will take processor down', local_status);


{       osp$fatal_system_error ('Unable to change MRT data', ^local_status);
       IFEND;
      IFEND;
    IFEND;

    { Start the CPU if the desired state is on.

    IF state_data.state = cmc$on THEN
      dsp$start_additional_cpu (processor_id);
    IFEND;

{ Clear the recovery lock to allow the other CPU to resume scheduling resources
    mtv$recovery_lock1 := FALSE;

  PROCEND dsp$change_processor_state;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$change_secure_analysis', EJECT ??

{ PURPOSE:
{   This procedure changes the secure mode state in the global processor entry in the MRT.

  PROCEDURE [XDCL] dsp$change_secure_analysis
    (    secure_analysis: boolean;
     VAR status: ost$status);

    VAR
      access_function: 0 .. 0ff(16),
      mrt_entry: dst$mrt_entry,
      unused_mode: 0 .. 0ffff(16);

    status.normal := TRUE;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      IF secure_analysis THEN
        access_function := dsc$dft_activate_secure_mode;
      ELSE
        access_function := dsc$dft_deactivate_secure_mode;
      IFEND;
      dsp$access_secure_mode (access_function, unused_mode, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    ELSE
      dsp$read_mrt_entry (dsc$mrt_id_global_processor, 0, mrt_entry, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF mrt_entry.global_processor.secure_analysis <> secure_analysis THEN
        mrt_entry.global_processor.secure_analysis := secure_analysis;
        dsp$write_mrt_entry (dsc$mrt_id_global_processor, 0, mrt_entry, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      IFEND;
    IFEND;

  PROCEND dsp$change_secure_analysis;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$fetch_boot_data', EJECT ??

{ PURPOSE:
{   This procedure retrieves data from an area in the SSR that
{   contains data saved from the boot to system core.

  PROCEDURE [XDCL] dsp$fetch_boot_data
    (    data_kind: dst$boot_data_kinds;
     VAR data_p: ^SEQ ( * ));

    VAR
      boot_data_list: t$boot_data_list,
      boot_data_list_seq_p: ^SEQ ( * ),
      seq_p: ^SEQ ( * ),
      temp_data_p: ^SEQ ( * );

    IF dsv$boot_data_base_p = NIL THEN
      jmv$sdt.st [osc$segnum_job_pageable_heap] := osv$boot_sdte;
      dsp$build_sequence_p (#ADDRESS (1, osc$segnum_job_pageable_heap, 0), 0fffffff(16),
            dsv$boot_data_base_p);
    IFEND;

    boot_data_list_seq_p := #SEQ (boot_data_list);
    dsp$get_data_from_ssr (dsc$ssr_boot_pointer_area, boot_data_list_seq_p);
    seq_p := #PTR (boot_data_list [data_kind], dsv$boot_data_base_p^);
    RESET data_p;
    RESET seq_p;
    IF #SIZE (data_p^) > #SIZE (seq_p^) THEN
      NEXT temp_data_p: [[REP #SIZE (seq_p^) OF cell]] IN data_p;
      temp_data_p^ := seq_p^;
    ELSE
      NEXT temp_data_p: [[REP #SIZE (data_p^) OF cell]] IN seq_p;
      data_p^ := temp_data_p^;
    IFEND;
    RESET data_p;

  PROCEND dsp$fetch_boot_data;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$get_cpu_attributes', EJECT ??

{ PURPOSE:
{   This procedure retrieves the CPU attributes for each CPU on the system.
{ DESIGN:
{   A request to DFT is used to retrieve the CPU attributes.

  PROCEDURE [XDCL] dsp$get_cpu_attributes
    (VAR cpu_attributes: dst$cpu_attributes);

    VAR
      cpu_index: ost$logical_processor_id,
      element_entry: dst$dft_get_cpu_element,
      element_entry_seq_p: ^SEQ ( * ),
      element_id: 0 .. 0ff(16),
      local_status: ost$status,
      mrt_entry: dst$mrt_entry;

    cpu_attributes.count := 0;
    element_id := dsc$dftb_eid_cpu0_element;
    element_entry_seq_p := #SEQ (element_entry);

    FOR cpu_index := LOWERVALUE (ost$logical_processor_id) TO UPPERVALUE (ost$logical_processor_id) DO
      IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
        RESET element_entry_seq_p;
        dsp$get_cy2000_element (element_id, dsc$dft_sub_none, element_entry_seq_p, local_status);
        IF NOT local_status.normal THEN
          osp$fatal_system_error ('Unable to read MRT data.', ^local_status);
        IFEND;

        IF element_entry.state <> dsc$dft_state_not_installed THEN
          cpu_attributes.count := cpu_attributes.count + 1;
          CASE element_entry.state OF
          = dsc$dft_state_on =
            cpu_attributes.cpu [cpu_index].state := cmc$on;
            cpu_attributes.cpu [cpu_index].down_reason := dsc$pdr_null;
          = dsc$dft_state_down_by_system =
            cpu_attributes.cpu [cpu_index].state := cmc$down;
            cpu_attributes.cpu [cpu_index].down_reason := dsc$pdr_down_by_system;
          = dsc$dft_state_down_by_operator =
            cpu_attributes.cpu [cpu_index].state := cmc$down;
            cpu_attributes.cpu [cpu_index].down_reason := dsc$pdr_down_by_operator;
          ELSE
            cpu_attributes.cpu [cpu_index].state := cmc$off;
            cpu_attributes.cpu [cpu_index].down_reason := dsc$pdr_null;
          CASEND;
          cpu_attributes.cpu [cpu_index].memory_port_number := element_entry.port;
          cpu_attributes.cpu [cpu_index].element_id.fill := 0;
          cpu_attributes.cpu [cpu_index].element_id.element_number := element_entry.element_id.element_number;
          cpu_attributes.cpu [cpu_index].element_id.model_number := element_entry.element_id.model_number;
          cpu_attributes.cpu [cpu_index].element_id.serial_number := element_entry.element_id.serial_number;
          cpu_attributes.cpu [cpu_index].vectors_not_available := (element_entry.vector_degrade = 1);
        IFEND;
        element_id := element_id + 10(16);
      ELSE
        dsp$read_mrt_entry (dsc$mrt_id_processor, cpu_index, mrt_entry, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;

        cpu_attributes.count := cpu_attributes.count + 1;
        IF mrt_entry.processor.processor_off THEN
          cpu_attributes.cpu [cpu_index].state := cmc$off;
          cpu_attributes.cpu [cpu_index].down_reason := dsc$pdr_null;
        ELSEIF mrt_entry.processor.processor_down THEN
          cpu_attributes.cpu [cpu_index].state := cmc$down;
          IF mrt_entry.processor.processor_down_by_system THEN
            cpu_attributes.cpu [cpu_index].down_reason := dsc$pdr_down_by_system;
          ELSE
            cpu_attributes.cpu [cpu_index].down_reason := dsc$pdr_down_by_operator;
          IFEND;
        ELSE
          cpu_attributes.cpu [cpu_index].state := cmc$on;
          cpu_attributes.cpu [cpu_index].down_reason := dsc$pdr_null;
        IFEND;
        cpu_attributes.cpu [cpu_index].memory_port_number := mrt_entry.processor.memory_port;
        cpu_attributes.cpu [cpu_index].element_id.fill := 0;
        cpu_attributes.cpu [cpu_index].element_id.element_number :=
              mrt_entry.processor.element_id.element_number;
        cpu_attributes.cpu [cpu_index].element_id.model_number := mrt_entry.processor.element_id.model_number;
        cpu_attributes.cpu [cpu_index].element_id.serial_number :=
              mrt_entry.processor.element_id.serial_number_upper * 10000(8) +
              mrt_entry.processor.element_id.serial_number_lower;
        cpu_attributes.cpu [cpu_index].vectors_not_available :=
              NOT mrt_entry.processor.disable_maintenance_mode;
      IFEND;
    FOREND;

  PROCEND dsp$get_cpu_attributes;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$read_channel_states', EJECT ??

{ PURPOSE:
{   This procedure reads the channel states from the MRT.

  PROCEDURE [XDCL] dsp$read_channel_states
    (VAR channel_state_list: dst$entire_channel_state_list;
     VAR status: ost$status);

?? NEWTITLE := 'retrieve_channel_states', EJECT ??

{ PURPOSE:
{   This procedure builds an array of channel states from the MRT.  NOS/VE has three channel
{   states: ON, DOWN, OFF.  The MRT has four channel states: ON-OFF, UP-DOWN.  The following
{   chart shows how these two groups relate to one another.
{       NOS/VE       MRT                    MEANING
{       ******   ***********   **********************************
{        ON    =  ON & UP    =  available for overall use
{        DOWN  =  ON & DOWN  =  available for use by maintenance
{        OFF   =  OFF & UP   =  NOT available for ANY use
{        OFF   =  OFF & DOWN =  treated the same as OFF & UP
{       ******   ***********   **********************************

    PROCEDURE retrieve_channel_states
      (    number_of_entries: 1 .. 12;
           iou_number: dst$iou_number;
           channel_protocol: dst$channel_protocol_type;
           mrt_channel_states: ARRAY [1 .. *] OF dst$mrt_two_channel_descriptor;
       VAR channel_state_list: dst$entire_channel_state_list);

      VAR
        channel_number: 0 .. 34(8),
        index: 1 .. 12;

      channel_number := 0;
      FOR index := 1 TO number_of_entries DO

        { Retrieve the channel state from the 'a' channel entry in the two channel entry from the MRT.

        IF (NOT mrt_channel_states [index].a_channel_on_off_status) AND
              (NOT mrt_channel_states [index].a_channel_up_down_status) THEN
          channel_state_list [iou_number] [channel_protocol] [channel_number] := cmc$on;
        ELSEIF (NOT mrt_channel_states [index].a_channel_on_off_status) AND
              mrt_channel_states [index].a_channel_up_down_status THEN
          channel_state_list [iou_number] [channel_protocol] [channel_number] := cmc$down;
        ELSE
          channel_state_list [iou_number] [channel_protocol] [channel_number] := cmc$off;
        IFEND;
        channel_number := channel_number + 1;

        { Retrieve the channel state from the 'b' channel entry in the two channel entry from the MRT.

        IF (NOT mrt_channel_states [index].b_channel_on_off_status) AND
              (NOT mrt_channel_states [index].b_channel_up_down_status) THEN
          channel_state_list [iou_number] [channel_protocol] [channel_number] := cmc$on;
        ELSEIF (NOT mrt_channel_states [index].b_channel_on_off_status) AND
              mrt_channel_states [index].b_channel_up_down_status THEN
          channel_state_list [iou_number] [channel_protocol] [channel_number] := cmc$down;
        ELSE
          channel_state_list [iou_number] [channel_protocol] [channel_number] := cmc$off;
        IFEND;
        channel_number := channel_number + 1;
        IF channel_number = 14(8) THEN
          channel_number := 20(8);
        IFEND;
      FOREND;

    PROCEND retrieve_channel_states;

?? OLDTITLE, EJECT ??

    VAR
      iou_index: dst$number_of_ious,
      iou_information_table: dst$iou_information_table,
      iou_number: dst$iou_number,
      mrt_channel_states: ARRAY [1 .. 12] OF dst$mrt_two_channel_descriptor,
      mrt_entry: dst$mrt_entry,
      number_index: dst$physical_resource_number,
      number_of_ious: dst$number_of_ious,
      protocol_index: dst$channel_protocol_type;

    status.normal := TRUE;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      cy2000_read_channel_states (channel_state_list, status);
      RETURN;
    IFEND;

    { Initialize the channel state list.

    FOR iou_number := LOWERVALUE (dst$iou_number) TO UPPERVALUE (dst$iou_number) DO
      FOR protocol_index := LOWERVALUE (dst$channel_protocol_type) TO
            UPPERVALUE (dst$channel_protocol_type) DO
        FOR number_index := LOWERVALUE (dst$physical_resource_number) TO
              UPPERVALUE (dst$physical_resource_number) DO
          channel_state_list [iou_number] [protocol_index] [number_index] := cmc$down;
        FOREND;
      FOREND;
    FOREND;

    dsp$retrieve_iou_information (number_of_ious, iou_information_table);

    FOR iou_index := 1 TO number_of_ious DO

      { Read the IOU entry from the MRT.

      dsp$read_mrt_entry (dsc$mrt_id_iou, iou_information_table [iou_index].physical_iou_number,
            mrt_entry, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      { Retrieve the NIO channel states.

      mrt_channel_states [1] := mrt_entry.iou.channel_00_01;
      mrt_channel_states [2] := mrt_entry.iou.channel_02_03;
      mrt_channel_states [3] := mrt_entry.iou.channel_04_05;
      mrt_channel_states [4] := mrt_entry.iou.channel_06_07;
      mrt_channel_states [5] := mrt_entry.iou.channel_10b_11b;
      mrt_channel_states [6] := mrt_entry.iou.channel_12b_13b;
      mrt_channel_states [7] := mrt_entry.iou.channel_20b_21b;
      mrt_channel_states [8] := mrt_entry.iou.channel_22b_23b;
      mrt_channel_states [9] := mrt_entry.iou.channel_24b_25b;
      mrt_channel_states [10] := mrt_entry.iou.channel_26b_27b;
      mrt_channel_states [11] := mrt_entry.iou.channel_30b_31b;
      mrt_channel_states [12] := mrt_entry.iou.channel_32b_33b;

      IF iou_information_table [iou_index].model_type = dsc$imn_i4_44_model THEN
        retrieve_channel_states (12, iou_information_table [iou_index].physical_iou_number,
              dsc$cpt_cio, mrt_channel_states, channel_state_list);
      ELSE
        retrieve_channel_states (12, iou_information_table [iou_index].physical_iou_number,
              dsc$cpt_nio, mrt_channel_states, channel_state_list);

        { Retrieve the CIO channel states.

        mrt_channel_states [1] := mrt_entry.iou.i4_cio_channel_00_01;
        mrt_channel_states [2] := mrt_entry.iou.i4_cio_channel_02_03;
        mrt_channel_states [3] := mrt_entry.iou.i4_cio_channel_04_05;
        mrt_channel_states [4] := mrt_entry.iou.i4_cio_channel_06_07;
        mrt_channel_states [5] := mrt_entry.iou.i4_cio_channel_10b_11b;

        retrieve_channel_states (5, iou_information_table [iou_index].physical_iou_number,
              dsc$cpt_cio, mrt_channel_states, channel_state_list);
      IFEND;

    FOREND;

  PROCEND dsp$read_channel_states;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$retrieve_channel_type', EJECT ??

{ PURPOSE:
{   This procedure retrieves a channel type from the channel types array.

  PROCEDURE [XDCL, #GATE] dsp$retrieve_channel_type
    (    channel: dst$iou_resource;
     VAR channel_type: cmt$channel_type;
     VAR channel_type_found: boolean);

    channel_type_found := v$mrt_channel_types [channel.iou_number] [channel.channel_protocol]
          [channel.number].known_channel_type;
    IF channel_type_found THEN
      channel_type := v$mrt_channel_types [channel.iou_number] [channel.channel_protocol]
            [channel.number].channel_type;
    IFEND;

  PROCEND dsp$retrieve_channel_type;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$retrieve_mf_element_entry', EJECT ??

{ PURPOSE:
{   This procedure retrieves an entry from the Mainframe element table.

  PROCEDURE [XDCL, #GATE] dsp$retrieve_mf_element_entry
    (    element_number: dst$mf_element_number;
         dft_entry_id: dst$mf_element_number;
     VAR element_entry: dst$mf_element_table_entry;
     VAR status: ost$status);

    VAR
      element_id: dst$mf_element_id,
      entry_index: ost$processor_element_number;

    status.normal := TRUE;
    element_id.element_number := element_number;
    element_id.dft_entry_id := dft_entry_id;

    FOR entry_index := LOWERBOUND (dsv$mf_element_table_p^) TO UPPERBOUND (dsv$mf_element_table_p^) DO
      IF dsv$mf_element_table_p^ [entry_index].element_id = element_id THEN
        element_entry := dsv$mf_element_table_p^ [entry_index];
        RETURN;
      IFEND;
    FOREND;

    osp$set_status_abnormal (dsc$display_processor_id, dse$mf_element_id_not_found, '', status);

  PROCEND dsp$retrieve_mf_element_entry;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$retrieve_iou_information', EJECT ??

{ PURPOSE:
{   This procedure retrieves the IOU information from the IOU Information Table.

  PROCEDURE [XDCL, #GATE] dsp$retrieve_iou_information
    (VAR number_of_ious: dst$number_of_ious;
     VAR iou_information_table: dst$iou_information_table);

    number_of_ious := v$number_of_ious;
    iou_information_table := v$iou_information_table;

  PROCEND dsp$retrieve_iou_information;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$save_boot_data_pointer', EJECT ??

{ PURPOSE:
{   This procedure saves data in an area in the SSR that is reserved to save data from the boot
{   to system core.

  PROCEDURE [XDCL] dsp$save_boot_data_pointer
    (    data_kind: dst$boot_data_kinds;
         boot_data_p: ^SEQ ( * ));

    VAR
      boot_data_list: t$boot_data_list,
      boot_data_list_seq_p: ^SEQ ( * );

    IF dsv$boot_data_base_p = NIL THEN
      dsp$build_sequence_p (#ADDRESS (1, #SEGMENT (^dsv$boot_data_base_p), 0), 0fffffff(16),
            dsv$boot_data_base_p);
    IFEND;

    boot_data_list_seq_p := #SEQ (boot_data_list);
    dsp$get_data_from_ssr (dsc$ssr_boot_pointer_area, boot_data_list_seq_p);
    boot_data_list [data_kind] := #REL (boot_data_p, dsv$boot_data_base_p^);
    dsp$store_data_in_ssr (dsc$ssr_boot_pointer_area, #SEQ (boot_data_list));

  PROCEND dsp$save_boot_data_pointer;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$update_time_zone', EJECT ??

{ PURPOSE:
{   This procedure updates the time zone data in the VCU area of the CDA.

  PROCEDURE [XDCL] dsp$update_time_zone
    (    time_zone: ost$time_zone;
     VAR status: ost$status);

    VAR
      time_zone_data: dst$vcu_time_zone_data,
      time_zone_data_seq_p: ^SEQ ( * );

    status.normal := TRUE;
    time_zone_data.initialized := TRUE;
    time_zone_data.time_zone := time_zone;

    time_zone_data_seq_p := #SEQ (time_zone_data);
    dsp$access_vcu_cda_data (dsc$vcu_write_access, dsc$vcu_time_zone_data, time_zone_data_seq_p, status);

  PROCEND dsp$update_time_zone;
MODEND dsm$deadstart_services;
