?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE CM : Maintenance Services Ring1' ??
MODULE cmm$maintenance_services_r1;

{ PURPOSE:
{   This module contains Ring 1 procedures that call Deadstart Services interfaces to load, idle, and
{   resume PPs.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cmd$null_equipment_number
*copyc cme$logical_configuration_mgr
*copyc cme$physical_configuration_mgr
*copyc cme$reserve_element
*copyc cmt$element_definition
*copyc cmt$pp_commands
*copyc cmt$pp_memory_length
*copyc cmt$pp_registers
*copyc cmt$request_block
*copyc dse$error_codes
*copyc dst$dft_pp_registers
*copyc iot$disk_request
*copyc iot$io_request
*copyc ost$hardware_subranges
?? POP ??
*copyc cmp$assign_pp_r1
*copyc cmp$convert_iou_number
*copyc cmp$get_controller_type
*copyc cmp$get_element_state
*copyc cmp$get_logical_pp_index
*copyc cmp$pc_get_element
*copyc cmp$request_resources
*copyc cmp$retrieve_logical_pp_index
*copyc dsp$get_pp_registers
*copyc dsp$idle_pp
*copyc dsp$load_pp
*copyc dsp$resume_pp
*copyc dsp$retrieve_iou_information
*copyc i#call_monitor
*copyc i#move
*copyc osp$append_status_integer
*copyc osp$set_status_abnormal
*copyc osp$system_error
*copyc osp$set_status_condition
?? EJECT ??
*copyc cmv$logical_pp_table_p
*copyc cmv$physical_configuration
*copyc osv$170_os_type
*copyc osv$external_interrupt_selector
*copyc osv$mainframe_wired_cb_heap
*copyc osv$mainframe_wired_heap
?? OLDTITLE ??
?? NEWTITLE := 'seek_redundant_controller', EJECT ??

{ PURPOSE:
{    This procedure determines whether or not the given controller element is redundant. A controller is
{    considered primary if it is the first element in the upline connection of any units connected to it,
{    otherwise, it is redundant.
{ NOTE:
{   IGNORE_STATE is a flag set to TRUE if this procedure is called as a result of manual state change. This
{   is needed because state of the element is not yet updated in memory. When using this procedure during
{   deadstart i.e during configuration activation, ignore_state must be set to FALSE.

  PROCEDURE seek_redundant_controller
     (   element: cmt$element_definition;
         ignore_state: boolean;
     VAR redundant: boolean);

    VAR
      channel_state: cmt$element_state,
      controller_type: cmt$controller_type,
      controller_element_p: ^cmt$element_definition,
      controller_state: cmt$element_state,
      found_first_controller: boolean,
      iou_name: cmt$element_name,
      local_status: ost$status,
      port: cmt$data_storage_port_number,
      pun: cmt$physical_unit_number,
      state: cmt$element_state,
      unit_element_p: ^cmt$element_definition,
      upline_port: integer;

    redundant := FALSE;
    found_first_controller := FALSE;
    IF element.element_type <> cmc$controller_element THEN
      RETURN;
    IFEND;

    cmp$get_controller_type (element.product_id, controller_type, local_status);
    IF NOT local_status.normal OR
          ((controller_type <> cmc$mscm3_ct) AND (controller_type <> cmc$mt5680_xx)) THEN
      RETURN;
    IFEND;

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

      cmp$pc_get_element (element.controller.connection.unit [pun].element_name, iou_name, unit_element_p,
            local_status);
      IF NOT local_status.normal THEN
        CYCLE /search_units/;
      IFEND;

      IF NOT ignore_state THEN
        cmp$get_element_state (unit_element_p^.element_name, iou_name, state, local_status);
      ELSE
        state := cmc$on;
      IFEND;
      IF state <> cmc$on THEN
        CYCLE /search_units/;
      IFEND;

     /search_upline_connection/
      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 /search_upline_connection/;
        IFEND;

        { Look at the first ON element in the upline connection of this unit.  If this is a request done
        { during manual state change, the state of the controller will be ignored.

        IF NOT ignore_state THEN
          cmp$get_element_state (unit_element_p^.storage_device.connection.port [port].element_name,
                iou_name, controller_state, local_status);
        ELSE
          controller_state := cmc$on;
        IFEND;
        IF controller_state <> cmc$on THEN
          CYCLE /search_upline_connection/;
        IFEND;

        cmp$pc_get_element (unit_element_p^.storage_device.connection.port [port].element_name, iou_name,
              controller_element_p, local_status);
        IF NOT local_status.normal THEN
          CYCLE /search_upline_connection/;
        IFEND;
        channel_state := cmc$on;
        IF NOT ignore_state THEN

          { Make sure this controller has channel in the ON state.

         /find_first_on_channel/
          FOR upline_port := LOWERVALUE (cmt$controller_port_number) TO
                UPPERVALUE (cmt$controller_port_number) DO
            IF controller_element_p^.controller.connection.port [upline_port].configured THEN
              cmp$get_element_state (
                    controller_element_p^.controller.connection.port [upline_port].element_name,
                    controller_element_p^.controller.connection.port [upline_port].iou, channel_state,
                    local_status);
              IF NOT local_status.normal THEN
                CYCLE /find_first_on_channel/;
              IFEND;
              IF channel_state <> cmc$on THEN
                found_first_controller := TRUE;
                CYCLE /find_first_on_channel/; { go to next channel }
              ELSE
                found_first_controller := FALSE;
                EXIT /find_first_on_channel/;
              IFEND;
            IFEND;
          FOREND /find_first_on_channel/;
        IFEND;

        IF channel_state <> cmc$on THEN

          { Cannot find a useable channel from this controller.

          CYCLE /search_upline_connection/;
        IFEND;

        { If first ON controller connected to this unit matches the controller name passed in, then it is
        { not a redundant controller.

        redundant := ((controller_element_p^.element_name <> element.element_name) OR
              found_first_controller);
        EXIT /search_upline_connection/;
      FOREND /search_upline_connection/;

      { If the controller is not redundant at this point, return, else keep searching until all units are
      { scanned, for it could be the first element on the upline connection of other units.

      IF NOT redundant THEN
        RETURN;
      IFEND;
    FOREND /search_units/;

  PROCEND seek_redundant_controller;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$acquire_resources', EJECT ??

{ PURPOSE:
{   This procedure obtains resources for operations initiated by CM external interface calls.  This is the
{   routine that obtains resources for MALET, NAM/VE, RHF, etc.
{ DESIGN:
{   If the request type is a PP request, then the output parameter physical_pp contains the information on
{   which PP was obtained.  The caller must save this information in order to later release the PP.

  PROCEDURE [XDCL, #GATE] cmp$acquire_resources
    (    request_type: dst$resource_request_types;
         channel: cmt$physical_channel;
         iou_number: dst$iou_number;
         equipment_number: 0 .. cmc$null_equipment_number;
         unit_number: 0 .. cmc$null_unit_number;
         driver_pp: boolean;
         specific_pp: boolean;
         get_pp_by_channel: boolean;
     VAR physical_pp: dst$iou_resource;
     VAR status: ost$status);

    VAR
      channel_type: dst$channel_protocol_type,
      ious_in_configuration: dst$iou_information_table,
      number_of_ious: dst$number_of_ious,
      resource_request: dst$resource_request;

    status.normal := TRUE;

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

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

    CASE request_type OF
    = dsc$rrt_get_channel =
      cmp$request_resources (request_type, resource_request, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    = dsc$rrt_get_equipment =

      { PROGRAMMING NOTE - The only call to this procedure with request_type = dsc$rrt_get_equipment is made
      { from cmm$pcu_ring1_helper when activating the configuration (to get channel but not load pp).  If
      { external interface modules cmm$reserve_elements or msm$request_maintenance_access ever call this
      { procedure with this request_type, code will be needed to not ignore certain abnormal statuses.

      resource_request.equipment_number := ORD (equipment_number);
      resource_request.unit_number := ORD (unit_number);
      cmp$request_resources (request_type, resource_request, status);
      IF NOT status.normal THEN
        IF (status.condition = dse$resource_already_assigned) OR
           (status.condition = dse$ch_assigned_to_ve) THEN
          status.normal := TRUE;
          cmp$request_resources (dsc$rrt_get_channel, resource_request, status);
          IF NOT status.normal THEN
            IF (status.condition <> dse$resource_already_assigned) AND
               (status.condition <> dse$ch_assigned_to_ve) THEN
              RETURN;
            ELSE
              status.normal := TRUE;
            IFEND;
          IFEND;
        IFEND;
      IFEND;

    = dsc$rrt_get_pp =
      resource_request.options := $dst$resource_request_options [];
      IF specific_pp THEN
        IF (osv$170_os_type <> osc$ot7_none) THEN
          osp$set_status_condition (cme$specific_pp_not_reservable,  status);
          RETURN;
        IFEND;
        resource_request.channel.number := 15; { dummy channel value
        resource_request.channel.channel_protocol := physical_pp.channel_protocol;
        resource_request.channel.iou_number := physical_pp.iou_number;
        resource_request.options := $dst$resource_request_options [dsc$rro_specific_pp];
        resource_request.primary_pp := physical_pp;
      ELSEIF get_pp_by_channel THEN
        ;
      ELSE {driver_pp or any_pp
        dsp$retrieve_iou_information (number_of_ious, ious_in_configuration);
        IF driver_pp THEN
          IF (number_of_ious = 1) AND ((ious_in_configuration [1].model_type = dsc$imn_i1_13_model) OR
                (ious_in_configuration [1].model_type = dsc$imn_i1_14_model)) THEN { 810 or 830 machine }
            resource_request.options := $dst$resource_request_options [dsc$rro_driver_pp];
          ELSE { same as any_pp
            resource_request.options := $dst$resource_request_options [dsc$rro_any_pp];
          IFEND;
        ELSE { any_pp
          resource_request.options := $dst$resource_request_options [dsc$rro_any_pp];
        IFEND;
        resource_request.channel.number := 15; { dummy channel value
        resource_request.channel.channel_protocol := dsc$cpt_nio;
        resource_request.channel.iou_number := ious_in_configuration [1].physical_iou_number;
      IFEND;
      cmp$request_resources (request_type, resource_request, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      physical_pp := resource_request.primary_pp;

    ELSE
    CASEND;

  PROCEND cmp$acquire_resources;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$deadstart_pp', EJECT ??

{ PURPOSE:
{   This procedure calls a Deadstart interface to load a PP program from the PP library built from the
{   deadstart tape or from the input PP Program sequence pointer parameter.

  PROCEDURE [XDCL, #GATE] cmp$deadstart_pp
    (    pp_index: iot$pp_number;
         pp_table_rma: ost$real_memory_address;
         search_from_dstape: boolean;
         pp_program_p: ^SEQ ( * );
     VAR status: ost$status);

    status.normal := TRUE;

    IF search_from_dstape THEN
      dsp$load_pp (dsc$load_pp_by_name, cmv$logical_pp_table_p^ [pp_index].pp_info.physical_pp, NIL,
            cmv$logical_pp_table_p^ [pp_index].pp_info.cip_driver_name, pp_table_rma, status);
    ELSE
      dsp$load_pp (dsc$load_pp_image, cmv$logical_pp_table_p^ [pp_index].pp_info.physical_pp, pp_program_p,
            cmv$logical_pp_table_p^ [pp_index].pp_info.cip_driver_name, pp_table_rma, status);
    IFEND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cmv$logical_pp_table_p^ [pp_index].flags.pp_loaded := TRUE;

  PROCEND cmp$deadstart_pp;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$determine_redundant_channel', EJECT ??

{ PURPOSE:
{   This procedure determines whether or not the channel is a redundant channel.  It scans all upline
{   connections of controllers connected to the channel, if the channel is not the first channel on any
{   of the connection, then redundant is set to TRUE.  A channel is not redundant if it is not the first
{   ON channel on the upline connection of a controller or storage device.

  PROCEDURE [XDCL, #GATE] cmp$determine_redundant_channel
    (    channel: cmt$physical_channel,
         iou_number: dst$iou_number;
         ignore_state: boolean;
     VAR redundant: boolean;
     VAR status: ost$status);

  VAR
    channel_p: ^cmt$element_definition,
    element_p: ^cmt$element_definition,
    first_channel_state: cmt$element_state,
    found_first_channel: boolean,
    index: integer,
    iou_name: cmt$element_name,
    pen: cmt$physical_equipment_number,
    port: cmt$controller_port_number;

    status.normal := TRUE;
    redundant := FALSE;
    cmp$convert_iou_number (iou_number, iou_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { Search all of the configuration to determine redundant channel. If a redundant channel is found, do not
    { stop because although the channel is defined as redundant on one controller, the other port could be
    { defined as primary.

   /search_configuration/
    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 /search_configuration/;
      IFEND;

      IF (cmv$physical_configuration^ [index].data_channel.number <> channel.number) OR
            (cmv$physical_configuration^ [index].data_channel.concurrent <> channel.concurrent) OR
            (cmv$physical_configuration^ [index].data_channel.iou <> iou_name) THEN
        CYCLE /search_configuration/;
      IFEND;

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

        cmp$pc_get_element (cmv$physical_configuration^ [index].data_channel.connection.
              equipment [pen].element_name, iou_name, element_p, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        seek_redundant_controller (element_p^, ignore_state, redundant);
        IF redundant THEN
          CYCLE /search_next_controller/;
        IFEND;

        found_first_channel := FALSE;
        port := LOWERVALUE (cmt$controller_port_number);
        WHILE (port <= UPPERVALUE (cmt$controller_port_number)) AND NOT found_first_channel DO
          IF element_p^.controller.connection.port [port].configured AND
               (element_p^.controller.connection.port [port].mainframe_ownership =
               cmv$physical_configuration^ [index].data_channel.mainframe_ownership) THEN
            found_first_channel := TRUE;
            cmp$pc_get_element (element_p^.controller.connection.port [port].element_name,
                  element_p^.controller.connection.port [port].iou, channel_p, status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;

            IF (channel_p^.data_channel.number = cmv$physical_configuration^[index].data_channel.number) AND
                  (channel_p^.data_channel.concurrent =
                  cmv$physical_configuration^[index].data_channel.concurrent) AND
                  (channel_p^.data_channel.iou = cmv$physical_configuration^ [index].data_channel.iou) THEN
              redundant := FALSE;
              RETURN;
            IFEND;

            cmp$get_element_state (channel_p^.element_name, channel_p^.data_channel.iou, first_channel_state,
                  status);
            IF first_channel_state <> cmc$on THEN
              redundant := FALSE;
              RETURN;
            IFEND;
            redundant := TRUE;
            CYCLE /search_next_controller/;
          IFEND;
          port := port + 1;
        WHILEND;
      FOREND /search_next_controller/;
    FOREND /search_configuration/;

  PROCEND cmp$determine_redundant_channel;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$free_pp_request', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$free_pp_request
    (    pp_index: iot$pp_number);

    IF cmv$logical_pp_table_p^ [pp_index].pp_info.saved_io_request_p <> NIL THEN
      IF cmv$logical_pp_table_p^ [pp_index].pp_info.saved_io_request_p^.device_request_p <> NIL THEN
        FREE cmv$logical_pp_table_p^ [pp_index].pp_info.saved_io_request_p^.device_request_p IN
              osv$mainframe_wired_cb_heap^;
      IFEND;
      FREE cmv$logical_pp_table_p^ [pp_index].pp_info.saved_io_request_p IN osv$mainframe_wired_cb_heap^;
      cmv$logical_pp_table_p^ [pp_index].pp_info.saved_io_request_p := NIL;
    IFEND;

  PROCEND cmp$free_pp_request;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_pp_reg ', EJECT ??

{ PURPOSE:
{   This procedure calls a deadstart interface to retrieve the PP registers.

  PROCEDURE [XDCL, #GATE] cmp$get_pp_reg
    (    pp: dst$iou_resource;
     VAR pp_registers: dst$dft_pp_registers;
     VAR status: ost$status);

    dsp$get_pp_registers (pp, pp_registers, status);

  PROCEND cmp$get_pp_reg;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$hardware_idle_pp', EJECT ??

{ PURPOSE:
{   This procedure calls a deadstart interface to hardware idle a PP.

  PROCEDURE [XDCL, #GATE] cmp$hardware_idle_pp
    (    pp: dst$iou_resource;
         dump_pp: boolean;
         dump_registers_only: boolean;
         pp_memory_p: ^SEQ ( * );
     VAR actual_pp_memory_size: cmt$pp_memory_length;
     VAR pp_registers: cmt$pp_registers;
     VAR status: ost$status);

    VAR
      dump_area_p: ^SEQ ( * ),
      pp_memory_seq_p: ^SEQ ( * ),
      pp_reg_p: ^dst$dft_pp_registers,
      size: integer;

    status.normal := TRUE;
    dump_area_p := NIL;
    IF dump_pp THEN
      IF pp_memory_p = NIL THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_nil_pointer_detected,
              'CMP$HARDWARE_IDLE_PP', status);
        RETURN;
      IFEND;
      size := #SIZE (pp_memory_p^) + #SIZE (dst$dft_pp_registers);
    ELSEIF dump_registers_only THEN
      size := #SIZE (dst$dft_pp_registers);
    IFEND;

    IF dump_pp OR dump_registers_only THEN
      ALLOCATE dump_area_p: [[REP size OF cell]] IN osv$mainframe_wired_heap^;
    IFEND;

   /dump_area_allocated/
    BEGIN
      dsp$idle_pp (pp, dump_registers_only, dump_pp, dump_area_p, status);
      IF NOT status.normal THEN
        EXIT /dump_area_allocated/;
      IFEND;
      actual_pp_memory_size := 0;
      pp_registers.a_register := 0;
      pp_registers.k_register := 0;
      pp_registers.p_register := 0;
      pp_registers.q_register := 0;

      IF dump_pp OR dump_registers_only THEN
        RESET dump_area_p;
        NEXT pp_reg_p IN dump_area_p;
        pp_registers.a_register := pp_reg_p^.a_register;
        pp_registers.k_register := pp_reg_p^.k_register;
        pp_registers.p_register := pp_reg_p^.p_register;
        pp_registers.q_register := pp_reg_p^.q_register;
        IF dump_pp THEN
          NEXT pp_memory_seq_p: [[REP #SIZE (pp_memory_p^) OF cell]] IN dump_area_p;
          actual_pp_memory_size := #SIZE (pp_memory_seq_p^);
          i#move (pp_memory_seq_p, pp_memory_p, #SIZE (pp_memory_p^));
        IFEND;
      IFEND;
    END /dump_area_allocated/;

    IF dump_area_p <> NIL THEN
      FREE dump_area_p IN osv$mainframe_wired_heap^;
    IFEND;

  PROCEND cmp$hardware_idle_pp;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$hardware_resume_pp ', EJECT ??

{ PURPOSE:
{   This procedure calls a deadstart interface to hardware resume a PP.

  PROCEDURE [XDCL, #GATE] cmp$hardware_resume_pp
    (    pp: dst$iou_resource;
         start_address: 0 .. 0ffff(16);
     VAR status: ost$status);

    dsp$resume_pp (pp, start_address, status);

  PROCEND cmp$hardware_resume_pp;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$pp_queue_lock', EJECT ??

{ PURPOSE:
{   This function determines whether or not a PP currently has its pp queue locked.

  FUNCTION [XDCL, #GATE] cmp$pp_queue_lock
    (    pp_index: iot$pp_number): boolean;

    cmp$pp_queue_lock := FALSE;
    IF cmv$logical_pp_table_p^ [pp_index].flags.configured THEN
      cmp$pp_queue_lock := cmv$logical_pp_table_p^ [pp_index].pp_info.pp_interface_table_p^.lockword.lock;
    IFEND;

  FUNCEND cmp$pp_queue_lock;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$reacquire_resources', EJECT ??

{ PURPOSE:
{   This routine is used by CHANGE_ELEMENT_STATE to reacquire resources when state changes to DOWN or ON are
{   performed.
{ DESIGN:
{   The parameter reload_driver dictates whether to reload the driver or just reserve the resource.

  PROCEDURE [XDCL, #GATE] cmp$reacquire_resources
    (    request_type: dst$resource_request_types;
         channel: cmt$physical_channel;
         iou_number: dst$iou_number;
         equipment_number: 0 .. cmc$null_equipment_number;
         unit_number: 0 .. cmc$null_unit_number;
         driver_name: cmt$element_name;
         pp_table_rma: ost$real_memory_address;
         controller_type: cmt$controller_type;
         reload_driver: boolean;
     VAR status: ost$status);

    VAR
      channel_type: dst$channel_protocol_type,
      partner_pp_index: iot$pp_number,
      pp_index: iot$pp_number,
      resource_request: dst$resource_request;

    status.normal := TRUE;

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

    cmp$retrieve_logical_pp_index (channel, iou_number, cmv$logical_pp_table_p, pp_index, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    partner_pp_index := cmv$logical_pp_table_p^ [pp_index].pp_info.logical_partner_pp_index;

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

    IF request_type = dsc$rrt_get_equipment THEN
      resource_request.equipment_number := ORD (equipment_number);
      resource_request.unit_number := ORD (unit_number);
    IFEND;

    IF request_type <> dsc$rrt_get_pp THEN
      cmp$request_resources (request_type, resource_request, status);
      IF NOT status.normal THEN
        IF (status.condition <> dse$resource_already_assigned) AND
           (status.condition <> dse$ch_assigned_to_ve) THEN
          RETURN;
        ELSE
          status.normal := TRUE;
        IFEND;
      IFEND;
    IFEND;

    IF NOT reload_driver OR cmv$logical_pp_table_p^ [pp_index].flags.resources_acquired THEN
      RETURN;
    IFEND;

    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$logical_pp_table_p^ [pp_index].pp_info.physical_pp := resource_request.primary_pp;
    cmv$logical_pp_table_p^ [pp_index].flags.resources_acquired := TRUE;
    IF partner_pp_index > 0 THEN
      cmv$logical_pp_table_p^ [partner_pp_index].pp_info.physical_pp := resource_request.secondary_pp;
      cmv$logical_pp_table_p^ [partner_pp_index].flags.resources_acquired := TRUE;
    IFEND;

    dsp$load_pp (dsc$load_pp_by_name, resource_request.primary_pp, NIL,
          cmv$logical_pp_table_p^ [pp_index].pp_info.cip_driver_name, pp_table_rma, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    cmp$assign_pp_r1 (TRUE, pp_index);

    IF partner_pp_index > 0 THEN
      IF cmv$logical_pp_table_p^ [pp_index].pp_info.pp_communication_buffer_p = NIL THEN
        osp$set_status_condition (cme$no_pp_communication_buffer, status);
        osp$append_status_integer (osc$status_parameter_delimiter, pp_index, 16, true, status);
        RETURN; {----->
      IFEND;
      dsp$load_pp (dsc$load_pp_by_name, resource_request.secondary_pp, NIL,
          cmv$logical_pp_table_p^ [pp_index].pp_info.cip_driver_name,
          cmv$logical_pp_table_p^ [pp_index].pp_info.pp_communication_buffer_p^.partner_pp, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      cmp$assign_pp_r1 (TRUE, partner_pp_index);
    IFEND;

  PROCEND cmp$reacquire_resources;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$resume_pp_r1', EJECT ??

{ PURPOSE:
{   This procedure sets up the monitor request block to soft resume a PP.

  PROCEDURE [XDCL, #GATE] cmp$resume_pp_r1
    (    channel_name: cmt$element_name;
         iou_name: cmt$element_name;
     VAR status: ost$status);

    VAR
      channel_element_p: ^cmt$element_definition,
      logical_pp_index: iot$pp_number,
      ignore_status: ^ost$status,
      request_block: cmt$request_block;

    status.normal := TRUE;

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

    cmp$get_logical_pp_index (channel_element_p^, logical_pp_index, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    request_block.request_code := syc$rc_config_mgmt_request;
    request_block.kind := cmc$rbk_resume_pp;
    request_block.resumed_pp := logical_pp_index;
    request_block.send_resume := TRUE;
    i#call_monitor (#LOC (request_block) , #SIZE (request_block));
    IF NOT request_block.status.normal THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$unable_to_resume,
            'PP did not respond to resume request.', status);

     osp$system_error ('PP did not respond' , ignore_status);
    IFEND;

  PROCEND cmp$resume_pp_r1;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$send_pp_command', EJECT ??

{ PURPOSE:
{   This procedure queues an idle pp or a resume pp request.

  PROCEDURE [XDCL, #GATE] cmp$send_pp_command
    (    pp_index: iot$pp_number;
         pp_command: cmt$pp_commands;
     VAR successful: boolean;
     VAR status: ost$status);

    VAR
      disk_request_p: ^iot$disk_request,
      dmv$external_interrupt_selector: [XREF] 0 .. 0ff(16),
      initial_pp_request: [STATIC] iot$disk_pp_request := [0, NIL, 0, 0, ioc$min_request_length, 0,
            ioc$attempt_recovery, [FALSE, 1], 1, [FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 0], FALSE, 0, 0,
            0, 0, 0, [[0, [TRUE, FALSE, 0], 8, 0], [0, [TRUE, FALSE, 0], 8, 0], [0, [TRUE, FALSE, 0], 8, 0]]],
      io_request_p: ^iot$io_request,
      request_block: cmt$request_block;

    status.normal := TRUE;
    successful := FALSE;
    IF NOT cmv$logical_pp_table_p^ [pp_index].flags.configured THEN
      osp$set_status_condition (cme$ppit_not_built, status);
      RETURN;
    IFEND;

    ALLOCATE disk_request_p IN osv$mainframe_wired_cb_heap^;
    disk_request_p^.request_index := 0;
    disk_request_p^.link := NIL;
    disk_request_p^.request := initial_pp_request;

    IF pp_command = cmc$idle_command THEN
      disk_request_p^.request.command [1].command_code := ioc$cc_idle;
    ELSE  { pp_command = cmc$resume_command }
      disk_request_p^.request.command [1].command_code := ioc$cc_resume;
    IFEND;

    IF dmv$external_interrupt_selector = 1 THEN
      disk_request_p^.request.interrupt.value := TRUE;
      disk_request_p^.request.interrupt.port_number := osv$external_interrupt_selector;
    IFEND;
    ALLOCATE io_request_p IN osv$mainframe_wired_cb_heap^;
    io_request_p^.device_request_p := disk_request_p;
    io_request_p^.pp_request_p := ^disk_request_p^.request;

    request_block.request_code := syc$rc_config_mgmt_request;
    request_block.kind := cmc$rbk_queue_pp_request;
    request_block.queued_pp := pp_index;
    request_block.request_p := io_request_p;

    cmv$logical_pp_table_p^ [pp_index].pp_info.saved_io_request_p := io_request_p;
    i#call_monitor (#LOC (request_block), #SIZE (request_block));
    IF NOT request_block.status.normal THEN
      IF pp_command = cmc$idle_command THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$unable_to_idle,
              'PP did not respond to idle request.', status);
      ELSE  { pp_command = cmc$resume_command }
        osp$set_status_abnormal (cmc$configuration_management_id, cme$unable_to_resume,
              'PP did not respond to resume request.', status);
      IFEND;
      RETURN;
    IFEND;

    IF pp_command = cmc$idle_command THEN
      IF NOT cmv$logical_pp_table_p^ [pp_index].flags.pp_idle_resume_supported THEN
       successful := TRUE;
      ELSE
      successful := cmv$logical_pp_table_p^ [pp_index].pp_info.pp_interface_table_p^.idle_status;
      IFEND;
    ELSE  { pp_command = cmc$resume_command }
      successful := NOT cmv$logical_pp_table_p^ [pp_index].pp_info.pp_interface_table_p^.idle_status;
    IFEND;

  PROCEND cmp$send_pp_command;
?? OLDTITLE ??
MODEND cmm$maintenance_services_r1;
