?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE CM : Physical Configuration manager' ??
MODULE cmm$physical_config_mgr_r1;

{ PURPOSE:
{   This module contains procedures to manage the physical configuration, configure the system and/or
{   deadstart device.
{
{ DESIGN:
{   Because of the size of the data structure, the physical configuration table is being kept in mainframe
{   pageable.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cmc$default_channel_name
*copyc cmc$logical_conf_dev_file_name
*copyc cmc$logical_unit_constants
*copyc cmc$physical_conf_dev_file_name
*copyc cme$access_device_files
*copyc cme$logical_configuration_mgr
*copyc cme$physical_configuration_mgr
*copyc cmt$controller_type
*copyc cmt$cpu_element_definition
*copyc cmt$device_file_header
*copyc cmt$element_definition
*copyc cmt$element_name
*copyc cmt$ms_class_info
*copyc cmt$ms_logical_unit_list
*copyc cmt$request_block
*copyc cmt$state_information
*copyc cmt$unit_type
*copyc dmt$error_condition_codes
*copyc dst$rb_system_deadstart_status
*copyc dst$mainframe_type
*copyc oss$mainframe_paged_literal
*copyc ost$cpu_state_table
*copyc rmd$volume_declarations
?? POP ??
*copyc cmp$acquire_deadstart_resources
*copyc cmp$build_interface_tables
*copyc cmp$build_iou_table
*copyc cmp$build_pct
*copyc cmp$build_state_table
*copyc cmp$convert_iou_name
*copyc cmp$convert_iou_number
*copyc cmp$find_redundant_path
*copyc cmp$get_channel_def
*copyc cmp$get_controller_type
*copyc cmp$get_driver_by_controller
*copyc cmp$get_element_state
*copyc cmp$get_logical_pp_index
*copyc cmp$get_logical_unit_number
*copyc cmp$get_pp_table_rma
*copyc cmp$get_unit_type
*copyc cmp$load_controller_module
*copyc cmp$pc_get_element
*copyc cmp$pc_get_logical_unit
*copyc cmp$reacquire_resources
*copyc cmp$release_pp_by_index
*copyc cmp$search_active_volume_table
*copyc cmp$set_illegal_channel_status
*copyc cmp$support_redundant_channel
*copyc cmp$valid_channel_name
*copyc dmp$create_device_file
*copyc dmp$detach_device_file
*copyc dsp$change_channel_states
*copyc dsp$get_cpu_attributes
*copyc dsp$retrieve_iou_information
*copyc i#call_monitor
*copyc i#real_memory_address
*copyc iop$tape_initialization
*copyc osp$append_status_parameter
*copyc osp$append_status_integer
*copyc osp$clear_signature_lock
*copyc osp$set_signature_lock
*copyc osp$set_status_abnormal
*copyc osp$system_error
?? EJECT ??
*copyc cmv$logical_pp_table_p
*copyc cmv$logical_unit_table
*copyc cmv$max_number_of_pp
*copyc cmv$new_device_file
*copyc cmv$peripheral_element_table
*copyc cmv$physical_configuration
*copyc cmv$state_info_table
*copyc cmv$system_device_data
*copyc cmv$system_device_pp
*copyc dmv$active_volume_table
*copyc dmv$system_device_information
*copyc dsv$mainframe_type
*copyc iov$initial_queue_lock_sc
*copyc mtv$cst0
*copyc mtv$scb
*copyc osv$170_os_type
*copyc osv$cpus_physically_configured
*copyc osv$mainframe_wired_heap
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
  VAR
    cmv$device_file_lock: [XDCL] ost$signature_lock,
    mtv$cy2000_sp_recovery: [XREF] boolean;

  VAR
    mtv$recovery_lock1: [XREF] boolean;


?? OLDTITLE ??
?? NEWTITLE := 'build_logical_unit_list', EJECT ??

{ PURPOSE:
{   This procedure sets up a list of all logical units whose UIT RMA is not zero.

  PROCEDURE build_logical_unit_list
    (    primary_element: cmt$element_definition;
         ignore_controller_state: boolean;
         update_controller_address: boolean;
         new_state: cmt$element_state;
         logical_pp: iot$pp_number;
         logical_unit_list_p: ^ARRAY [ * ] OF cmt$rb_logical_unit_address;
     VAR logical_unit_count: integer);

    VAR
      ctport: cmt$controller_port_number,
      channel_p: ^cmt$element_definition,
      controller_p: ^cmt$element_definition,
      controller_state: cmt$element_state,
      element_lun: iot$logical_unit,
      iou_name: cmt$element_name,
      local_status: ost$status,
      logical_unit: iot$logical_unit,
      lun_index: integer,
      port: cmt$data_storage_port_number,
      ppit_p: ^iot$pp_interface_table,
      status: ost$status,
      unit_element_p: ^cmt$element_definition,
      ud: iot$logical_unit;

    logical_unit_count := 0;
    ppit_p := cmv$logical_pp_table_p^ [logical_pp].pp_info.pp_interface_table_p;

    IF primary_element.element_type = cmc$storage_device_element THEN
      cmp$get_logical_unit_number(primary_element.element_name, element_lun, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    CASE new_state OF
    = cmc$off, cmc$down =

    /loop_thru_logical_units_1/
      FOR ud := LOWERBOUND (ppit_p^.unit_descriptors) TO UPPERBOUND (ppit_p^.unit_descriptors) DO
        IF ppit_p^.unit_descriptors [ud].unit_interface_table_rma = 0 THEN
          CYCLE /loop_thru_logical_units_1/;
        IFEND;

        IF (primary_element.element_type = cmc$storage_device_element) AND (ud <> element_lun) THEN
          CYCLE /loop_thru_logical_units_1/;
        IFEND;

        IF update_controller_address AND (primary_element.element_type = cmc$controller_element) THEN

          { Only update logical units accessible from the controller being DOWN/OFF.

          IF ppit_p^.unit_descriptors [ud].physical_path.controller_number <>
                primary_element.controller.physical_equipment_number THEN
            CYCLE /loop_thru_logical_units_1/;
          IFEND;
        IFEND;

        logical_unit := ppit_p^.unit_descriptors [ud].logical_unit;
        logical_unit_count := logical_unit_count + 1;
        IF logical_unit_list_p <> NIL THEN
          logical_unit_list_p^ [logical_unit_count].logical_unit := logical_unit;
          logical_unit_list_p^ [logical_unit_count].controller  :=
                ppit_p^.unit_descriptors [ud].physical_path.controller_number;
        IFEND;

        IF update_controller_address THEN
          cmp$pc_get_logical_unit (logical_unit, unit_element_p, local_status);
          IF NOT local_status.normal THEN
            RETURN;
          IFEND;

        /loop_thru_upline_connections/
          FOR port := LOWERVALUE (cmt$data_storage_port_number) TO
                UPPERVALUE (cmt$data_storage_port_number) DO
            IF NOT unit_element_p^.storage_device.connection.port [port].configured THEN
              CYCLE /loop_thru_upline_connections/;
            IFEND;

            cmp$pc_get_element (unit_element_p^.storage_device.connection.port [port].element_name,
                  iou_name, controller_p, status);
            IF NOT local_status.normal THEN
              CYCLE /loop_thru_upline_connections/;
            IFEND;

            CASE primary_element.element_type OF
            = cmc$data_channel_element =
              IF NOT ignore_controller_state THEN
                cmp$get_element_state (unit_element_p^.storage_device.connection.port [port].element_name,
                      iou_name, controller_state, local_status);
                IF controller_state <> cmc$on THEN
                  CYCLE /loop_thru_upline_connections/;
                IFEND;
              IFEND;

              IF controller_p^.controller.physical_equipment_number =
                    ppit_p^.unit_descriptors [ud].physical_path.controller_number THEN
                FOR ctport := LOWERVALUE (cmt$controller_port_number) TO
                      UPPERVALUE (cmt$controller_port_number) DO
                  IF (controller_p^.controller.connection.port [ctport].configured) AND
                        (controller_p^.controller.connection.port [ctport].mainframe_ownership =
                        primary_element.data_channel.mainframe_ownership) THEN
                    cmp$pc_get_element (controller_p^.controller.connection.port [ctport].element_name,
                          controller_p^.controller.connection.port [ctport].iou, channel_p, status);
                    IF status.normal THEN
                      IF (channel_p^.data_channel.number <> primary_element.data_channel.number) OR
                            (channel_p^.data_channel.concurrent <> primary_element.data_channel.
                            concurrent) OR (channel_p^.data_channel.iou <> primary_element.data_channel.iou)
                            THEN
                        IF logical_unit_list_p <> NIL THEN
                          logical_unit_list_p^ [logical_unit_count].controller :=
                                controller_p^.controller.physical_equipment_number;
                        IFEND;
                      IFEND;
                    IFEND;
                  IFEND;
                FOREND;
              IFEND;

            = cmc$controller_element =

              { Take the controller number of the redundant controller connected to this unit.

              IF controller_p^.element_name <> primary_element.element_name THEN
                IF logical_unit_list_p <> NIL THEN
                  IF update_controller_address THEN
                    logical_unit_list_p^ [logical_unit_count].controller :=
                          controller_p^.controller.physical_equipment_number;
                  IFEND;
                IFEND;
              IFEND;
            ELSE
            CASEND;
          FOREND /loop_thru_upline_connections/;
        IFEND;
      FOREND /loop_thru_logical_units_1/;

    ELSE  { = cmc$on = }

      { count all lun whose first channel connections is the current channel passed in the procedure.

    /loop_thru_logical_units_2/
      FOR ud := LOWERBOUND (ppit_p^.unit_descriptors) TO UPPERBOUND (ppit_p^.unit_descriptors) DO
        IF ppit_p^.unit_descriptors [ud].unit_interface_table = NIL THEN
          CYCLE /loop_thru_logical_units_2/;
        IFEND;

        IF (primary_element.element_type = cmc$storage_device_element) AND (ud <> element_lun) THEN
          CYCLE /loop_thru_logical_units_2/;
        IFEND;

        logical_unit := ppit_p^.unit_descriptors [ud].logical_unit;

        cmp$pc_get_logical_unit (logical_unit, unit_element_p, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;

      /loop_thru_upline_connections_2/
        FOR port := LOWERVALUE (cmt$data_storage_port_number) TO
              UPPERVALUE (cmt$data_storage_port_number) DO
          IF NOT unit_element_p^.storage_device.connection.port [port].configured THEN
            CYCLE /loop_thru_upline_connections_2/;
          IFEND;

          cmp$pc_get_element (unit_element_p^.storage_device.connection.port [port].element_name, iou_name,
                controller_p, status);
          IF NOT local_status.normal THEN
            CYCLE /loop_thru_upline_connections_2/;
          IFEND;

          CASE primary_element.element_type OF
          = cmc$data_channel_element =
            IF NOT ignore_controller_state THEN
              cmp$get_element_state (unit_element_p^.storage_device.connection.port [port].element_name,
                    iou_name, controller_state, local_status);
              IF controller_state <> cmc$on THEN
                CYCLE /loop_thru_upline_connections_2/;
              IFEND;
            IFEND;

            IF controller_p^.controller.physical_equipment_number =
                  ppit_p^.unit_descriptors [ud].physical_path.controller_number THEN
              FOR ctport := LOWERVALUE (cmt$controller_port_number) TO
                    UPPERVALUE (cmt$controller_port_number) DO
                IF (controller_p^.controller.connection.port [ctport].configured) AND
                      (controller_p^.controller.connection.port [ctport].mainframe_ownership =
                      primary_element.data_channel.mainframe_ownership) THEN
                  cmp$pc_get_element (controller_p^.controller.connection.port [ctport].element_name,
                        controller_p^.controller.connection.port [ctport].iou, channel_p, status);
                  IF status.normal THEN
                    IF (channel_p^.data_channel.number = primary_element.data_channel.number) OR
                          (channel_p^.data_channel.concurrent = primary_element.data_channel.concurrent) OR
                          (channel_p^.data_channel.iou = primary_element.data_channel.iou) THEN
                      logical_unit_count := logical_unit_count + 1;
                      IF logical_unit_list_p <> NIL THEN
                        logical_unit_list_p^ [logical_unit_count].logical_unit := logical_unit;
                        IF update_controller_address THEN
                          logical_unit_list_p^ [logical_unit_count].controller :=
                                controller_p^.controller.physical_equipment_number;
                        IFEND;
                      IFEND;
                    IFEND;
                  IFEND;
                IFEND;
              FOREND;
            IFEND;

          = cmc$controller_element =

            { Take the controller number of the primary controller connected to this unit.

            IF controller_p^.element_name = primary_element.element_name THEN
              logical_unit_count := logical_unit_count + 1;
              IF logical_unit_list_p <> NIL THEN
                logical_unit_list_p^ [logical_unit_count].logical_unit := logical_unit;
                IF update_controller_address THEN
                  logical_unit_list_p^ [logical_unit_count].controller :=
                        controller_p^.controller.physical_equipment_number;
                IFEND;
              IFEND;
            IFEND;

          = cmc$storage_device_element =
            logical_unit_count := logical_unit_count + 1;
            IF logical_unit_list_p <> NIL THEN
              logical_unit_list_p^ [logical_unit_count].logical_unit := logical_unit;
              IF update_controller_address THEN
                logical_unit_list_p^ [logical_unit_count].controller :=
                      controller_p^.controller.physical_equipment_number;
              IFEND;
            IFEND;
          ELSE
          CASEND;
        FOREND /loop_thru_upline_connections_2/;
      FOREND /loop_thru_logical_units_2/;
    CASEND;

  PROCEND build_logical_unit_list;
?? OLDTITLE ??
?? NEWTITLE := 'configure_ds_device', EJECT ??

{ PURPOSE:
{   Configure the deadstart tape device by taking information from the boot menu.

  PROCEDURE configure_ds_device
    (VAR status: ost$status);

    VAR
      channel_definition: cmt$data_channel_definition,
      channel_descriptor: cmt$channel_descriptor,
      i : integer;

    status.normal := TRUE;

   { Initialize channel entry }

    cmv$physical_configuration^ [4].element_name :=
          cmv$system_device_data [cmc$sdt_tape_device].channel_name;
    cmv$physical_configuration^ [4].element_type := cmc$data_channel_element;
    cmv$physical_configuration^ [4].product_id.product_number := ' ';
    cmv$physical_configuration^ [4].product_id.underscore := ' ';
    cmv$physical_configuration^ [4].product_id.model_number := ' ';
    cmp$convert_iou_number (cmv$system_device_data [cmc$sdt_tape_device].iou_number,
          channel_descriptor.iou, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    channel_descriptor.use_logical_identification := TRUE;
    channel_descriptor.name := cmv$system_device_data [cmc$sdt_tape_device].channel_name;
    cmp$get_channel_def (channel_descriptor, channel_definition, status);
    IF NOT status.normal THEN
      osp$system_error ('Unable to determine Channel characteristics in configure_ds_device', ^status);
    IFEND;
    cmv$physical_configuration^ [4].data_channel := channel_definition;
    cmv$physical_configuration^ [4].data_channel.mainframe_ownership := '  ';

    FOR i := 0 TO UPPERVALUE (cmt$physical_equipment_number) DO
      cmv$physical_configuration^ [4].data_channel.connection.equipment [i].configured := FALSE;
    FOREND;

    cmv$physical_configuration^ [4].data_channel.connection.equipment
          [cmv$system_device_data [cmc$sdt_tape_device].equipment_number].configured := TRUE;
    cmv$physical_configuration^ [4].data_channel.connection.equipment
          [cmv$system_device_data [cmc$sdt_tape_device].equipment_number].element_name :=
          cmv$system_device_data [cmc$sdt_tape_device].equipment_name;

    IF ((cmv$physical_configuration^ [4].data_channel.number >= 12) AND
          (cmv$physical_configuration^ [4].data_channel.number <= 15)) OR
          (cmv$physical_configuration^ [4].data_channel.concurrent AND
          (cmv$physical_configuration^ [4].data_channel.number > 25)) THEN
      cmp$set_illegal_channel_status (cmv$physical_configuration^ [4].data_channel.number,
            cme$pc_unsupported_channel, status);
      RETURN;
    IFEND;

    { Initialize controller entry }

    cmv$physical_configuration^ [5].element_name :=
          cmv$system_device_data [cmc$sdt_tape_device].equipment_name;
    cmv$physical_configuration^ [5].element_type := cmc$controller_element;
    cmv$physical_configuration^ [5].product_id :=
          cmv$system_device_data [cmc$sdt_tape_device].equipment_id;
    cmv$physical_configuration^ [5].controller.physical_equipment_number :=
          cmv$system_device_data [cmc$sdt_tape_device].equipment_number;
    cmv$physical_configuration^ [5].controller.connection.port [0].configured := TRUE;
    cmv$physical_configuration^ [5].controller.connection.port [0].element_name :=
          cmv$system_device_data [cmc$sdt_tape_device].channel_name;
    cmv$physical_configuration^ [5].controller.connection.port [0].upline_connection_type :=
          cmc$data_channel_element;
    cmv$physical_configuration^ [5].controller.connection.port [0].mainframe_ownership := ' ';
    cmv$physical_configuration^ [5].controller.connection.port [0].iou :=
          cmv$physical_configuration^ [4].data_channel.iou;

    FOR i := 1 TO UPPERVALUE (cmt$controller_port_number) DO
      cmv$physical_configuration^ [5].controller.connection.port [i].configured := FALSE;
    FOREND;

    FOR i := 0 TO UPPERVALUE (cmt$physical_unit_number) DO
      cmv$physical_configuration^ [5].controller.connection.unit [i].configured := FALSE;
    FOREND;

    cmv$physical_configuration^ [5].controller.connection.unit
          [cmv$system_device_data [cmc$sdt_tape_device].unit_number].configured := TRUE;
    cmv$physical_configuration^ [5].controller.connection.unit
          [cmv$system_device_data [cmc$sdt_tape_device].unit_number].element_name :=
          cmv$system_device_data [cmc$sdt_tape_device].unit_name;

    {  Initialize data device entry }

    cmv$physical_configuration^ [6].element_name := cmv$system_device_data [cmc$sdt_tape_device].unit_name;
    cmv$physical_configuration^ [6].product_id := cmv$system_device_data [cmc$sdt_tape_device].unit_id;
    cmv$physical_configuration^ [6].element_type := cmc$storage_device_element;
    cmv$physical_configuration^ [6].storage_device.physical_unit_number :=
          cmv$system_device_data [cmc$sdt_tape_device].unit_number;
    cmv$physical_configuration^ [6].storage_device.connection.port [0].configured := TRUE;
    cmv$physical_configuration^ [6].storage_device.connection.port [0].element_name :=
          cmv$system_device_data [cmc$sdt_tape_device].equipment_name;
    cmv$physical_configuration^ [6].storage_device.connection.port [0].upline_connection_type :=
          cmc$controller_element;
    FOR i := 1 TO UPPERVALUE (cmt$data_storage_port_number) DO
      cmv$physical_configuration^ [6].storage_device.connection.port [i].configured := FALSE;
    FOREND;

  PROCEND configure_ds_device;
?? OLDTITLE ??
?? NEWTITLE := 'validate_all_units ', EJECT ??

{ PURPOSE :
{   This procedure validate all units against the list of redundant pp. If a unit can not
{   be found in the unit descriptors of the redundant pps then it has to be non system critical

  PROCEDURE validate_all_units
    (    logical_unit_list_p: ^ARRAY [ * ] OF cmt$rb_logical_unit_address;
         pp_list: ARRAY [cmt$physical_equipment_number] OF iot$pp_number;
         number_of_path: integer;
     VAR found_critical_device: boolean);

    VAR
      entry_not_found: boolean,
      found: boolean,
      lun_index: integer,
      ms_class_info: cmt$ms_class_info,
      pp_index: cmt$physical_equipment_number,
      ppit_p: ^iot$pp_interface_table,
      recorded_vsn: rmt$recorded_vsn,
      search_key: dmt$avt_search_key,
      ud: iot$logical_unit,
      volume_found: boolean;

    found_critical_device := FALSE;
    FOR lun_index := LOWERBOUND (logical_unit_list_p^) TO UPPERBOUND (logical_unit_list_p^) DO
      found := FALSE;
      pp_index := LOWERBOUND (pp_list);
      WHILE (NOT found) AND (pp_index <= number_of_path) DO

        ppit_p := cmv$logical_pp_table_p^ [pp_list[pp_index]].pp_info.pp_interface_table_p;

       /match_lun/
        FOR ud := LOWERBOUND (ppit_p^.unit_descriptors) TO UPPERBOUND (ppit_p^.unit_descriptors) DO
          IF (logical_unit_list_p^ [lun_index].logical_unit = ppit_p^.unit_descriptors [ud].logical_unit) AND
                (ppit_p^.unit_descriptors [ud].unit_interface_table <> NIL) THEN
            found := TRUE;
            EXIT /match_lun/;
          IFEND;
        FOREND /match_lun/;
        pp_index := pp_index + 1;
      WHILEND;

      IF NOT found THEN

        { There is a dangling units in the path with no redundant access.
        { Check if this is a critical device.

        search_key.value := dmc$search_avt_by_lun;
        search_key.logical_unit_number := logical_unit_list_p^ [lun_index].logical_unit;
        cmp$search_active_volume_table (search_key, recorded_vsn, entry_not_found);
        IF NOT entry_not_found THEN
          cmp$get_ms_class_on_volume_r1 (recorded_vsn, volume_found, ms_class_info);
          IF volume_found THEN
            IF ms_class_info.allocation_allowed AND
                  (ms_class_info.classes ['J']) AND (ms_class_info.classes ['Q']) THEN
              found_critical_device := TRUE;
              RETURN;
            IFEND;
          IFEND;
        IFEND;
      IFEND;
    FOREND;

  PROCEND validate_all_units;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$assign_logical_unit_numbers', EJECT ??

{ PURPOSE:
{   This procedure assign logical unit number to all storage device, channel adapter, communications and
{   external processor elements.

  PROCEDURE [XDCL, #GATE] cmp$assign_logical_unit_numbers
    (    channel_iou: cmt$element_name;
         equipment_number: cmt$physical_equipment_number;
         unit_number: cmt$physical_unit_number;
         system_device_lun: iot$logical_unit;
     VAR status: ost$status);

    VAR
      assigned_lun: integer,
      cm_unit_type: cmt$unit_type,
      cont_name: cmt$element_name,
      found: boolean,
      found2: boolean,
      io_unit_type: iot$unit_type,
      io_unit_type2: iot$unit_type,
      pc_index: integer,
      pc_index2: integer,
      state_count: integer,
      state_index: integer,
      unit_class: cmt$unit_class,
      unit_class2: cmt$unit_class,
      unit_name: cmt$element_name,
      unit_type: cmt$unit_type;

    status.normal := TRUE;

    IF (cmv$physical_configuration = NIL) OR (cmv$state_info_table = NIL) THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$pc_nil_cm_table,
            'Try to assign logical units when CM tables are not yet built.', status);
      RETURN;
    IFEND;

   /outer_loop/
    BEGIN

     /loop1/
      FOR pc_index := LOWERBOUND(cmv$physical_configuration^) TO UPPERBOUND (cmv$physical_configuration^) DO
        IF cmv$physical_configuration^ [pc_index].element_type = cmc$data_channel_element THEN
          IF (cmv$physical_configuration^ [pc_index].element_name =
                cmv$system_device_data [cmc$sdt_disk_device].channel_name) AND
                (cmv$physical_configuration^ [pc_index].data_channel.iou = channel_iou) THEN

            cont_name := cmv$physical_configuration^ [pc_index].data_channel.
                  connection.equipment [equipment_number].element_name;

           /loop2/
            FOR pc_index2 := LOWERBOUND(cmv$physical_configuration^) TO
                  UPPERBOUND (cmv$physical_configuration^) DO
              IF cmv$physical_configuration^ [pc_index2].element_name = cont_name THEN
                unit_name := cmv$physical_configuration^ [pc_index2].controller.
                      connection.unit [unit_number].element_name;
                cmp$get_unit_type (cmv$physical_configuration^ [pc_index2].product_id, cm_unit_type,
                      io_unit_type2, unit_class2, found2);
                IF found2 THEN
                  IF cm_unit_type = cmc$mshydra THEN
                    unit_name := cont_name;
                  IFEND;
                IFEND;
                EXIT /outer_loop/;
              IFEND;
            FOREND /loop2/;
          IFEND;
        IFEND;
      FOREND /loop1/;

      osp$set_status_abnormal (cmc$configuration_management_id, cme$pc_unit_not_found, ' ', status);
      osp$append_status_integer (osc$status_parameter_delimiter , system_device_lun, 10, FALSE, status);
      RETURN;
    END /outer_loop/;

    state_count := UPPERBOUND (cmv$state_info_table^);

    { Assign system device lun.

    FOR state_index := 1 TO state_count DO
      IF cmv$state_info_table^ [state_index].element_type <> cmc$data_channel_element THEN
        IF cmv$state_info_table^ [state_index].element_name = unit_name THEN
          cmv$state_info_table^ [state_index].logical_unit := system_device_lun;
        ELSE
          cmv$state_info_table^ [state_index].logical_unit := 0;
        IFEND;
      IFEND;
    FOREND;

    { Assign other luns.

    assigned_lun := system_device_lun + 1;

    FOR state_index := 1 TO state_count DO
      IF (cmv$physical_configuration^ [state_index].element_type <> cmc$data_channel_element) AND
            (cmv$physical_configuration^ [state_index].element_type <> cmc$controller_element) THEN
        cmp$get_unit_type (cmv$state_info_table^ [state_index].product_id, unit_type, io_unit_type,
              unit_class, found);
        IF (found OR (unit_type = cmc$foreign_unit) OR (unit_class = cmc$network_unit) OR
              (unit_class = cmc$rhfam_unit)) AND
              (cmv$state_info_table^ [state_index].logical_unit = 0) THEN
          cmv$state_info_table^ [state_index].logical_unit := assigned_lun;
          assigned_lun := assigned_lun + 1;
        IFEND;
      IFEND;
    FOREND;

  PROCEND cmp$assign_logical_unit_numbers;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$change_state_info_table', EJECT ??

{ PURPOSE:
{   This procedure updates the state value in the state info table based on the element name passed in.

  PROCEDURE [XDCL, #GATE] cmp$change_state_info_table
    (    element_name: cmt$element_name;
         iou_name: cmt$element_name;
         state: cmt$element_state;
     VAR status: ost$status);

    VAR
      channel: cmt$physical_channel,
      channel_state_list_p: ^ARRAY [ * ] OF dst$channel_state,
      channel_identification: cmt$channel_descriptor,
      channel_definition: cmt$data_channel_definition,
      cio_channel_name: cmt$element_name,
      found: boolean,
      index: integer,
      index_2: integer,
      ignore_status: ost$status,
      iou_number: dst$iou_number,
      lock_set: boolean,
      state_table_index: integer,
      text: string (80),
      update_mrt: boolean;

    status.normal := TRUE;
    found := FALSE;
    lock_set := FALSE;
    update_mrt := FALSE;
    channel.concurrent := FALSE;

   /main_program/
    BEGIN
      found := FALSE;

     /table_search_block/
      BEGIN

       /peripheral_loop_1/
        FOR index := 1 TO UPPERBOUND (cmv$peripheral_element_table.pointer^) DO
          IF element_name <> cmv$peripheral_element_table.pointer^ [index].element_name THEN
            CYCLE /peripheral_loop_1/;
          IFEND;

          IF cmv$peripheral_element_table.pointer^ [index].physical_descriptor.element_type =
                cmc$data_channel_element THEN
            cmp$convert_iou_name (iou_name, iou_number, status);
            IF NOT status.normal THEN
              EXIT /main_program/;
            IFEND;
            IF iou_number <>
                  cmv$peripheral_element_table.pointer^ [index].physical_descriptor.channel_path.iou THEN
              CYCLE /peripheral_loop_1/;
            IFEND;
          IFEND;

          osp$set_signature_lock (cmv$peripheral_element_table.lock, osc$wait, status);
          IF NOT status.normal THEN
            EXIT /main_program/;
          IFEND;
          lock_set := TRUE;
          cmv$peripheral_element_table.pointer^ [index].element_status.state := state;
          cmv$peripheral_element_table.pointer^ [index].state_change_request.pending := FALSE;

         /loop/
          FOR state_table_index := 1 TO UPPERBOUND (cmv$state_info_table^) DO
            IF element_name = cmv$state_info_table^ [state_table_index].element_name THEN
              IF (cmv$state_info_table^ [state_table_index].element_type = cmc$data_channel_element) AND
                    (iou_name <> cmv$state_info_table^ [state_table_index].iou) THEN
                CYCLE /loop/;
              IFEND;
              found := TRUE;
              IF cmv$state_info_table^ [state_table_index].element_type = cmc$data_channel_element THEN
                update_mrt := TRUE;
                channel :=
                      cmv$peripheral_element_table.pointer^ [index].physical_descriptor.channel_path.channel;
              IFEND;
              cmv$state_info_table^ [state_table_index].status.state := state;
              EXIT /loop/;
            IFEND;
          FOREND /loop/;
          IF NOT found THEN
            IF cmp$valid_channel_name(element_name) THEN
              text (1, 5) := iou_name (1, 5);
              text (6, *) := element_name;
            ELSE
              text (1, *) := element_name;
            IFEND;
            osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_element_not_found, text,
                  status);
            EXIT /main_program/;
          IFEND;
          EXIT /table_search_block/;
        FOREND /peripheral_loop_1/;

        { If control reaches here, the element name is not in the peripheral element table.

        IF cmp$valid_channel_name(element_name) THEN
          text (1, 5) := iou_name (1, 5);
          text (6, *) := element_name;
        ELSE
          text (1, *) := element_name;
        IFEND;
        osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_element_not_found, text, status);
        EXIT /main_program/;
      END /table_search_block/;

      { If the channel is concurrent and has a port value then make sure the other channel port on the same
      { IOU also has the same state.

      IF update_mrt AND channel.concurrent AND (channel.port <> cmc$unspecified_port) THEN

       /peripheral_loop_2/
        FOR index_2 := LOWERBOUND (cmv$peripheral_element_table.pointer^) TO
              UPPERBOUND (cmv$peripheral_element_table.pointer^) DO
          IF (cmv$peripheral_element_table.pointer^ [index_2].
                physical_descriptor.element_type = cmc$data_channel_element) AND
                (cmv$peripheral_element_table.pointer^ [index_2].
                physical_descriptor.channel_path.channel.number = channel.number) AND
                (cmv$peripheral_element_table.pointer^ [index_2].
                physical_descriptor.channel_path.channel.concurrent = channel.concurrent) AND
                (cmv$peripheral_element_table.pointer^ [index_2].
                physical_descriptor.channel_path.iou = iou_number) THEN
            cmv$peripheral_element_table.pointer^ [index_2].element_status.state := state;
            cmv$state_info_table^ [index_2].status.state := state;
          IFEND;
        FOREND /peripheral_loop_2/;
      IFEND;

      { Call deadstart to update the MRT if the element is a channel.

      IF update_mrt THEN

        { Try to clear the lock so Deadstart can set the lock during accessing the deadstart sector for
        { updating the MRT.

        IF lock_set THEN
          osp$clear_signature_lock (cmv$peripheral_element_table.lock, ignore_status);
          lock_set := FALSE;
        IFEND;

        channel_identification.iou := iou_name;
        channel_identification.use_logical_identification := TRUE;
        channel_identification.name := element_name;
        cmp$get_channel_def (channel_identification, channel_definition, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
        PUSH channel_state_list_p : [1 .. 1];
        channel_state_list_p^ [1].channel.iou_number := iou_number;
        IF channel_definition.concurrent THEN
          channel_state_list_p^ [1].channel.channel_protocol := dsc$cpt_cio;
        ELSE
          channel_state_list_p^ [1].channel.channel_protocol := dsc$cpt_nio;
        IFEND;
        channel_state_list_p^ [1].channel.number := channel_definition.number;
        channel_state_list_p^ [1].element_state := state;
        dsp$change_channel_states (channel_state_list_p^, status);
      IFEND;

    END /main_program/;

    IF lock_set THEN
      osp$clear_signature_lock (cmv$peripheral_element_table.lock, ignore_status);
      IF status.normal THEN
        status := ignore_status;
      IFEND;
    IFEND;

  PROCEND cmp$change_state_info_table;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$change_state_r1', EJECT ??

{ PURPOSE:
{   This procedure sets up the monitor request block to change the state of an element in Monitor.

  PROCEDURE [XDCL, #GATE] cmp$change_state_r1
    (    element_name: cmt$element_name;
         element_type: cmt$element_type;
         controller_type: cmt$controller_type;
         system_critical_element: boolean;
         new_state: cmt$element_state;
         iou: dst$iou_number,
         pp: iot$pp_number;
         channel: cmt$physical_channel;
         controller: cmt$physical_equipment_number;
         logical_unit: iot$logical_unit;
     VAR status: ost$status);

    VAR
      channel_data: cmt$element_definition,
      count: integer,
      current_channel_state: cmt$element_state,
      driver_name: pmt$program_name,
      dummy_pp_number: dst$iou_resource,
      element_p: ^cmt$element_definition,
      found_critical_device: boolean,
      iou_name: cmt$element_name,
      logical_pp_index: iot$pp_number,
      loop_index: integer,
      number_of_path: integer,
      physical_channel: cmt$physical_channel,
      pp_table_rma_list: ARRAY [cmt$physical_equipment_number] OF ost$real_memory_address,
      primary_controller_p: ^cmt$peripheral_element_entry,
      redundant: boolean,
      redundant_channel_list: ARRAY [cmt$physical_equipment_number] OF cmt$physical_address,
      redundant_controller: ARRAY [cmt$physical_equipment_number] OF cmt$physical_equipment_number,
      redundant_path_available: boolean,
      redundant_path_pp_list: ARRAY [cmt$physical_equipment_number] OF iot$pp_number,
      request_block: cmt$request_block,
      text: string (80);

    status.normal := TRUE;

  /main_program/
    BEGIN
      redundant_path_available := FALSE;
      request_block.request_code := syc$rc_config_mgmt_request;
      request_block.kind := cmc$rbk_change_state;
      request_block.element_name := element_name;
      request_block.new_state := new_state;
      request_block.iou := iou;
      request_block.redundant_path_available := FALSE;
      request_block.update_controller_address := FALSE;
      request_block.logical_unit_list_p := NIL;
      request_block.redundant_path_pp_list_p := NIL;
      request_block.element_type := element_type;

      cmp$convert_iou_number (iou, iou_name, status);
      cmp$pc_get_element (element_name, iou_name, element_p, status);
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;

      IF element_type = cmc$data_channel_element THEN
        text (1, 6) := iou_name;
        text (7, *) := element_name;
        cmp$get_element_state (element_name, iou_name, current_channel_state, status);
        IF (new_state <> cmc$on) AND (current_channel_state <> cmc$on) THEN
          EXIT /main_program/;
        IFEND;
      ELSE
        text := element_name;
      IFEND;

      IF cmp$support_redundant_channel (controller_type) THEN
        count := 0;
        cmp$search_redundant_path (element_p^, iou, channel, new_state, redundant_path_available,
              request_block.update_controller_address, number_of_path, redundant_channel_list,
              redundant_path_pp_list, driver_name, pp_table_rma_list);
        IF redundant_path_available THEN
          request_block.redundant_path_available := TRUE;
          ALLOCATE request_block.redundant_path_pp_list_p: [0 .. number_of_path] IN osv$mainframe_wired_heap^;
          FOR loop_index := LOWERVALUE (cmt$physical_equipment_number) TO number_of_path DO
            request_block.redundant_path_pp_list_p^ [loop_index] := redundant_path_pp_list [loop_index];
          FOREND;

          { Determine all logical units that need to be changed.

          build_logical_unit_list (element_p^, FALSE {ignore_controller_state},
                request_block.update_controller_address, new_state, pp, request_block.logical_unit_list_p,
                count);
          IF count <> 0 THEN
            ALLOCATE request_block.logical_unit_list_p: [1 .. count] IN osv$mainframe_wired_heap^;
            build_logical_unit_list (element_p^, FALSE {ignore_controller_state},
                  request_block.update_controller_address, new_state, pp, request_block.logical_unit_list_p,
                  count);

            IF new_state <> cmc$on THEN

              { Make sure all units on the current channel have redundant access.
              { If not, they have to be non critical devices.

              validate_all_units (request_block.logical_unit_list_p, redundant_path_pp_list, number_of_path,
                    found_critical_device);
              IF found_critical_device THEN
                osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_system_critical_element,
                      text, status);
                EXIT /main_program/;
              IFEND;
            IFEND;
          IFEND;

          FOR loop_index := LOWERVALUE (cmt$physical_equipment_number) TO number_of_path DO

            { If there is not a PP in the channel(s) and if the new state is not ON then acquire the PP
            { all redundant path(s).  If the new state is ON, and the redundant channel(s) is inactive
            { then there is no need to acquire PP.

            channel_data.element_type := cmc$data_channel_element;
            cmp$convert_iou_number (redundant_channel_list [loop_index].iou, channel_data.data_channel.iou,
                  status);
            IF NOT status.normal THEN
              EXIT /main_program/;
            IFEND;
            channel_data.data_channel.number := redundant_channel_list [loop_index].channel.number;
            channel_data.data_channel.port := redundant_channel_list [loop_index].channel.port;
            channel_data.data_channel.concurrent := redundant_channel_list [loop_index].channel.concurrent;
            cmp$get_logical_pp_index (channel_data, logical_pp_index, status);
            IF NOT status.normal THEN
              EXIT /main_program/;
            IFEND;
            IF NOT cmv$logical_pp_table_p^ [logical_pp_index].flags.resources_acquired AND
                  (new_state <> cmc$on) THEN
              physical_channel.number := redundant_channel_list [loop_index].channel.number;
              physical_channel.port := redundant_channel_list [loop_index].channel.port;
              physical_channel.concurrent := redundant_channel_list [loop_index].channel.concurrent;

              cmp$reacquire_resources (dsc$rrt_get_pp, physical_channel,
                    redundant_channel_list [loop_index].iou, cmc$null_equipment_number,
                    cmc$null_unit_number, driver_name, pp_table_rma_list [loop_index], controller_type,
                    TRUE, status);
              IF NOT status.normal THEN

                { If system critical element, return error because we cannot get a pp
                { or load the driver on the redundant channel.

                IF system_critical_element THEN
                  osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_system_critical_element,
                        text, status);
                  EXIT /main_program/;
                IFEND;
              IFEND;
            IFEND;
          FOREND;
        ELSE

          { Return error if system critical element and there is not redundant channel available.

          IF system_critical_element AND (new_state <> cmc$on) THEN
            osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_system_critical_element, text,
                  status);
            EXIT /main_program/;
          IFEND;
        IFEND;
      IFEND;

      CASE element_type OF
      = cmc$data_channel_element =
        request_block.channel_pp := pp;
        request_block.channel := channel.number;
      = cmc$controller_element =
        request_block.controller_pp := pp;
        request_block.controller_channel := channel.number;
        request_block.controller := controller;
      = cmc$storage_device_element =
        request_block.unit_pp := pp;
        request_block.unit_channel := channel.number;
        request_block.unit_controller := controller;
        request_block.logical_unit := logical_unit;
      ELSE
        EXIT /main_program/;
      CASEND;

      i#call_monitor (#LOC (request_block) , #SIZE (request_block));
      IF NOT request_block.status.normal THEN
        status.normal := FALSE;
        status.condition := request_block.status.condition;
      IFEND;
    END /main_program/;

    IF request_block.logical_unit_list_p <> NIL THEN
      FREE request_block.logical_unit_list_p IN osv$mainframe_wired_heap^;
    IFEND;
    IF request_block.redundant_path_pp_list_p <> NIL THEN
      FREE request_block.redundant_path_pp_list_p IN osv$mainframe_wired_heap^;
    IFEND;

  PROCEND cmp$change_state_r1;

?? OLDTITLE ??
?? NEWTITLE := 'cmp$configure_system_device', EJECT ??
*copy cmh$configure_system_device

  PROCEDURE [XDCL, #GATE] cmp$configure_system_device
    (VAR status: ost$status);

    VAR
      acquire_by_channel: boolean,
      acquire_tape_by_channel: boolean,
      channel_descriptor: cmt$channel_descriptor,
      channel_definition: cmt$data_channel_definition,
      channel: cmt$physical_channel,
      cm_unit_type: cmt$unit_type,
      controller_type: cmt$controller_type,
      disk_controller_type: cmt$controller_type,
      dual_pp: boolean,
      equipment_number: 0 .. cmc$max_equipment_per_channel,
      found: boolean,
      i: integer,
      ignore_alternate: dst$driver_name,
      io_unit_type: iot$unit_type,
      iou: dst$iou_number,
      iou_information_table: dst$iou_information_table,
      iou_number: dst$iou_number,
      iou_program_name: dst$driver_name,
      local_status: ost$status,
      need_to_load_controlware: boolean,
      number_of_ious: dst$number_of_ious,
      pc_entries: ARRAY [1 .. 6] OF cmt$element_definition,
      pp_count: iot$pp_number,
      state_entries: ARRAY [1 .. 6] OF cmt$state_information,
      unit_class: cmt$unit_class,
      unit_count: 0 .. 2,
      unit_number: 0 .. cmc$max_units_per_controller;

    status.normal := TRUE;

  /main_program/
    BEGIN

      { Initialize channel entry.

      pc_entries [1].element_name := cmv$system_device_data [cmc$sdt_disk_device].channel_name;
      pc_entries [1].product_id.product_number := ' ';
      pc_entries [1].product_id.underscore := ' ';
      pc_entries [1].product_id.model_number := ' ';
      pc_entries [1].element_type := cmc$data_channel_element;
      cmp$convert_iou_number (cmv$system_device_data [cmc$sdt_disk_device].iou_number, channel_descriptor.iou,
            status);
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;
      channel_descriptor.use_logical_identification := TRUE;
      channel_descriptor.name := cmv$system_device_data [cmc$sdt_disk_device].channel_name;
      cmp$get_channel_def (channel_descriptor, channel_definition, status);
      IF NOT status.normal THEN
        osp$system_error ('Unable to determine Channel characteristics in cmp$configure_system_device',
              ^status);
      IFEND;
      pc_entries [1].data_channel := channel_definition;
      pc_entries [1].data_channel.mainframe_ownership := ' ';
      cmp$get_unit_type (cmv$system_device_data [cmc$sdt_disk_device].unit_id, cm_unit_type, io_unit_type,
            unit_class, found);
      IF NOT found THEN
        osp$system_error ('Unknown Unit type', ^status);
      IFEND;
      IF cm_unit_type = cmc$ms895_2 THEN
        pp_count := 2;
      ELSE
        pp_count := 1;
      IFEND;

      FOR i := 0 TO UPPERVALUE (cmt$physical_equipment_number) DO
        pc_entries [1].data_channel.connection.equipment [i].configured := FALSE;
      FOREND;

      IF cm_unit_type = cmc$mshydra THEN
        pc_entries [1].data_channel.connection.equipment
              [cmv$system_device_data [cmc$sdt_disk_device].unit_number].configured := TRUE;
        pc_entries [1].data_channel.connection.equipment
              [cmv$system_device_data [cmc$sdt_disk_device].unit_number].element_name :=
              cmv$system_device_data [cmc$sdt_disk_device].unit_name;
      ELSE
        pc_entries [1].data_channel.connection.equipment
              [cmv$system_device_data [cmc$sdt_disk_device].equipment_number].configured := TRUE;
        pc_entries [1].data_channel.connection.equipment
              [cmv$system_device_data [cmc$sdt_disk_device].equipment_number].element_name :=
              cmv$system_device_data [cmc$sdt_disk_device].equipment_name;
      IFEND;
      IF ((pc_entries [1].data_channel.number >= 12) AND (pc_entries [1].data_channel.number <= 15)) OR
            ((pc_entries [1].data_channel.number > 25) AND pc_entries [1].data_channel.concurrent) THEN
        cmp$set_illegal_channel_status (pc_entries [1].data_channel.number, cme$pc_unsupported_channel,
              status);
        EXIT /main_program/;
      IFEND;

      unit_count := 1;
      CASE cm_unit_type OF
      = cmc$ms844_4x .. cmc$ms885_4x =
        acquire_by_channel := FALSE;
      ELSE
        acquire_by_channel := TRUE;
      CASEND;

      { Initialize controller entry.

      IF cm_unit_type <> cmc$mshydra THEN
        pc_entries [2].element_name := cmv$system_device_data [cmc$sdt_disk_device].equipment_name;
        pc_entries [2].product_id := cmv$system_device_data [cmc$sdt_disk_device].equipment_id;
        pc_entries [2].element_type := cmc$controller_element;
        pc_entries [2].controller.physical_equipment_number :=
              cmv$system_device_data [cmc$sdt_disk_device].equipment_number;
        pc_entries [2].controller.connection.port [0].configured := TRUE;
        pc_entries [2].controller.connection.port [0].element_name :=
              cmv$system_device_data [cmc$sdt_disk_device].channel_name;
        pc_entries [2].controller.connection.port [0].upline_connection_type := cmc$data_channel_element;
        pc_entries [2].controller.connection.port [0].mainframe_ownership := '  ';
        pc_entries [2].controller.connection.port [0].iou := pc_entries [1].data_channel.iou;

        FOR i := 1 TO UPPERVALUE (cmt$controller_port_number) DO
          pc_entries [2].controller.connection.port [i].configured := FALSE;
        FOREND;

        FOR i := 0 TO UPPERVALUE (cmt$physical_unit_number) DO
          pc_entries [2].controller.connection.unit [i].configured := FALSE;
        FOREND;

        pc_entries [2].controller.connection.unit
              [cmv$system_device_data [cmc$sdt_disk_device].unit_number].configured := TRUE;
        pc_entries [2].controller.connection.unit
              [cmv$system_device_data [cmc$sdt_disk_device].unit_number].element_name :=
              cmv$system_device_data [cmc$sdt_disk_device].unit_name;
      IFEND;

      { Initialize the storage device entry.

      pc_entries [3].element_name := cmv$system_device_data [cmc$sdt_disk_device].unit_name;
      pc_entries [3].product_id := cmv$system_device_data [cmc$sdt_disk_device].unit_id;
      pc_entries [3].element_type := cmc$storage_device_element;
      pc_entries [3].storage_device.physical_unit_number :=
            cmv$system_device_data [cmc$sdt_disk_device].unit_number;
      pc_entries [3].storage_device.connection.port [0].configured := TRUE;

      IF cm_unit_type = cmc$mshydra THEN
        pc_entries [3].storage_device.connection.port [0].element_name :=
              cmv$system_device_data [cmc$sdt_disk_device].channel_name;
        pc_entries [3].storage_device.connection.port [0].upline_connection_type := cmc$data_channel_element;
        pc_entries [3].storage_device.connection.port [0].mainframe_ownership := '  ';
        pc_entries [3].storage_device.connection.port [0].iou := pc_entries [1].data_channel.iou;
      ELSE
        pc_entries [3].storage_device.connection.port [0].element_name :=
              cmv$system_device_data [cmc$sdt_disk_device].equipment_name;
        pc_entries [3].storage_device.connection.port [0].upline_connection_type := cmc$controller_element;
      IFEND;

      FOR i := 1 TO UPPERVALUE (cmt$data_storage_port_number) DO
        pc_entries [3].storage_device.connection.port [i].configured := FALSE;
      FOREND;

      IF cmv$system_device_data [cmc$sdt_tape_device].specified THEN
        cmp$build_pct (6, pc_entries, status);
      ELSE
        cmp$build_pct (3, pc_entries, status);
      IFEND;
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;

      cmp$get_unit_type (cmv$system_device_data [cmc$sdt_disk_device].unit_id, cm_unit_type, io_unit_type,
            unit_class, found);
      IF cm_unit_type <> cmc$mshydra THEN
        cmp$get_controller_type (cmv$system_device_data [cmc$sdt_disk_device].equipment_id,
              disk_controller_type, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
        cmp$convert_iou_name (cmv$physical_configuration^ [1].data_channel.iou, iou, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
        cmp$get_driver_by_controller (disk_controller_type,
              cmv$physical_configuration^ [1].data_channel.concurrent, iou, iou_program_name,
              ignore_alternate);
        cmv$physical_configuration^ [2].controller.peripheral_driver_name := iou_program_name;
      ELSE
        disk_controller_type := cmc$mshydra_ct;
      IFEND;

      FOR i := 1 TO 6 DO
        state_entries [i].application_info_size := 0;
        state_entries [i].application_info_p := NIL;
        state_entries [i].site_info_size := 0;
        state_entries [i].site_info_p := NIL;
      FOREND;

      state_entries [1].element_name := cmv$system_device_data [cmc$sdt_disk_device].channel_name;
      state_entries [1].element_type := cmc$data_channel_element;
      state_entries [1].status.state := cmc$on;
      state_entries [1].iou := pc_entries [1].data_channel.iou;
      IF cm_unit_type <> cmc$mshydra THEN
        state_entries [2].element_name := cmv$system_device_data [cmc$sdt_disk_device].equipment_name;
        state_entries [2].element_type := cmc$controller_element;
        state_entries [2].status.state := cmc$on;
        state_entries [2].product_id := cmv$system_device_data [cmc$sdt_disk_device].equipment_id;
        state_entries [2].logical_unit := 0;
      ELSE
        state_entries [2].element_name := ' ';
      IFEND;
      state_entries [3].element_name := cmv$system_device_data [cmc$sdt_disk_device].unit_name;
      state_entries [3].element_type := cmc$storage_device_element;
      state_entries [3].status.state := cmc$on;
      state_entries [3].product_id := cmv$system_device_data [cmc$sdt_disk_device].unit_id;
      state_entries [3].logical_unit := cmc$job_template_unit_ordinal;

      { Set up the IOU table based on the number of IOUs, and also allocate the appropriate number
      { of channel lock

      dsp$retrieve_iou_information (number_of_ious, iou_information_table);
      cmp$build_iou_table (number_of_ious, iou_information_table);

      IF cmv$system_device_data [cmc$sdt_tape_device].specified THEN
        configure_ds_device (status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
        state_entries [4].element_type := cmc$data_channel_element;
        state_entries [4].element_name := cmv$system_device_data [cmc$sdt_tape_device].channel_name;
        state_entries [4].status.state := cmc$on;
        state_entries [4].iou := 'IOU0';
        state_entries [5].element_name := cmv$system_device_data [cmc$sdt_tape_device].equipment_name;
        state_entries [5].element_type := cmc$controller_element;
        state_entries [5].status.state := cmc$on;
        state_entries [5].product_id := cmv$system_device_data [cmc$sdt_tape_device].equipment_id;
        state_entries [5].logical_unit := 0;
        state_entries [6].element_name := cmv$system_device_data [cmc$sdt_tape_device].unit_name;
        state_entries [6].element_type := cmc$storage_device_element;
        state_entries [6].status.state := cmc$on;
        state_entries [6].product_id := cmv$system_device_data [cmc$sdt_tape_device].unit_id;
        state_entries [6].logical_unit := cmc$job_template_unit_ordinal + 1;
        cmp$build_state_table (6, state_entries, {use_mrt_state=} FALSE, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
        cmp$get_controller_type (cmv$system_device_data [cmc$sdt_tape_device].equipment_id,
              controller_type, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
        acquire_tape_by_channel := (controller_type = cmc$mt5698_xx) OR
          (((controller_type = cmc$mt698_xx) OR (controller_type = cmc$mt5680_xx)) AND
            (osv$170_os_type = osc$ot7_dual_state_nos_be)) OR
             (controller_type = cmc$mt7221_1);

        cmp$convert_iou_name (cmv$physical_configuration^ [4].data_channel.iou, iou, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
        cmp$get_driver_by_controller (controller_type,
              cmv$physical_configuration^ [4].data_channel.concurrent, iou, iou_program_name,
              ignore_alternate);
        cmv$physical_configuration^ [5].controller.peripheral_driver_name := iou_program_name;

        cmp$get_unit_type (cmv$system_device_data [cmc$sdt_tape_device].unit_id, cm_unit_type, io_unit_type,
              unit_class, found);
        need_to_load_controlware := (cm_unit_type = cmc$mt639_1) OR (cm_unit_type = cmc$mt639_s0) OR
              (cm_unit_type = cmc$mt698_3x) OR (cm_unit_type = cmc$mt5682_1x);
        IF controller_type = cmc$mt5680_xx THEN
          pp_count := pp_count + 2;
        ELSE
          pp_count := pp_count + 1;
        IFEND;
        unit_count := 2;
      ELSE
        cmp$build_state_table (3, state_entries, {use_mrt_state=} FALSE, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
      IFEND;

      cmp$build_interface_tables (pp_count, unit_count, FALSE, cmv$logical_unit_table,
            cmv$logical_pp_table_p, status);
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;
      cmv$max_number_of_pp := pp_count;

      IF cmv$system_device_data [cmc$sdt_tape_device].specified THEN
        channel.number := cmv$physical_configuration^ [4].data_channel.number;
        channel.concurrent := cmv$physical_configuration^ [4].data_channel.concurrent;
        channel.port := cmv$physical_configuration^ [4].data_channel.port;
        iou_number := cmv$system_device_data [cmc$sdt_tape_device].iou_number;
        IF acquire_tape_by_channel THEN
          unit_number := cmc$null_unit_number;
          equipment_number := cmc$null_equipment_number;
        ELSE
          unit_number := cmv$physical_configuration^ [6].storage_device.physical_unit_number;
          equipment_number := cmv$physical_configuration^ [5].controller.physical_equipment_number;
        IFEND;

        IF need_to_load_controlware THEN
          cmp$load_controller_module (cmc$load_controlware, cmv$logical_pp_table_p, status);
          IF NOT status.normal THEN
            EXIT /main_program/;
          IFEND;
        IFEND;

        cmp$acquire_deadstart_resources (channel, iou_number, equipment_number, unit_number, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;

        iop$tape_initialization (cmv$logical_unit_table, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
      IFEND;

      channel.number := pc_entries [1].data_channel.number;
      channel.port := pc_entries [1].data_channel.port;
      channel.concurrent := pc_entries [1].data_channel.concurrent;
      iou_number := cmv$system_device_data [cmc$sdt_disk_device].iou_number;

      IF acquire_by_channel THEN
        unit_number := cmc$null_unit_number;
        equipment_number := cmc$null_equipment_number;
      ELSE
        unit_number := pc_entries [3].storage_device.physical_unit_number;
        equipment_number := pc_entries [2].controller.physical_equipment_number;
      IFEND;

      { Load the controlware from the CIP device to memory.

      cmp$load_controller_module (cmc$load_controlware, cmv$logical_pp_table_p, status);
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;

      { Load the control module from the CIP device to memory.

      IF (disk_controller_type = cmc$ms7255_1_1) OR (disk_controller_type = cmc$ms7255_1_2) THEN
        cmp$load_controller_module (cmc$load_control_module, cmv$logical_pp_table_p, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
      IFEND;

      cmp$acquire_deadstart_resources (channel,iou_number, equipment_number, unit_number, status);
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;

      cmv$system_device_pp.software_idle := TRUE;

    END /main_program/;

  PROCEND cmp$configure_system_device;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$create_cm_device_files', EJECT ??
*copy cmh$create_cm_device_files

  PROCEDURE [XDCL] cmp$create_cm_device_files
    (VAR status: ost$status);

    VAR
      file_modified: boolean,
      fmd_modified: boolean,
      lc_max_size: integer,
      system_file_id: gft$system_file_identifier,
      p_file_attributes: ARRAY [1 .. 1] OF dmt$new_device_file_attribute;

    status.normal := TRUE;

    p_file_attributes [1].keyword := dmc$clear_space;
    p_file_attributes [1].required := FALSE;

    lc_max_size := 8 * 64 * #SIZE (cmt$element_definition) + #SIZE (cmt$device_file_header);
    dmp$create_device_file (cmc$physical_configuration_file, dmv$system_device_recorded_vsn,
          ^p_file_attributes, lc_max_size, system_file_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    dmp$detach_device_file (system_file_id, file_modified, fmd_modified, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cmv$new_device_file.recorded_vsn := dmv$system_device_recorded_vsn;
    cmv$new_device_file.version := 'ORIGINAL VERSION NUMBER 1';
    cmv$new_device_file.relative_time := cmc$rt_new;

  PROCEND cmp$create_cm_device_files;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$disable_unit', EJECT ??

{ PURPOSE:
{   This procedure sets the disable bit to true in the unit interface table of the corresponding logical unit.
{   This interface is intended to be used when DOWNing or OFFing elements other than mass storages (i.e, tape,
{   etc .. )

  PROCEDURE [XDCL, #GATE] cmp$disable_unit
    (    logical_unit_number: iot$logical_unit);

    IF cmv$logical_unit_table^ [logical_unit_number].unit_interface_table <> NIL THEN
      IF NOT cmv$logical_unit_table^ [logical_unit_number].unit_interface_table^.unit_lockword.lock AND
            NOT cmv$logical_unit_table^ [logical_unit_number].unit_interface_table^.unit_q_lockword.lock
            THEN
        cmv$logical_unit_table^ [logical_unit_number].unit_interface_table^.unit_status.disabled := TRUE;
      IFEND;
    IFEND;

  PROCEND cmp$disable_unit;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$enable_unit', EJECT ??

{ PURPOSE:
{   This procedure sets the disable bit to FALSE in the unit interface table of the corresponding logical
{   unit. This interface is intended to be used when ONing non mass storage devices such as tape units.

  PROCEDURE [XDCL, #GATE] cmp$enable_unit
    (    logical_unit_number: iot$logical_unit);

    VAR
      unit_interface_table_p: ^iot$unit_interface_table;

    unit_interface_table_p := cmv$logical_unit_table^ [logical_unit_number].unit_interface_table;
    IF unit_interface_table_p <> NIL THEN
      unit_interface_table_p^.unit_lockword := iov$initial_queue_lock_sc;
      unit_interface_table_p^.unit_q_lockword := iov$initial_queue_lock_sc;
      unit_interface_table_p^.next_request := NIL;
      unit_interface_table_p^.next_request_rma := 0;
      unit_interface_table_p^.unit_status.disabled := FALSE;
    IFEND;

  PROCEND cmp$enable_unit;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_connected_elements', EJECT ??

{ PURPOSE:
{   This procedure returns a list of element name connected to a channel.  The list of names must be
{   allocated by caller.

  PROCEDURE [XDCL, #GATE] cmp$get_connected_elements
    (    element: cmt$element_definition;
         element_name_list_p: {input, output} ^ARRAY [ * ] OF cmt$element_name;
      VAR number_of_entries: integer;
      VAR status: ost$status);

?? NEWTITLE := 'element_not_in_list', EJECT ??
    FUNCTION element_not_in_list
      (VAR element_name: cmt$element_name): boolean;

      VAR
        list_index: integer;

      element_not_in_list := TRUE;
      IF number_of_entries > 0 THEN

       /search_loop/
        FOR list_index := LOWERBOUND (element_name_list_p^) TO number_of_entries DO
          IF element_name_list_p^ [list_index] = element_name THEN
            element_not_in_list := FALSE;
            EXIT /search_loop/;
          IFEND;
        FOREND /search_loop/;
      IFEND;

    FUNCEND element_not_in_list;
?? OLDTITLE ??

    VAR
      pen: cmt$physical_equipment_number,
      table_index: integer;

    status.normal := TRUE;
    number_of_entries := 0;

    IF (element_name_list_p = NIL) OR (element.element_type <> cmc$data_channel_element) THEN
      RETURN;
    IFEND;

    IF cmv$physical_configuration = NIL THEN
      RETURN;
    IFEND;

   /loop/
    FOR table_index := LOWERBOUND (cmv$physical_configuration^) TO UPPERBOUND (cmv$physical_configuration^) DO
      IF (cmv$physical_configuration^ [table_index].element_type <> cmc$data_channel_element) THEN
        CYCLE /loop/;
      IFEND;

      IF (cmv$physical_configuration^ [table_index].data_channel.number <> element.data_channel.number) OR
            (cmv$physical_configuration^ [table_index].data_channel.concurrent <>
            element.data_channel.concurrent) OR
            (cmv$physical_configuration^ [table_index].data_channel.iou <> element.data_channel.iou) THEN
        CYCLE /loop/;
      IFEND;

      FOR pen := LOWERVALUE (cmt$physical_equipment_number) TO UPPERVALUE (cmt$physical_equipment_number) DO
        IF cmv$physical_configuration^ [table_index].data_channel.connection.equipment [pen].configured THEN
          IF number_of_entries < UPPERBOUND (element_name_list_p^) THEN

            { See if the element name already exists in the list before counting it.

            IF element_not_in_list (cmv$physical_configuration^ [table_index].
                  data_channel.connection.equipment [pen].element_name) THEN
              number_of_entries := number_of_entries + 1;
              element_name_list_p^ [number_of_entries] := cmv$physical_configuration^ [table_index].
                    data_channel.connection.equipment [pen].element_name;
            IFEND;
          ELSE

            { Users has not allocated enough entries in array element_name_list_p Return error.

            osp$set_status_abnormal (cmc$configuration_management_id, cme$pc_not_enough_entries, ' ', status);
            RETURN;
          IFEND;
        IFEND;
      FOREND;

      IF NOT element.data_channel.concurrent THEN
        RETURN;
      IFEND;
    FOREND;

  PROCEND cmp$get_connected_elements;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_cpu_element_r1', EJECT ??
*copyc cmh$get_cpu_element_r1

  PROCEDURE [XDCL, #GATE] cmp$get_cpu_element_r1
    (    processor_id: ost$processor_id;
         update_cst: boolean;
     VAR cpu_element: cmt$cpu_element_definition;
     VAR status: ost$status);


    VAR
      cpu_attributes: dst$cpu_attributes,
      element: ost$cpu_state_table,
      length: integer,
      str: string (3);

    status.normal := TRUE;

    IF processor_id > (osv$cpus_physically_configured - 1) THEN
      str (3) := $CHAR ($INTEGER ('0') + processor_id);
      str (1, 2) := 'CP';
      osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_element_not_found, str, status);
      RETURN;
    IFEND;

    IF update_cst THEN

      { Get the current CPU attributes from the MRT and update the CPU state table.

      dsp$get_cpu_attributes (cpu_attributes);

      IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
        IF ((cpu_attributes.cpu [processor_id].state = cmc$on) AND
             (mtv$cst0 [processor_id].processor_state = cmc$down)) THEN
          mtv$cst0 [processor_id].next_processor_state := cmc$on;
          mtv$cst0 [processor_id].previous_processor_state := cmc$down;
          mtv$cst0 [processor_id].log_cpu_state_change := TRUE;
          mtv$cy2000_sp_recovery := TRUE;
        ELSE
          mtv$cst0 [processor_id].processor_state :=
                cpu_attributes.cpu [processor_id].state;
        IFEND;
      ELSE
        mtv$cst0 [processor_id].processor_state := cpu_attributes.cpu [processor_id].state;
      IFEND;

      IF cpu_attributes.cpu [processor_id].state = cmc$down THEN
        IF cpu_attributes.cpu [processor_id].down_reason = dsc$pdr_down_by_operator THEN
          mtv$cst0 [processor_id].reason_for_current_state := osc$cdsr_downed_by_operator;
        ELSEIF (cpu_attributes.cpu [processor_id].down_reason = dsc$pdr_down_by_system) AND
              (mtv$cst0 [processor_id].reason_for_current_state = osc$cdsr_downed_by_dft) THEN

          { Don't change the CST!  It is the only place that we retain the fact that the CPU was downed by
          { DFT; the MRT can't "remember" this reason for all CYBER models.

        ELSE
          mtv$cst0 [processor_id].reason_for_current_state := osc$cdsr_downed_by_system;
        IFEND;
      ELSE {processor not down}
        mtv$cst0 [processor_id].reason_for_current_state := osc$cdsr_null;
      IFEND;
    IFEND;

    cpu_element.element_number := mtv$cst0 [processor_id].element_id.element_number;
    cpu_element.model_number := mtv$cst0 [processor_id].element_id.model_number;
    cpu_element.serial_number := mtv$cst0 [processor_id].element_id.serial_number;
    cpu_element.processor_state := mtv$cst0 [processor_id].processor_state;
    cpu_element.reason_for_current_state := mtv$cst0 [processor_id].reason_for_current_state;


  PROCEND cmp$get_cpu_element_r1;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_mainframe_element', EJECT ??
*copy cmh$get_mainframe_element

  PROCEDURE [XDCL, #GATE] cmp$get_mainframe_element
    (    element_name: cmt$element_name;
         iou_name: cmt$element_name;
     VAR mainframe_element: cmt$element_definition;
     VAR status: ost$status);

    VAR
      element_p: ^cmt$element_definition;

    status.normal := TRUE;
    cmp$pc_get_element (element_name, iou_name, element_p, status);
    IF status.normal THEN
      mainframe_element := element_p^;
    IFEND;

  PROCEND cmp$get_mainframe_element;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_ms_class_on_volume_r1', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$get_ms_class_on_volume_r1
    (    recorded_vsn: rmt$recorded_vsn;
     VAR volume_found: boolean;
     VAR ms_class_info: cmt$ms_class_info);

    VAR
      entry_p: ^dmt$active_volume_table_entry,
      i: integer,
      ms_class: cmt$ms_class_members;

    volume_found := FALSE;

  /search_avt/
    FOR i := LOWERBOUND (dmv$active_volume_table.table_p^) TO UPPERBOUND (dmv$active_volume_table.table_p^) DO
      entry_p := ^dmv$active_volume_table.table_p^ [i];
      IF (entry_p^.entry_available) OR (recorded_vsn <> entry_p^.mass_storage.recorded_vsn) THEN
        CYCLE /search_avt/; {----->
      IFEND;

      volume_found := TRUE;
      ms_class_info.allocation_allowed := entry_p^.mass_storage.allocation_allowed;
      ms_class_info.volume_available := NOT entry_p^.mass_storage.volume_unavailable;
      FOR ms_class := LOWERBOUND (ms_class_info.classes) TO UPPERBOUND (ms_class_info.classes) DO
        ms_class_info.classes [ms_class] := (ms_class IN entry_p^.mass_storage.class) AND
              (NOT entry_p^.mass_storage.volume_unavailable);
      FOREND;

      RETURN; {----->
    FOREND /search_avt/;

  PROCEND cmp$get_ms_class_on_volume_r1;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_ms_logical_unit_numbers', EJECT ??
*copy cmh$get_ms_logical_unit_numbers

  PROCEDURE [XDCL] cmp$get_ms_logical_unit_numbers
    (VAR ms_logical_unit_list: cmt$ms_logical_unit_list;
     VAR list_count: iot$logical_unit;
     VAR status: ost$status);

    VAR
      cm_unit_type: cmt$unit_type,
      io_unit_type: iot$unit_type,
      found: boolean,
      unit_class: cmt$unit_class,
      lun: iot$logical_unit,
      element_p: ^cmt$element_definition,
      local_status: ost$status,
      high_list: integer;

    status.normal := TRUE;
    high_list := UPPERBOUND (ms_logical_unit_list);
    list_count := 0;

    FOR lun := cmc$job_template_unit_ordinal TO UPPERVALUE (lun) DO
      cmp$pc_get_logical_unit (lun, element_p, local_status);
      IF NOT local_status.normal THEN
        RETURN;
      IFEND;

      cmp$get_unit_type (element_p^.product_id, cm_unit_type, io_unit_type, unit_class, found);
      IF found AND (unit_class = cmc$mass_storage_unit) THEN
        list_count := list_count + 1;
        IF list_count <= high_list THEN
          ms_logical_unit_list [list_count].lun := lun;
          ms_logical_unit_list [list_count].pid := element_p^.product_id;
        IFEND;
      IFEND;
    FOREND;

  PROCEND cmp$get_ms_logical_unit_numbers;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$manage_device_file_lock ' , EJECT ??

{ PURPOSE:
{   This procedure Set/Clear device file lock to prevent deadlock situation where two tasks are trying to
{   update the physical configuration device file at the same time.

  PROCEDURE [XDCL, #GATE] cmp$manage_device_file_lock
    (    set_lock: boolean;
     VAR status: ost$status);

    status.normal := TRUE;
    IF set_lock THEN
      osp$set_signature_lock (cmv$device_file_lock, osc$wait, status);
    ELSE
      osp$clear_signature_lock (cmv$device_file_lock, status);
    IFEND;

  PROCEND cmp$manage_device_file_lock;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$process_cpu_state_change_r1', EJECT ??

{ PURPOSE:
{   This procedure processes the "front end" of a CPU state change.  It sets up flags which are processed in
{   monitor mode (MTP$MONITOR_PROCESSOR_STATUS) to drive the CPU to the desired state.  The "back end" is
{   done after monitor mode sets a system flag in the $SYSTEM job's $JOBMONITOR task to finalize the CPU
{   state change processing in job mode (SYP$MFH_CPU_CONFIG_CHANGE), where the DFT request is made to change
{   the processor's state.

  PROCEDURE [XDCL, #GATE] cmp$process_cpu_state_change_r1
    (    processor_id: ost$processor_id;
         new_state: cmt$element_state;
     VAR status: ost$status);

    VAR
      cpu_attributes: dst$cpu_attributes,
      cst_p: ^ost$cpu_state_table,
      rb: dst$rb_system_deadstart_status;

    status.normal := TRUE;
    cst_p := ^mtv$cst0 [processor_id];

    cst_p^.previous_processor_state := cst_p^.processor_state;
    IF cst_p^.processor_state = cmc$on THEN

      { The CPU can be placed in the new state by the operator.

      cst_p^.pre_processed_for_reconfig := osc$ppfr_processing_in_progress;
      cst_p^.reason_for_current_state := osc$cdsr_downed_by_operator;
      cst_p^.next_processor_state := new_state;

    ELSEIF new_state = cmc$on THEN

      dsp$get_cpu_attributes (cpu_attributes);
      IF cpu_attributes.cpu [processor_id].vectors_not_available THEN
        mtv$scb.vector_simulation_control.vector_divide_degraded :=
              mtv$scb.vector_simulation_control.vector_divide_degraded + $ost$processor_id_set [processor_id];
      ELSE
        mtv$scb.vector_simulation_control.vector_divide_degraded :=
              mtv$scb.vector_simulation_control.vector_divide_degraded - $ost$processor_id_set [processor_id];
      IFEND;

      { The processor is DOWN, and the CPU can be placed in the new state by the operator.
      { (The processor_state of OFF is caught in caller of this procedure.)

      IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
        IF ((cpu_attributes.cpu [processor_id].state = cmc$on) AND
              (cst_p^.processor_state = cmc$down)) THEN
          cst_p^.next_processor_state := cmc$on;
          cst_p^.previous_processor_state := cmc$down;
          cst_p^.log_cpu_state_change := TRUE;
          mtv$cy2000_sp_recovery := TRUE;

           { Set the recovery lock to prevent job manager from mucking
           { with scheduling on this cpu until we at least get it started.

             mtv$recovery_lock1 := true;

        ELSE
          cst_p^.processor_state :=
            cpu_attributes.cpu [processor_id].state;
        IFEND;
      ELSE
        mtv$cst0 [processor_id].processor_state := cpu_attributes.cpu [processor_id].state;
      IFEND;

      cst_p^.cpu_alive_flag := #FREE_RUNNING_CLOCK (0);
      cst_p^.next_processor_state := new_state;


      { Restore the values for the 'cache purged' and/or 'page map purged' times for the deconfigured CPU.
      { The following lines are necessary to enable this CPU to purge its cache and/or page maps.

      cst_p^.time_last_cache_purge := 0;
      cst_p^.time_last_map_request := 0;

      rb.reqcode := syc$rc_system_deadstart_status;
      rb.action := dsc$rb_sds_clear_bct_flag;
      rb.bct_flags := dsc$rb_sds_bct_both_cpu_error;
      i#call_monitor (#LOC (rb), #SIZE (rb));
    IFEND;

  PROCEND cmp$process_cpu_state_change_r1;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$search_redundant_path ', EJECT ??

{ PURPOSE:
{   This procedures searches for an available redundant channel given the primary channel definition. It
{   returns the driver name, the controller type and the RMA to the PPIT of the redundant channel.
{ NOTE:
{   A channel is redundant if it is connected to a certain group of disk and tape subsystems and if it is
{   not the first on channel in the connection.

  PROCEDURE [XDCL, #GATE] cmp$search_redundant_path
    (    primary_path_element: cmt$element_definition;
         iou: dst$iou_number;
         channel: cmt$physical_channel;
         new_state: cmt$element_state;
     VAR redundant_path_available: boolean;
     VAR update_controller_address: boolean;
     VAR number_of_path: integer;
     VAR redundant_channel_list: array [cmt$physical_equipment_number] of cmt$physical_address;
     VAR redundant_path_pp_list: array [cmt$physical_equipment_number] of iot$pp_number;
     VAR driver_name: pmt$program_name;
     VAR pp_table_rma_list: array [cmt$physical_equipment_number] of ost$real_memory_address);

    VAR
      local_status: ost$status,
      lun: iot$logical_unit,
      physical_address: cmt$physical_address,
      pp: iot$pp_number,
      pp_found: boolean,
      ppit_p: ^iot$pp_interface_table,
      unit_desc: iot$unit_descriptor_entry;

    IF primary_path_element.element_type = cmc$data_channel_element THEN
      physical_address.address_specifier := $cmt$physical_address_specifier [cmc$iou, cmc$channel];
      physical_address.iou := iou;
      physical_address.channel.number := primary_path_element.data_channel.number;
      physical_address.channel.port := primary_path_element.data_channel.port;
      physical_address.channel.concurrent := primary_path_element.data_channel.concurrent;
    ELSEIF primary_path_element.element_type = cmc$controller_element THEN
      physical_address.address_specifier :=
            $cmt$physical_address_specifier [cmc$iou, cmc$channel, cmc$channel_address];
      physical_address.iou := iou;
      physical_address.channel := channel;
      physical_address.channel_address := primary_path_element.controller.physical_equipment_number;
    ELSEIF primary_path_element.element_type = cmc$storage_device_element THEN
      cmp$get_logical_unit_number(primary_path_element.element_name, lun, local_status);
      IF NOT local_status.normal THEN
        redundant_path_available := FALSE;
        RETURN;
      IFEND;

      pp_found := FALSE;
    /pp_loop/
      FOR pp := LOWERBOUND (cmv$logical_pp_table_p^) TO UPPERBOUND (cmv$logical_pp_table_p^) DO
        IF NOT cmv$logical_pp_table_p^ [pp].flags.configured THEN
          CYCLE /pp_loop/;
        IFEND;

        ppit_p := cmv$logical_pp_table_p^ [pp].pp_info.pp_interface_table_p;

        IF (lun < LOWERBOUND (ppit_p^.unit_descriptors)) OR (lun > UPPERBOUND (ppit_p^.unit_descriptors)) THEN
          CYCLE /pp_loop/;
        IFEND;

        unit_desc := ppit_p^.unit_descriptors [lun];

        IF unit_desc.unit_interface_table = NIL THEN
          CYCLE /pp_loop/;
        IFEND;

        IF unit_desc.logical_unit = lun THEN
          pp_found := TRUE;
          EXIT /pp_loop/;
        IFEND;
      FOREND /pp_loop/;

      IF NOT pp_found THEN
        redundant_path_available := FALSE;
        RETURN;
      IFEND;

      physical_address.address_specifier :=
            $cmt$physical_address_specifier [cmc$iou, cmc$channel, cmc$channel_address, cmc$unit_address];
      physical_address.iou := iou;
      physical_address.channel := channel;
      physical_address.channel_address := cmv$logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.
            unit_descriptors [lun].physical_path.controller_number;
      physical_address.unit_address := primary_path_element.storage_device.physical_unit_number;
    ELSE
      redundant_path_available := FALSE;
      RETURN;
    IFEND;

    cmp$find_redundant_path (physical_address, new_state, redundant_path_available, update_controller_address,
          number_of_path, redundant_channel_list, redundant_path_pp_list, driver_name, pp_table_rma_list);

  PROCEND cmp$search_redundant_path;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$switch_tape_channel', EJECT ??

{ PURPOSE:
{   This procedure switch access to the redundant tape channel by going through the redundant pp's unit
{   descriptors and un-Nil the RMA to the UIT.

  PROCEDURE [XDCL, #GATE] cmp$switch_tape_channel
    (    primary_channel: cmt$element_definition;
         ignore_controller_state: boolean;
         number_of_redundant_path: integer;
         redundant_channel_list: ARRAY [cmt$physical_equipment_number] OF cmt$physical_address;
         new_state: cmt$element_state;
         redundant_pp_list: ARRAY [cmt$physical_equipment_number] OF iot$pp_number;
     VAR status: ost$status);

    VAR
      channel_data: cmt$element_definition,
      count: integer,
      index: integer,
      iou_number: dst$iou_number,
      logical_pp_index: iot$pp_number,
      primary_pp: iot$pp_number,
      request_block: cmt$request_block;

    status.normal := TRUE;
    cmp$get_logical_pp_index (primary_channel, primary_pp, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    cmp$convert_iou_name (primary_channel.data_channel.iou, iou_number, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    request_block.request_code := syc$rc_config_mgmt_request;
    request_block.kind := cmc$rbk_change_state;
    request_block.element_name := primary_channel.element_name;
    request_block.new_state := new_state;
    request_block.iou := iou_number;
    request_block.element_type := cmc$data_channel_element;
    request_block.channel := primary_channel.data_channel.number;
    request_block.channel_pp := primary_pp;
    request_block.update_controller_address := FALSE;
    request_block.redundant_path_available := TRUE;
    request_block.redundant_path_pp_list_p := NIL;
    request_block.logical_unit_list_p := NIL;

    ALLOCATE request_block.redundant_path_pp_list_p: [0 .. number_of_redundant_path] IN
          osv$mainframe_wired_heap^;
    FOR index := LOWERVALUE (cmt$physical_equipment_number) TO number_of_redundant_path DO
      request_block.redundant_path_pp_list_p^ [index] := redundant_pp_list [index];
    FOREND;

    build_logical_unit_list (primary_channel, ignore_controller_state, FALSE, new_state, primary_pp,
          request_block.logical_unit_list_p, count);
    IF count <> 0 THEN
      ALLOCATE request_block.logical_unit_list_p: [1 .. count] IN osv$mainframe_wired_heap^;
      build_logical_unit_list (primary_channel, ignore_controller_state, FALSE, new_state, primary_pp,
            request_block.logical_unit_list_p, count);
    IFEND;

    i#call_monitor (#LOC (request_block), #SIZE (request_block));
    IF request_block.logical_unit_list_p <> NIL THEN
      FREE request_block.logical_unit_list_p IN osv$mainframe_wired_heap^;
    IFEND;
    IF request_block.redundant_path_pp_list_p <> NIL THEN
      FREE request_block.redundant_path_pp_list_p IN osv$mainframe_wired_heap^;
    IFEND;

    { See if PP on redundant channel(s) need to be returned.

    IF new_state = cmc$on THEN
      FOR index := LOWERVALUE (cmt$physical_equipment_number) TO number_of_redundant_path DO
        build_logical_unit_list (primary_channel, FALSE, FALSE, cmc$down, redundant_pp_list [index], NIL,
              count);
        channel_data.element_type := cmc$data_channel_element;
        cmp$convert_iou_number (redundant_channel_list [index].iou, channel_data.data_channel.iou, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        channel_data.data_channel.number := redundant_channel_list [index].channel.number;
        channel_data.data_channel.port := redundant_channel_list [index].channel.port;
        channel_data.data_channel.concurrent := redundant_channel_list [index].channel.concurrent;
        cmp$get_logical_pp_index (channel_data, logical_pp_index, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        IF cmv$logical_pp_table_p^ [logical_pp_index].flags.resources_acquired AND (count = 0) THEN
          cmp$release_pp_by_index (logical_pp_index, status);
        IFEND;
      FOREND;
    IFEND;

  PROCEND cmp$switch_tape_channel;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$zero_out_uit_rma', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$zero_out_uit_rma
    (    logical_unit: iot$logical_unit;
         channel: cmt$element_definition;
         new_state: cmt$element_state;
     VAR status: ost$status);

    VAR
      logical_pp: iot$pp_number,
      rma: integer;

    status.normal := TRUE;
    cmp$get_logical_pp_index (channel, logical_pp, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF new_state = cmc$on THEN
      i#real_memory_address (#LOC (cmv$logical_unit_table^ [logical_unit].unit_interface_table^), rma);
      cmv$logical_pp_table_p^ [logical_pp].pp_info.pp_interface_table_p^.
            unit_descriptors [logical_unit].unit_interface_table_rma := rma;
    ELSE
      cmv$logical_pp_table_p^ [logical_pp].pp_info.pp_interface_table_p^.
            unit_descriptors [logical_unit].unit_interface_table_rma := 0;
    IFEND;

  PROCEND cmp$zero_out_uit_rma;
?? OLDTITLE ??
MODEND cmm$physical_config_mgr_r1;
