?? TITLE := 'NOS/VE Subsystem IO' ??
MODULE iom$subsystem_io_r236;
?? RIGHT := 110 ??
{
{  PURPOSE: This module contains the ring 236 code to support subsystem io.
{
{  DESIGN:
{
?? TITLE := '  Declarations', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$mainframe_paged_literal
*copyc oss$mainframe_wired
*copyc oss$task_private
*copyc cme$physical_configuration_mgr
*copyc ioe$st_errors
*copyc cmt$io_commands
*copyc cmt$subsystem_io_request_id
*copyc jmt$name
*copyc ost$execution_control_block
*copyc ost$system_flag
*copyc pmt$task_id
?? POP ??
*copyc cmp$add_ssiot_entry_avail_queue
*copyc cmp$build_wired_queue_request
*copyc cmp$check_io_status
*copyc cmp$clear_ioct_serial_lock
*copyc cmp$destroy_io_completion_tb_r2
*copyc cmp$down_foreign_io
*copyc cmp$enable_foreign_io
*copyc cmp$get_element_information
*copyc cmp$get_io_completion_tbl_entry
*copyc cmp$get_logical_pp_number
*copyc cmp$get_number_of_io_entries
*copyc cmp$get_ssiot_entry_avail_queue
*copyc cmp$get_subsys_equip_desc_r1
*copyc cmp$get_unit_type
*copyc cmp$hardware_idle_pp
*copyc cmp$pc_get_element
*copyc cmp$queue_request_r1
*copyc cmp$set_ioct_serial_lock
*copyc cmp$ssiot_end_handler
*copyc cmp$ssiot_recovery_complete
*copyc cmp$ssiot_recovery_condition
*copyc cmp$ssiot_termination
*copyc cmp$store_ssiot_entry_info
*copyc cmp$test_and_clear_ioct_lock
*copyc cmp$update_error_count
*copyc iop$clear_response_ptr
*copyc iop$return_wired_request
*copyc iop$set_status_abnormal
*copyc jmp$job_exists
*copyc mmp$fetch_segment_attributes
*copyc mmp$verify_access
*copyc osp$fetch_locked_variable
*copyc osp$set_locked_variable
*copyc pmp$cause_task_condition
*copyc pmp$continue_to_cause
*copyc pmp$disestablish_cond_handler
*copyc pmp$disestablish_end_handler
*copyc pmp$establish_condition_handler
*copyc pmp$establish_end_handler
*copyc pmp$format_compact_time
*copyc pmp$get_executing_task_gtid_r6
*copyc pmp$get_time
*copyc pmp$log
*copyc pmp$long_term_wait
*copyc pmp$wait
*copyc cmv$logical_pp_table_p
*copyc cmv$subsys_io_responses
*copyc cmv$subsys_io_scan_variable
*copyc osv$page_size
?? TITLE := '  Global Variables', EJECT ??

  VAR
    data_descriptor_error_msg: [STATIC, READ, oss$mainframe_paged_literal] string (100) :=
          'IOMSSIOR236 Data Descriptor Entry - ',
    command_code_error_msg: [STATIC, READ, oss$mainframe_paged_literal] string (100) :=
          'IOMSSIOR236 Command Code Entry - ',
    job_recovery_condition: [STATIC, READ, oss$mainframe_paged_literal] pmt$condition :=
          [pmc$user_defined_condition, 'OSC$JOB_RECOVERY'],
    interactive_terminate_condition: [STATIC, READ, oss$mainframe_paged_literal] pmt$condition :=
          [ifc$interactive_condition, ifc$terminate_break],
    task_end_handler_established: [STATIC, oss$task_private] boolean := FALSE;

*if $true(osv$debug_code)
  VAR
    cmv$free_trap: [XREF] boolean;
*ifend

?? TITLE := '  [XDCL, #GATE] cmp$check_initiated_io_status', EJECT ??

*copyc cmh$check_initiated_io_status
*copyc iop$get_in_out_ptrs


  PROCEDURE [XDCL, #GATE] cmp$check_initiated_io_status
    (    io_status_p: ^cmt$subsystem_io_status;
     VAR index: integer;
     VAR status: ost$status);

    VAR
      io_completed: boolean,
      number_of_ssio_table_entries: cmt$io_completion_queue_index,
      global_task_id: ost$global_task_id,
      subsystem_io_request_id: cmt$subsystem_io_request_id,
      io_completion_table_entry_p: ^cmt$io_completion_table_entry,
      io_status_index: integer,
      job_completion_queue_index: cmt$io_completion_queue_index,
      io_status: cmt$subsystem_io_completion_sta,
      ignore_status: ost$status;






  /process_request/
    BEGIN
      status.normal := TRUE;
      index := 0;

      pmp$get_executing_task_gtid_r6 (global_task_id);

      iop$mfh_subsystem_io_completion (ioc$subsystem_io_completed);

      IF io_status_p <> NIL THEN

      /io_status_loop/
        FOR io_status_index := 1 TO UPPERBOUND (io_status_p^) DO

          subsystem_io_request_id := io_status_p^ [io_status_index].request_identification;
          job_completion_queue_index := subsystem_io_request_id.system_supplied;

          cmp$get_io_completion_tbl_entry (job_completion_queue_index, io_completion_table_entry_p);

          io_status := io_completion_table_entry_p^.io_status;

          IF io_completion_table_entry_p^.available THEN
            io_status_p^ [io_status_index].completion_status := io_status;
            CYCLE /io_status_loop/; {----->
          IFEND;

          IF io_completion_table_entry_p^.global_task_id <> global_task_id THEN
            iop$set_status_abnormal (ioe$request_id_mismatch,
                  'Request id not available to current task - IOMSSIOR236', status);
            index := io_status_index;
            EXIT /process_request/; {----->
          IFEND;

          IF io_completion_table_entry_p^.request_identification <> subsystem_io_request_id THEN
            iop$set_status_abnormal (ioe$request_id_mismatch, 'Mismatch in request ids - IOMSSIOR236',
                  status);
            index := io_status_index;
            EXIT /process_request/; {----->
          IFEND;


          io_status_p^ [io_status_index].completion_status := io_status;

          io_completed := (io_status = cmc$subsystem_io_complete);
          IF io_completed THEN
            IF index <= 0 THEN
              index := io_status_index;
            IFEND;
          IFEND;
        FOREND /io_status_loop/;

      ELSE
        cmp$get_number_of_io_entries (number_of_ssio_table_entries);

        FOR job_completion_queue_index := 1 TO number_of_ssio_table_entries DO
          cmp$get_io_completion_tbl_entry (job_completion_queue_index, io_completion_table_entry_p);
          IF NOT io_completion_table_entry_p^.available THEN
            IF io_completion_table_entry_p^.global_task_id = global_task_id THEN
              io_status := io_completion_table_entry_p^.io_status;
              io_completed := (io_status = cmc$subsystem_io_complete);
              IF io_completed THEN
                IF index <= 0 THEN
                  index := job_completion_queue_index;
                IFEND;

              IFEND;
            IFEND;
          IFEND;
        FOREND;
      IFEND;

    END /process_request/;

  PROCEND cmp$check_initiated_io_status;
?? TITLE := '  [XDCL, #GATE] cmp$complete_ssiot_recovery', EJECT ??

*copyc cmh$complete_ssiot_recovery

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


    status.normal := TRUE;
    cmp$ssiot_recovery_complete (status);

  PROCEND cmp$complete_ssiot_recovery;
?? TITLE := '  [XDCL, #GATE] cmp$create_and_submit_io_req', EJECT ??

*copyc cmh$create_and_submit_io_req

  PROCEDURE [XDCL, #GATE] cmp$create_and_submit_io_req
    (    request_type: cmt$io_request_type;
         element_name: cmt$element_name;
         command_table_p: ^cmt$io_command_table;
         data_command_descriptors_p: ^cmt$data_command_descriptors;
         unit_queue_control: cmt$unit_queuing_options;
         recovery_options: iot$request_recovery;
         wait_for_io_completion: cmt$wait_for_io_completion;
         io_identification: cmt$user_io_identification;
         io_response_p: ^cmt$os_subsystem_io_response;
     VAR request_id: cmt$subsystem_io_request_id;
     VAR status: ost$status);

    VAR
      logical_pp_number: iot$pp_number,
      cmv$foreign_interface_down: [XREF] boolean,
      ignore_status: ost$status;


    status.normal := TRUE;

    IF cmv$foreign_interface_down THEN
      cmp$get_logical_pp_number (element_name, logical_pp_number, status);
      IF status.condition = cme$pc_not_logically_conf THEN
        iop$set_status_abnormal (ioe$foreign_interface_down, 'Subsystem PP not available', status);
        RETURN; {----->
      ELSE
        cmp$enable_foreign_io (status);
      IFEND;
    IFEND;


  /process_request/
    BEGIN

      cmp$create_io_request (request_type, element_name, command_table_p, data_command_descriptors_p,
            io_identification, io_response_p, request_id, status);
      IF NOT status.normal THEN
        EXIT /process_request/; {----->
      IFEND;

      cmp$queue_io_request (request_id, unit_queue_control, recovery_options, wait_for_io_completion, status);
      IF NOT status.normal THEN
        cmp$destroy_io_request (request_id, ignore_status);
      IFEND;

    END /process_request/;


  PROCEND cmp$create_and_submit_io_req;

?? TITLE := '  [XDCL, #GATE] cmp$create_io_request', EJECT ??

*copyc cmh$create_io_request

  PROCEDURE [XDCL, #GATE] cmp$create_io_request
    (    request_type: cmt$io_request_type;
         element_name: cmt$element_name;
         command_table_p: ^cmt$io_command_table;
         data_command_descriptors_p: ^cmt$data_command_descriptors;
         io_identification: cmt$user_io_identification;
         io_response_p: ^cmt$os_subsystem_io_response;
     VAR request_id: cmt$subsystem_io_request_id;
     VAR status: ost$status);

    VAR
      data_descriptor_index: integer,
      data_pva_p: ^cell,
      data_length: cmt$data_descriptor_length,
      command_index: cmt$command_index,
      command_code: cmt$command_code,
      lock_data_pages: boolean,
      verify_access_mode: boolean,
      data_cannot_span_pages: boolean,
      request_id_to_terminate_p: ^cmt$subsystem_io_request_id,
      io_completion_table_entry_p: ^cmt$io_completion_table_entry,
      iou_name: cmt$element_name,
      access_mode: mmt$va_access_mode,
      ssiot_entry_information_p: ^cmt$ssiot_entry_information,
      ssiot_entry_timing_info_p: ^cmt$ssiot_entry_information,
      time_format: ost$time_formats,
      time: ost$time,
      move_data_to_wired_area: boolean,
      move_data_from_wired_area: boolean,
      need_to_lock_data_descriptors: boolean,
      computed_io_direction: cmt$io_direction,
      io_direction: cmt$io_direction,
      job_completion_queue_index: cmt$io_completion_queue_index,
      product_identification: cmt$product_identification,
      element_information_p: ^cmt$element_information,
      element_descriptor: cmt$element_descriptor,
      last_element_name: [STATIC] cmt$element_name := ' ',
      cm_unit_type: [STATIC] cmt$unit_type,
      command_sequence: boolean,
      sequence_of_commands_allowed: boolean,
      unit_command_sequence: boolean,
      io_unit_type: [STATIC] iot$unit_type,
      verify_not_code_segment: boolean,
      verify_wired_cache_bypass_seg: boolean,
      number_of_ioct_entries: cmt$io_completion_queue_index,
      segment_attributes_p: ^array [ * ] of mmt$attribute_descriptor,
      unit_class: [STATIC] cmt$unit_class,
      number_of_commands: cmt$command_index,
      element_found: [STATIC] boolean,
      data_descriptor_error: string (100),
      command_code_error: string (100),
      element: ^cmt$element_definition,
      conversion_length: integer,
      ignore_status: ost$status;


    status.normal := TRUE;

  /process_request/
    BEGIN
      need_to_lock_data_descriptors := FALSE;

      io_response_p^.io_status := $INTEGER (cmc$subsys_io_resp_not_avail);

      IF NOT task_end_handler_established THEN
        pmp$establish_end_handler (^cmp$subsystem_io_end_handler, status);
        IF NOT status.normal THEN
          EXIT /process_request/; {----->
        IFEND;
        task_end_handler_established := TRUE;
      IFEND;

      IF element_name <> last_element_name THEN
        element := NIL;
        cmp$pc_get_element (element_name, {not used} iou_name, element, status);
        IF NOT status.normal THEN
          iop$set_status_abnormal (ioe$unable_to_build_io_request,
                'Subsystem io not defined for element - IOMSSIOR236', status);
          EXIT /process_request/; {----->
        IFEND;
        IF element <> NIL THEN
          last_element_name := element_name;
          product_identification := element^.product_id;

          cmp$get_unit_type (product_identification, cm_unit_type, io_unit_type, unit_class, element_found);
        ELSE
          iop$set_status_abnormal (ioe$unable_to_build_io_request,
                'Subsystem io not defined for element - IOMSSIOR236', status);
          EXIT /process_request/; {----->
        IFEND;
      IFEND;

      IF (NOT element_found) AND (io_unit_type <> ioc$dt_foreign_device) AND
            (unit_class <> cmc$network_unit) THEN
        iop$set_status_abnormal (ioe$unable_to_build_io_request,
              'Subsystem io not defined for element - IOMSSIOR236', status);
        EXIT /process_request/; {----->
      IFEND;

      IF (unit_class <> cmc$map_unit) AND (io_unit_type <> ioc$dt_foreign_device) AND
            (unit_class <> cmc$network_unit) THEN

        iop$set_status_abnormal (ioe$unable_to_build_io_request,
              'Subsystem io not defined for element - IOMSSIOR236', status);
        EXIT /process_request/; {----->
      IFEND;

      cmp$ssiot_recovery_condition (status);
      IF NOT status.normal THEN
        EXIT /process_request/; {----->
      IFEND;

      request_id.system_supplied := 0;
      request_id.user_supplied := 0;

      PUSH ssiot_entry_information_p: [1 .. 1];

      PUSH segment_attributes_p: [1 .. 2];
      segment_attributes_p^ [1].keyword := mmc$kw_hardware_attributes;
      segment_attributes_p^ [2].keyword := mmc$kw_software_attributes;

      CASE request_type OF
      = cmc$pp_io, cmc$unit_io =
      ELSE
        iop$set_status_abnormal (ioe$unable_to_build_io_request, 'Unsupported io request type - IOMSSIOR236',
              status);
        EXIT /process_request/; {----->
      CASEND;

      IF io_response_p = NIL THEN
        iop$set_status_abnormal (ioe$unable_to_build_io_request,
              'Subsystem response not specified - IOMSSIOR236', status);
        EXIT /process_request/; {----->
      IFEND;


      IF command_table_p = NIL THEN
        iop$set_status_abnormal (ioe$unable_to_build_io_request,
              'IO command table not specified - IOMSSIOR236', status);
        EXIT /process_request/; {----->
      IFEND;

      number_of_commands := UPPERBOUND (command_table_p^);
      sequence_of_commands_allowed := TRUE;
      command_sequence := FALSE;
      unit_command_sequence := TRUE;


      cmp$get_ssiot_entry_avail_queue (job_completion_queue_index);
      IF job_completion_queue_index = 0 THEN
        iop$set_status_abnormal (ioe$unable_to_build_io_request,
              'Unable to get job completion queue entry - IOMSSIOR236', status);
        EXIT /process_request/; {----->
      IFEND;

      request_id.system_supplied := job_completion_queue_index;
      request_id.user_supplied := io_identification;

      cmp$build_wired_queue_request (element_name, request_type, command_table_p, data_command_descriptors_p,
            request_id, io_response_p, status);
      IF NOT status.normal THEN
        ssiot_entry_information_p^ [1].keyword := cmc$ssiote_io_status;
        ssiot_entry_information_p^ [1].io_status := cmc$subsystem_io_not_active;
        cmp$store_ssiot_entry_info (job_completion_queue_index, ssiot_entry_information_p, ignore_status);
        cmp$add_ssiot_entry_avail_queue (job_completion_queue_index);

        request_id.system_supplied := 0;
        request_id.user_supplied := 0;
        EXIT /process_request/; {----->
      IFEND;


      ssiot_entry_information_p^ [1].keyword := cmc$ssiote_request_id;
      ssiot_entry_information_p^ [1].request_id := request_id;
      ssiot_entry_information_p^ [1].subsystem_response_p := io_response_p;
      ssiot_entry_information_p^ [1].data_command_descriptors_p := data_command_descriptors_p;
      cmp$store_ssiot_entry_info (job_completion_queue_index, ssiot_entry_information_p, ignore_status);

    END /process_request/;


  PROCEND cmp$create_io_request;

?? TITLE := '  [XDCL,#GATE] cmp$destroy_io_completion_table', EJECT ??

*copyc cmh$destroy_io_completion_table

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


    status.normal := TRUE;

  /process_request/
    BEGIN

      cmp$ssiot_recovery_condition (status);
      IF status.normal THEN
        cmp$destroy_io_completion_tb_r2 (status);
        IF status.normal THEN
          IF task_end_handler_established THEN
            pmp$disestablish_end_handler (^cmp$subsystem_io_end_handler, status);
            task_end_handler_established := FALSE;
          IFEND;
        IFEND;
      IFEND;

    END /process_request/;


  PROCEND cmp$destroy_io_completion_table;
?? TITLE := '  [XDCL, #GATE] cmp$destroy_io_request', EJECT ??

*copyc cmh$destroy_io_request

  PROCEDURE [XDCL, #GATE] cmp$destroy_io_request
    (VAR request_id: cmt$subsystem_io_request_id;
     VAR status: ost$status);

    VAR
      actual_pp_memory_size: cmt$pp_memory_length,
      logical_pp_number: iot$pp_number,
      physical_pp: dst$iou_resource,
      pp_registers: cmt$pp_registers,
      time_format: ost$time_formats,
      time: ost$time,
      user_id: string (8),
      user_id_length: integer,
      request_created_p: ^pmt$log_msg_text,
      request_queued_p: ^pmt$log_msg_text,
      request_entered_mtr_p: ^pmt$log_msg_text,
      request_queued_by_mtr_p: ^pmt$log_msg_text,
      request_destroyed_p: ^pmt$log_msg_text,
      response_seen_by_mtr_p: ^pmt$log_msg_text,
      response_sent_to_job_by_mtr_p: ^pmt$log_msg_text,
      response_received_p: ^pmt$log_msg_text,
      response_returned_p: ^pmt$log_msg_text,
      io_completion_queue_index: cmt$io_completion_queue_index,
      io_completion_table_entry_p: ^cmt$io_completion_table_entry;

    status.normal := TRUE;

  /process_request/
    BEGIN
      user_id := ' ';

      cmp$ssiot_recovery_condition (status);
      IF NOT status.normal THEN
        EXIT /process_request/; {----->
      IFEND;

      io_completion_queue_index := request_id.system_supplied;
      cmp$get_io_completion_tbl_entry (io_completion_queue_index, io_completion_table_entry_p);

      IF io_completion_table_entry_p^.available THEN
        request_id.system_supplied := 0;
        EXIT /process_request/; {----->
      IFEND;

      IF io_completion_table_entry_p^.request_identification <> request_id THEN
        iop$set_status_abnormal (ioe$unable_to_destroy_io_req, 'Request id mismatch - IOMSSIOR236', status);
        EXIT /process_request/; {----->
      IFEND;


      IF io_completion_table_entry_p^.io_status <> cmc$subsystem_io_complete THEN

        cmp$get_logical_pp_number (io_completion_table_entry_p^.io_request_type.element_name,
              logical_pp_number, status);
        IF NOT status.normal THEN
          EXIT /process_request/; {----->
        IFEND;

        { Hardware idle the PP first.

        IF cmv$logical_pp_table_p^ [logical_pp_number].flags.pp_loaded THEN
          physical_pp := cmv$logical_pp_table_p^ [logical_pp_number].pp_info.physical_pp;
          cmp$hardware_idle_pp (physical_pp, FALSE, FALSE, NIL, actual_pp_memory_size, pp_registers, status);
          IF NOT status.normal THEN
            EXIT /process_request/; {----->
          IFEND;
        IFEND;
      IFEND;

      cmp$add_ssiot_entry_avail_queue (request_id.system_supplied);

      request_id.system_supplied := 0;
    END /process_request/;

  PROCEND cmp$destroy_io_request;
?? TITLE := '  [XDCL, #GATE] cmp$get_subsys_equipment_desc', EJECT ??

*copyc cmh$get_subsys_equipment_desc

  PROCEDURE [XDCL, #GATE] cmp$get_subsys_equipment_desc
    (    pp_number: iot$pp_number;
         logical_unit: iot$logical_unit;
     VAR equipment_description: cmt$subsystem_equip_description;
     VAR status: ost$status);

    status.normal := TRUE;

    cmp$get_subsys_equip_desc_r1 (pp_number, logical_unit, equipment_description, status);

  PROCEND cmp$get_subsys_equipment_desc;
?? TITLE := '  [XDCL, #GATE] cmp$initiated_job_status', EJECT ??

*copyc cmh$initiated_job_status

  PROCEDURE [XDCL, #GATE] cmp$initiated_job_status
    (    job_name: jmt$name;
     VAR job_executing: boolean);

    VAR
      job_exists: boolean,
      job_state_set: jmt$job_state_set,
      local_status: ost$status,
      name: ost$name;

    local_status.normal := TRUE;
    job_executing := FALSE;

    job_state_set := $jmt$job_state_set [jmc$initiated_job, jmc$terminating_job];
    IF job_name.kind = jmc$system_supplied_name THEN
      name := job_name.system_supplied_name;
    ELSE
      name := job_name.user_supplied_name;
    IFEND;

    jmp$job_exists (name, job_state_set, job_exists, local_status);
    job_executing := job_exists AND local_status.normal;
  PROCEND cmp$initiated_job_status;
?? TITLE := '  [XDCL, #GATE] cmp$queue_io_request', EJECT ??

*copyc cmh$queue_io_request

  PROCEDURE [XDCL, #GATE] cmp$queue_io_request
    (VAR request_id: cmt$subsystem_io_request_id;
         queue_control: cmt$unit_queuing_options;
         recovery_options: iot$request_recovery;
         wait_for_io_completion: cmt$wait_for_io_completion;
     VAR status: ost$status);

    VAR
      user_io_status: integer,
      caller_io_response_p: ^cmt$os_subsystem_io_response,
      wired_pp_response_p: ^cmt$collected_pp_response,
      ssiot_entry_information_p: ^cmt$ssiot_entry_information,
      ssiot_entry_timing_info_p: ^cmt$ssiot_entry_information,
      job_completion_queue_index: cmt$io_completion_queue_index,
      job_recovery_handler_in_effect: boolean,
      io_completion_table_entry_p: ^cmt$io_completion_table_entry,
      terminal_condition_descriptor_p: ^pmt$established_handler,
      io_response_available: boolean,
      io_request: cmt$io_request,
      try_count: integer,
      starting_wait_time: ost$free_running_clock,
      requested_wait_time: ost$free_running_clock,
      elapsed_wait_time: ost$free_running_clock,
      time_format: ost$time_formats,
      time: ost$time,
      ignore_status: ost$status;


    PROCEDURE cmp$job_recovery_handler
      (    job_recovery_condition: pmt$condition;
           condition_descriptor_p: ^pmt$condition_information;
           save_area_p: ^ost$stack_frame_save_area;
       VAR status: ost$status);

      status.normal := TRUE;
      pmp$continue_to_cause (pmc$execute_standard_procedure, status);

    PROCEND cmp$job_recovery_handler;

    PROCEDURE cmp$interactive_handler
      (    interactive_condition: pmt$condition;
           condition_descriptor_p: ^pmt$condition_information;
           save_area_p: ^ost$stack_frame_save_area;
       VAR status: ost$status);

      status.normal := TRUE;
      pmp$continue_to_cause (pmc$execute_standard_procedure, status);

    PROCEND cmp$interactive_handler;

    status.normal := TRUE;

  /process_request/
    BEGIN
      PUSH terminal_condition_descriptor_p;

      cmp$ssiot_recovery_condition (status);
      IF NOT status.normal THEN
        EXIT /process_request/; {----->
      IFEND;

      job_completion_queue_index := request_id.system_supplied;
      PUSH ssiot_entry_information_p: [1 .. 2];

      cmp$get_io_completion_tbl_entry (job_completion_queue_index, io_completion_table_entry_p);

      IF io_completion_table_entry_p^.request_identification <> request_id THEN
        iop$set_status_abnormal (ioe$unable_to_queue_io_request, 'Request id mismatch - IOMSSIOR236', status);
        EXIT /process_request/; {----->
      IFEND;

      wired_pp_response_p := io_completion_table_entry_p^.wired_unit_queue_request_p^.wired_pp_response_p;
      caller_io_response_p := io_completion_table_entry_p^.subsystem_response_p;
      io_request := io_completion_table_entry_p^.io_request_type;


      ssiot_entry_information_p^ [1].keyword := cmc$ssiote_io_status;
      ssiot_entry_information_p^ [1].io_status := cmc$subsystem_io_started;
      ssiot_entry_information_p^ [2].keyword := cmc$ssiote_wait_for_io_complete;
      ssiot_entry_information_p^ [2].wait_for_io_completion := wait_for_io_completion;

      cmp$store_ssiot_entry_info (job_completion_queue_index, ssiot_entry_information_p, ignore_status);

      job_recovery_handler_in_effect := FALSE;

      cmp$queue_request_r1 (request_id, queue_control, recovery_options,
            wait_for_io_completion.wait_for_io_completion, status);

      IF job_recovery_handler_in_effect THEN
        pmp$disestablish_cond_handler (job_recovery_condition, ignore_status);
      IFEND;

      IF NOT status.normal THEN
        ssiot_entry_information_p^ [1].io_status := cmc$subsystem_io_not_active;
        ssiot_entry_information_p^ [2].keyword := cmc$ssiote_null_entry;

        cmp$store_ssiot_entry_info (job_completion_queue_index, ssiot_entry_information_p, ignore_status);
        EXIT /process_request/; {----->
      IFEND;

      starting_wait_time := #FREE_RUNNING_CLOCK (0); {us}


      IF wait_for_io_completion.wait_for_io_completion THEN
        pmp$establish_condition_handler (interactive_terminate_condition, ^cmp$interactive_handler,
              terminal_condition_descriptor_p, status);
        IF NOT status.normal THEN
          EXIT /process_request/; {----->
        IFEND;

        requested_wait_time := wait_for_io_completion.requested_wait_time;
        elapsed_wait_time := 0;
        try_count := 0;

      /wait_for_response/
        REPEAT
          io_response_available := (wired_pp_response_p^.response_status = cmc$subsys_io_resp_completed);
          IF io_response_available THEN
            EXIT /wait_for_response/; {----->
          IFEND;
          IF elapsed_wait_time >= requested_wait_time THEN
            EXIT /wait_for_response/; {----->
          IFEND;
          pmp$wait (5000, 5000);
          elapsed_wait_time := elapsed_wait_time + 5000;
          cmp$check_io_status (request_id, status);
          IF NOT status.normal THEN
            IF status.condition = cme$pc_not_logically_conf THEN
              cmp$down_foreign_io (request_id, status);
            IFEND;
            EXIT /wait_for_response/; {----->
          IFEND;
        UNTIL io_response_available;

        IF io_response_available THEN
          iop$mfh_subsystem_io_completion (ioc$subsystem_io_completed);
        IFEND;

        pmp$disestablish_cond_handler (interactive_terminate_condition, ignore_status);

        osp$fetch_locked_variable (caller_io_response_p^.io_status, user_io_status);

        IF user_io_status = $INTEGER (cmc$subsys_io_resp_available) THEN
          request_id.system_supplied := 0;
        IFEND;

      IFEND;
    END /process_request/;

  PROCEND cmp$queue_io_request;
?? TITLE := '  cmp$subsystem_io_end_handler', EJECT ??

  PROCEDURE cmp$subsystem_io_end_handler
    (    termination_status: ost$status;
     VAR status: ost$status);

    status.normal := TRUE;
    cmp$ssiot_end_handler (termination_status, status);

  PROCEND cmp$subsystem_io_end_handler;
?? TITLE := '  [XDCL] iop$mfh_subsystem_io_completion', EJECT ??

*copyc ioh$mfh_subsystem_io_completion

  PROCEDURE [XDCL] iop$mfh_subsystem_io_completion
    (    flag_id: ost$system_flag);

    VAR
      last_in6: iot$response_buffer_offset,
      last_out6: iot$response_buffer_offset,
      last_in7: iot$response_buffer_offset,
      last_out7: iot$response_buffer_offset,
      active_task_count: integer,
      destroy_io_request: boolean,
      found: boolean,
      id_index: integer,
      wait_for_io_completion: boolean,
      ssiot_entry_information_p: ^cmt$ssiot_entry_information,
      ssiot_entry_timing_info_p: ^cmt$ssiot_entry_information,
      wired_unit_queue_request_p: ^cmt$wired_unit_queue_request,
      wired_pp_response_p: ^cmt$collected_pp_response,
      scan_index: integer,
      subsystem_response_p: ^cmt$os_subsystem_io_response,
      job_completion_queue_index: cmt$io_completion_queue_index,
      new_io_status: cmt$subsys_io_response_status,
      pp_response_p: ^cmt$os_subsystem_response,
      global_task_id: ost$global_task_id,
      local_status: ost$status,
      temp_gtid: ost$global_task_id,
      job_recovery_handler_in_effect: boolean,
      lock_status: ost$status,
      response_to_be_processed: boolean,
      io_response_complete_area_p: ^cmt$subsys_io_response_area,
      response_complete_flag: char,
      clear_complete_flag: char,
      cause_user_condition_for_io: boolean,
*if $true(osv$debug_code)
      stop: cell,
      kill: ^cell,
*ifend
      request_id: cmt$subsystem_io_request_id,
      new_subsystem_io_status_set: boolean,
      io_completion_table_entry_p: ^cmt$io_completion_table_entry,
      current_task_id: ost$global_task_id,
      task_list: array [0 .. 255] of ost$global_task_id,
      time_format: ost$time_formats,
      time: ost$time,
      try_count: integer,
      xcb: ^ost$execution_control_block,

      status: ost$status;


    VAR
      job_xcb_list: [XREF, oss$job_fixed] record
        head: ^ost$execution_control_block,
        lock: ost$signature_lock,
      recend;

  /process_request/
    BEGIN
      new_io_status := cmc$subsys_io_resp_available;

      PUSH ssiot_entry_information_p: [1 .. 1];
      ssiot_entry_information_p^ [1].keyword := cmc$ssiote_io_status;

      pmp$get_executing_task_gtid_r6 (global_task_id);

      cause_user_condition_for_io := FALSE;

      active_task_count := 0;
      xcb := job_xcb_list.head;
      WHILE (xcb <> NIL) AND (active_task_count < 255) DO
        task_list [active_task_count] := xcb^.global_task_id;
        active_task_count := active_task_count + 1;
        xcb := xcb^.link;
      WHILEND;


    /move_response/
      REPEAT
{    cmp$set_ioct_serial_lock (lock_status);
{     IF NOT lock_status.normal THEN
{       RETURN;
{     IFEND;

        #SCAN (cmv$subsys_io_scan_variable, cmv$subsys_io_responses_p^, scan_index, response_to_be_processed);

        IF response_to_be_processed THEN
          job_completion_queue_index := scan_index;

          cmp$get_io_completion_tbl_entry (job_completion_queue_index, io_completion_table_entry_p);

{  Check the global task id to ensure that the table entry is associated with this task.
{  If it is not, do not move the wired response, skip it and continue scanning.

          IF io_completion_table_entry_p^.global_task_id <> global_task_id THEN

{   Make sure that this task is still active in the system. If not, get rid
{   of the response.
            IF io_completion_table_entry_p^.available THEN
{   This entry is no longer in use.

              iop$clear_response_ptr (scan_index, status);
              IF NOT status.normal THEN
                RETURN; {----->
              IFEND;

{           cmv$subsys_io_responses_p^ (scan_index,1) := 'N';
              cmp$update_error_count (local_status);

*if $true(osv$debug_code)
              IF cmv$free_trap THEN
             stop := kill^;
              IFEND;
*ifend

{           cmp$clear_ioct_serial_lock (lock_status);
              CYCLE /move_response/; {----->
            IFEND;
            temp_gtid := io_completion_table_entry_p^.global_task_id;

            current_task_id := io_completion_table_entry_p^.global_task_id;
            found := FALSE;
            FOR id_index := 0 TO active_task_count DO
              IF temp_gtid = task_list [id_index] THEN
                found := TRUE;
              IFEND;
            FOREND;

            IF NOT found THEN

{  Either the task no longer lives or the
{  Completion table entry has been released by another asychronous task.  In
{  either case, ignore the response residue and continue.

              iop$clear_response_ptr (scan_index, status);
              IF NOT status.normal THEN
                RETURN; {----->
              IFEND;

{             cmv$subsys_io_responses_p^ (scan_index,1) := 'N';
              cmp$update_error_count (local_status);
            IFEND;
            {            cmp$clear_ioct_serial_lock (lock_status);
            pmp$long_term_wait (0, 0);
            CYCLE /move_response/; {----->
          IFEND;



          wired_unit_queue_request_p := io_completion_table_entry_p^.wired_unit_queue_request_p;
          wired_pp_response_p := wired_unit_queue_request_p^.wired_pp_response_p;

          ssiot_entry_information_p^ [1].io_status := cmc$subsystem_io_completing;
          cmp$store_ssiot_entry_info (job_completion_queue_index, ssiot_entry_information_p, status);

          request_id := io_completion_table_entry_p^.request_identification;
          wait_for_io_completion := io_completion_table_entry_p^.io_request_type.wait_for_io_completion.
                wait_for_io_completion;

          IF wait_for_io_completion THEN
            destroy_io_request := TRUE;
          ELSE
            destroy_io_request := io_completion_table_entry_p^.io_request_type.wait_for_io_completion.
                  destroy_io_req_upon_completion;
          IFEND;

          io_response_complete_area_p := io_completion_table_entry_p^.io_request_type.wait_for_io_completion.
                io_complete_response_p;
          response_complete_flag := io_completion_table_entry_p^.io_request_type.wait_for_io_completion.
                io_complete_flag;
          {
          { Move wired response to subsystem response area.
          {
          subsystem_response_p := io_completion_table_entry_p^.subsystem_response_p;
          pp_response_p := ^subsystem_response_p^.pp_response;
          pp_response_p^.pp_number := wired_pp_response_p^.pp_number;
          pp_response_p^.pp_response := wired_pp_response_p^.pp_response;
          subsystem_response_p^.detailed_status := wired_pp_response_p^.detailed_status;

          iop$return_wired_request (job_completion_queue_index, status);

          IF NOT wait_for_io_completion THEN
            cause_user_condition_for_io := TRUE;
          IFEND;

          ssiot_entry_information_p^ [1].io_status := cmc$subsystem_io_complete;
          cmp$store_ssiot_entry_info (job_completion_queue_index, ssiot_entry_information_p, status);

          cmp$set_subsystem_io_status (^subsystem_response_p^.io_status, new_io_status,
                new_subsystem_io_status_set);
          IF new_subsystem_io_status_set THEN
            IF (io_response_complete_area_p <> NIL) THEN
              io_response_complete_area_p^ ((request_id.user_supplied MOD
                    (STRLENGTH (io_response_complete_area_p^) + 1)), 1) := response_complete_flag;
            IFEND;


            IF destroy_io_request THEN
              cmp$destroy_io_request (request_id, status);
            IFEND;
          IFEND;

        IFEND;
{     cmp$clear_ioct_serial_lock (lock_status);

      UNTIL NOT response_to_be_processed;

      IF cause_user_condition_for_io THEN
        pmp$cause_task_condition ('SUBSYSTEM_IO_COMPLETION        ', NIL, FALSE, FALSE, FALSE, FALSE, status);
      IFEND;
    END /process_request/;

{   cmp$test_and_clear_ioct_lock (status);


  PROCEND iop$mfh_subsystem_io_completion;
?? TITLE := '  [XDCL] cmp$set_subsystem_io_status', EJECT ??

*copyc ioh$set_subsystem_io_status

  PROCEDURE [XDCL] cmp$set_subsystem_io_status
    (    io_status_p: ^cmt$subsystem_io_comp_status;
         new_subsystem_io_status: cmt$subsys_io_response_status;
     VAR new_subsystem_io_status_set: boolean);

    VAR
      last_io_status: ost$compare_swap_lock,
      current_io_status: ost$compare_swap_lock;

    new_subsystem_io_status_set := FALSE;

    osp$fetch_locked_variable (io_status_p^, current_io_status);

    REPEAT
      last_io_status := current_io_status;
      osp$set_locked_variable (io_status_p^, last_io_status, $INTEGER (new_subsystem_io_status),
            current_io_status, new_subsystem_io_status_set);
    UNTIL new_subsystem_io_status_set;

  PROCEND cmp$set_subsystem_io_status;

?? OLDTITLE ??

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

*if $true(osv$debug_code)
    VAR
      killer: cell,
      stop_it: ^cell;
*ifend
    status.normal := TRUE;
    cmp$ssiot_termination (status);

  PROCEND cmp$ssiot_termination_cleanup;

MODEND iom$subsystem_io_r236;
