?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE CM : PCU Ring1 Helper' ??
MODULE cmm$pcu_ring1_helper;

{ PURPOSE:
{   This module contains the ring 1 procedures that help the PCU procedures that run at job_template_23d.
{   These procedures are used to build the full configuration tables.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cmc$logical_unit_constants
*copyc cme$logical_configuration_mgr
*copyc cme$physical_configuration_mgr
*copyc cmt$channel_descriptor
*copyc cmt$deadstart_signal
*copyc cmt$physical_channel
*copyc cmt$physical_equipment_number
*copyc cmt$physical_unit_number
*copyc dse$resource_errors
*copyc oss$mainframe_paged_literal
*copyc pmt$signal
?? POP ??
*copyc cmp$acquire_resources
*copyc cmp$build_element_def_table
*copyc cmp$build_interface_tables
*copyc cmp$convert_channel_number
*copyc cmp$convert_iou_name
*copyc cmp$convert_iou_number
*copyc cmp$determine_redundant_channel
*copyc cmp$free_element_def_table
*copyc cmp$get_channel_def
*copyc cmp$get_controller_type
*copyc cmp$get_driver_by_controller
*copyc cmp$get_element_state
*copyc cmp$get_max_number_of_pp
*copyc cmp$get_unit_type
*copyc cmp$idle_pp_r1
*copyc cmp$load_controller_module
*copyc cmp$pc_get_element
*copyc cmp$pc_get_logical_unit
*copyc cmp$pc_get_next_channel
*copyc cmp$release_channel_resource
*copyc cmp$release_equipment_resource
*copyc cmp$release_pp_by_channel
*copyc cmp$release_pp_resource
*copyc cmp$request_resources
*copyc cmp$retrieve_logical_pp_index
*copyc cmp$set_illegal_channel_status
*copyc cmp$update_connection_states_r1
*copyc dmp$allocate_avt
*copyc dsp$load_pp
*copyc iop$allocate_usage_counters
*copyc iop$tape_initialization
*copyc osp$set_status_abnormal
*copyc pmp$get_mainframe_id
*copyc pmp$zero_out_table
*copyc syp$process_deadstart_status
*copyc syp$trace_deadstart_message
?? EJECT ??
*copyc cmv$acquire_pp_for_redundant_ch
*copyc cmv$configuration_activated
*copyc cmv$controller_location
*copyc cmv$logical_pp_table_p
*copyc cmv$logical_unit_table
*copyc cmv$max_number_of_pp
*copyc cmv$new_logical_pp_table_p
*copyc cmv$new_logical_unit_table
*copyc cmv$physical_configuration
*copyc cmv$post_deadstart
*copyc cmv$save_pct_p
*copyc cmv$save_state_table_p
*copyc cmv$state_info_table
*copyc cmv$system_device_data
*copyc cmv$system_device_pp
*copyc osv$170_os_type
*copyc osv$mainframe_pageable_heap
*copyc osv$mainframe_wired_cb_heap
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  TYPE
    t$resources_assigned = RECORD
      assigned: boolean,
      channel: cmt$physical_channel,
      iou_number: dst$iou_number,
      equipment: 0 .. cmc$null_equipment_number,
      unit: 0 .. cmc$null_unit_number,
      driver_name: cmt$element_name,
      pp_resources_needed: boolean,
    RECEND;

  VAR
    cmv$deadstart_signals: [XDCL, #GATE] ^cmt$deadstart_signal := NIL,
    cmv$signal_handler_active: [XDCL, #GATE] boolean := FALSE,
    v$first_time: boolean := TRUE,
    v$save_lpt_p: ^cmt$logical_pp_table := NIL,
    v$save_lut_p: ^cmt$logical_unit_table := NIL;

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

{ PURPOSE:
{   This procedure acquires all the needed IOU resources. This is achieved by going through the structure
{   previously built by determine_resources.

  PROCEDURE acquire_all_resources
    (VAR resources_assigned_p: ^ARRAY [ * ] OF t$resources_assigned;
     VAR status: ost$status);

    VAR
      dummy_pp: dst$iou_resource,
      index: integer,
      pp_number: iot$pp_number,
      tape_channel: cmt$physical_channel,
      tape_channel_name: cmt$element_name,
      tape_element_p: ^cmt$element_definition,
      tape_iou: dst$iou_number,
      tape_iou_name: cmt$element_name;

    status.normal := TRUE;

    { Clear the table which tells which PP has controlware or control module loaded.  This is done so that
    { the new logical pp table will be created with new RMA lists.

    FOR pp_number := LOWERBOUND (cmv$new_logical_pp_table_p^) TO UPPERBOUND (cmv$new_logical_pp_table_p^) DO
      cmv$new_logical_pp_table_p^ [pp_number].controller_info.controlware_loaded := FALSE;
      cmv$new_logical_pp_table_p^ [pp_number].controller_info.control_module_loaded := FALSE;
    FOREND;

    { Load the controlware from the CIP device to memory.

    cmp$load_controller_module (cmc$load_controlware, cmv$new_logical_pp_table_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

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

    cmp$load_controller_module (cmc$load_control_module, cmv$new_logical_pp_table_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF resources_assigned_p = NIL THEN
      RETURN;
    IFEND;

    { Idle the tape driver so it can be acquired again.

    IF v$first_time THEN
      IF cmv$system_device_data [cmc$sdt_tape_device].specified THEN
        tape_channel_name := cmv$system_device_data [cmc$sdt_tape_device].channel_name;
        tape_iou := cmv$system_device_data [cmc$sdt_tape_device].iou_number;
        cmp$convert_iou_number (tape_iou, tape_iou_name, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        cmp$pc_get_element (tape_channel_name, tape_iou_name, tape_element_p, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        tape_channel.number := tape_element_p^.data_channel.number;
        tape_channel.concurrent := tape_element_p^.data_channel.concurrent;
        tape_channel.port := tape_element_p^.data_channel.port;

        cmp$idle_pp_r1 (tape_element_p^.element_name, tape_iou_name, status);

        cmp$release_pp_by_channel (tape_channel, tape_iou, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        IF (cmv$system_device_data [cmc$sdt_tape_device].unit_id.product_number = '  $639') OR
              ((cmv$system_device_data [cmc$sdt_tape_device].equipment_id.product_number = '  $698') AND
              (osv$170_os_type = osc$ot7_dual_state_nos_be)) OR
              (cmv$system_device_data [cmc$sdt_tape_device].equipment_id.product_number = ' $5698') THEN
          cmp$release_channel_resource (tape_channel, tape_iou, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
        ELSE
          cmp$release_equipment_resource (tape_channel, tape_iou,
                cmv$system_device_data [cmc$sdt_tape_device].equipment_number,
                cmv$system_device_data [cmc$sdt_tape_device].unit_number);
        IFEND;
        v$first_time := FALSE;
      IFEND;
    IFEND;

    FOR index := LOWERBOUND (resources_assigned_p^) TO UPPERBOUND (resources_assigned_p^) DO
      IF resources_assigned_p^ [index].driver_name <> ' ' THEN
        IF resources_assigned_p^ [index].pp_resources_needed THEN
          obtain_pp_resource (resources_assigned_p^ [index], status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          resources_assigned_p^ [index].assigned := TRUE;
        ELSE

          { Attempt to get only the channel/equipment but no PP.

          IF (resources_assigned_p^ [index].equipment = cmc$null_equipment_number) OR
                (resources_assigned_p^ [index].unit = cmc$null_unit_number) THEN
            cmp$acquire_resources (dsc$rrt_get_channel, resources_assigned_p^ [index].channel,
                  resources_assigned_p^ [index].iou_number, cmc$null_equipment_number,
                  cmc$null_unit_number, FALSE, FALSE, FALSE, dummy_pp, status);
          ELSE
            cmp$acquire_resources (dsc$rrt_get_equipment, resources_assigned_p^ [index].channel,
                  resources_assigned_p^ [index].iou_number,
                  resources_assigned_p^ [index].equipment, resources_assigned_p^ [index].unit, FALSE,
                  FALSE, FALSE, dummy_pp, status);
          IFEND;
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          resources_assigned_p^ [index].assigned := TRUE;
        IFEND;
      IFEND;
    FOREND;

  PROCEND acquire_all_resources;
?? OLDTITLE ??
?? NEWTITLE := 'begin_conf_transition', EJECT ??

{ PURPOSE:
{   This procedure starts the transition from System/Deadstart devices to the full configuration. This
{   involves IDLE and RELOAD of the system device driver and loading of all drivers.

  PROCEDURE begin_conf_transition
    (    system_device_lun: iot$logical_unit;
     VAR resources_assigned_p: ^ARRAY [ * ] OF t$resources_assigned;
     VAR status: ost$status);

    VAR
      allocate_ok: boolean,
      cm_unit_type: cmt$unit_type,
      controller_configured: boolean,
      controller_type: cmt$controller_type,
      data_storage_port: cmt$data_storage_port_number,
      disk_unit_count: integer,
      element_name: cmt$element_name,
      io_unit_type: iot$unit_type,
      iou_name: cmt$element_name,
      iou_number: dst$iou_number,
      local_status: ost$status,
      partner_pp_index: iot$pp_number,
      pp_index: iot$pp_number,
      storage_device_found: boolean,
      sys_dev_channel_p: ^cmt$element_definition,
      sys_dev_element_p: ^cmt$element_definition,
      sys_eq_element_p: ^cmt$element_definition,
      system_device_iou: cmt$element_name,
      system_device_channel: cmt$physical_channel,
      system_device_equipment: cmt$physical_equipment_number,
      system_device_unit: cmt$physical_unit_number,
      unit_class: cmt$unit_class,
      unit_index: iot$logical_unit;

    status.normal := TRUE;

    cmp$pc_get_logical_unit (system_device_lun, sys_dev_element_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cmp$get_system_device_path (cmc$sdt_disk_device, system_device_iou, system_device_channel,
          system_device_equipment, system_device_unit, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    controller_configured := FALSE;

   /loop/
    FOR data_storage_port := LOWERVALUE (cmt$data_storage_port_number) TO
          UPPERVALUE (cmt$data_storage_port_number) DO
      IF NOT sys_dev_element_p^.storage_device.connection.port [data_storage_port].configured THEN
        CYCLE /loop/;
      IFEND;
      element_name := sys_dev_element_p^.storage_device.connection.port [data_storage_port].element_name;
      IF sys_dev_element_p^.storage_device.connection.port [data_storage_port].upline_connection_type =
            cmc$data_channel_element THEN
        iou_name := sys_dev_element_p^.storage_device.connection.port [data_storage_port].iou;
      ELSE
        iou_name := osc$null_name;
      IFEND;
      cmp$pc_get_element (element_name, iou_name, sys_eq_element_p, local_status);
      IF NOT local_status.normal THEN
        CYCLE /loop/;
      IFEND;
      controller_configured := TRUE;
      EXIT /loop/;
    FOREND /loop/;
    IF NOT controller_configured THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$pc_equip_not_configured,
            'Equipment specified not configured in begin_conf_transition', status);
      RETURN;
    IFEND;

    cmp$get_unit_type (sys_dev_element_p^.product_id, cm_unit_type, io_unit_type, unit_class,
          storage_device_found);
    IF NOT storage_device_found THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$unknown_product_id,
            sys_dev_element_p^.product_id.product_number, status);
      RETURN;
    IFEND;
    IF cm_unit_type <> cmc$mshydra THEN
      cmp$get_controller_type (sys_eq_element_p^.product_id, controller_type, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    ELSE
      controller_type := cmc$mshydra_ct;
    IFEND;

    cmp$convert_iou_name (system_device_iou, iou_number, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cmp$retrieve_logical_pp_index (system_device_channel, iou_number, cmv$new_logical_pp_table_p,
          pp_index, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { Do not obtain pp, only the reload driver.

    partner_pp_index := cmv$new_logical_pp_table_p^ [pp_index].pp_info.logical_partner_pp_index;
    cmv$new_logical_pp_table_p^ [pp_index].pp_info.physical_pp := cmv$system_device_pp.primary_pp;
    cmv$new_logical_pp_table_p^ [pp_index].flags.resources_acquired := TRUE;
    IF partner_pp_index > 0 THEN
      cmv$new_logical_pp_table_p^ [partner_pp_index].pp_info.physical_pp := cmv$system_device_pp.partner_pp;
      cmv$new_logical_pp_table_p^ [partner_pp_index].flags.resources_acquired := TRUE;
      cmv$system_device_pp.ppit_rma :=
            cmv$new_logical_pp_table_p^ [pp_index].pp_info.pp_communication_buffer_p^.partner_pp;
    IFEND;

    { One request will load both master and slave pp if dual pp exists.

    dsp$load_pp (dsc$load_pp_by_name, cmv$new_logical_pp_table_p^ [pp_index].pp_info.physical_pp, NIL,
          cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name,
          cmv$new_logical_pp_table_p^ [pp_index].pp_info.pp_interface_table_rma, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    cmv$new_logical_pp_table_p^ [pp_index].flags.pp_loaded := TRUE;
    IF partner_pp_index > 0 THEN
      cmv$new_logical_pp_table_p^ [partner_pp_index].flags.pp_loaded := TRUE;
    IFEND;

    load_all_other_drivers (system_device_channel, iou_number, status);
    IF NOT status.normal THEN
      syp$process_deadstart_status (' ', TRUE, status);
      RETURN;
    IFEND;

    disk_unit_count := 0;
    FOR unit_index := cmc$job_template_unit_ordinal TO UPPERBOUND (cmv$logical_unit_table^) DO
      IF cmv$logical_unit_table^ [unit_index].configured AND
            (cmv$logical_unit_table^ [unit_index].unit_interface_table^.unit_type >= ioc$lowest_disk_unit) AND
            (cmv$logical_unit_table^ [unit_index].unit_interface_table^.unit_type <=
            ioc$highest_disk_unit) THEN
        disk_unit_count := disk_unit_count + 1;
      IFEND;
    FOREND;

    dmp$allocate_avt (disk_unit_count, allocate_ok);
    IF NOT allocate_ok THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$pc_allocate_avt_error,
            'DMP$ALLOCATE_AVT', status);
      RETURN;
    IFEND;

    iop$allocate_usage_counters (status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { FREE resources_assigned_p if no errors occurred

    IF resources_assigned_p <> NIL THEN
      FREE resources_assigned_p IN osv$mainframe_pageable_heap^;
    IFEND;

  PROCEND begin_conf_transition;
?? OLDTITLE ??
?? NEWTITLE := 'determine_resources', EJECT ??

{ PURPOSE:
{   This procedures determines all of the IOU resources needed to acquire.
{ DESIGN:
{   Allocate a table with the number of entries equal to the number of entries in the configuration table.
{   This structure will contain one entry per Equipment/Channel to be acquired.  The same structure will be
{   saved so clean up can be performed should an error occured during resources acquisition.

  PROCEDURE determine_resources
    (VAR resources_assigned_p: ^ARRAY [ * ] OF t$resources_assigned;
     VAR status: ost$status);

    VAR
      ch_element_p: ^cmt$element_definition,
      ch_iou_number: dst$iou_number,
      channel_state: cmt$element_state,
      cm_unit_type: cmt$unit_type,
      controller_type: cmt$controller_type,
      count: integer,
      current_channel: integer,
      current_ch_is_system_device_ch: boolean,
      driver_name: string (4),
      equip_element_p: ^cmt$element_definition,
      equip_state: cmt$element_state,
      found: boolean,
      get_full_path: boolean,
      index_count: integer,
      io_unit_type: iot$unit_type,
      local_status: ost$status,
      number_of_controller_on: integer,
      number_of_units_configured: integer,
      pen: cmt$physical_equipment_number,
      pp_resources_needed: boolean,
      pun: cmt$physical_unit_number,
      system_device_channel: cmt$physical_channel,
      system_device_iou: cmt$element_name,
      system_device_equipment: cmt$physical_equipment_number,
      system_device_unit: cmt$physical_unit_number,
      table_setup: boolean,
      temp_table_p: ^ARRAY [ * ] OF t$resources_assigned,
      total_resources: integer,
      unit_class: cmt$unit_class,
      unit_element_p: ^cmt$element_definition,
      unit_state: cmt$element_state;

    status.normal := TRUE;

    current_channel := 0;
    get_full_path := FALSE;
    total_resources := 0;

    count := UPPERBOUND (cmv$physical_configuration^);
    PUSH temp_table_p: [1 .. count];
    FOR index_count := 1 TO count DO
      temp_table_p^ [index_count].driver_name := ' ';
      temp_table_p^ [index_count].assigned := FALSE;
      temp_table_p^ [index_count].pp_resources_needed := FALSE;
    FOREND;

    cmp$get_system_device_path (cmc$sdt_disk_device, system_device_iou, system_device_channel,
          system_device_equipment, system_device_unit, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

  /loop_thru_channels/
    WHILE total_resources <= count DO
      cmp$pc_get_next_channel (current_channel, ch_element_p, local_status);
      IF NOT local_status.normal THEN
        EXIT /loop_thru_channels/;
      IFEND;
      current_channel := current_channel + 1;

      cmp$get_element_state (ch_element_p^.element_name, ch_element_p^.data_channel.iou, channel_state,
            status);
      IF channel_state = cmc$off THEN
        CYCLE /loop_thru_channels/;
      IFEND;

      cmp$convert_iou_name (ch_element_p^.data_channel.iou, ch_iou_number, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      current_ch_is_system_device_ch := FALSE;
      get_full_path := FALSE;
      number_of_controller_on := 0;
      table_setup := FALSE;

    /loop_thru_controllers/
      FOR pen := LOWERVALUE (cmt$physical_equipment_number) TO UPPERVALUE (cmt$physical_equipment_number) DO
        IF NOT ch_element_p^.data_channel.connection.equipment [pen].configured THEN
          CYCLE /loop_thru_controllers/;
        IFEND;

        cmp$pc_get_element (ch_element_p^.data_channel.connection.equipment [pen].element_name, osc$null_name,
              equip_element_p, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        { For S0, not get channel associated with ICA. }

        IF ((equip_element_p^.element_type = cmc$channel_adapter_element) AND
              (equip_element_p^.product_id.product_number = ' $2629')) OR
              (equip_element_p^.element_type = cmc$communications_element) THEN
          EXIT /loop_thru_controllers/;
        IFEND;

        cmp$get_element_state (equip_element_p^.element_name, osc$null_name, equip_state, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        IF equip_state = cmc$off THEN
          CYCLE /loop_thru_controllers/;
        IFEND;

        CASE equip_element_p^.element_type OF
        = cmc$controller_element =
          cmp$get_controller_type (equip_element_p^.product_id, controller_type, local_status);
          IF NOT local_status.normal THEN
            EXIT /loop_thru_controllers/;
          IFEND;

          get_full_path :=
                (controller_type = cmc$ms5831_x)   OR (controller_type = cmc$msntdc_1) OR
                (controller_type = cmc$msntdc_2)   OR
               ((controller_type = cmc$mt698_xx)  AND (osv$170_os_type = osc$ot7_dual_state_nos_be)) OR
                (controller_type = cmc$ms7165_2x)  OR (controller_type = cmc$mscm3_ct) OR
                (controller_type = cmc$mshydra_ct) OR (controller_type = cmc$ms7255_1_1) OR
                (controller_type = cmc$ms7255_1_2) OR (controller_type = cmc$mt7221_1) OR
                (controller_type = cmc$mt5698_xx)  OR (controller_type = cmc$mt5680_xx) OR
                (controller_type = cmc$mt7221_2_s0);

          current_ch_is_system_device_ch :=
                (ch_element_p^.data_channel.number = system_device_channel.number) AND
                (ch_element_p^.data_channel.concurrent = system_device_channel.concurrent) AND
                (ch_element_p^.data_channel.port = system_device_channel.port) AND
                (ch_element_p^.data_channel.iou = system_device_iou);

          IF get_full_path AND current_ch_is_system_device_ch THEN
            EXIT /loop_thru_controllers/;
          IFEND;

          IF equip_state = cmc$on THEN
            number_of_controller_on := number_of_controller_on + 1;
          IFEND;

          { If the current controller is DOWN, need to go to the next controller on the channel and check
          { its state.

          IF get_full_path THEN
            IF (number_of_controller_on <> 0) OR (pen = UPPERVALUE (cmt$physical_equipment_number)) THEN
              total_resources := total_resources + 1;
              pp_resources_needed := (number_of_controller_on <> 0);
              setup_resources_table (total_resources, equip_element_p^.controller.peripheral_driver_name,
                    ch_iou_number, ch_element_p^.data_channel, cmc$null_equipment_number,
                    cmc$null_unit_number, pp_resources_needed, temp_table_p);
              table_setup := TRUE;
              EXIT /loop_thru_controllers/;
            ELSE
              CYCLE /loop_thru_controllers/;
            IFEND;
          IFEND;

          number_of_units_configured := 0;

        /loop_thru_units/
          FOR pun := LOWERVALUE (cmt$physical_unit_number) TO UPPERVALUE (cmt$physical_unit_number) DO
            IF NOT equip_element_p^.controller.connection.unit [pun].configured THEN
              CYCLE /loop_thru_units/;
            IFEND;

            IF ((current_ch_is_system_device_ch) AND (system_device_equipment = pen) AND
                  (system_device_unit = pun)) THEN
              CYCLE /loop_thru_units/;
            IFEND;

            cmp$pc_get_element (equip_element_p^.controller.connection.unit [pun].element_name,
                  {iou not used} osc$null_name, unit_element_p, status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;

            cmp$get_element_state (unit_element_p^.element_name, osc$null_name, unit_state, status);
            IF (unit_state = cmc$on) OR (unit_state = cmc$down) THEN
              number_of_units_configured := number_of_units_configured + 1;
              total_resources := total_resources + 1;
              pp_resources_needed := (channel_state = cmc$on) AND (equip_state = cmc$on);
              setup_resources_table (total_resources, equip_element_p^.controller.peripheral_driver_name,
                    ch_iou_number, ch_element_p^.data_channel, pen, pun, pp_resources_needed, temp_table_p);
            IFEND;
          FOREND /loop_thru_units/;

          IF number_of_units_configured = 0 THEN
            total_resources := total_resources + 1;
            pp_resources_needed := (channel_state = cmc$on) AND (equip_state = cmc$on);
            setup_resources_table (total_resources, equip_element_p^.controller.peripheral_driver_name,
                  ch_iou_number, ch_element_p^.data_channel, cmc$null_equipment_number, cmc$null_unit_number,
                  pp_resources_needed, temp_table_p);
            EXIT /loop_thru_controllers/;
          IFEND;

        = cmc$external_processor_element =
          total_resources := total_resources + 1;
          pp_resources_needed := (channel_state = cmc$on) AND (equip_state = cmc$on);
          setup_resources_table (total_resources, equip_element_p^.external_processor.peripheral_driver_name,
                ch_iou_number, ch_element_p^.data_channel, cmc$null_equipment_number, cmc$null_unit_number,
                pp_resources_needed, temp_table_p);
          EXIT /loop_thru_controllers/;

        = cmc$storage_device_element =
          IF NOT ((ch_element_p^.data_channel.number = system_device_channel.number) AND
                (ch_element_p^.data_channel.concurrent = system_device_channel.concurrent) AND
                (ch_element_p^.data_channel.port = system_device_channel.port) AND
                (ch_element_p^.data_channel.iou = system_device_iou)) THEN

            cmp$get_unit_type (equip_element_p^.product_id, cm_unit_type, io_unit_type, unit_class, found);
            IF found THEN
              IF cm_unit_type = cmc$mshydra THEN
                total_resources := total_resources + 1;
                IF equip_state = cmc$down THEN
                  number_of_units_configured := 0;
                  FOR index_count := pen TO UPPERVALUE (cmt$physical_equipment_number) DO
                    IF ch_element_p^.data_channel.connection.equipment [index_count].configured THEN
                      cmp$get_element_state (ch_element_p^.data_channel.connection.equipment [index_count].
                            element_name, osc$null_name, unit_state, status);
                      IF NOT status.normal THEN
                        RETURN;
                      IFEND;
                      IF unit_state = cmc$on THEN
                        number_of_units_configured := number_of_units_configured + 1;
                      IFEND;
                    IFEND;
                  FOREND;
                IFEND;
                pp_resources_needed := (channel_state = cmc$on) AND
                      ((equip_state = cmc$on) OR (number_of_units_configured > 0));
                setup_resources_table (total_resources, 'E9S887                         ', ch_iou_number,
                      ch_element_p^.data_channel, cmc$null_equipment_number, cmc$null_unit_number,
                      pp_resources_needed, temp_table_p);
                EXIT /loop_thru_controllers/;
              IFEND;
            ELSEIF io_unit_type = ioc$dt_foreign_device THEN
              EXIT /loop_thru_controllers/;
            IFEND;
          ELSE
            EXIT /loop_thru_controllers/;
          IFEND;
        ELSE
          ; { Do nothing for other type of elements }
        CASEND;
      FOREND /loop_thru_controllers/;

      IF get_full_path AND (NOT table_setup) AND (NOT current_ch_is_system_device_ch) THEN
        IF (number_of_controller_on <> 0) OR (pen = UPPERVALUE (cmt$physical_equipment_number)) THEN
          total_resources := total_resources + 1;
          pp_resources_needed := (number_of_controller_on <> 0);
          setup_resources_table (total_resources, equip_element_p^.controller.peripheral_driver_name,
                ch_iou_number, ch_element_p^.data_channel, cmc$null_equipment_number, cmc$null_unit_number,
                pp_resources_needed, temp_table_p);
        IFEND;
      IFEND;
    WHILEND /loop_thru_channels/;

    { Now sort table with disk subsystems first, then dual pp tape subsystems, then single PP subsystems,
    { then other subsystems.

    IF total_resources <= 0 THEN
      RETURN;
    IFEND;
    count := 0;

    ALLOCATE resources_assigned_p: [1 .. total_resources] IN osv$mainframe_pageable_heap^;
    pmp$zero_out_table (#LOC (resources_assigned_p^), #SIZE (resources_assigned_p^));

    { Process disk subsystems.

    FOR index_count := LOWERBOUND (resources_assigned_p^) TO UPPERBOUND (resources_assigned_p^) DO
      IF (temp_table_p^ [index_count].driver_name = 'E5P5831') OR
         (temp_table_p^ [index_count].driver_name = 'E9P5831') OR
         (temp_table_p^ [index_count].driver_name = 'E5PNTDD') OR
         (temp_table_p^ [index_count].driver_name = 'E9PNTDD') OR
         (temp_table_p^ [index_count].driver_name = 'E5PPICO') OR
         (temp_table_p^ [index_count].driver_name = 'E9PPICO') OR
         (temp_table_p^ [index_count].driver_name = 'DSKE') OR
         (temp_table_p^ [index_count].driver_name = 'E1C7155') OR
         (temp_table_p^ [index_count].driver_name = 'E1A7155') OR
         (temp_table_p^ [index_count].driver_name = 'E1I7255') OR
         (temp_table_p^ [index_count].driver_name = 'E9S887 ') OR
         (temp_table_p^ [index_count].driver_name = 'E9P9853') OR
         (temp_table_p^ [index_count].driver_name = 'E5P9836') OR
         (temp_table_p^ [index_count].driver_name = 'E2C7165') OR
         (temp_table_p^ [index_count].driver_name = 'E9A7165') THEN
        count := count + 1;
        resources_assigned_p^ [count] := temp_table_p^ [index_count];
        temp_table_p^ [index_count].assigned := TRUE;
        resources_assigned_p^ [count].assigned := FALSE;
      IFEND;
    FOREND;

    { Process dual PP tape subsystems followed by single PP tape subsystems.

    FOR index_count := LOWERBOUND (resources_assigned_p^) TO UPPERBOUND (resources_assigned_p^) DO
      IF (temp_table_p^ [index_count].driver_name = 'E2C7021') OR
            (temp_table_p^ [index_count].driver_name = 'E2A7021') OR
            (temp_table_p^ [index_count].driver_name = 'E1A7021') OR
            (temp_table_p^ [index_count].driver_name = 'E5P5698') OR
            (temp_table_p^ [index_count].driver_name = 'E2A5680') OR
            (temp_table_p^ [index_count].driver_name = 'E2C5680') OR
            (temp_table_p^ [index_count].driver_name = 'E9P5698') OR
            (temp_table_p^ [index_count].driver_name = 'E1C7021') OR
            (temp_table_p^ [index_count].driver_name = 'E5I9639') THEN
        count := count + 1;
        resources_assigned_p^ [count] := temp_table_p^ [index_count];
        temp_table_p^ [index_count].assigned := TRUE;
        resources_assigned_p^ [count].assigned := FALSE;
      IFEND;
    FOREND;

   { Process other subsystems.

    FOR index_count := LOWERBOUND (resources_assigned_p^) TO UPPERBOUND (resources_assigned_p^) DO
      IF (NOT temp_table_p^ [index_count].assigned) AND
            (temp_table_p^ [index_count].driver_name <> ' ') THEN
        count := count + 1;
        resources_assigned_p^ [count] := temp_table_p^ [index_count];
        temp_table_p^ [index_count].assigned := TRUE;
        resources_assigned_p^ [count].assigned := FALSE;
      IFEND;
    FOREND;

  PROCEND determine_resources;
?? OLDTITLE ??
?? NEWTITLE := 'free_tables', EJECT ??

{ PURPOSE:
{   This procedure frees the logical PP table and the logical unit table.

  PROCEDURE free_tables
    (VAR logical_pp_table_p: ^cmt$logical_pp_table;
     VAR logical_unit_table_p: ^cmt$logical_unit_table);

    VAR
      index: integer,
      pp_index: iot$pp_number;

    IF logical_pp_table_p <> NIL THEN
      FOR pp_index := LOWERBOUND (logical_pp_table_p^) TO UPPERBOUND (logical_pp_table_p^) DO
        IF logical_pp_table_p^ [pp_index].flags.configured THEN
          IF logical_pp_table_p^ [pp_index].pp_info.pp_interface_table_p <> NIL THEN
            FREE logical_pp_table_p^ [pp_index].pp_info.pp_interface_table_p^.response_buffer IN
                  osv$mainframe_wired_cb_heap^;
            FREE logical_pp_table_p^ [pp_index].pp_info.pp_interface_table_p IN osv$mainframe_wired_cb_heap^;
          IFEND;
          IF logical_pp_table_p^ [pp_index].pp_info.pp_communication_buffer_p <> NIL THEN
            FREE logical_pp_table_p^ [pp_index].pp_info.pp_communication_buffer_p IN
                  osv$mainframe_wired_cb_heap^;
          IFEND;
        IFEND;
      FOREND;
      FREE logical_pp_table_p IN osv$mainframe_wired_cb_heap^;
    IFEND;

    IF logical_unit_table_p <> NIL THEN
      FOR index := (cmc$job_template_unit_ordinal + 1) TO UPPERBOUND (logical_unit_table_p^) DO
        IF logical_unit_table_p^ [index].configured THEN
          IF logical_unit_table_p^ [index].unit_communication_buffer_pva <> NIL THEN
            FREE logical_unit_table_p^ [index].unit_communication_buffer_pva IN osv$mainframe_wired_cb_heap^;
          IFEND;
          IF logical_unit_table_p^ [index].unit_interface_table <> NIL THEN
            FREE logical_unit_table_p^ [index].unit_interface_table IN osv$mainframe_wired_cb_heap^;
          IFEND;
        IFEND;
      FOREND;
      FREE logical_unit_table_p IN osv$mainframe_wired_cb_heap^;
    IFEND;

  PROCEND free_tables;
?? OLDTITLE ??
?? NEWTITLE := 'generate_interface_tables', EJECT ??

{ PURPOSE:
{   This procedure scans the physical configuration table to determine the number of logical units and
{   logical pp entries required.  It then builds the Interface Tables to contain all PPs and Units
{   needed for the fully configured system.

  PROCEDURE generate_interface_tables
    (VAR status: ost$status);

    VAR
      cm_unit_type: cmt$unit_type,
      controller_type: cmt$controller_type,
      element_p: ^cmt$element_definition,
      found: boolean,
      io_unit_type: iot$unit_type,
      pc_index: integer,
      pen: cmt$physical_equipment_number,
      pp_count: iot$pp_number,
      two_pps_needed: boolean,
      unit_class: cmt$unit_class,
      unit_count: iot$logical_unit;

    status.normal := TRUE;

    pp_count := 0;
    unit_count := 0;

   /scan_table/
    FOR pc_index := 1 TO UPPERBOUND (cmv$physical_configuration^) DO
      CASE cmv$physical_configuration^ [pc_index].element_type OF
      = cmc$channel_adapter_element, cmc$communications_element, cmc$external_processor_element,
            cmc$storage_device_element =
        unit_count := unit_count + 1;

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

        two_pps_needed := FALSE;
        FOR pen := LOWERVALUE (cmt$physical_equipment_number) TO UPPERVALUE (cmt$physical_equipment_number) DO
          IF cmv$physical_configuration^ [pc_index].data_channel.connection.equipment [pen].configured THEN
            cmp$pc_get_element (
                  cmv$physical_configuration^ [pc_index].data_channel.connection.equipment [pen].element_name,
                  osc$null_name, element_p, status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
            CASE element_p^.element_type OF
            = cmc$channel_adapter_element =
              IF element_p^.product_id.product_number = ' $2629' THEN
                CYCLE /scan_table/;
              IFEND;
            = cmc$communications_element =
              CYCLE /scan_table/;
            = cmc$controller_element =
              cmp$get_controller_type (element_p^.product_id, controller_type, status);
              IF NOT status.normal THEN
                status.normal := TRUE;
                CYCLE /scan_table/; { foreign device }
              IFEND;
              IF (element_p^.controller.peripheral_driver_name (2, 1) = '2') AND
                    (controller_type <> cmc$mt7221_2_s0) THEN
                two_pps_needed := TRUE;
              IFEND;
            = cmc$storage_device_element =
              cmp$get_unit_type (element_p^.product_id, cm_unit_type, io_unit_type, unit_class, found);
              IF NOT found THEN
                CYCLE /scan_table/;
              IFEND;
            ELSE
            CASEND;
          IFEND;
        FOREND;
        pp_count := pp_count + 1;
        IF two_pps_needed THEN
          pp_count := pp_count + 1;
        IFEND;

      ELSE
      CASEND;
    FOREND /scan_table/;

    cmp$build_interface_tables (pp_count, unit_count, TRUE, cmv$new_logical_unit_table,
          cmv$new_logical_pp_table_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

  PROCEND generate_interface_tables;
?? OLDTITLE ??
?? NEWTITLE := 'load_all_other_drivers', EJECT ??

{ PURPOSE:
{   Search the logical PP table and load drivers for all channels which have been assigned.  This routine is
{   called during PCU activating the configuration.
{ DESIGN:
{   The system device driver is not loaded since it is still loaded from the deadstart process.

  PROCEDURE load_all_other_drivers
    (    system_device_channel: cmt$physical_channel;
     VAR system_device_iou: dst$iou_number;
     VAR status: ost$status);

    VAR
      partner_pp_index: iot$pp_number,
      pp_index: iot$pp_number,
      system_device_ch_type: dst$channel_protocol_type;

    status.normal := TRUE;

    IF system_device_channel.concurrent THEN
      system_device_ch_type := dsc$cpt_cio;
    ELSE
      system_device_ch_type := dsc$cpt_nio;
    IFEND;

   /table_loop/
    FOR pp_index := LOWERBOUND (cmv$new_logical_pp_table_p^) TO UPPERBOUND (cmv$new_logical_pp_table_p^) DO
      IF NOT cmv$new_logical_pp_table_p^ [pp_index].flags.configured OR
            NOT cmv$new_logical_pp_table_p^ [pp_index].flags.resources_acquired OR
            cmv$new_logical_pp_table_p^ [pp_index].flags.pp_loaded OR
            (cmv$new_logical_pp_table_p^ [pp_index].pp_info.driver_name = ' ') THEN
        CYCLE /table_loop/;
      IFEND;

      IF (system_device_channel.number = cmv$new_logical_pp_table_p^ [pp_index].pp_info.channel.number) AND
            (system_device_ch_type =
            cmv$new_logical_pp_table_p^ [pp_index].pp_info.channel.channel_protocol) AND
            (system_device_iou = cmv$new_logical_pp_table_p^ [pp_index].pp_info.channel.iou_number) THEN
        CYCLE /table_loop/;
      IFEND;

      dsp$load_pp (dsc$load_pp_by_name, cmv$new_logical_pp_table_p^ [pp_index].pp_info.physical_pp,
            NIL, cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name,
            cmv$new_logical_pp_table_p^ [pp_index].pp_info.pp_interface_table_rma, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      cmv$new_logical_pp_table_p^ [pp_index].flags.pp_loaded := TRUE;

      partner_pp_index := cmv$new_logical_pp_table_p^ [pp_index].pp_info.logical_partner_pp_index;
      IF partner_pp_index > 0 THEN
        dsp$load_pp (dsc$load_pp_by_name, cmv$new_logical_pp_table_p^ [partner_pp_index].pp_info.physical_pp,
              NIL, cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name,
              cmv$new_logical_pp_table_p^ [pp_index].pp_info.pp_communication_buffer_p^.partner_pp, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        cmv$new_logical_pp_table_p^ [partner_pp_index].flags.pp_loaded := TRUE;
      IFEND;
    FOREND /table_loop/;

  PROCEND load_all_other_drivers;
?? OLDTITLE ??
?? NEWTITLE := 'modify_interface_pointer', EJECT ??

{ PURPOSE:
{   This procedure modifies the unit interface table RMA of the system device to reference the RMA used
{   at System core time.

  PROCEDURE modify_interface_pointer
    (VAR status: ost$status);

    VAR
      first_lun: iot$logical_unit,
      last_lun: iot$logical_unit,
      pp: iot$pp_number;

    IF (cmv$logical_pp_table_p = NIL) OR (cmv$logical_unit_table = NIL) OR
          (cmv$new_logical_pp_table_p = NIL) OR (cmv$new_logical_unit_table = NIL) THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$pc_nil_cm_table, 'NIL CM table', status);
      RETURN;
    IFEND;

    { Modify new tables to use the system device unit interface table.

    FREE cmv$new_logical_unit_table^ [cmc$job_template_unit_ordinal].unit_interface_table IN
          osv$mainframe_wired_cb_heap^;
    FREE cmv$new_logical_unit_table^ [cmc$job_template_unit_ordinal].unit_communication_buffer_pva IN
          osv$mainframe_wired_cb_heap^;
    cmv$new_logical_unit_table^ [cmc$job_template_unit_ordinal].unit_interface_table :=
          v$save_lut_p^ [cmc$job_template_unit_ordinal].unit_interface_table;
    cmv$new_logical_unit_table^ [cmc$job_template_unit_ordinal].unit_communication_buffer_pva :=
          v$save_lut_p^ [cmc$job_template_unit_ordinal].unit_communication_buffer_pva;

    FOR pp := LOWERBOUND (cmv$new_logical_pp_table_p^) TO UPPERBOUND (cmv$new_logical_pp_table_p^) DO
      IF cmv$new_logical_pp_table_p^ [pp].flags.configured THEN
        first_lun := cmv$new_logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.first_logical_unit;
        last_lun := cmv$new_logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.number_of_units +
              first_lun;

        IF (cmc$job_template_unit_ordinal >= first_lun) AND (cmc$job_template_unit_ordinal <= last_lun) THEN

          { Change unit interface table pointers.

          cmv$new_logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.
                unit_descriptors [cmc$job_template_unit_ordinal].unit_interface_table :=
                v$save_lpt_p^ [1].pp_info.pp_interface_table_p^.
                unit_descriptors [cmc$job_template_unit_ordinal].unit_interface_table;

          IF (cmv$new_logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.
                unit_descriptors [cmc$job_template_unit_ordinal].unit_interface_table_rma <> 0) THEN
            cmv$new_logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.
                  unit_descriptors [cmc$job_template_unit_ordinal].unit_interface_table_rma :=
                  v$save_lpt_p^ [1].pp_info.pp_interface_table_p^.
                  unit_descriptors [cmc$job_template_unit_ordinal].unit_interface_table_rma;
          IFEND;
        IFEND;
      IFEND;
    FOREND;

  PROCEND modify_interface_pointer;
?? OLDTITLE ??
?? NEWTITLE := 'obtain_pp_resource', EJECT ??

{ PURPOSE:
{   Obtain a PP which can access the given channel number and also the correct channel and/or equipment.
{   This routine is called during PCU activating the configuration.
{ DESIGN:
{   The drivers are not loaded here to make clean up easier in the case where all resources cannot be obtained
{   for some reason, i.e. the resources are not available to NOS/VE in dual state.

  PROCEDURE obtain_pp_resource
    (    resource_assigned: t$resources_assigned;
     VAR status: ost$status);

    VAR
      channel_name: cmt$element_name,
      channel_ordinal: cmt$channel_ordinal,
      channel_state: cmt$element_state,
      channel_type: dst$channel_protocol_type,
      iou_name: cmt$element_name,
      partner_pp_index: iot$pp_number,
      pp_index: iot$pp_number,
      pp_needed: boolean,
      redundant: boolean,
      resource_request: dst$resource_request,
      system_device_channel: cmt$physical_channel,
      system_device_equipment: cmt$physical_equipment_number,
      system_device_iou: cmt$element_name,
      system_device_unit: cmt$physical_unit_number,
      valid_channel: boolean;

    status.normal := TRUE;

    IF resource_assigned.channel.concurrent THEN
      channel_type := dsc$cpt_cio;
    ELSE
      channel_type := dsc$cpt_nio;
    IFEND;

    cmp$retrieve_logical_pp_index (resource_assigned.channel, resource_assigned.iou_number,
          cmv$new_logical_pp_table_p, pp_index, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pp_needed := NOT cmv$new_logical_pp_table_p^ [pp_index].flags.resources_acquired;

    partner_pp_index := cmv$new_logical_pp_table_p^ [pp_index].pp_info.logical_partner_pp_index;

    cmp$convert_iou_number (resource_assigned.iou_number, iou_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cmp$get_system_device_path (cmc$sdt_disk_device, system_device_iou, system_device_channel,
          system_device_equipment, system_device_unit, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF pp_needed THEN
      pp_needed := NOT ((resource_assigned.channel.number = system_device_channel.number) AND
            (resource_assigned.channel.concurrent = system_device_channel.concurrent) AND
            (iou_name = system_device_iou));
    IFEND;

    { For redundant tape channels, the pp_needed will be set to FALSE to prevent obtaining a PP until the
    { channel is actually used.

    IF pp_needed AND (cmv$new_logical_pp_table_p^ [pp_index].pp_info.pp_type = cmc$lpt_tape_pp_type) THEN
      IF (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'TAPC') OR
            (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'TAPD') OR
            (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E9Q5698') OR
            (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E2X5680') THEN
        cmp$determine_redundant_channel (resource_assigned.channel, resource_assigned.iou_number,
              {ignore_state=}FALSE, redundant, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        pp_needed := NOT redundant;
      IFEND;
    IFEND;

    { IF auto reconfiguration is disabled then the allocation of PP's to redundant disk channels will
    { be prevented in the same way as the tape channels.

    IF NOT cmv$acquire_pp_for_redundant_ch AND pp_needed AND
          (cmv$new_logical_pp_table_p^ [pp_index].pp_info.pp_type = cmc$lpt_disk_pp_type) THEN
      IF (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E5P5831') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E9P5831') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E5PNTDD') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E9PNTDD') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E5PPICO') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E9PPICO') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'ISD') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'DSK7154') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'DSKI') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'E9P9853') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'DSK55A') OR
         (cmv$new_logical_pp_table_p^ [pp_index].pp_info.cip_driver_name = 'DSK55C7') THEN
        cmp$determine_redundant_channel (resource_assigned.channel, resource_assigned.iou_number,
              {ignore_state=}FALSE, redundant, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        pp_needed := NOT redundant;
      IFEND;
    IFEND;

    resource_request.channel.iou_number := resource_assigned.iou_number;
    resource_request.channel.channel_protocol := channel_type;
    resource_request.channel.number := resource_assigned.channel.number;

    IF ((resource_assigned.unit = cmc$null_unit_number) AND
          (resource_assigned.equipment = cmc$null_equipment_number)) THEN
      cmp$request_resources (dsc$rrt_get_channel, resource_request, status);
      IF NOT status.normal AND ((status.condition <> dse$resource_already_assigned) AND
            (status.condition <> dse$ch_assigned_to_ve)) THEN
        RETURN;
      IFEND;
    ELSE
      resource_request.equipment_number := ORD (resource_assigned.equipment);
      resource_request.unit_number := ORD (resource_assigned.unit);
      cmp$request_resources (dsc$rrt_get_equipment, resource_request, status);
      IF NOT status.normal AND ((status.condition <> dse$resource_already_assigned) AND
            (status.condition <> dse$ch_assigned_to_ve)) THEN
        RETURN;
      IFEND;
      cmp$request_resources (dsc$rrt_get_channel, resource_request, status);
      IF NOT status.normal AND ((status.condition <> dse$resource_already_assigned) AND
            (status.condition <> dse$ch_assigned_to_ve)) THEN
        RETURN;
      IFEND;
    IFEND;

    cmp$convert_channel_number (resource_assigned.channel.number, resource_assigned.channel.concurrent,
          resource_assigned.channel.port, channel_ordinal, channel_name, valid_channel);

    cmp$get_element_state (channel_name, iou_name, channel_state, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF pp_needed AND (channel_state = cmc$on) THEN
      IF partner_pp_index > 0 THEN
        resource_request.options := $dst$resource_request_options [dsc$rro_partner_pp];
      ELSEIF channel_type = dsc$cpt_nio THEN
        resource_request.options := $dst$resource_request_options [dsc$rro_driver_pp];
      ELSE
        resource_request.options := $dst$resource_request_options [];
      IFEND;
      cmp$request_resources (dsc$rrt_get_pp, resource_request, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      cmv$new_logical_pp_table_p^ [pp_index].pp_info.physical_pp := resource_request.primary_pp;
      cmv$new_logical_pp_table_p^ [pp_index].flags.resources_acquired := TRUE;
      IF partner_pp_index > 0 THEN
        cmv$new_logical_pp_table_p^ [partner_pp_index].pp_info.physical_pp := resource_request.secondary_pp;
        cmv$new_logical_pp_table_p^ [partner_pp_index].flags.resources_acquired := TRUE;
      IFEND;
    IFEND;

  PROCEND obtain_pp_resource;
?? OLDTITLE ??
?? NEWTITLE := 'release_all_resources', EJECT ??

{ PURPOSE:
{   This procedure releases all the resources acquired. This routine is called if an error such as
{   channel/equipment not available occurs during configuration activation.

  PROCEDURE release_all_resources
    (VAR resources_assigned_p: ^ARRAY [ * ] OF t$resources_assigned);

    VAR
      channel_type: dst$channel_protocol_type,
      controller_type: cmt$controller_type,
      dual_access: boolean,
      index: integer,
      local_status: ost$status,
      other_channel: cmt$physical_channel,
      other_channel_iou: dst$iou_number,
      other_eq: cmt$physical_equipment_number,
      pp_index: iot$pp_number,
      system_device_channel: cmt$physical_channel,
      system_device_equipment: cmt$physical_equipment_number,
      system_device_iou: cmt$element_name,
      system_device_iou_number: dst$iou_number,
      system_device_unit: cmt$physical_unit_number,
      table_index: integer;

    IF resources_assigned_p = NIL THEN
      RETURN;
    IFEND;

    cmp$get_system_device_path (cmc$sdt_disk_device, system_device_iou, system_device_channel,
          system_device_equipment, system_device_unit, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    verify_dual_access (system_device_iou, system_device_channel, system_device_equipment,
          system_device_unit, dual_access, other_channel, other_channel_iou, other_eq, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    cmp$convert_iou_name (system_device_iou, system_device_iou_number, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

   /return_channels/
    FOR index := LOWERBOUND (resources_assigned_p^) TO UPPERBOUND (resources_assigned_p^) DO
      IF NOT resources_assigned_p^ [index].assigned THEN
        CYCLE /return_channels/;
      IFEND;

      IF resources_assigned_p^ [index].equipment = cmc$null_equipment_number THEN
        IF (resources_assigned_p^ [index].channel.number = system_device_channel.number) AND
              (resources_assigned_p^ [index].channel.concurrent = system_device_channel.concurrent) AND
              (resources_assigned_p^ [index].iou_number = system_device_iou_number) THEN
          CYCLE /return_channels/;
        IFEND;

        cmp$release_channel_resource (resources_assigned_p^ [index].channel,
              resources_assigned_p^ [index].iou_number, local_status);
      ELSE

        { Do not release system_device equipment.

        IF (resources_assigned_p^ [index].channel = system_device_channel) AND
              (resources_assigned_p^ [index].iou_number = system_device_iou_number) AND
              (resources_assigned_p^ [index].equipment = system_device_equipment) AND
              (resources_assigned_p^ [index].unit = system_device_unit) THEN
          CYCLE /return_channels/;
        IFEND;

        { Do not release alternate path to system device.

        IF dual_access AND (resources_assigned_p^ [index].channel = other_channel) AND
              (resources_assigned_p^ [index].iou_number = other_channel_iou) AND
              (resources_assigned_p^ [index].equipment = other_eq) AND
              (resources_assigned_p^ [index].unit = system_device_unit) THEN
          CYCLE /return_channels/;
        IFEND;

        cmp$release_equipment_resource (resources_assigned_p^ [index].channel,
              resources_assigned_p^ [index].iou_number, resources_assigned_p^ [index].equipment,
              resources_assigned_p^ [index].unit);
      IFEND;
    FOREND /return_channels/;
    FREE resources_assigned_p IN osv$mainframe_pageable_heap^;

    { Now return all PPs.

    IF system_device_channel.concurrent THEN
      channel_type := dsc$cpt_cio;
    ELSE
      channel_type := dsc$cpt_nio;
    IFEND;

   /table_loop/
    FOR pp_index := LOWERBOUND (cmv$new_logical_pp_table_p^) TO UPPERBOUND (cmv$new_logical_pp_table_p^) DO
      IF NOT cmv$new_logical_pp_table_p^ [pp_index].flags.configured OR
            NOT cmv$new_logical_pp_table_p^ [pp_index].flags.resources_acquired THEN
        CYCLE /table_loop/;
      IFEND;
      IF (system_device_channel.number = cmv$new_logical_pp_table_p^ [pp_index].pp_info.channel.number) AND
            (channel_type = cmv$new_logical_pp_table_p^ [pp_index].pp_info.channel.channel_protocol) AND
            (system_device_iou_number =
                  cmv$new_logical_pp_table_p^ [pp_index].pp_info.channel.iou_number) THEN
        CYCLE /table_loop/;
      IFEND;
      cmp$release_pp_resource (cmv$new_logical_pp_table_p^ [pp_index].pp_info.physical_pp, local_status);
    FOREND /table_loop/;

    { Free all allocated tables.

    IF cmv$physical_configuration <> NIL THEN
      FREE cmv$physical_configuration IN osv$mainframe_pageable_heap^;
    IFEND;

    IF cmv$state_info_table <> NIL THEN
      FOR table_index := LOWERBOUND (cmv$state_info_table^) TO UPPERBOUND (cmv$state_info_table^) DO
        IF cmv$state_info_table^ [table_index].element_type <> cmc$data_channel_element THEN
          IF cmv$state_info_table^ [table_index].application_info_p <> NIL THEN
            FREE cmv$state_info_table^ [table_index].application_info_p IN osv$mainframe_pageable_heap^;
          IFEND;
          IF cmv$state_info_table^ [table_index].site_info_p <> NIL THEN
            FREE cmv$state_info_table^ [table_index].site_info_p IN osv$mainframe_pageable_heap^;
          IFEND;
        IFEND;
      FOREND;
      FREE cmv$state_info_table IN osv$mainframe_pageable_heap^;
    IFEND;

    cmv$physical_configuration := cmv$save_pct_p;
    cmv$state_info_table := cmv$save_state_table_p;

    free_tables (cmv$new_logical_pp_table_p, cmv$new_logical_unit_table);

  { FOR controller_type := LOWERVALUE (cmt$controller_type) TO UPPERVALUE (cmt$controller_type) DO
  {   IF cmv$controller_location [controller_type].controlware_loaded THEN
  {     FREE cmv$controller_location [controller_type].controlware_rma_list_p IN osv$mainframe_wired_cb_heap^;
  {     FREE cmv$controller_location [controller_type].controlware_location_p IN osv$mainframe_wired_cb_heap^;
  {     cmv$controller_location [controller_type].controlware_loaded := FALSE;
  {   IFEND;
  {   IF cmv$controller_location [controller_type].control_module_loaded THEN
  {     FREE cmv$controller_location [controller_type].control_module_rma_list_p IN
  {           osv$mainframe_wired_cb_heap^;
  {     FREE cmv$controller_location [controller_type].control_module_location_p IN
  {           osv$mainframe_wired_cb_heap^;
  {     cmv$controller_location [controller_type].control_module_loaded := FALSE;
  {   IFEND;
  { FOREND;
  { cmp$free_element_def_table;

  PROCEND release_all_resources;
?? OLDTITLE ??
?? NEWTITLE := 'setup_resources_table', EJECT ??

{ PURPOSE:
{   This procedure builds the resources table to be used for acquiring and releasing channel/equipment/unit.

  PROCEDURE setup_resources_table
    (    table_index: integer;
         driver_name: cmt$element_name;
         ch_iou_number: dst$iou_number;
         channel: cmt$data_channel_definition;
         equipment: 0 .. cmc$null_equipment_number;
         unit: 0 .. cmc$null_unit_number;
         pp_resources_needed: boolean;
     VAR resources_table_p: ^ARRAY [ * ] OF t$resources_assigned);

    IF resources_table_p = NIL THEN
      RETURN;
    IFEND;

    IF table_index > UPPERBOUND (resources_table_p^) THEN
      RETURN;
    IFEND;

    resources_table_p^ [table_index].driver_name := driver_name;
    resources_table_p^ [table_index].channel.concurrent := channel.concurrent;
    resources_table_p^ [table_index].channel.number := channel.number;
    resources_table_p^ [table_index].channel.port := channel.port;
    resources_table_p^ [table_index].iou_number := ch_iou_number;
    resources_table_p^ [table_index].equipment := equipment;
    resources_table_p^ [table_index].unit := unit;
    resources_table_p^ [table_index].pp_resources_needed := pp_resources_needed;

  PROCEND setup_resources_table;
?? OLDTITLE ??
?? NEWTITLE := 'verify_dual_access', EJECT ??

{ PURPOSE:
{   This procedure determines if the system device is dual access.  If so, then during release_all_resources,
{   do not return the system device.

  PROCEDURE verify_dual_access
    (    system_device_iou: cmt$element_name;
         system_device_channel: cmt$physical_channel;
         system_device_equipment: cmt$physical_equipment_number;
         system_device_unit: cmt$physical_unit_number;
     VAR dual_access: boolean;
     VAR other_channel: cmt$physical_channel;
     VAR other_channel_iou: dst$iou_number;
     VAR other_eq: cmt$physical_equipment_number;
     VAR status: ost$status);

    VAR
      ch_element_p: ^cmt$element_definition,
      ch_port: cmt$controller_port_number,
      ct_element_p: ^cmt$element_definition,
      element_p: ^cmt$element_definition,
      index: integer,
      iou_name: cmt$element_name,
      port: cmt$data_storage_port_number,
      system_device_name: cmt$element_name,
      system_device_controller: cmt$element_name;

    { This procedure check to see if there is more than one path to the system disk. If so then it returns
    { the physical address of the path, channel number and equipment number.

    status.normal := TRUE;
    dual_access := FALSE;

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

      IF (cmv$physical_configuration^ [index].data_channel.number = system_device_channel.number) AND
            (cmv$physical_configuration^ [index].data_channel.port = system_device_channel.port) AND
            (cmv$physical_configuration^ [index].data_channel.concurrent =
            system_device_channel.concurrent) AND
            (cmv$physical_configuration^ [index].data_channel.iou = system_device_iou) THEN

        IF cmv$physical_configuration^ [index].data_channel.connection.equipment [system_device_equipment].
              configured THEN
          cmp$pc_get_element (cmv$physical_configuration^ [index].
                data_channel.connection.equipment [system_device_equipment].element_name,
                {iou not used} osc$null_name, element_p, status);
          IF status.normal THEN

            { Find the system disk name.

            IF element_p^.element_type = cmc$controller_element THEN
              IF element_p^.controller.connection.unit [system_device_unit].configured THEN
                system_device_controller := element_p^.element_name;
                system_device_name := element_p^.controller.connection.unit [system_device_unit].element_name;
                EXIT /loop_thru_pc/;
              IFEND;
            ELSE
              system_device_name := element_p^.element_name;
            IFEND;
          IFEND;
        ELSEIF cmv$physical_configuration^ [index].data_channel.connection.equipment [system_device_unit].
              configured THEN
          system_device_name := cmv$physical_configuration^ [index].
                data_channel.connection.equipment [system_device_unit].element_name;
          EXIT /loop_thru_pc/;
        IFEND;
      IFEND;
    FOREND /loop_thru_pc/;

    cmp$pc_get_element (system_device_name, {iou not used} osc$null_name, element_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

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

      IF element_p^.storage_device.connection.port [port].upline_connection_type =
            cmc$data_channel_element THEN
        iou_name := element_p^.storage_device.connection.port [port].iou;
      ELSE
        iou_name := osc$null_name;
      IFEND;

      cmp$pc_get_element (element_p^.storage_device.connection.port [port].element_name, iou_name,
            ct_element_p, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      IF ct_element_p^.element_type = cmc$controller_element THEN
        IF ct_element_p^.element_name <> system_device_controller THEN

          { Could be dual access.

          other_eq := ct_element_p^.controller.physical_equipment_number;
          FOR ch_port := LOWERVALUE (cmt$controller_port_number)
                TO UPPERVALUE (cmt$controller_port_number) DO
            IF ct_element_p^.controller.connection.port [ch_port].configured THEN
              cmp$pc_get_element (ct_element_p^.controller.connection.port [ch_port].element_name,
                    ct_element_p^.controller.connection.port [ch_port].iou, ch_element_p, status);
              IF status.normal THEN
                IF NOT (ch_element_p^.data_channel.number = system_device_channel.number) AND
                      (ch_element_p^.data_channel.concurrent = system_device_channel.concurrent) AND
                      (ch_element_p^.data_channel.port = system_device_channel.port) AND
                      (ch_element_p^.data_channel.iou = system_device_iou) THEN
                  dual_access := TRUE;
                  other_channel.number := ch_element_p^.data_channel.number;
                  other_channel.port := ch_element_p^.data_channel.port;
                  other_channel.concurrent := ch_element_p^.data_channel.concurrent;
                  cmp$convert_iou_name (ch_element_p^.data_channel.iou, other_channel_iou, status);
                  RETURN;
                IFEND;
              IFEND;
            IFEND;
          FOREND;
        IFEND;
      ELSEIF ct_element_p^.element_type = cmc$data_channel_element THEN

        IF NOT (ct_element_p^.data_channel.number = system_device_channel.number) AND
              (ct_element_p^.data_channel.concurrent = system_device_channel.concurrent) AND
              (ct_element_p^.data_channel.port = system_device_channel.port) AND
              (ct_element_p^.data_channel.iou = system_device_iou) THEN
          dual_access := TRUE;
          other_channel.number := ct_element_p^.data_channel.number;
          other_channel.concurrent := ct_element_p^.data_channel.concurrent;
          other_channel.number := ct_element_p^.data_channel.number;
          cmp$convert_iou_name (ct_element_p^.data_channel.iou, other_channel_iou, status);
          RETURN;
        IFEND;
      IFEND;
    FOREND /loop_thru_ports/;

  PROCEND verify_dual_access;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$acquire_all_peripherals_r1', EJECT ??

{ PURPOSE:
{   This procedure determines how many IOU resources to acquire, builds the I/O interface tables and
{   activates the full configuration.

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

    VAR
      mainframe_id: pmt$mainframe_id,
      resources_assigned_p: ^ARRAY [ * ] OF t$resources_assigned,
      system_device_lun: iot$logical_unit;

    status.normal := TRUE;
    resources_assigned_p := NIL;

    system_device_lun := cmc$job_template_unit_ordinal;

    syp$trace_deadstart_message ('activating the configuration');

    determine_resources (resources_assigned_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { Build the pp interface tables and request the other resources needed.

   /release_resources_on_error/
    BEGIN
      v$save_lut_p := cmv$logical_unit_table;
      v$save_lpt_p := cmv$logical_pp_table_p;

      generate_interface_tables (status);
      IF NOT status.normal THEN
        EXIT /release_resources_on_error/;
      IFEND;

      acquire_all_resources (resources_assigned_p, status);
      IF NOT status.normal THEN
        EXIT /release_resources_on_error/;
      IFEND;

      pmp$get_mainframe_id (mainframe_id, status);
      cmp$build_element_def_table (mainframe_id, status);
      IF NOT status.normal THEN
        EXIT /release_resources_on_error/;
      IFEND;

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

      modify_interface_pointer (status);
      IF NOT status.normal THEN
        EXIT /release_resources_on_error/;
      IFEND;

      begin_conf_transition (system_device_lun, resources_assigned_p, status);
      IF NOT status.normal THEN
        EXIT /release_resources_on_error/;
      IFEND;
    END /release_resources_on_error/;

    IF NOT status.normal THEN
      release_all_resources (resources_assigned_p);
      cmv$logical_unit_table := v$save_lut_p;
      cmv$logical_pp_table_p := v$save_lpt_p;
      cmp$get_max_number_of_pp (cmv$max_number_of_pp);
      RETURN;
    IFEND;

    { Release the original tables.

    free_tables (v$save_lpt_p, v$save_lut_p);

    cmp$update_connection_states_r1 (mainframe_id, status);

  PROCEND cmp$acquire_all_peripherals_r1;
?? OLDTITLE ??
?? NEWTITLE :='cmp$activate_signal_handler', EJECT ??

{ PURPOSE:
{   This procedure simply sets the variable cmv$signal_handler_active to TRUE.  When this variable is set to
{   FALSE all CM signals are queued for future processing.  When TRUE, CM signals are processed immediatly.

  PROCEDURE [XDCL, #GATE] cmp$activate_signal_handler;

    cmv$signal_handler_active := TRUE;

  PROCEND cmp$activate_signal_handler;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$free_deadstart_signals', EJECT ??

{ PURPOSE:
{   This procedure frees the space used by the linked list pointed to by the variable cmv$deadstart_signals.

  PROCEDURE [XDCL, #GATE] cmp$free_deadstart_signals;

    VAR
      deadstart_signal_p: ^cmt$deadstart_signal,
      next_deadstart_signal_p: ^cmt$deadstart_signal;

    IF cmv$deadstart_signals = NIL THEN
      RETURN;
    IFEND;

    deadstart_signal_p := cmv$deadstart_signals;
    WHILE deadstart_signal_p <> NIL DO
      next_deadstart_signal_p := deadstart_signal_p^.next_signal;

      FREE deadstart_signal_p IN osv$mainframe_pageable_heap^;
      deadstart_signal_p := next_deadstart_signal_p;
    WHILEND;

  PROCEND cmp$free_deadstart_signals;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_system_device_path', EJECT ??

{ PURPOSE:
{   This procedure returns the physical path of the system device.
{ DESIGN:
{   The system device path is determined from cmv$system_device_data.

  PROCEDURE [XDCL, #GATE] cmp$get_system_device_path
    (    device: cmt$system_device_types;
     VAR iou: cmt$element_name;
     VAR channel: cmt$physical_channel;
     VAR equipment_number: cmt$physical_equipment_number;
     VAR unit_number: cmt$physical_unit_number;
     VAR status: ost$status);

    VAR
      channel_descriptor: cmt$channel_descriptor,
      channel_definition: cmt$data_channel_definition,
      cm_unit_type: cmt$unit_type,
      found: boolean,
      io_unit_type: iot$unit_type,
      unit_class: cmt$unit_class;

    status.normal := TRUE;

    cmp$convert_iou_number (cmv$system_device_data [device].iou_number, iou, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    channel_descriptor.iou := iou;
    channel_descriptor.use_logical_identification := TRUE;
    channel_descriptor.name := cmv$system_device_data [device].channel_name;
    cmp$get_channel_def (channel_descriptor, channel_definition, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    channel.number := channel_definition.number;
    channel.concurrent := channel_definition.concurrent;
    channel.port := channel_definition.port;

    cmp$get_unit_type (cmv$system_device_data [device].unit_id, cm_unit_type, io_unit_type, unit_class,
          found);

    IF found AND (cm_unit_type = cmc$mshydra) THEN
      equipment_number := cmv$system_device_data [device].unit_number;
    ELSE
      equipment_number := cmv$system_device_data [device].equipment_number;
    IFEND;
    unit_number := cmv$system_device_data [device].unit_number;

  PROCEND cmp$get_system_device_path;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$queue_deadstart_signal', EJECT ??

{ PURPOSE:
{   This procedure will add the specified signal to a linked list of "deadstart" signals.  These signals are
{   actually executed by the routine cmp$process_deadstart_signals.  They are released by the procedure
{   cmp$free_deadstart_signals.

  PROCEDURE [XDCL, #GATE] cmp$queue_deadstart_signal
    (    originator: ost$global_task_id;
         signal: pmt$signal);

    VAR
      deadstart_signal_p: ^cmt$deadstart_signal,
      temp_deadstart_signal_p: ^cmt$deadstart_signal;

    ALLOCATE deadstart_signal_p IN osv$mainframe_pageable_heap^;
    deadstart_signal_p^.originator := originator;
    deadstart_signal_p^.signal := signal;
    deadstart_signal_p^.next_signal := NIL;

    IF cmv$deadstart_signals = NIL THEN
      cmv$deadstart_signals := deadstart_signal_p;
      RETURN;
    IFEND;

    temp_deadstart_signal_p := cmv$deadstart_signals;
    WHILE temp_deadstart_signal_p^.next_signal <> NIL DO
      temp_deadstart_signal_p := temp_deadstart_signal_p^.next_signal;
    WHILEND;

    temp_deadstart_signal_p^.next_signal := deadstart_signal_p;

  PROCEND cmp$queue_deadstart_signal;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$set_active_flag', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$set_active_flag
    (    configuration_state: boolean);

    cmv$configuration_activated := configuration_state;

  PROCEND cmp$set_active_flag;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$set_post_ds_flag', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$set_post_ds_flag;

    VAR
     mmv$post_deadstart: [XREF] boolean;

    cmv$post_deadstart := TRUE;
    mmv$post_deadstart := TRUE;

  PROCEND cmp$set_post_ds_flag;
?? OLDTITLE ??
MODEND cmm$pcu_ring1_helper;
