MODULE iom$tape_queue_manager_ring1;

?? RIGHT := 110 ??

*copyc osd$default_pragmats

?? OLDTITLE ??
?? NEWTITLE := ' global definitions ' ??
?? EJECT ??

*copyc cmv$logical_pp_table_p
*copyc cmv$new_logical_pp_table_p
*copyc cmv$logical_unit_table
*copyc iov$tape_completion_q_table
*copyc osv$job_pageable_heap
*copyc osv$mainframe_pageable_heap
*copyc osv$mainframe_wired_cb_heap
*copyc osv$mainframe_wired_heap
*copyc tmv$null_global_task_id

  VAR
    iov$establish_tape_statistics: [XDCL, #GATE, STATIC, oss$mainframe_pageable] boolean := TRUE,
    iov$number_of_tape_units: [XDCL, #GATE, STATIC, oss$mainframe_pageable] iot$no_of_tape_units := 0,
    iov$tape_scan_frequency: [XDCL, #GATE, oss$mainframe_pageable] integer := 5 {seconds},
    iov$tusl_lock: [XDCL, oss$mainframe_pageable] ost$signature_lock := [0],
    iov$tusl_p: [XDCL, #GATE, oss$mainframe_pageable] ^iot$tape_unit_status_list := NIL,
    iov$wired_tape_tables: [XDCL, oss$mainframe_pageable] ^ARRAY [ 1 .. *] OF iot$wired_tape_tables := NIL;

?? PUSH (LISTEXT := ON) ??

*copyc cmc$logical_unit_constants
*copyc cmt$element_state
*copyc ioe$tape_io_conditions
*copyc iot$tape_block_count
*copyc iot$tape_collected_pp_response
*copyc iot$tape_command_heap
*copyc iot$tape_command_table_entry
*copyc iot$tape_unit_status_list
*copyc iot$wired_tape_tables
*copyc mme$condition_codes
*copyc osd$virtual_address
*copyc oss$mainframe_pageable
*copyc ost$page_size
*copyc syc$monitor_request_codes
*copyc syt$monitor_request_code
?? POP ??

?? OLDTITLE ??
?? NEWTITLE := ' xref definitions ' ??
?? EJECT ??

*copyc i#call_monitor
*copyc cmp$get_element_name_via_lun
*copyc cmp$get_logical_unit_state
*copyc mmp$test_for_cache_bypass
*copyc osp$initialize_signature_lock
*copyc osp$set_status_abnormal
*copyc osp$unpack_status_identifier
*copyc pmp$find_executing_task_xcb

?? OLDTITLE ??
?? NEWTITLE := ' iop$allocate_wired_tape_tables ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$allocate_wired_tape_tables (
    index: iot$no_of_tape_units;
    multiple_requests_possible: boolean);

    VAR
      i: 1 .. ioc$max_multiple_tape_requests,
      j: 1 .. ioc$max_multiple_tape_requests,
      wired_table_p: ^iot$wired_tape_tables;

    wired_table_p := ^iov$wired_tape_tables^ [index];

    IF multiple_requests_possible THEN
      j := ioc$max_multiple_tape_requests;
    ELSE { only need one set of tables
      j := 1;
      FOR i := 2 to ioc$max_multiple_tape_requests DO {ensure unallocated slots are not used
        wired_table_p^ [i].slot_in_use := TRUE;
      FOREND;
    IFEND;

    FOR i := 1 to j DO
      wired_table_p^ [i].slot_in_use := FALSE;
      ALLOCATE wired_table_p^ [i].io_request_p IN osv$mainframe_wired_cb_heap^;
      ALLOCATE wired_table_p^ [i].wired_tape_request_p IN osv$mainframe_wired_cb_heap^;
      ALLOCATE wired_table_p^ [i].wired_tape_request_p^.pp_response_p IN
            osv$mainframe_wired_cb_heap^;
      ALLOCATE wired_table_p^ [i].wired_tape_request_p^.wired_read_description_p IN
            osv$mainframe_wired_heap^;

{ The wired_write_description_p is only allocated if a write is performed on the tape.

      wired_table_p^ [i].wired_tape_request_p^.wired_write_description_p := NIL;

      ALLOCATE wired_table_p^ [i].request_block_p IN osv$mainframe_wired_cb_heap^;
      wired_table_p^ [i].io_request_p^.device_request_p := wired_table_p^ [i].wired_tape_request_p;

{ Use pp_request_p pointer in io_request_p (iot$io_request) to point to the completion_q_table_entry
{ for this request.

      wired_table_p^ [i].io_request_p^.pp_request_p := ^iov$tape_completion_q_table^ [index].req [i];

      wired_table_p^ [i].request_block_p^.request_code := syc$rc_tape_io;
      wired_table_p^ [i].request_block_p^.io_request_p := wired_table_p^ [i].io_request_p;
      iov$tape_completion_q_table^ [index].req [i].waiting_response := FALSE;
      iov$tape_completion_q_table^ [index].req [i].request_not_processed := FALSE;
      iov$tape_completion_q_table^ [index].req [i].io_id := 0;
      iov$tape_completion_q_table^ [index].req [i].io_request := NIL;
      iov$tape_completion_q_table^ [index].req [i].task_id := tmv$null_global_task_id;
      iov$tape_completion_q_table^ [index].req [i].check_task_id := FALSE;
    FOREND;

    iov$tape_completion_q_table^ [index].sync_set := FALSE;
    iov$tape_completion_q_table^ [index].cart_writes_pending := 0;

  PROCEND iop$allocate_wired_tape_tables;

?? OLDTITLE ??
?? NEWTITLE := ' iop$change_tape_scan_freq_113 ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$change_tape_scan_freq_113
    (    scan_frequency: integer);

    IF scan_frequency > 0 THEN
      iov$tape_scan_frequency := scan_frequency;
    IFEND;

  PROCEND iop$change_tape_scan_freq_113;

?? OLDTITLE ??
?? NEWTITLE := ' iop$free_tape_tables ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$free_tape_tables;

    VAR
      i: iot$no_of_tape_units;

    iov$number_of_tape_units := 0;
    iov$establish_tape_statistics := TRUE;

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

    IF iov$wired_tape_tables <> NIL THEN
      FOR i := 1 TO UPPERBOUND(iov$wired_tape_tables^) DO
        iop$free_wired_tape_tables (i);
      FOREND;
      FREE iov$wired_tape_tables IN osv$mainframe_pageable_heap^;
    IFEND;

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

  PROCEND iop$free_tape_tables;

?? OLDTITLE ??
?? NEWTITLE := ' iop$free_wired_tape_tables ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$free_wired_tape_tables (
    index: iot$no_of_tape_units);

    VAR
      i: 1 .. ioc$max_multiple_tape_requests,
      wired_table_p: ^iot$wired_tape_tables;

    wired_table_p := ^iov$wired_tape_tables^ [index];
    FOR i := 1 to ioc$max_multiple_tape_requests DO
      IF wired_table_p^ [i].io_request_p <> NIL THEN
        IF NOT wired_table_p^ [i].slot_in_use THEN
          FREE wired_table_p^ [i].io_request_p IN osv$mainframe_wired_cb_heap^;
        ELSE
          wired_table_p^ [i].io_request_p := NIL;   { Do not free memory
        IFEND;
        FREE wired_table_p^ [i].wired_tape_request_p^.pp_response_p IN
              osv$mainframe_wired_cb_heap^;
        FREE wired_table_p^ [i].wired_tape_request_p^.wired_read_description_p IN
              osv$mainframe_wired_heap^;
        IF wired_table_p^ [i].wired_tape_request_p^.wired_write_description_p <> NIL THEN
          FREE wired_table_p^ [i].wired_tape_request_p^.wired_write_description_p IN
                osv$mainframe_wired_heap^;
        IFEND;
        FREE wired_table_p^ [i].wired_tape_request_p IN osv$mainframe_wired_cb_heap^;
        FREE wired_table_p^ [i].request_block_p IN osv$mainframe_wired_cb_heap^;
      IFEND;
      wired_table_p^ [i].slot_in_use := FALSE;
    FOREND;

  PROCEND iop$free_wired_tape_tables;

?? OLDTITLE ??
?? NEWTITLE := ' iop$tape_clear_activate_stats ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$tape_clear_activate_stats (VAR status: ost$status);

    status.normal := TRUE;

{ Set the boolean flag to FALSE to indicate tape statistics do not need to be established.

   iov$establish_tape_statistics := FALSE;

  PROCEND iop$tape_clear_activate_stats;

?? OLDTITLE ??
?? NEWTITLE := ' iop$tape_enable_ready_task ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$tape_enable_ready_task (
        i: iot$no_of_tape_units;
        j: 1 .. ioc$max_multiple_tape_requests);

    VAR
      ccc_cart_unit_comm_buffer_p: ^iot$ccc_cart_unit_comm_buffer,
      wired_request_p: ^iot$wired_tape_request,
      xcb_p: ^ost$execution_control_block;

    wired_request_p := iov$tape_completion_q_table^ [i].req [j].io_request^.device_request_p;
    IF ((wired_request_p^.io_type = ioc$explicit_write) AND (wired_request_p^.pp_response_p^.
          controller_type = cmc$mt5680_xx)) THEN
      RESET cmv$logical_unit_table^ [wired_request_p^.request.logical_unit].unit_communication_buffer_pva;
      NEXT ccc_cart_unit_comm_buffer_p IN cmv$logical_unit_table^ [wired_request_p^.request.logical_unit].
            unit_communication_buffer_pva;
      ccc_cart_unit_comm_buffer_p^.request_pva := iov$tape_completion_q_table^ [i].req [j].io_request;
      ccc_cart_unit_comm_buffer_p^.force_sync := 0;
    IFEND;
    pmp$find_executing_task_xcb (xcb_p);
    wired_request_p^.task_id := xcb_p^.global_task_id;
    #SPOIL (wired_request_p^.task_id);
    wired_request_p^.ready_task := TRUE;

  PROCEND iop$tape_enable_ready_task;

?? OLDTITLE ??
?? NEWTITLE := ' iop$tape_enable_taskid_check ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$tape_enable_taskid_check (
        i: iot$no_of_tape_units;
        j: 1 .. ioc$max_multiple_tape_requests);

    VAR
      xcb_p: ^ost$execution_control_block;

    pmp$find_executing_task_xcb (xcb_p);
    iov$tape_completion_q_table^ [i].req [j].task_id := xcb_p^.global_task_id;
    #SPOIL (iov$tape_completion_q_table^ [i].req [j].task_id);
    iov$tape_completion_q_table^ [i].req [j].check_task_id := TRUE;

  PROCEND iop$tape_enable_taskid_check;

?? OLDTITLE ??
?? NEWTITLE := ' iop$tape_initialization ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$tape_initialization (logical_unit_table: ^cmt$logical_unit_table;
    VAR status: ost$status);

    VAR
      element_name: ost$name,
      i: iot$logical_unit,
      ignore_status: ost$status,
      j: integer,
      length: iot$logical_unit,
      lun: iot$logical_unit,
      state: cmt$element_state,
      unit_index: iot$no_of_tape_units;

    BEGIN
      status.normal := TRUE;

      length := UPPERBOUND (logical_unit_table^);

      iop$free_tape_tables;

{ Count number of tape units for ALLOCATE.

      FOR i := cmc$job_template_unit_ordinal TO length DO
        IF (logical_unit_table^ [i].unit_interface_table <> NIL) THEN
          IF (logical_unit_table^ [i].unit_interface_table^.unit_type <= ioc$highest_tape_unit) THEN
            iov$number_of_tape_units := iov$number_of_tape_units + 1;
          IFEND;
        IFEND;
      FOREND;

      IF iov$number_of_tape_units = 0 THEN
        RETURN;
      IFEND;

      IF iov$number_of_tape_units > ioc$max_number_tape_units THEN
        osp$set_status_abnormal ('IO', ioe$too_many_tapes_defined, ' ', status);
        RETURN;
      IFEND;

{ Allocate and initialize the tape completion queue table.

      ALLOCATE iov$tape_completion_q_table: [1 .. iov$number_of_tape_units] IN
            osv$mainframe_wired_heap^;

      unit_index := 0;

      FOR i := cmc$job_template_unit_ordinal TO length DO
        IF (logical_unit_table^ [i].unit_interface_table <> NIL) THEN
          IF (logical_unit_table^ [i].unit_interface_table^.unit_type <= ioc$highest_tape_unit) THEN
            unit_index := unit_index + 1;

{ Initialize the logical unit number field.

            iov$tape_completion_q_table^ [unit_index].lun := i;
          IFEND;
        IFEND;
      FOREND;

{ Initialize the tape completion queue table request entries.

      FOR i := 1 TO iov$number_of_tape_units DO
        iov$tape_completion_q_table^ [i].sync_set := FALSE;
        iov$tape_completion_q_table^ [i].cart_writes_pending := 0;
        FOR j := 1 to ioc$max_multiple_tape_requests DO
          iov$tape_completion_q_table^ [i].req [j].waiting_response := FALSE;
          iov$tape_completion_q_table^ [i].req [j].request_not_processed := FALSE;
          iov$tape_completion_q_table^ [i].req [j].io_id := 0;
          iov$tape_completion_q_table^ [i].req [j].io_request := NIL;
          iov$tape_completion_q_table^ [i].req [j].task_id := tmv$null_global_task_id;
          iov$tape_completion_q_table^ [i].req [j].check_task_id := FALSE;
        FOREND;
      FOREND;

{ Allocate and initialize wired request table.  Note - the completion_q_index
{ for a unit is also the index into this table.

      ALLOCATE iov$wired_tape_tables: [1 .. iov$number_of_tape_units] IN osv$mainframe_pageable_heap^;

      FOR i := 1 TO iov$number_of_tape_units DO
        FOR j := 1 to ioc$max_multiple_tape_requests DO
          iov$wired_tape_tables^ [i][j].slot_in_use := FALSE;
          iov$wired_tape_tables^ [i][j].io_request_p := NIL;
          iov$wired_tape_tables^ [i][j].wired_tape_request_p := NIL;
          iov$wired_tape_tables^ [i][j].request_block_p := NIL;
        FOREND;
      FOREND;

{ Allocate and initialize the Tape_Unit_Status_List (TUSL)

      ALLOCATE iov$tusl_p: [1 .. iov$number_of_tape_units] IN osv$mainframe_pageable_heap^;

      FOR i := LOWERBOUND(iov$tusl_p^) TO UPPERBOUND(iov$tusl_p^) DO
        lun := iov$tape_completion_q_table^ [i].lun;
        cmp$get_element_name_via_lun (lun, element_name, status);
        iov$tusl_p^[i].element_name := element_name;
        cmp$get_logical_unit_state (lun, logical_unit_table, state);
        iov$tusl_p^[i].tape_unit_state := state;
        find_logical_pps_for_unit (lun, iov$tusl_p^[i].logical_pp, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        iov$tusl_p^[i].unit_ready := FALSE;
        iov$tusl_p^[i].read_error := FALSE;
        iov$tusl_p^[i].evsn := rmc$unspecified_vsn;
        iov$tusl_p^[i].rvsn := rmc$unspecified_vsn;
        iov$tusl_p^[i].reassign_device_control.command_allowed := FALSE;
        iov$tusl_p^[i].ssn := jmc$blank_system_supplied_name;

{ Set sfid to the equivalent of dmv$null_sfid.  We cannot use dmv$null_sfid here
{ because it is not defined in the boot.

        iov$tusl_p^[i].sfid.file_entry_index := 0;
        iov$tusl_p^[i].sfid.residence := gfc$tr_null_residence;
        iov$tusl_p^[i].sfid.file_hash := 0;
        iov$tusl_p^[i].assignment_state := ioc$not_assigned;
        iov$tusl_p^[i].detected_tape_characteristics.label_type := amc$labelled;
        iov$tusl_p^[i].detected_tape_characteristics.character_set := amc$ascii;
        iov$tusl_p^[i].detected_tape_characteristics.write_ring := FALSE;
        iov$tusl_p^[i].detected_tape_characteristics.density := rmc$200;
        iov$tusl_p^[i].unit_type := logical_unit_table^ [lun].unit_interface_table^.unit_type;
        osp$initialize_signature_lock (iov$tusl_p^[i].lock, ignore_status);
      FOREND;

    END
  PROCEND iop$tape_initialization;

?? OLDTITLE ??
?? NEWTITLE := ' iop$tape_queue_request_setup ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$tape_queue_request_setup (tape_request_p: ^iot$tape_request;
    VAR status: ost$status);

    VAR
      buffer_length: iot$tape_block_length,
      cache_bypass: boolean,
      command_heap_p: ^iot$tape_command_heap,
      dummy_array_pointer: ^array [1 .. amc$maximum_block] of 0 .. 0ff(16),
      dump: 0 .. 0ff(16),
      dump1: 0 .. 0ff(16),
      dump2: iot$tape_transfer_count,
      found: boolean,
      i: 1 .. ioc$max_multiple_tape_requests,
      identifier: ost$status_identifier,
      l: iot$tape_block_count,
      m: 0 .. osc$max_segment_length DIV osc$min_page_size,
      no_of_pages: 0 .. osc$max_segment_length DIV osc$min_page_size,
      osv$page_size: [XREF] ost$page_size,
      page_size: ost$page_size,
      wired_tape_request_p: ^iot$wired_tape_request,
      wired_tape_tables: ^iot$wired_tape_tables;

    status.normal := TRUE;

    wired_tape_tables := ^iov$wired_tape_tables^ [tape_request_p^.ud^.completion_q_index];
    found := FALSE;

  /search_for_empty_entry/
    FOR i := 1 to ioc$max_multiple_tape_requests DO
      IF NOT wired_tape_tables^ [i].slot_in_use THEN
        wired_tape_tables^ [i].slot_in_use := TRUE;
        found := TRUE;
        EXIT /search_for_empty_entry/;
      IFEND;
    FOREND /search_for_empty_entry/;

    IF NOT found THEN
      osp$set_status_abnormal ('IO', ioc$os_failure,
            'unable to find wired request entry in tape_queue_manager_ring1.', status);
      RETURN;
    IFEND;

    wired_tape_request_p := wired_tape_tables^ [i].wired_tape_request_p;
    IF (tape_request_p^.request_type = ioc$tape_read) OR (tape_request_p^.request_type =
          ioc$tape_read_backwards) THEN
      wired_tape_request_p^.wired_read_description_p^ := tape_request_p^.read_block_description^;
    IFEND;
    IF tape_request_p^.request_type = ioc$tape_write THEN
      IF (wired_tape_request_p^.wired_write_description_p = NIL) THEN  { Allocate write description
        ALLOCATE wired_tape_request_p^.wired_write_description_p IN osv$mainframe_wired_heap^;
      IFEND;
      wired_tape_request_p^.wired_write_description_p^ := tape_request_p^.write_block_description^;
    IFEND;
    ALLOCATE command_heap_p: [1 .. tape_request_p^.estimated_address_pair_count] IN
          osv$mainframe_wired_cb_heap^;
    command_heap_p^.rma_list [1].length := 0;
    wired_tape_request_p^.completion_q_index := tape_request_p^.ud^.completion_q_index;
    wired_tape_request_p^.no_of_data_commands := tape_request_p^.no_of_data_commands;
    wired_tape_request_p^.max_input_count := tape_request_p^.max_input_count;
    wired_tape_request_p^.first_data_command := tape_request_p^.first_data_command;
    wired_tape_request_p^.io_id := tape_request_p^.io_id;
    wired_tape_request_p^.recovery_requeue := tape_request_p^.recovery_requeue;
    wired_tape_request_p^.request_type := tape_request_p^.request_type;
    wired_tape_request_p^.io_type := tape_request_p^.io_type;
    wired_tape_request_p^.allocated_address_pair_count :=
          tape_request_p^.estimated_address_pair_count;
    wired_tape_request_p^.wired_command_heap_p := command_heap_p;
    wired_tape_request_p^.pp_response_p^.controller_type := tape_request_p^.ud^.controller_type;
    wired_tape_request_p^.request := tape_request_p^.request;
    wired_tape_request_p^.tape_request_p := tape_request_p;
    wired_tape_request_p^.address_pair_count := 0;
    wired_tape_request_p^.list_p := NIL;
    wired_tape_request_p^.data_pages_locked := TRUE;
    wired_tape_request_p^.ready_task := FALSE;
    wired_tape_request_p^.wired_tape_table_index := i;
    IF tape_request_p^.io_type = ioc$explicit_read THEN
      mmp$test_for_cache_bypass(tape_request_p^.read_block_description^ [1].buffer_area,
            cache_bypass, status);   {Bad status will be detected later}
      wired_tape_request_p^.cache_purge_required_data := NOT cache_bypass;
      IF cache_bypass THEN
        mmp$test_for_cache_bypass(tape_request_p^.read_block_description^ [1].
              block_transfer_length, cache_bypass, status);   {Bad status will be detected later}
        wired_tape_request_p^.cache_purge_required_length := NOT cache_bypass;
      ELSE { do not repeat purge_cache if already did it on data pages
        wired_tape_request_p^.cache_purge_required_length := FALSE;
      IFEND;
    IFEND;

  /issue_monitor_req/
    WHILE TRUE DO

      i#call_monitor (#LOC (wired_tape_tables^ [i].request_block_p^),
            #SIZE (wired_tape_tables^ [i].request_block_p^));

      status.normal := wired_tape_tables^ [i].request_block_p^.status.normal;
      status.condition := wired_tape_tables^ [i].request_block_p^.status.condition;
      IF status.normal OR (NOT status.normal AND (status.condition <>
            mme$page_frame_not_assigned)) THEN
        EXIT /issue_monitor_req/;
      IFEND;

{ Reference each page to cause it to be loaded into memory.  This is only done
{ if a mme$page_frame_not_assigned status is returned from monitor after an
{ attempt to issue the request.  This error can only be returned if the operation
{ is ioc$explicit_read or ioc$explicit_write.

      page_size := osv$page_size;
      FOR l := 1 TO tape_request_p^.no_of_data_commands DO
        IF tape_request_p^.io_type = ioc$explicit_read THEN
          buffer_length := tape_request_p^.max_input_count;
          dummy_array_pointer := tape_request_p^.read_block_description^ [l].buffer_area;
        ELSE
          buffer_length := tape_request_p^.write_block_description^ [l].transfer_length;
          dummy_array_pointer := tape_request_p^.write_block_description^ [l].buffer_area;
        IFEND;
        no_of_pages := buffer_length DIV page_size;
        dump := dummy_array_pointer^ [1];
        dump1 := dummy_array_pointer^ [buffer_length];
        IF no_of_pages > 0 THEN
          FOR m := 1 TO no_of_pages DO
            dump := dummy_array_pointer^ [m * page_size];
          FOREND;
        IFEND;
        IF tape_request_p^.io_type = ioc$explicit_read THEN
          dump2 := tape_request_p^.read_block_description^ [l].block_transfer_length^;
        IFEND;
      FOREND;
    WHILEND /issue_monitor_req/;

    IF NOT status.normal THEN
      osp$unpack_status_identifier (wired_tape_tables^ [i].request_block_p^.status.condition, identifier);
      osp$set_status_abnormal (identifier, wired_tape_tables^ [i].request_block_p^.status.
            condition, 'Bad status from tape I/O monitor ', status);
      wired_tape_tables^ [i].slot_in_use := FALSE;
      FREE wired_tape_request_p^.wired_command_heap_p IN osv$mainframe_wired_cb_heap^;
    IFEND;

  PROCEND iop$tape_queue_request_setup;

?? OLDTITLE ??
?? NEWTITLE := ' iop$tape_request_not_processed ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$tape_request_not_processed (i: iot$io_id;
        j: iot$no_of_tape_units;
        q: 1 .. ioc$max_multiple_tape_requests;
    VAR status: ost$status);

    status.normal := TRUE;

{ Check if call to clear out waiting response on a request_not_processed completion_code (i = 0).

    IF i = 0 THEN
      iov$tape_completion_q_table^ [j].req [q].io_id := 0;
      iov$tape_completion_q_table^ [j].req [q].request_not_processed := FALSE;
      iov$tape_completion_q_table^ [j].req [q].waiting_response := FALSE;
      iov$tape_completion_q_table^ [j].req [q].io_request := NIL;
      iov$tape_completion_q_table^ [j].req [q].task_id := tmv$null_global_task_id;
      iov$tape_completion_q_table^ [j].req [q].check_task_id := FALSE;
    ELSE

{ Set request_not_processed status in iov$tape_completion_queue_table for the provided io_id.

      iov$tape_completion_q_table^ [j].req [q].io_id := i;
      iov$tape_completion_q_table^ [j].req [q].request_not_processed := TRUE;
      iov$tape_completion_q_table^ [j].req [q].waiting_response := TRUE;
    IFEND;

  PROCEND iop$tape_request_not_processed;

?? OLDTITLE ??
?? NEWTITLE := ' iop$tape_return_wired_request ' ??
?? EJECT ??

  PROCEDURE [XDCL, #GATE] iop$tape_return_wired_request (i: iot$no_of_tape_units;
        j: 1 .. ioc$max_multiple_tape_requests;
    VAR tape_request_p: ^iot$tape_request;
    VAR status: ost$status);

    VAR
      k: 1 .. ioc$max_multiple_tape_requests,
      m: iot$no_of_tape_units,
      n: 1 .. ioc$max_multiple_tape_requests,
      p_next_request: ^iot$io_request,
      p_ud: ^iot$tape_job_unit_descriptor,
      p_unit_table: ^iot$unit_interface_table,
      pending_wired_requests: array [1 .. ioc$max_multiple_tape_requests + 1] of ^iot$wired_tape_request,
      wired_request_p: ^iot$wired_tape_request;

    status.normal := TRUE;

{ Update pageable request and set wired_tape_tables slot to not is use.

    wired_request_p := iov$tape_completion_q_table^ [i].req [j].io_request^.device_request_p;
    tape_request_p := wired_request_p^.tape_request_p;
    tape_request_p^.pp_response_p^ := wired_request_p^.pp_response_p^;
    tape_request_p^.last_command_processed := wired_request_p^.pp_response_p^.pp_response.last_command -
          wired_request_p^.pp_response_p^.pp_response.request_rma;
    FREE wired_request_p^.wired_command_heap_p IN osv$mainframe_wired_cb_heap^;
    iov$wired_tape_tables^ [i][wired_request_p^.wired_tape_table_index].slot_in_use := FALSE;

{ Check for alert_condition where PP disabled the unit.

    IF tape_request_p^.pp_response_p^.pp_response.alert_conditions.disabled_unit THEN
      p_unit_table := cmv$logical_unit_table^ [tape_request_p^.request.logical_unit].unit_interface_table;

{ Check for pending_requests.

      IF p_unit_table^.next_request <> NIL THEN
        p_next_request := p_unit_table^.next_request;
        wired_request_p := p_next_request^.device_request_p;
        p_ud := wired_request_p^.tape_request_p^.ud;

{ Delink pending_requests from UIT.

        p_unit_table^.next_request := NIL;
        p_unit_table^.next_request_rma := 0;

{ Save wired_pending_request pointers in job_unit_descriptor_array.

      /pending_request_search/
        FOR k := 1 to ioc$max_multiple_tape_requests DO
          pending_wired_requests [k] := p_next_request^.device_request_p;
          p_next_request := pending_wired_requests [k]^.request.next_pp_request;
          IF p_next_request = NIL THEN
            pending_wired_requests [k + 1] := NIL;
            EXIT /pending_request_search/
          IFEND;
        FOREND /pending_request_search/;

{ Delink the wired_pending requests by clearing tape_completion_q_table, saving pointers
{ to pageable request in job_unit_descriptor, FREE wired_request structures, and finally
{ clear the disabled boolean in the UIT for this unit.

      /delink_pending_requests/
        FOR k := 1 to ioc$max_multiple_tape_requests DO
          wired_request_p := pending_wired_requests [k];
          p_ud^.pending_pageable_requests [k] := NIL;
          IF wired_request_p = NIL THEN
            EXIT /delink_pending_requests/
          IFEND;
          m := wired_request_p^.completion_q_index;
        /clear_completion_q_entry/
          FOR n := 1 to ioc$max_multiple_tape_requests DO
            IF iov$tape_completion_q_table^ [m].req [n].io_id = wired_request_p^.io_id THEN
              iov$tape_completion_q_table^ [m].req [n].io_id := 0;
              iov$tape_completion_q_table^ [m].req [n].io_request := NIL;
              iov$tape_completion_q_table^ [m].req [n].waiting_response := FALSE;
              iov$tape_completion_q_table^ [m].req [n].request_not_processed := FALSE;
              iov$tape_completion_q_table^ [m].req [n].task_id := tmv$null_global_task_id;
              iov$tape_completion_q_table^ [m].req [n].check_task_id := FALSE;
              EXIT /clear_completion_q_entry/
            IFEND;
          FOREND /clear_completion_q_entry/;

{ Save pointer to pending job_pageable_request in job_unit_descriptor.

          p_ud^.pending_pageable_requests [k] := wired_request_p^.tape_request_p;
          pending_wired_requests [k] := NIL;

{ Set wired_tape_tables slot to not in use and free RMA list.

          FREE wired_request_p^.wired_command_heap_p IN osv$mainframe_wired_cb_heap^;
          iov$wired_tape_tables^ [m][wired_request_p^.wired_tape_table_index].slot_in_use := FALSE;

        FOREND /delink_pending_requests/;
      IFEND;

{ Must clear unit_disabled status in UIT.

      p_unit_table^.unit_status.disabled := FALSE;

    IFEND;

{ Clear out the tape_completion_packet for this request/io_id.

    iov$tape_completion_q_table^ [i].req [j].waiting_response := FALSE;
    iov$tape_completion_q_table^ [i].req [j].request_not_processed := FALSE;
    iov$tape_completion_q_table^ [i].req [j].io_id := 0;
    iov$tape_completion_q_table^ [i].req [j].io_request := NIL;
    iov$tape_completion_q_table^ [i].req [j].task_id := tmv$null_global_task_id;
    iov$tape_completion_q_table^ [i].req [j].check_task_id := FALSE;

  PROCEND iop$tape_return_wired_request;

?? OLDTITLE ??
?? NEWTITLE := ' find_logical_pps_for_unit ' ??
?? EJECT ??

  PROCEDURE find_logical_pps_for_unit (lun: iot$logical_unit;
    VAR logical_pp: array [1 .. 4] of iot$pp_number;
    VAR status: ost$status);

    VAR
      index: 1 .. 4,
      logical_pp_table: ^cmt$logical_pp_table,
      lpp_index: iot$pp_number,
      ppit_p: ^iot$pp_interface_table,
      unit_descriptor_index: integer,
      unit_descriptors_p: ^iot$unit_descriptors;

    status.normal := TRUE;

    FOR index := 1 to 4 DO
      logical_pp [index] := 0;
    FOREND;
    index := 1;

    IF (cmv$new_logical_pp_table_p = NIL) OR (cmv$logical_pp_table_p = cmv$new_logical_pp_table_p) THEN
      logical_pp_table := cmv$logical_pp_table_p;
    ELSE
      logical_pp_table := cmv$new_logical_pp_table_p;
    IFEND;

    /lpp_search_loop/
    FOR lpp_index := LOWERBOUND (logical_pp_table^) TO UPPERBOUND (logical_pp_table^) DO
      IF logical_pp_table^ [lpp_index].flags.configured AND
          ((logical_pp_table^ [lpp_index].pp_info.pp_communication_buffer_p = NIL)
          OR (NOT logical_pp_table^ [lpp_index].pp_info.pp_communication_buffer_p^.slave)) THEN
        ppit_p := logical_pp_table^ [lpp_index].pp_info.pp_interface_table_p;
        IF (ppit_p^.first_logical_unit <= lun) AND (ppit_p^.first_logical_unit +
              ppit_p^.number_of_units > lun) THEN
          unit_descriptors_p := ^ppit_p^.unit_descriptors;
          FOR unit_descriptor_index := ppit_p^.first_logical_unit TO
                (ppit_p^.first_logical_unit + ppit_p^.number_of_units - 1) DO
            IF unit_descriptors_p^ [unit_descriptor_index].unit_interface_table <> NIL THEN
              IF unit_descriptors_p^ [unit_descriptor_index].logical_unit = lun THEN
                logical_pp [index] := lpp_index;
                IF index = 4 THEN
                  EXIT /lpp_search_loop/;  { found maximum number of logical pps
                ELSE
                  index := index + 1;
                  CYCLE /lpp_search_loop/;
                IFEND;
              IFEND;
            IFEND;
          FOREND;
        IFEND;
      IFEND;
    FOREND /lpp_search_loop/;

    IF index = 1 THEN {did not find any logical pp table containing input logical unit number
      osp$set_status_abnormal ('IO', ioc$os_failure,
            'unable to find logical pp table in tape_queue_manager_ring1.', status);
    IFEND;

  PROCEND find_logical_pps_for_unit;

?? OLDTITLE ??

MODEND iom$tape_queue_manager_ring1;

