?? RIGHT := 110 ??
?? TITLE := ' Maintenance services module' ??
MODULE msm$request_maintenance_access;
?? RIGHT := 110 ??

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$job_paged_literal
*copyc rmc$dedicated_maintenance
*copyc rmd$volume_declarations
*copyc cme$logical_configuration_mgr
*copyc cme$reserve_element
*copyc dme$tape_errors
*copyc mse$request_maintenance_access
*copyc cmt$element_definition
*copyc cmt$element_descriptor
*copyc cmt$element_status
*copyc mst$access_type
*copyc ost$caller_identifier
?? POP ??
*copyc avp$get_capability
*copyc cmp$acquire_resources
*copyc cmp$clear_unit_shared
*copyc cmp$convert_iou_name
*copyc cmp$convert_iou_number
*copyc cmp$execute_pp_program
*copyc cmp$format_error_message
*copyc cmp$get_element_definition
*copyc cmp$get_element_information
*copyc cmp$get_logical_unit_number
*copyc cmp$get_mainframe_element
*copyc cmp$get_pp_registers
*copyc cmp$get_unit_type
*copyc cmp$idle_pp
*copyc cmp$mount_storage_medium
*copyc cmp$release_element
*copyc cmp$request_channels
*copyc cmp$reserve_element
*copyc cmp$resume_pp
*copyc cmp$search_active_volume_table
*copyc cmp$search_peripheral_table
*copyc cmp$set_unit_shared
*copyc cmp$validate_unused_channel
*copyc dsp$retrieve_iou_information
*copyc msp$add_con_access_job
*copyc msp$delete_con_access_job
*copyc msp$mark_element_requested
*copyc msp$search_con_access_job
*copyc msp$unmark_element_requested
*copyc ofp$format_operator_menu
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
*copyc pmp$get_executing_task_gtid
*copyc pmp$get_job_names
*copyc pmp$get_mainframe_id
*copyc rmp$release_tape_unit
*copyc stp$get_volumes_set_name
*copyc stp$is_volume_in_set
*copyc cmv$logical_unit_table
*copyc cmv$peripheral_element_table
*copyc cmv$physical_configuration
*copyc cmv$task_reserved_element_count
*copyc gfv$null_sfid
*copyc msv$con_access_gtid_list
*copyc osv$task_shared_heap

{Debug
*copyc dpp$put_critical_message
{Debug End
?? OLDTITLE ??
?? NEWTITLE := '  msp$request_maintenance_access', EJECT ??

*copyc msh$request_maintenance_access

  PROCEDURE [XDCL, #GATE] msp$request_maintenance_access
    (    element: cmt$element_descriptor;
         access: mst$access_type;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier,
      capability: boolean,
      channel_index: integer,
      channel_ordinal: cmt$channel_ordinal,
      dedicated_element_info: array [1 .. 1] of cmt$element_info_item,
      definition: cmt$element_definition,
      element_descriptor,
      element_description: cmt$element_descriptor,
      element_reservation: cmt$element_reservation,
      found: boolean,
      gtid_found: boolean,
      gtid: ost$global_task_id,
      host_mainframe: pmt$mainframe_id,
{???  i: integer,
      iou: dst$iou_number,
      iou_information_table: dst$iou_information_table,
      job_name: jmt$system_supplied_name,
      job_name_found: boolean,
      lun: integer,
      mainframe_list_p: ^array [ * ] of pmt$mainframe_id,
      maintenance_allowed: boolean,
      need_to_warn_operator: boolean,
      number_of_ious: dst$number_of_ious,
      pc_index_1: integer,
      pc_index_2: integer,
      privileged_job: boolean,
      peripheral_index: integer,
      physical_id: cmt$physical_identification,
      physical_pp: dst$iou_resource,
      request_type: dst$resource_request_types,
      terminate_reason: string (osc$max_string_size),
      upline_port: integer,
      user_job_name: jmt$user_supplied_name;

{D} VAR
{D}   i: integer,
{D}   local_status: ost$status,
{D}   str: string (80);
?? NEWTITLE := 'MENU_FOR_MAINTENANCE_REQUEST', EJECT ??

    PROCEDURE menu_for_maintenance_request
      (VAR status: ost$status);

      CONST
        default_terminate_reason = 'Request terminated by operator.',
        number_of_choices = 2,
        parameter_max = 5;

      VAR
        column: 1 .. 80,
        i: integer,
        list_string: string (80),
        menu_parameters: array [1 .. parameter_max] of ^ost$message_parameter,
        parameter_index: 1 .. parameter_max,
        parameter_names: ^ost$parameter_help_names,
        response: oft$number_of_choices,
        response_string: ost$string,
        string_index: 1 .. 80,
        string_size: ost$name_size;

      status.normal := TRUE;

      menu_parameters [1] := ^definition.element_name;
      list_string := ' ';
      string_index := 1;
      column := 14;
      parameter_index := 2;
      FOR i := LOWERBOUND (mainframe_list_p^) TO UPPERBOUND (mainframe_list_p^) DO
        IF mainframe_list_p^ [i] <> ' ' THEN
          IF column > 70 THEN
            menu_parameters [parameter_index] := ^list_string;
            string_index := 1;
            column := 14;
            list_string := ' ';
            IF parameter_index < parameter_max THEN
              parameter_index := parameter_index + 1;
            IFEND;
          IFEND;
          list_string (string_index, 9) := mainframe_list_p^ [i] (9, * );
          string_index := string_index + 10;
          column := column + 10;
        IFEND;
      FOREND;
      menu_parameters [parameter_index] := ^list_string;
      IF parameter_index < parameter_max THEN
        FOR i := parameter_index + 1 TO parameter_max DO
          menu_parameters [i] := NIL;
        FOREND;
      IFEND;

      PUSH parameter_names: [1 .. number_of_choices];
      parameter_names^ [1] := 'TERMINATE_REQUEST';
      parameter_names^ [2] := 'ALLOW_MAINTENANCE';

      ofp$format_operator_menu (rmc$dedicated_maintenance, parameter_names, ^menu_parameters,
            number_of_choices, ofc$removable_media_operator, response, response_string, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

      CASE response OF
      = 1 =
        IF response_string.size > 0 THEN
          terminate_reason := response_string.value (1, response_string.size);
        ELSE
          terminate_reason := default_terminate_reason;
        IFEND;
        osp$set_status_abnormal (rmc$resource_management_id, dme$operator_stop, terminate_reason, status);
      = 2 =
        ;
      ELSE
      CASEND;
    PROCEND menu_for_maintenance_request;
?? OLDTITLE ??
?? EJECT ??

    #CALLER_ID (caller_id);
    mainframe_list_p := NIL;
    privileged_job := caller_id.ring <= 6;
    status.normal := TRUE;

    pmp$get_mainframe_id (host_mainframe, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    avp$get_capability (avc$engineering_operation, avc$user, capability, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF (NOT capability) AND (caller_id.ring > 6) THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
            'MSP$REQUEST_MAINTENANCE_ACCESS', status);
      RETURN; {----->
    IFEND;

    pmp$get_job_names (user_job_name, job_name, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    dsp$retrieve_iou_information (number_of_ious, iou_information_table);

    element_descriptor.element_type := element.element_type;
    CASE element_descriptor.element_type OF
    = cmc$data_channel_element =
      element_descriptor.channel_descriptor := element.channel_descriptor;
      IF number_of_ious = 1 THEN
        cmp$convert_iou_number (iou_information_table [1].physical_iou_number,
              element_descriptor.channel_descriptor.iou, status);
      ELSE { validate IOU passed in is a valid name}
        cmp$convert_iou_name (element_descriptor.channel_descriptor.iou, iou, status);
      IFEND;

    = cmc$channel_adapter_element, cmc$controller_element, cmc$storage_device_element,
          cmc$communications_element, cmc$external_processor_element =
      element_descriptor.peripheral_descriptor := element.peripheral_descriptor;
      IF NOT element_descriptor.peripheral_descriptor.use_logical_identification THEN
        IF number_of_ious = 1 THEN
          cmp$convert_iou_number (iou_information_table [1].physical_iou_number,
                element_descriptor.peripheral_descriptor.hardware_address.iou, status);
        ELSE { validate IOU passed in is a valid name}
          cmp$convert_iou_name (element_descriptor.peripheral_descriptor.hardware_address.iou, iou, status);
        IFEND;
      IFEND;

    ELSE
    CASEND;
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    pmp$get_executing_task_gtid (gtid);

    cmp$get_element_definition (element_descriptor, definition, status);
    IF NOT status.normal THEN
      cmp$format_error_message (element_descriptor, {not used} physical_id, FALSE, cme$lcm_element_not_found,
            status);
      RETURN; {----->
    IFEND;

    IF element_descriptor.element_type <> definition.element_type THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$incorrect_element_type,
            definition.element_name, status);
      RETURN; {----->
    IFEND;

    CASE element_descriptor.element_type OF
    = cmc$data_channel_element =
      IF NOT element_descriptor.channel_descriptor.use_logical_identification THEN
        element_descriptor.channel_descriptor.use_logical_identification := TRUE;
        element_descriptor.channel_descriptor.name := definition.element_name;
        element_descriptor.channel_descriptor.iou := definition.data_channel.iou;
      IFEND;

    = cmc$channel_adapter_element, cmc$controller_element, cmc$storage_device_element,
          cmc$communications_element, cmc$external_processor_element =
      IF NOT element_descriptor.peripheral_descriptor.use_logical_identification THEN
        element_descriptor.peripheral_descriptor.use_logical_identification := TRUE;
        element_descriptor.peripheral_descriptor.element_name := definition.element_name;
      IFEND;

    ELSE
    CASEND;

    cmp$search_peripheral_table (element_descriptor, element_reservation, FALSE, peripheral_index, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF element_descriptor.element_type = cmc$data_channel_element THEN
      cmp$validate_unused_channel (cmv$peripheral_element_table.pointer^ [peripheral_index].element_name,
            element_descriptor.channel_descriptor.iou, maintenance_allowed, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
      IF NOT maintenance_allowed THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$non_active_path,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        RETURN; {----->
      IFEND;
    IFEND;

{ Check if element is in DEDICATED maintenance access }
    IF cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.access =
          msc$dedicated_access THEN
      osp$set_status_abnormal (msc$maintenance_services_id, mse$dedicated_access_granted,
            cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, cmv$peripheral_element_table.
            pointer^ [peripheral_index].maintenance_activity.dedicated_accessor.job_identification, status);
      RETURN; {----->
    IFEND;

{ Check if element already RESERVED or ASSIGNED to any job }
    IF element.element_type = cmc$storage_device_element THEN
      lun := cmv$peripheral_element_table.pointer^ [peripheral_index].logical_unit_number;
      IF (lun <> 0)
{   } AND (cmv$logical_unit_table^ [lun].status.assignable_device)
{   } AND (cmv$logical_unit_table^ [lun].status.assigned) THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$element_already_assigned,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        osp$append_status_parameter (osc$status_parameter_delimiter,
              cmv$logical_unit_table^ [lun].status.assigned_jsn, status);
        RETURN; {----->
      IFEND;
    IFEND;

    IF (cmv$peripheral_element_table.pointer^ [peripheral_index].entry_interlock)
{ } AND (cmv$peripheral_element_table.pointer^ [peripheral_index].reserved_status) THEN
      osp$set_status_abnormal (msc$maintenance_services_id, cme$element_already_reserved,
            cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, cmv$peripheral_element_table.
            pointer^ [peripheral_index].reserved_job, status);
      RETURN; {----->
    IFEND;

    CASE access OF
    = msc$concurrent_access =

{ Check if element is not in ON or DOWN state }
      IF cmv$peripheral_element_table.pointer^ [peripheral_index].element_status.state = cmc$off THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$element_state_not_proper,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        RETURN; {----->
      IFEND;

      msp$search_con_access_job (peripheral_index, job_name, job_name_found, status);
      IF job_name_found THEN
        msp$search_con_access_gtid (gtid, peripheral_index, gtid_found, status);
        IF gtid_found THEN
          osp$set_status_abnormal (msc$maintenance_services_id, mse$concurrent_access_granted,
                cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, 'the same TASK of this job', status);
          RETURN; {----->
        ELSE
          msp$add_con_access_gtid (gtid, peripheral_index, status);
        IFEND;
      ELSE
        msp$add_con_access_job (peripheral_index, job_name, status);
        msp$add_con_access_gtid (gtid, peripheral_index, status);
      IFEND;
      IF element.element_type = cmc$storage_device_element THEN
        IF lun <> 0 THEN
          cmp$set_unit_shared (lun, TRUE);
        IFEND;
      IFEND;

    = msc$dedicated_access =
      dedicated_element_info [1].selector := cmc$system_critical_element;

      cmp$get_element_information (element_descriptor, dedicated_element_info, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

{ Check if element is SYSTEM-CRITICAL }
      IF dedicated_element_info [1].item_returned THEN
        IF dedicated_element_info [1].system_critical_element THEN
          CASE element_descriptor.element_type OF
          = cmc$data_channel_element =
            osp$set_status_abnormal (msc$maintenance_services_id, mse$system_critical_element,
                  element_descriptor.channel_descriptor.name, status);
          = cmc$controller_element, cmc$storage_device_element, cmc$communications_element,
                cmc$channel_adapter_element, cmc$external_processor_element =
            osp$set_status_abnormal (msc$maintenance_services_id, mse$system_critical_element,
                  element_descriptor.peripheral_descriptor.element_name, status);
          CASEND;
          RETURN; {----->
        IFEND;
      IFEND;

{ Check if element is not in DOWN state }
      IF cmv$peripheral_element_table.pointer^ [peripheral_index].element_status.state <> cmc$down THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$element_state_not_proper,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        RETURN; {----->
      IFEND;

{ Check if element in CONCURRENT maintenance access }
      IF (cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.access =
            msc$concurrent_access) AND (cmv$peripheral_element_table.pointer^ [peripheral_index].
            maintenance_activity.con_access_job_list <> NIL) THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$concurrent_access_granted,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, cmv$peripheral_element_table.
              pointer^ [peripheral_index].maintenance_activity.con_access_job_list^.job_name, status);
        RETURN; {----->
      IFEND;

{ Check if element is CONTROLLER and in active physical configuration connected to another mainframe }
      need_to_warn_operator := FALSE;
      CASE element.element_type OF
      = cmc$controller_element =
        FOR upline_port := LOWERVALUE (cmt$controller_port_number)
              TO UPPERVALUE (cmt$controller_port_number) DO
          IF (definition.controller.connection.port [upline_port].configured)
{       } AND (definition.controller.connection.port [upline_port].upline_connection_type =
                cmc$data_channel_element)
{       } AND (definition.controller.connection.port [upline_port].mainframe_ownership <> host_mainframe) THEN

            need_to_warn_operator := TRUE;
            IF mainframe_list_p = NIL THEN
              PUSH mainframe_list_p: [0 .. UPPERVALUE (cmt$controller_port_number)];
              FOR i := LOWERBOUND (mainframe_list_p^) TO UPPERBOUND (mainframe_list_p^) DO
                mainframe_list_p^ [i] := ' ';
              FOREND;
            IFEND;
            mainframe_list_p^ [upline_port] := definition.controller.connection.port [upline_port].
                  mainframe_ownership;
          IFEND;
        FOREND;

      = cmc$communications_element =
        FOR upline_port := LOWERVALUE (cmt$communications_port_number)
              TO UPPERVALUE (cmt$communications_port_number) DO
          IF (definition.communications_element.connection.port [upline_port].configured)
{       } AND (definition.communications_element.connection.port [upline_port].upline_connection_type =
                cmc$data_channel_element)
{       } AND (definition.communications_element.connection.port [upline_port].mainframe_ownership <>
                host_mainframe) THEN

            need_to_warn_operator := TRUE;
            IF mainframe_list_p = NIL THEN
              PUSH mainframe_list_p: [0 .. UPPERVALUE (cmt$communications_port_number)];
              FOR i := LOWERBOUND (mainframe_list_p^) TO UPPERBOUND (mainframe_list_p^) DO
                mainframe_list_p^ [i] := ' ';
              FOREND;
            IFEND;
            mainframe_list_p^ [upline_port] := definition.communications_element.connection.
                  port [upline_port].mainframe_ownership;
          IFEND;
        FOREND;

      = cmc$storage_device_element =
        FOR upline_port := LOWERVALUE (cmt$data_storage_port_number)
              TO UPPERVALUE (cmt$data_storage_port_number) DO
          IF (definition.storage_device.connection.port [upline_port].configured)
{       } AND (definition.storage_device.connection.port [upline_port].upline_connection_type =
                cmc$data_channel_element)
{       } AND (definition.storage_device.connection.port [upline_port].mainframe_ownership <>
                host_mainframe) THEN

            need_to_warn_operator := TRUE;
            IF mainframe_list_p = NIL THEN
              PUSH mainframe_list_p: [0 .. UPPERVALUE (cmt$data_storage_port_number)];
              FOR i := LOWERBOUND (mainframe_list_p^) TO UPPERBOUND (mainframe_list_p^) DO
                mainframe_list_p^ [i] := ' ';
              FOREND;
            IFEND;
            mainframe_list_p^ [upline_port] := definition.storage_device.connection.port [upline_port].
                  mainframe_ownership;
          IFEND;
        FOREND;
      ELSE
        { Other type of elements do not have multiple mainframe connections }
        ;
      CASEND;

      IF need_to_warn_operator THEN
        maintenance_allowed := FALSE;

      /operator_menu/
        BEGIN
          menu_for_maintenance_request (status);
          IF NOT status.normal THEN
            IF ((status.condition = dme$termination_condition) OR (status.condition = dme$operator_stop)) THEN
              EXIT /operator_menu/; {----->
            IFEND;
          IFEND;
          maintenance_allowed := TRUE;
        END /operator_menu/;
        IF NOT maintenance_allowed THEN
          osp$set_status_abnormal (msc$maintenance_services_id, mse$maintenance_access_denied,
                definition.element_name, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, terminate_reason, status);
          RETURN; {----->
        IFEND;
      IFEND;

      { Check to see if the element in the active physical }
      { configuration shows there being more channels connected to the }
      { controller than have been configured in active logical configuration }
      { If so, acquire all additional channels from the real state system }

      cmp$request_channels (dsc$rrt_get_channel, definition, host_mainframe, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
      msp$mark_element_requested (element_descriptor, access, job_name, gtid, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

      IF access = msc$dedicated_access THEN
{ msp$mark_element_requested only sets the GTID for dedicated access
        cmv$task_reserved_element_count := cmv$task_reserved_element_count + 1;
{D} STRINGREP (str, i, 'PP cmv$task_reserved_element_count: ', cmv$task_reserved_element_count);
{D} dpp$put_critical_message (str (1, i), local_status);
      IFEND;
    CASEND;

  PROCEND msp$request_maintenance_access;

?? OLDTITLE ??
?? NEWTITLE := '  msp$release_maintenance_access', EJECT ??

*copyc msh$release_maintenance_access

  PROCEDURE [XDCL, #GATE] msp$release_maintenance_access
    (    element: cmt$element_descriptor;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier,
      capability: boolean,
      concurrent_access: boolean,
      dedicated_access_released: boolean,
      element_descriptor: cmt$element_descriptor,
      element_name: cmt$element_name,
      element_found: boolean,
      element_reservation: cmt$element_reservation,
      definition: cmt$element_definition,
      gtid: ost$global_task_id,
      gtid_found: boolean,
      iou: dst$iou_number,
      iou_information_table: dst$iou_information_table,
      job_name: jmt$system_supplied_name,
      job_name_found: boolean,
      lun: iot$logical_unit,
      lun_entry_locked: boolean,
      lun_entry_unlocked: boolean,
      local_status: ost$status,
      mainframe_id: pmt$mainframe_id,
      number_of_ious: dst$number_of_ious,
      physical_id: cmt$physical_identification,
      peripheral_index: integer,
      privileged_job: boolean,
      user_job_name: jmt$user_supplied_name;

{Debug

    VAR
      i: integer,
      str: string (80);

{Debug End

    #CALLER_ID (caller_id);
    privileged_job := caller_id.ring <= 6;
    status.normal := TRUE;

    avp$get_capability (avc$engineering_operation, avc$user, capability, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF (NOT capability) AND (caller_id.ring > 6) THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
            'MSP$RELEASE_MAINTENANCE_ACCESS', status);
      RETURN; {----->
    IFEND;

    pmp$get_job_names (user_job_name, job_name, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    dsp$retrieve_iou_information (number_of_ious, iou_information_table);

    element_descriptor.element_type := element.element_type;
    CASE element_descriptor.element_type OF
    = cmc$data_channel_element =
      element_descriptor.channel_descriptor := element.channel_descriptor;
      IF number_of_ious = 1 THEN
        cmp$convert_iou_number (iou_information_table [1].physical_iou_number,
              element_descriptor.channel_descriptor.iou, status);
      ELSE { validate IOU passed in is a valid name}
        cmp$convert_iou_name (element_descriptor.channel_descriptor.iou, iou, status);
      IFEND;

    = cmc$channel_adapter_element, cmc$controller_element, cmc$storage_device_element,
          cmc$communications_element, cmc$external_processor_element =
      element_descriptor.peripheral_descriptor := element.peripheral_descriptor;
      IF NOT element_descriptor.peripheral_descriptor.use_logical_identification THEN
        IF number_of_ious = 1 THEN
          cmp$convert_iou_number (iou_information_table [1].physical_iou_number,
                element_descriptor.peripheral_descriptor.hardware_address.iou, status);
        ELSE { validate IOU passed in is a valid name}
          cmp$convert_iou_name (element_descriptor.peripheral_descriptor.hardware_address.iou, iou, status);
        IFEND;
      IFEND;

    ELSE
    CASEND;
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    pmp$get_executing_task_gtid (gtid);
    cmp$get_element_definition (element_descriptor, definition, status);
    IF NOT status.normal THEN
      cmp$format_error_message (element_descriptor, {not_used} physical_id, FALSE, cme$lcm_element_not_found,
            status);
      RETURN; {----->
    IFEND;

    IF element_descriptor.element_type <> definition.element_type THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$incorrect_element_type,
            definition.element_name, status);
      RETURN; {----->
    IFEND;

    CASE element_descriptor.element_type OF

    = cmc$data_channel_element =
      IF NOT element_descriptor.channel_descriptor.use_logical_identification THEN
        element_descriptor.channel_descriptor.use_logical_identification := TRUE;
        element_descriptor.channel_descriptor.name := definition.element_name;
        element_descriptor.channel_descriptor.iou := definition.data_channel.iou;
      IFEND;

    = cmc$controller_element, cmc$storage_device_element, cmc$communications_element,
          cmc$channel_adapter_element, cmc$external_processor_element =
      IF NOT element_descriptor.peripheral_descriptor.use_logical_identification THEN
        element_descriptor.peripheral_descriptor.use_logical_identification := TRUE;
        element_descriptor.peripheral_descriptor.element_name := definition.element_name;
      IFEND;

    ELSE
    CASEND;

    cmp$search_peripheral_table (element_descriptor, element_reservation, FALSE, peripheral_index, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    lun := cmv$peripheral_element_table.pointer^ [peripheral_index].logical_unit_number;

    IF cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.access =
          msc$dedicated_access THEN
      pmp$get_mainframe_id (mainframe_id, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
      msp$unmark_element_requested (job_name, gtid, peripheral_index, mainframe_id, dedicated_access_released,
            status);
      IF dedicated_access_released THEN
{Debug
        IF cmv$task_reserved_element_count < 1 THEN
          STRINGREP (str, i, 'cmv$task_reserved_element_count underrun by ', job_name);
          dpp$put_critical_message (str (1, i), local_status);
          cmv$task_reserved_element_count := cmv$task_reserved_element_count + 1;
        IFEND;
{Debug End
        cmv$task_reserved_element_count := cmv$task_reserved_element_count - 1;
{D} STRINGREP (str, i, 'PP cmv$task_reserved_element_count: ', cmv$task_reserved_element_count);
{D} dpp$put_critical_message (str (1, i), local_status);
      IFEND;
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
    ELSE
      IF cmv$peripheral_element_table.pointer^ [peripheral_index].physical_descriptor.element_type =
            cmc$storage_device_element THEN
        IF lun <> 0 THEN
          cmp$clear_unit_shared (lun, TRUE);
        IFEND;
      IFEND;

      concurrent_access := TRUE;
      msp$search_con_access_job (peripheral_index, job_name, job_name_found, status);
      IF NOT job_name_found THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$element_not_requested,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        RETURN; {----->
      ELSE
        msp$search_con_access_gtid (gtid, peripheral_index, gtid_found, status);
        IF NOT gtid_found THEN
          osp$set_status_abnormal (msc$maintenance_services_id, mse$element_not_requested,
                cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
          RETURN; {----->
        ELSE
          msp$delete_con_access_gtid (gtid, peripheral_index, status);
          msp$search_element_con_accessed (peripheral_index, element_found, status);
          IF NOT element_found THEN
            msp$delete_con_access_job (peripheral_index, job_name, status);
          IFEND;
        IFEND;
      IFEND;

    IFEND;

    IF cmv$peripheral_element_table.pointer^ [peripheral_index].physical_descriptor.element_type =
          cmc$storage_device_element THEN
      IF lun <> 0 THEN
        IF cmv$logical_unit_table^ [lun].status.assignable_device THEN
          rmp$release_tape_unit (gfv$null_sfid, lun, {delete_request_from_vsn_queue} FALSE, local_status);
        IFEND;
      IFEND;
    IFEND;

  PROCEND msp$release_maintenance_access;
?? OLDTITLE ??
?? NEWTITLE := 'MSP$SEARCH_CON_ACCESS_GTID', EJECT ??

{ PURPOSE:
{   This procedure determines whether or not the given global
{   task id is part of the concurrent access task id list.

  PROCEDURE msp$search_con_access_gtid
    (    gtid: ost$global_task_id;
         peripheral_index: integer;
     VAR found: boolean;
     VAR status: ost$status);

    VAR
      con_access_gtid_list: mst$con_access_gtid_list;

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

    con_access_gtid_list := msv$con_access_gtid_list;

    WHILE (con_access_gtid_list <> NIL) AND (NOT found) DO
      IF (con_access_gtid_list^.gtid = gtid) AND (con_access_gtid_list^.element_index = peripheral_index) THEN
        found := TRUE;
      ELSE
        con_access_gtid_list := con_access_gtid_list^.forward_link;
      IFEND;
    WHILEND;

  PROCEND msp$search_con_access_gtid;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate] MSP$SEARCH_ELEMENT_CON_ACCESSED', EJECT ??

{ PURPOSE:
{   This procedure determines whether or not the given index to
{   the element is in the concurrent access list.


  PROCEDURE [XDCL, #GATE] msp$search_element_con_accessed
    (    element_index: integer;
     VAR found: boolean;
     VAR status: ost$status);

    VAR
      con_access_gtid_list: mst$con_access_gtid_list;

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

    con_access_gtid_list := msv$con_access_gtid_list;

    WHILE (con_access_gtid_list <> NIL) AND (NOT found) DO
      IF con_access_gtid_list^.element_index = element_index THEN
        found := TRUE;
      ELSE
        con_access_gtid_list := con_access_gtid_list^.forward_link;
      IFEND;
    WHILEND;

  PROCEND msp$search_element_con_accessed;
?? OLDTITLE ??
?? NEWTITLE := '  msp$add_con_access_gtid', EJECT ??

{ PURPOSE:
{   This procedure adds a task id to the concurrent access list.

  PROCEDURE msp$add_con_access_gtid
    (    gtid: ost$global_task_id;
         element_index: integer;
     VAR status: ost$status);

    VAR
      node: mst$con_access_gtid_list;

{D} VAR
{D}   i: integer,
{D}   local_status: ost$status,
{D}   str: string (80);
    status.normal := TRUE;
    ALLOCATE node IN osv$task_shared_heap^;
    node^.gtid := gtid;
    node^.element_index := element_index;
    node^.forward_link := NIL;

    IF msv$con_access_gtid_list = NIL THEN
      msv$con_access_gtid_list := node;
    ELSE
      node^.forward_link := msv$con_access_gtid_list;
      msv$con_access_gtid_list := node;
    IFEND;

    cmv$task_reserved_element_count := cmv$task_reserved_element_count + 1;
{D} STRINGREP (str, i, 'PP cmv$task_reserved_element_count: ', cmv$task_reserved_element_count);
{D} dpp$put_critical_message (str (1, i), local_status);

  PROCEND msp$add_con_access_gtid;
?? OLDTITLE ??
?? NEWTITLE := '  msp$delete_con_access_gtid', EJECT ??

{ PURPOSE:
{   This procedure deletes a task id from the concurrent access list.

  PROCEDURE [XDCL, #GATE] msp$delete_con_access_gtid
    (    gtid: ost$global_task_id;
         element_index: integer;
     VAR status: ost$status);

    VAR
      before_deleted_node: mst$con_access_gtid_list,
      deleted_node: mst$con_access_gtid_list,
      found: boolean;

{Debug

    VAR
      i: integer,
      job_name: jmt$system_supplied_name,
      local_status: ost$status,
      str: string (80),
      user_job_name: jmt$user_supplied_name;

{Debug End

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

    deleted_node := msv$con_access_gtid_list;
    before_deleted_node := NIL;

    WHILE (deleted_node <> NIL) AND (NOT found) DO
      IF (deleted_node^.gtid = gtid) AND (deleted_node^.element_index = element_index) THEN
        found := TRUE;
      ELSE
        before_deleted_node := deleted_node;
        deleted_node := deleted_node^.forward_link;
      IFEND;
    WHILEND;

    IF found THEN
      IF msv$con_access_gtid_list^.forward_link = NIL THEN
        FREE msv$con_access_gtid_list IN osv$task_shared_heap^;
      ELSEIF before_deleted_node = NIL THEN
        msv$con_access_gtid_list := msv$con_access_gtid_list^.forward_link;
        FREE deleted_node IN osv$task_shared_heap^;
      ELSE
        before_deleted_node^.forward_link := deleted_node^.forward_link;
        FREE deleted_node IN osv$task_shared_heap^;
      IFEND;
{Debug
      IF cmv$task_reserved_element_count < 1 THEN
        pmp$get_job_names (user_job_name, job_name, local_status);
        STRINGREP (str, i, 'cmv$task_reserved_element_count underrun by ', job_name);
        dpp$put_critical_message (str (1, i), local_status);
        cmv$task_reserved_element_count := cmv$task_reserved_element_count + 1;
      IFEND;
{Debug End
      cmv$task_reserved_element_count := cmv$task_reserved_element_count - 1;
{D} STRINGREP (str, i, 'PP cmv$task_reserved_element_count: ', cmv$task_reserved_element_count);
{D} dpp$put_critical_message (str (1, i), local_status);
    IFEND;

  PROCEND msp$delete_con_access_gtid;
?? OLDTITLE ??
?? NEWTITLE := '  msp$validate_media_access', EJECT ??

*copyc msh$validate_media_access

  PROCEDURE [XDCL, #GATE] msp$validate_media_access
    (    storage_device: cmt$element_name;
         access: mst$access_type;
     VAR status: ost$status);

    VAR
      avt_entry_not_found: boolean,
      caller_id: ost$caller_identifier,
      capability: boolean,
      cm_unit_type: cmt$unit_type,
      definition: cmt$element_definition,
      element_descriptor: cmt$element_descriptor,
      element_info: array [1 .. 1] of cmt$element_info_item,
      element_reservation: cmt$element_reservation,
      found: boolean,
      io_unit_type: iot$unit_type,
      job_name: jmt$system_supplied_name,
      job_found: boolean,
      lun: iot$logical_unit,
      privileged_job: boolean,
      peripheral_index: integer,
      recorded_vsn: rmt$recorded_vsn,
      set_name: stt$set_name,
      search_key: dmt$avt_search_key,
      unit_class: cmt$unit_class,
      user_job_name: jmt$user_supplied_name,
      volume_info: stt$volume_info;

    #CALLER_ID (caller_id);
    status.normal := TRUE;

    avp$get_capability (avc$engineering_operation, avc$user, capability, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF NOT capability THEN
      IF caller_id.ring > 6 THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
              'MSP$VALIDATE_MEDIA_ACCESS', status);
        RETURN; {----->
      IFEND;
    IFEND;

    pmp$get_job_names (user_job_name, job_name, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    element_descriptor.element_type := cmc$storage_device_element;
    element_descriptor.peripheral_descriptor.use_logical_identification := TRUE;
    element_descriptor.peripheral_descriptor.element_name := storage_device;

    cmp$get_element_definition (element_descriptor, definition, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF element_descriptor.element_type <> definition.element_type THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$element_not_storage_device,
            'MSP$VALIDATE_MEDIA_ACCESS', status);
      RETURN; {----->
    IFEND;

    element_info [1].selector := cmc$device_class;
    cmp$get_element_information (element_descriptor, element_info, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    IF element_info [1].item_returned THEN
      IF element_info [1].device_class <> rmc$mass_storage_device THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$mass_device_required, storage_device,
              status);
        RETURN; {----->
      IFEND;
    IFEND;
    cmp$search_peripheral_table (element_descriptor, element_reservation, FALSE, peripheral_index, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    lun := cmv$peripheral_element_table.pointer^ [peripheral_index].logical_unit_number;

    { Check if element already RESERVED to any job }

    IF (cmv$peripheral_element_table.pointer^ [peripheral_index].entry_interlock)
{   } AND (cmv$peripheral_element_table.pointer^ [peripheral_index].reserved_status) THEN
      osp$set_status_abnormal (msc$maintenance_services_id, cme$element_already_reserved,
            cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
      RETURN; {----->
    IFEND;

    { Check if element already ASSIGNED to any job. Mass storage device can not assigned ??? }
    IF (lun <> 0) AND (cmv$logical_unit_table^ [lun].status.assignable_device)
{   } AND (cmv$logical_unit_table^ [lun].status.assigned) THEN
      osp$set_status_abnormal (msc$maintenance_services_id, mse$element_already_assigned,
            cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
      osp$append_status_parameter (osc$status_parameter_delimiter,
            cmv$logical_unit_table^ [lun].status.assigned_jsn, status);
      RETURN; {----->
    IFEND;


    CASE access OF
    = msc$concurrent_access =

      { Check if element is not in ON or DOWN state }

      IF cmv$peripheral_element_table.pointer^ [peripheral_index].element_status.state = cmc$off THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$element_state_not_proper,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        RETURN; {----->
      IFEND;

{ Check to see if MASS storage device is the object of either CONCURRENT or DEDICATED maintenance. }
      CASE cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.access OF
      = msc$dedicated_access =
        IF (cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.dedicated_accessor.
              active) AND (cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.
              dedicated_accessor.job_identification <> job_name) THEN
          osp$set_status_abnormal (cmc$configuration_management_id, mse$dedicated_access_granted,
                cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, cmv$peripheral_element_table.
                pointer^ [peripheral_index].maintenance_activity.dedicated_accessor.job_identification,
                status);
          RETURN; {----->
        IFEND;

      = msc$concurrent_access =
        msp$search_con_access_job (peripheral_index, job_name, job_found, status);
        IF NOT job_found THEN
          osp$set_status_abnormal (cmc$configuration_management_id, mse$req_maint_access_required,
                cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
          RETURN; {----->
        IFEND;

      CASEND;

    = msc$dedicated_access =
{ NOTE : DEDICATED access will only GRANTED to media which does NOT have valid CUSTOMER or SYSTEM
{        data recorded on it. }


{ Check if element is not in DOWN state }
      IF cmv$peripheral_element_table.pointer^ [peripheral_index].element_status.state <> cmc$down THEN
        osp$set_status_abnormal (msc$maintenance_services_id, mse$element_state_not_proper,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        RETURN; {----->
      IFEND;

{ Check to see if MASS storage device is the object of DEDICATED maintenance. }
      IF cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.access =
            msc$dedicated_access THEN
        IF (cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.dedicated_accessor.
              active) AND (cmv$peripheral_element_table.pointer^ [peripheral_index].maintenance_activity.
              dedicated_accessor.job_identification <> job_name) THEN
          osp$set_status_abnormal (cmc$configuration_management_id, mse$dedicated_access_granted,
                cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, cmv$peripheral_element_table.
                pointer^ [peripheral_index].maintenance_activity.dedicated_accessor.job_identification,
                status);
          RETURN; {----->
        IFEND;
      ELSE
        osp$set_status_abnormal (cmc$configuration_management_id, mse$req_maint_access_required,
              cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
        RETURN; {----->
      IFEND;

      { Check if media MOUNTED which is NOT a member of an active NOS/VE mass storage set. }
      { If it is a member, media access is DENIED. However, CE may ask OPERATOR to delete }
      { member from the set to allow DEDICATED access to the media. }

      search_key.value := dmc$search_avt_by_lun;
      search_key.logical_unit_number := lun;
      cmp$search_active_volume_table (search_key, recorded_vsn, avt_entry_not_found);
      IF NOT avt_entry_not_found THEN
        stp$get_volumes_set_name (recorded_vsn, set_name, status);
        IF NOT status.normal THEN
          { This is a normal status }
          status.normal := TRUE;
          RETURN; {----->
        IFEND;

        stp$is_volume_in_set (recorded_vsn, set_name, volume_info, status);
        IF status.normal THEN
          osp$set_status_abnormal (msc$maintenance_services_id, mse$media_is_member_of_set,
                cmv$peripheral_element_table.pointer^ [peripheral_index].element_name, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, recorded_vsn, status);
          osp$append_status_parameter (osc$status_parameter_delimiter, set_name, status);
          RETURN; {----->
        ELSE
          status.normal := TRUE;
        IFEND;
      IFEND;
    CASEND;

{ SUCCESSFUL attempts to obtain maintenance access to media which has CUSTOMER data on it will be
{ logged in the ENGINEERING log. }

  PROCEND msp$validate_media_access;
?? OLDTITLE ??
?? NEWTITLE := '  Ring 3 helper for MAINTENANCE_SERVICES_UTILITY', ??

  PROCEDURE [XDCL, #GATE] msp$mount_storage_medium
    (    storage_device: cmt$peripheral_descriptor;
         medium: rmt$external_vsn;
         write_access: boolean;
         wait_for_attachment: fst$wait_for_attachment;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    IF caller_id.ring > 6 THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
            'MSP$MOUNT_STORAGE_MEDIUM', status);
      RETURN; {----->
    IFEND;
    status.normal := TRUE;
    cmp$mount_storage_medium (storage_device, medium, write_access, wait_for_attachment, status);

  PROCEND msp$mount_storage_medium;

  PROCEDURE [XDCL, #GATE] msp$reserve_element
    (VAR {input,output} element: array [ * ] of cmt$element_reservation;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    IF caller_id.ring > 6 THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
            'MSP$RESERVE_ELEMENT', status);
      RETURN; {----->
    IFEND;

    status.normal := TRUE;
    cmp$reserve_element (element, status);

  PROCEND msp$reserve_element;

  PROCEDURE [XDCL, #GATE] msp$release_element
    (    element: array [ * ] of cmt$element_reservation;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    IF caller_id.ring > 6 THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
            'MSP$RELEASE_ELEMENT', status);
      RETURN; {----->
    IFEND;

    status.normal := TRUE;
    cmp$release_element (element, status);

  PROCEND msp$release_element;

  PROCEDURE [XDCL, #GATE] msp$execute_pp_program
    (VAR program_description: array [1 .. * ] of cmt$pp_program_description;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    IF caller_id.ring > 6 THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
            'MSP$EXECUTE_PP_PROGRAM', status);
      RETURN; {----->
    IFEND;
    status.normal := TRUE;
    cmp$execute_pp_program (program_description, status);

  PROCEND msp$execute_pp_program;

  PROCEDURE [XDCL, #GATE] msp$idle_pp
    (    pp_identification: cmt$pp_identification;
         break_interlocks: boolean;
         hardware_idle_pp: boolean;
         pp_memory_area: ^SEQ ( * );
     VAR actual_pp_memory_size: cmt$pp_memory_length;
     VAR pp_registers: cmt$pp_registers;
     VAR pp_software_idled: boolean;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    IF caller_id.ring > 6 THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
            'MSP$EXECUTE_PP_PROGRAM', status);
      RETURN; {----->
    IFEND;
    status.normal := TRUE;
    cmp$idle_pp (pp_identification, break_interlocks, hardware_idle_pp, pp_memory_area, actual_pp_memory_size,
          pp_registers, pp_software_idled, status);

  PROCEND msp$idle_pp;


  PROCEDURE [XDCL, #GATE] msp$resume_pp
    (    pp_identification: cmt$pp_identification;
         hardware_resume_pp: boolean;
         start_address: cmt$pp_memory_length;
     VAR pp_software_resumed: boolean;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    IF caller_id.ring > 6 THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required, 'MSP$RESUME_PP',
            status);
      RETURN; {----->
    IFEND;
    status.normal := TRUE;
    cmp$resume_pp (pp_identification, hardware_resume_pp, start_address, pp_software_resumed, status);

  PROCEND msp$resume_pp;

  PROCEDURE [XDCL, #GATE] msp$get_pp_registers
    (    pp_identification: cmt$pp_identification;
     VAR pp_registers: cmt$pp_registers;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier;

    #CALLER_ID (caller_id);
    IF caller_id.ring > 6 THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$privileged_job_required,
            'MSP$GET_PP_REGISTERS', status);
      RETURN; {----->
    IFEND;

    status.normal := TRUE;
    cmp$get_pp_registers (pp_identification, pp_registers, status);

  PROCEND msp$get_pp_registers;
MODEND msm$request_maintenance_access;


