?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Strange IO : Subsystem IO Processing in Monitor' ??
MODULE iom$subsystem_io_mtr_processing;
?? RIGHT := 110 ??

{ PURPOSE:
{   This module contains the monitor code to queue subsystem io requests and to process the associated
{   pp response.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$mainframe_wired_cb
*copyc oss$mainframe_wired_literal
*copyc ioe$st_errors
*copyc cmt$foreign_equipment_error_log
*copyc cmt$io_commands
*copyc cmt$physical_equipment_number
*copyc iot$disk_statistics
*copyc iot$io_request
*copyc iot$logical_unit
*copyc iot$monitor_request_block
*copyc iot$pp_interface_table
*copyc iot$pp_number
*copyc iot$pp_response
*copyc iot$unit_interface_table
*copyc iot$wired_unit_queue_request
*copyc mmt$io_type
*copyc mmt$page_frame_table
*copyc ost$hardware_subranges
*copyc tmt$ptl_lock
?? POP ??
*copyc dsp$report_system_message
*copyc iop$clear_queue_lockword
*copyc iop$mtr_set_status_abnormal
*copyc iop$set_queue_lockword
*copyc mmp$build_lock_rma_list
*copyc mmp$unlock_rma_list
*copyc mmp$verify_pva
*copyc mmp$xtask_pva_to_sva
*copyc mtp$error_stop
*copyc mtp$get_date_time_at_timestamp
*copyc tmp$check_taskid
*copyc tmp$clear_lock
*copyc tmp$set_lock
*copyc tmp$set_system_flag
*copyc tmp$set_task_ready
*copyc cmv$logical_pp_table_p
*copyc cmv$logical_unit_table
*copyc mmv$pft_p
*copyc osv$external_interrupt_selector
*copyc osv$page_size
*copyc tmv$null_global_task_id
*copyc i#real_memory_address

  VAR
    dmv$external_interrupt_selector: [XREF] 0 .. 0ff(16),
    iov$response_trace_1: [XDCL, #GATE] integer := 0;

?? TITLE := 'Global Declarations Declared by This Module', EJECT ??

  VAR
    cmv$subsys_io_scan_character: [XDCL, READ, #GATE, oss$mainframe_wired_literal] char := 'Y';

  VAR
    iov$subsys_process_pp_response: [XDCL, #GATE, oss$mainframe_wired_cb] iot$response_processor :=
          ^iop$subsys_process_pp_response;

  VAR
    iov$process_subsystem_response: [XDCL, STATIC, #GATE,
          oss$mainframe_wired_cb] iot$response_processor := ^iop$unsolicited_subsystem_resp;

?? TITLE := 'iop$subsys_process_pp_response', EJECT ??

  PROCEDURE [XDCL] iop$subsys_process_pp_response
    (    pp_response_header_p: ^iot$pp_response;
         detailed_status_p: ^iot$detailed_status;
         pp_number: 1 .. ioc$pp_count;
     VAR monitor_status: syt$monitor_status);

    VAR
      address_word_pair_count: 0 .. mmc$max_rma_list_length,
      io_request_p: ^iot$io_request,
      system_flag: ost$system_flag,
      global_task_id: ost$global_task_id,
      response_area_p: ^cmt$subsys_io_response_area,
      io_completion_queue_index: cmt$io_completion_queue_index,
      need_to_unlock_data_descriptors: boolean,
      normal_io_termination: boolean,
      wired_subsystem_request_p: ^cmt$max_wired_unit_queue_req,
      date_time: ost$date_time,
      wired_subsystem_pp_response_p: ^cmt$collected_pp_response;

    monitor_status.normal := TRUE;
    normal_io_termination := TRUE;
    system_flag := ioc$subsystem_io_completed;
    io_request_p := pp_response_header_p^.request;
    wired_subsystem_request_p := io_request_p^.device_request_p;
    wired_subsystem_pp_response_p := wired_subsystem_request_p^.wired_pp_response_p;

    IF wired_subsystem_pp_response_p = NIL THEN
      RETURN; {----->
    IFEND;

    global_task_id := wired_subsystem_request_p^.task_id;
    tmp$check_taskid (global_task_id, tmc$opt_return, monitor_status);
    IF NOT monitor_status.normal THEN { Task no longer lives.
      iov$response_trace_1 := iov$response_trace_1 + 1;
      monitor_status.normal := TRUE;

{  Keep a record of the number of times we reject a response so we can determine
{  how often this occurs. Set monitor status to normal here in order to force
{  process_io_completions to update the in/out pointers.

      RETURN; {----->
    IFEND;

    io_completion_queue_index := wired_subsystem_request_p^.io_identification.system_supplied;
    response_area_p := wired_subsystem_request_p^.response_area_p;
    address_word_pair_count := wired_subsystem_request_p^.address_word_pair_count;
    need_to_unlock_data_descriptors := (wired_subsystem_request_p^.wired_data_command_descript_p <> NIL) AND
          (wired_subsystem_request_p^.number_of_data_descriptors > 0) AND (address_word_pair_count > 0);

{Move response to wired response area.
    wired_subsystem_pp_response_p^.pp_number := pp_number;
    wired_subsystem_pp_response_p^.pp_response := pp_response_header_p^;

{Move detailed status to wired response area.
    IF detailed_status_p <> NIL THEN
      wired_subsystem_pp_response_p^.detailed_status := detailed_status_p^;
    IFEND;

    IF (wired_subsystem_pp_response_p^.pp_response.response_code.primary_response = ioc$normal_response) OR
          (wired_subsystem_pp_response_p^.pp_response.response_code.primary_response = ioc$abnormal_response)
          THEN
      {
      { Unlock pages for data transfer request.
      {

      IF need_to_unlock_data_descriptors THEN
        cmp$unlock_wired_req_rma_list (wired_subsystem_request_p, normal_io_termination,
              address_word_pair_count, monitor_status);
        IF NOT monitor_status.normal THEN
          iop$mtr_set_status_abnormal (ioe$unable_to_unlock_rma_list, monitor_status);
          RETURN; {----->
        IFEND;
      IFEND;
    IFEND;


    wired_subsystem_pp_response_p^.response_status := cmc$subsys_io_resp_completed;

    response_area_p^ (io_completion_queue_index, 1) := cmv$subsys_io_scan_character;

    IF NOT wired_subsystem_request_p^.task_is_to_be_readied THEN
      tmp$set_system_flag (global_task_id, system_flag, monitor_status);
      IF NOT monitor_status.normal THEN
        iop$mtr_set_status_abnormal (ioe$unable_to_set_system_flag, monitor_status);
      IFEND;
    ELSE
      tmp$check_taskid (global_task_id, tmc$opt_return, monitor_status);
      IF NOT monitor_status.normal THEN
        iop$mtr_set_status_abnormal (ioe$task_missing, monitor_status);
        RETURN; {----->
      IFEND;

      tmp$set_task_ready (global_task_id, 0 {readying_task_priority} , tmc$rc_ready_conditional_wi);
    IFEND;

  PROCEND iop$subsys_process_pp_response;

?? TITLE := 'iop$subsystem_queue_request', EJECT ??

*copyc ioh$subsystem_queue_request

  PROCEDURE [XDCL] iop$subsystem_queue_request
    (VAR request_block: iot$monitor_request_block);

    VAR
      data_length: ost$byte_count,
      pp_request_p: ^cmt$pp_request,
      buffer_descriptor: mmt$buffer_descriptor,
      io_identifier: mmt$io_identifier,
      data_pva: ^cell,
      sva: ost$system_virtual_address,
      io_type: iot$io_function,
      access_mode: mmt$segment_access_type,
      logical_unit: iot$logical_unit,
      page_size: ost$page_size,
      page_offset: ost$segment_offset,
      data_command_descriptor_index: integer,
      rma_list_index: 0 .. mmc$max_rma_list_length,
      command_index: 0 .. mmc$max_rma_list_length,
      command_address_word_pair_count: 0 .. mmc$max_rma_list_length,
      unit_queuing_option: cmt$unit_queuing_options,
      io_request_p: ^iot$io_request,
      number_of_data_commands: cmt$command_index,
      data_command_description_p: ^cmt$wired_data_descriptors,
      address_word_pair_count: 0 .. mmc$max_rma_list_length,
      rma: integer,
      pva_rma_translation_required: boolean,
      normal_io_termination: boolean,
      command_rma_list_p: ^mmt$rma_list,
      date_time: ost$date_time,
      wired_unit_queue_request_p: ^cmt$max_wired_unit_queue_req,
      wired_subsystem_pp_response_p: ^cmt$collected_pp_response,
      command_heap_p: ^cmt$subsystem_command_heap,
      able_to_queue_unit_request: boolean,
      command_length: cmt$command_length,
      number_of_commands_available: cmt$command_index,
      create_indirect_rma_list: boolean,
      ignore_status: syt$monitor_status,
      monitor_status: syt$monitor_status;

  /process_request/
    BEGIN
      request_block.status.normal := TRUE;

      io_request_p := request_block.io_request_p;
      io_request_p^.response_processor_p := ^iop$subsys_process_pp_response;

      io_identifier.specified := FALSE;
      io_identifier.io_function := ioc$no_io;
      page_size := osv$page_size;
      normal_io_termination := TRUE;
      access_mode := mmc$sat_none;

      wired_unit_queue_request_p := io_request_p^.device_request_p;
      wired_subsystem_pp_response_p := wired_unit_queue_request_p^.wired_pp_response_p;

      unit_queuing_option := wired_unit_queue_request_p^.unit_queuing_control;
      logical_unit := wired_unit_queue_request_p^.request.logical_unit;
      address_word_pair_count := wired_unit_queue_request_p^.address_word_pair_count;
      pp_request_p := ^wired_unit_queue_request_p^.request;

      pp_request_p^.next_pp_request := NIL;
      IF dmv$external_interrupt_selector = 1 THEN
        pp_request_p^.interrupt.value := TRUE;
      ELSE
        pp_request_p^.interrupt.value := FALSE;
      IFEND;
      pp_request_p^.interrupt.port_number := osv$external_interrupt_selector;

      data_command_description_p := wired_unit_queue_request_p^.wired_data_command_descript_p;
      number_of_data_commands := wired_unit_queue_request_p^.number_of_data_descriptors;
      pva_rma_translation_required := (data_command_description_p <> NIL) AND (number_of_data_commands > 0);
      command_heap_p := wired_unit_queue_request_p^.wired_command_heap_p;
      number_of_commands_available := wired_unit_queue_request_p^.number_of_commands;
      rma_list_index := address_word_pair_count + 1;
      {
      { Create rma lists and lock pages.
      {
      IF pva_rma_translation_required THEN

        buffer_descriptor.buffer_descriptor_type := mmc$bd_explicit_io;

      /lock_data_pages/
        FOR data_command_descriptor_index := 1 TO number_of_data_commands DO
          IF NOT data_command_description_p^ [data_command_descriptor_index].lock_data_pages THEN
            CYCLE /lock_data_pages/; {----->
          IFEND;

          command_index := data_command_description_p^ [data_command_descriptor_index].command_index;
          IF command_index > number_of_commands_available THEN
            IF address_word_pair_count <> 0 THEN
              cmp$unlock_wired_req_rma_list (wired_unit_queue_request_p, normal_io_termination,
                    address_word_pair_count, monitor_status);
            IFEND;
            iop$mtr_set_status_abnormal (ioe$io_request_error, monitor_status);
            EXIT /process_request/; {----->
          IFEND;

          create_indirect_rma_list := pp_request_p^.commands [command_index].flags.indirect_address;
          CASE data_command_description_p^ [data_command_descriptor_index].io_direction OF
          = cmc$read_into_memory, cmc$read_write_memory =
            io_type := ioc$explicit_read;
            access_mode := mmc$sat_read_or_write;
          = cmc$write_from_memory =
            io_type := ioc$explicit_write;
            access_mode := mmc$sat_read_or_write;
          = cmc$no_memory_reference =
            CYCLE /lock_data_pages/; {----->
          CASEND;
          data_length := data_command_description_p^ [data_command_descriptor_index].length;
          data_pva := data_command_description_p^ [data_command_descriptor_index].address;
          command_rma_list_p := #LOC (command_heap_p^.rma_list [rma_list_index]);


          mmp$xtask_pva_to_sva (data_pva, sva, monitor_status);
          IF NOT monitor_status.normal THEN
            IF address_word_pair_count <> 0 THEN
              cmp$unlock_wired_req_rma_list (wired_unit_queue_request_p, normal_io_termination,
                    address_word_pair_count, ignore_status);
            IFEND;
            iop$mtr_set_status_abnormal (ioe$address_error, monitor_status);
            EXIT /process_request/; {----->
          IFEND;

          IF create_indirect_rma_list THEN
            command_address_word_pair_count := (((sva.offset + data_length + (page_size * 2) - 1)) DIV
                  page_size) - ((sva.offset + page_size) DIV page_size);
          ELSE
            command_address_word_pair_count := 1;
          IFEND;

          page_offset := sva.offset MOD page_size;
          buffer_descriptor.page_count := ((page_offset + data_length - 1) DIV page_size) + 1;
          buffer_descriptor.sva := sva;

          mmp$build_lock_rma_list (buffer_descriptor, data_length, io_type, command_rma_list_p,
                command_address_word_pair_count, monitor_status);
          IF NOT monitor_status.normal THEN
            IF address_word_pair_count > 0 THEN
              {
              { Unlock locked pages.
              {
              cmp$unlock_wired_req_rma_list (wired_unit_queue_request_p, normal_io_termination,
                    address_word_pair_count, ignore_status);
            IFEND;
            EXIT /process_request/; {----->
          IFEND;

          data_command_description_p^ [data_command_descriptor_index].rma_list_index := rma_list_index;
          address_word_pair_count := address_word_pair_count + command_address_word_pair_count;

          IF create_indirect_rma_list THEN
            i#real_memory_address (command_rma_list_p, rma);
            command_length := command_address_word_pair_count * 8;
          ELSE
            rma := command_heap_p^.rma_list [rma_list_index].rma;
            command_length := command_heap_p^.rma_list [rma_list_index].length;
          IFEND;

          pp_request_p^.commands [command_index].length := command_length;
          pp_request_p^.commands [command_index].address := rma;

          rma_list_index := rma_list_index + command_address_word_pair_count;

        FOREND /lock_data_pages/;

        wired_unit_queue_request_p^.address_word_pair_count := address_word_pair_count;

      IFEND;

      cmp$queue_unit_request_entry (logical_unit, unit_queuing_option, io_request_p,
            able_to_queue_unit_request);
      IF NOT able_to_queue_unit_request THEN
        {
        { Unlock locked pages. }
        {
        IF address_word_pair_count <> 0 THEN
          cmp$unlock_wired_req_rma_list (wired_unit_queue_request_p, normal_io_termination,
                address_word_pair_count, monitor_status);
        IFEND;
        iop$mtr_set_status_abnormal (ioe$unable_to_queue_io_request, monitor_status);
      IFEND;

    END /process_request/;

    request_block.status := monitor_status;

  PROCEND iop$subsystem_queue_request;

?? TITLE := 'cmp$queue_unit_request_entry', EJECT ??

  PROCEDURE cmp$queue_unit_request_entry
    (    logical_unit: iot$logical_unit;
         unit_queuing_option: cmt$unit_queuing_options;
     VAR io_request_p: ^iot$io_request;
     VAR able_to_queue_unit_request: boolean);

    VAR
      p_unit_interface_table: ^iot$unit_interface_table,
      lock_set: boolean,
      first_entry_in_queue: boolean,
      current_request_p: ^cmt$max_wired_unit_queue_req,
      queue_count: integer,
      next_io_request_p: ^iot$io_request,
      next_request_p: ^cmt$max_wired_unit_queue_req,
      rma: integer,
      next_request_rma: ost$word,
      previous_request_p: ^cmt$max_wired_unit_queue_req,
      pp_request_p: ^cmt$pp_request;

    able_to_queue_unit_request := TRUE;
    queue_count := 0;

    current_request_p := io_request_p^.device_request_p;
    pp_request_p := ^current_request_p^.request;

    pp_request_p^.next_pp_request := NIL;
    pp_request_p^.next_pp_request_rma := 0;

    p_unit_interface_table := cmv$logical_unit_table^ [logical_unit].unit_interface_table;

{ Set unit queue lockword. }
    iop$set_queue_lockword (p_unit_interface_table^.unit_q_lockword, lock_set);
    IF NOT lock_set THEN
      able_to_queue_unit_request := FALSE;
      RETURN; {----->
    IFEND;

  /unit_queue_lock_set/
    BEGIN
      IF p_unit_interface_table^.unit_status.disabled THEN
        able_to_queue_unit_request := FALSE;
        EXIT /unit_queue_lock_set/; {----->
      IFEND;


      {Insert request in unit queue.}
      {
      next_io_request_p := p_unit_interface_table^.next_request;
      next_request_rma := p_unit_interface_table^.next_request_rma;
      first_entry_in_queue := (next_io_request_p = NIL);

      i#real_memory_address (#LOC (pp_request_p^), rma);

      IF NOT first_entry_in_queue THEN
        CASE unit_queuing_option OF

        = cmc$first_in_first_out_queue =

        /insert_request_loop/
          WHILE next_io_request_p <> NIL DO
            previous_request_p := next_io_request_p^.device_request_p;
            next_io_request_p := previous_request_p^.request.next_pp_request;
          WHILEND /insert_request_loop/;

        ELSE
          able_to_queue_unit_request := FALSE;
          EXIT /unit_queue_lock_set/; {----->
        CASEND;
      IFEND;

      IF first_entry_in_queue THEN
        p_unit_interface_table^.next_request := io_request_p;
        p_unit_interface_table^.next_request_rma := rma;
      ELSE
        previous_request_p^.request.next_pp_request := io_request_p;
        previous_request_p^.request.next_pp_request_rma := rma;
      IFEND;

      able_to_queue_unit_request := TRUE;

{Increment unit_queue count.}
      p_unit_interface_table^.queue_count := (p_unit_interface_table^.queue_count + 1) MOD
            (UPPERVALUE (p_unit_interface_table^.queue_count) + 1);

    END /unit_queue_lock_set/;

    iop$clear_queue_lockword (p_unit_interface_table^.unit_q_lockword);

  PROCEND cmp$queue_unit_request_entry;
?? TITLE := 'iop$unsolicited_subsystem_resp', EJECT ??

*copyc ioh$unsolicited_subsystem_resp

  PROCEDURE [XDCL] iop$unsolicited_subsystem_resp
    (    pp_response_p: ^iot$pp_response;
         detailed_status_p: ^iot$detailed_status;
         pp: 1 .. ioc$pp_count;
     VAR status: syt$monitor_status);

    VAR
      equipment: cmt$physical_equipment_number,
      logical_unit: iot$logical_unit,
      unit_descriptor_index: integer,
      physical_unit: iot$physical_unit_number,
      physical_channel: iot$channel_number,
      unit_descriptor_entry_p: ^iot$unit_descriptor_entry,
      unit_descriptor_found: boolean,
      symptom_code: integer,
      logical_operation: iot$io_function,
      unrecovered_error: 0 .. 2,
      unit_type: iot$unit_type,
      msg_type: dst$system_logging_types,
      msg_level: dst$system_message_levels,
      msg_recorded: boolean,
      msg_descriptor_p: ^SEQ ( * ),
      foreign_equipment_error_log_p: ^cmt$foreign_equipment_error_log;


    status.normal := TRUE;

    IF NOT cmv$logical_pp_table_p^ [pp].flags.configured THEN
      RETURN; {----->
    IFEND;

    logical_unit := pp_response_p^.logical_unit;
    unit_descriptor_found := FALSE;

  /locate_unit_descriptor/
    FOR unit_descriptor_index := UPPERBOUND (cmv$logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.
          unit_descriptors) DOWNTO LOWERBOUND (cmv$logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.
          unit_descriptors) DO
      unit_descriptor_entry_p := ^cmv$logical_pp_table_p^ [pp].pp_info.pp_interface_table_p^.
            unit_descriptors [unit_descriptor_index];
      IF unit_descriptor_entry_p^.logical_unit = logical_unit THEN
        unit_descriptor_found := TRUE;
        EXIT /locate_unit_descriptor/; {----->
      IFEND;
    FOREND /locate_unit_descriptor/;

    IF NOT unit_descriptor_found THEN
      RETURN; {----->
    IFEND;

    physical_channel := unit_descriptor_entry_p^.physical_path.channel_number;
    physical_unit := unit_descriptor_entry_p^.physical_path.physical_unit_number;
    equipment := unit_descriptor_entry_p^.physical_path.controller_number;
    symptom_code := 0;
    unrecovered_error := 1;
    IF cmv$logical_unit_table^ [logical_unit].configured THEN
      unit_type := cmv$logical_unit_table^ [logical_unit].unit_interface_table^.unit_type;
    ELSE
      unit_type := 0;
    IFEND;

    PUSH msg_descriptor_p: [[REP #SIZE (cmt$foreign_equipment_error_log) OF ost$byte]];
    RESET msg_descriptor_p;

    NEXT foreign_equipment_error_log_p IN msg_descriptor_p;
    foreign_equipment_error_log_p^.pp_response := pp_response_p^;
    foreign_equipment_error_log_p^.channel := physical_channel;
    foreign_equipment_error_log_p^.equipment := equipment;
    foreign_equipment_error_log_p^.logical_unit := logical_unit;
    foreign_equipment_error_log_p^.symptom_code := symptom_code;
    foreign_equipment_error_log_p^.unit_type := unit_type;
    foreign_equipment_error_log_p^.logical_operation := ioc$no_value;
    foreign_equipment_error_log_p^.controller_type := $INTEGER (cmv$logical_pp_table_p^ [pp].controller_info.
          controller_type);
    foreign_equipment_error_log_p^.display_message := FALSE;
    foreign_equipment_error_log_p^.physical_unit := physical_unit;
    foreign_equipment_error_log_p^.failure_severity := unrecovered_error;
    foreign_equipment_error_log_p^.detailed_status := detailed_status_p^;

    msg_type := dsc$general_io_error;
    msg_level := dsc$unrecovered_error;
    dsp$report_system_message (msg_descriptor_p, msg_type, msg_level, msg_recorded);

  PROCEND iop$unsolicited_subsystem_resp;
?? TITLE := 'cmp$unlock_wired_req_rma_list', EJECT ??

  PROCEDURE [XDCL] cmp$unlock_wired_req_rma_list
    (    wired_subsystem_request_p: ^cmt$max_wired_unit_queue_req;
         normal_io_termination: boolean;
     VAR address_word_pair_count: 0 .. mmc$max_rma_list_length;
     VAR monitor_status: syt$monitor_status);

    VAR
      io_error: iot$io_error,
      io_identifier: mmt$io_identifier,
      rma_list_p: ^mmt$rma_list,
      io_type: iot$io_function,
      command_address_word_pair_count: 0 .. mmc$max_rma_list_length,
      page_offset: 0 .. 65535,
      pfti: mmt$page_frame_index,
      pfte_p: ^mmt$page_frame_table_entry,
      data_pva: ^cell,
      data_length: ost$byte_count,
      rma_list_index: 0 .. mmc$max_rma_list_length,
      number_of_data_commands: cmt$command_index,
      data_command_descriptor_index: integer,
      data_command_description_p: ^cmt$wired_data_descriptors,
      command_heap_p: ^cmt$subsystem_command_heap,
      pp_request_p: ^cmt$pp_request;

    monitor_status.normal := TRUE;

    io_identifier.specified := FALSE;
    pp_request_p := ^wired_subsystem_request_p^.request;
    data_command_description_p := wired_subsystem_request_p^.wired_data_command_descript_p;
    number_of_data_commands := wired_subsystem_request_p^.number_of_data_descriptors;
    command_heap_p := wired_subsystem_request_p^.wired_command_heap_p;

  /unlock_data_pages/
    FOR data_command_descriptor_index := 1 TO number_of_data_commands DO
      IF NOT data_command_description_p^ [data_command_descriptor_index].lock_data_pages THEN
        CYCLE /unlock_data_pages/; {----->
      IFEND;
      CASE data_command_description_p^ [data_command_descriptor_index].io_direction OF
      = cmc$read_into_memory, cmc$read_write_memory =
        io_type := ioc$explicit_read;
      = cmc$write_from_memory =
        io_type := ioc$explicit_write;
      = cmc$no_memory_reference =
        CYCLE /unlock_data_pages/; {----->
      CASEND;
      rma_list_index := data_command_description_p^ [data_command_descriptor_index].rma_list_index;
      IF rma_list_index = 0 THEN
        CYCLE /unlock_data_pages/; {----->
      IFEND;
      data_pva := data_command_description_p^ [data_command_descriptor_index].address;
      data_length := data_command_description_p^ [data_command_descriptor_index].length;
      rma_list_p := #LOC (command_heap_p^.rma_list [rma_list_index]);
      page_offset := #OFFSET (data_pva) MOD osv$page_size;
      command_address_word_pair_count := ((page_offset + data_length + osv$page_size - 1) DIV osv$page_size);

      IF normal_io_termination THEN
        io_error := ioc$no_error;
      ELSE
        io_error := ioc$unrecovered_error;
      IFEND;
      io_identifier.io_function := io_type;
{
{ Make sure there is a reason to unlock before calling monitor.
      pfti := rma_list_p^ [command_address_word_pair_count].rma DIV osv$page_size;
      pfte_p := ^mmv$pft_p^ [pfti];
      IF pfte_p^.active_io_count = 0 THEN
        iop$mtr_set_status_abnormal (ioe$unable_to_unlock_rma_list, monitor_status);

        EXIT /unlock_data_pages/; {----->
      IFEND;

      mmp$unlock_rma_list (io_type, rma_list_p, command_address_word_pair_count, io_identifier,
            {MF_JOB_FILE} FALSE, io_error, monitor_status);
      IF NOT monitor_status.normal THEN
        iop$mtr_set_status_abnormal (ioe$unable_to_unlock_rma_list, monitor_status);
        EXIT /unlock_data_pages/; {----->
      IFEND;

      address_word_pair_count := address_word_pair_count - command_address_word_pair_count;
      IF address_word_pair_count <= 0 THEN
        EXIT /unlock_data_pages/; {----->
      IFEND;

    FOREND /unlock_data_pages/;

    wired_subsystem_request_p^.address_word_pair_count := address_word_pair_count;

  PROCEND cmp$unlock_wired_req_rma_list;

  PROCEDURE [XDCL] cmp$unlock_wired_rma_list
    (VAR request_block: iot$monitor_request_block);

    VAR
      wired_request: ^cmt$max_wired_unit_queue_req,
      normal_termination: boolean,
      address_count: 0 .. mmc$max_rma_list_length,
      monitor_status: syt$monitor_status;

    normal_termination := TRUE;
    address_count := 1;
    monitor_status.normal := TRUE;
    wired_request := request_block.wired_request;

    cmp$unlock_wired_req_rma_list (wired_request, normal_termination, address_count, monitor_status);

  PROCEND cmp$unlock_wired_rma_list;
MODEND iom$subsystem_io_mtr_processing;
