?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Device Management' ??
MODULE dmm$activate_volume;
?? RIGHT := 110 ??

{ PURPOSE:
{  The purpose of this module is to complete the introduction of a device
{  to the system.  The mainframe is logged into the device, and space is
{  allocated to the mainframe for allocation.

?? NEWTITLE := 'Global Declarations Referenced By This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc i#call_monitor
*copyc mme$condition_codes
*copyc dmt$active_volume_table_index
*copyc dmt$dat_return_option
*copyc dmt$device_file_list_index
*copyc dmt$device_log_entries
*copyc dmt$error_condition_codes
*copyc dmt$mat_change_request
*copyc dmt$mat_converter
*copyc dmt$ms_device_allocation_table
*copyc ost$status
*copyc sft$file_space_limit_kind
?? POP ??
*copyc dmp$add_class_to_volume
*copyc dmp$attach_device_file
*copyc dmp$close_file
*copyc dmp$create_device_file
*copyc dmp$create_file_entry
*copyc dmp$destroy_file
*copyc dmp$detach_device_file
*copyc dmp$evacuate_active_device_log
*copyc dmp$get_mat_pointer
*copyc dmp$i_get_mat_pointer
*copyc dmp$initialize_device_log
*copyc dmp$lock_avt_entry
*copyc dmp$open_dat
*copyc dmp$open_dflt
*copyc dmp$open_login_table
*copyc dmp$process_sc_flaw_commands
*copyc dmp$search_avt_by_lun
*copyc dmp$unlock_avt_entry
*copyc dmp$volume_space_manager
*copyc dpp$put_critical_message
*copyc mmp$write_modified_pages
*copyc osp$clear_mainframe_sig_lock
*copyc osp$disable_pico_statistics
*copyc osp$enable_pico_statistics
*copyc osp$set_mainframe_sig_lock
*copyc osp$set_status_abnormal
*copyc osp$test_sig_lock
*copyc pmp$get_date
*copyc pmp$get_processor_attributes
*copyc pmp$get_time
*copyc pmp$zero_out_table
*copyc stp$disk_volume_active
*copyc syp$continue_to_cause
*copyc syp$disestablish_cond_handler
*copyc syp$establish_condition_handler
*copyc syp$process_deadstart_status
*copyc dmv$active_volume_table
*copyc dmv$idle_system
*copyc gfv$null_sfid
*copyc osv$recover_system_set_phase
*copyc syv$job_recovery_option
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared By This Module', EJECT ??

  VAR
    dmv$volume_class_kludge: [XREF] boolean,
    v$production_log_name: [STATIC, READ] ost$name := 'DMF$DEVICE_LOG',
    v$recovery_log_name: [STATIC, READ] ost$name := 'DMF$DUMMY_DEVICE_LOG';

?? OLDTITLE ??
?? NEWTITLE := 'P$CONDITION_HANDLER', EJECT ??

  PROCEDURE p$condition_handler
    (    avt_index: dmt$active_volume_table_index;
         monitor_fault: ost$monitor_fault;
         minimum_save_area_p: ^ost$minimum_save_area;
         dat_p: ^dmt$ms_device_allocation_table;
         dflt_p: ^dmt$ms_device_file_list_table;
         program_name: string ( * <= osc$max_name_size);
     VAR process_non_local_exit: boolean;
     VAR continue: syt$continue_option;
     VAR status: ost$status);

    VAR
      condition: ost$status_condition_code,
      identified_error: boolean,
      ignore_status: ost$status,
      lock_status: ost$signature_lock_status,
      msg1: string (26),
      msg2: string (6),
      p_sac: ^mmt$segment_access_condition,
      p_scc: ^syt$system_core_condition,
      str: string (70),
      strl: integer;

    process_non_local_exit := FALSE;
    IF monitor_fault.identifier = mmc$segment_fault_processor_id THEN
      p_sac := #LOC (monitor_fault.contents);
      IF p_sac^.identifier = mmc$sac_io_read_error THEN
        msg1 := 'I/O error on system table ';
        condition := mme$io_read_error;
        identified_error := TRUE;
      IFEND;

    ELSEIF monitor_fault.identifier = syc$system_core_condition THEN
      p_scc := #LOC (monitor_fault.system_core_condition);

      IF (p_scc^.condition = syc$user_defined_condition) AND
            (p_scc^.user_defined_condition = syc$udc_volume_unavailable) THEN
        msg1 := 'Volume unavailable ';
        identified_error := TRUE;
        condition := dme$volume_unavailable;
      IFEND;
    IFEND;

    IF identified_error THEN
      process_non_local_exit := TRUE;
      osp$test_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock, lock_status);
      IF lock_status = osc$sls_locked_by_current_task THEN
        osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);
      IFEND;
      IF dat_p <> NIL THEN
        msg2 := '-DAT-';
        dmp$close_file (dat_p, ignore_status);
      IFEND;
      IF dflt_p <> NIL THEN
        msg2 := '-DFL-';
        dmp$close_file (dflt_p, ignore_status);
      IFEND;

      STRINGREP (str, strl, msg1, msg2, dmv$active_volume_table.table_p^ [avt_index].mass_storage.
            recorded_vsn, ' - ', program_name);
      osp$set_status_abnormal (dmc$device_manager_ident, condition, str (1, strl), status);
    ELSE
      syp$continue_to_cause (monitor_fault, minimum_save_area_p, syc$condition_ignored, continue);
    IFEND;

  PROCEND p$condition_handler;
?? OLDTITLE ??
?? NEWTITLE := '[inline] P$END_RECOVERY_ALLOCATION', EJECT ??

  PROCEDURE [INLINE] p$end_recovery_allocation
    (    avt_index: dmt$active_volume_table_index);

    VAR
      p_mat: ^dmt$mainframe_allocation_table,
      mat_change_request: dmt$mat_change_request;

    dmp$get_mat_pointer (avt_index, p_mat);

    mat_change_request.request_code := syc$rc_apply_mat_changes;
    mat_change_request.avt_index := avt_index;
    mat_change_request.mat_change_type := dmc$change_dat_threshold;
    mat_change_request.dat_threshold := p_mat^.recovery_threshold;

    i#call_monitor (^mat_change_request, #SIZE (mat_change_request));

  PROCEND p$end_recovery_allocation;
?? OLDTITLE ??
?? NEWTITLE := '  p$establish_device_log', EJECT ??

  PROCEDURE p$establish_device_log
    (    device_log_name: ost$name;
     VAR avt_entry: {input/output} dmt$ms_active_vol_table_entry;
     VAR device_log_sfid: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      p_mat: ^dmt$mainframe_allocation_table,
      attributes: array [1 .. 1] of dmt$new_device_file_attribute,
      device_log_length: amt$file_byte_address;

    dmp$attach_device_file (avt_entry.recorded_vsn, device_log_name, device_log_sfid, status);

    IF NOT status.normal AND (status.condition = dme$unknown_device_file) THEN
      dmp$i_get_mat_pointer (avt_entry, p_mat);

      { The device log length must be enough to purge a file as big as the device
      { plus a little to spare. AND DO THIS * 3 FOR SAFETY AND FUTURE GROWTH

      device_log_length := (p_mat^.daus_per_position * p_mat^.positions_per_device *
            (#SIZE (dmt$dl_return_dau_block) + #SIZE (dmt$dl_release_dau_block) + 4
            {entry kind and check bytes} )) * 3;

      attributes [1].keyword := dmc$file_limit;
      attributes [1].limit := UPPERVALUE (attributes [1].limit);
      dmp$create_device_file (device_log_name, avt_entry.recorded_vsn, ^attributes, device_log_length,
            device_log_sfid, status);
    IFEND;

  PROCEND p$establish_device_log;
?? OLDTITLE ??
?? NEWTITLE := 'P$LOGIN_TO_VOLUME', EJECT ??

  PROCEDURE p$login_to_volume
    (    avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    VAR
      avt_entry_p: ^dmt$ms_active_vol_table_entry,
      p_login_table: ^dmt$ms_mainframe_login_table,
      status_p: ^ost$status;

?? NEWTITLE := 'P$INITIALIZE_LT_ENTRY', EJECT ??

    PROCEDURE p$initialize_lt_entry
      (    p_login_table: ^dmt$ms_mainframe_login_table;
           lt_entry_index: dmt$login_table_entry_index;
           login_sequence: dmt$login_table_sequence;
           recovery_status: dmt$login_table_recovery_status;
           avt_index: dmt$active_volume_table_index;
       VAR avt_entry: dmt$ms_active_vol_table_entry;
       VAR status: ost$status);

      VAR
        device_log_name: ost$name,
        global_file_name: dmt$global_file_name,
        login_table_entry_p: ^dmt$ms_mf_login_table_entry,
        processor_attributes: pmt$processor_attributes,
        system_file_id: gft$system_file_identifier;

      pmp$get_processor_attributes (processor_attributes, status); {status is always normal
      system_file_id := avt_entry.p_device_log;
      device_log_name := v$production_log_name;
      IF (system_file_id = gfv$null_sfid) THEN
        IF recovery_status = dmc$lt_recovering THEN
          device_log_name := v$recovery_log_name;
          dmp$create_file_entry (gfc$fk_global_unnamed, -$pft$usage_selections [], -$pft$share_selections [],
                dmc$minimum_file_share_his, NIL, 0, FALSE, global_file_name, system_file_id, status);
        ELSE
          p$establish_device_log (device_log_name, avt_entry, system_file_id, status);
        IFEND;
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      IFEND;

      login_table_entry_p := ^p_login_table^.body [lt_entry_index];
      login_table_entry_p^.mainframe_assigned.log_in_sequence := login_sequence;
      login_table_entry_p^.mainframe_assigned.log_in_index := lt_entry_index;
      login_table_entry_p^.mainframe_identification := processor_attributes;
      login_table_entry_p^.avt_index := avt_index;
      login_table_entry_p^.device_log_name := device_log_name;
      login_table_entry_p^.last_last_update_offset := 0;
      login_table_entry_p^.last_update_offset := 0;
      login_table_entry_p^.current_position_offset := 0;
      login_table_entry_p^.recovery_status := recovery_status;
      login_table_entry_p^.login_status := dmc$lt_mf_logged_in; {must be last}

      mmp$write_modified_pages (p_login_table, #SIZE (p_login_table^), osc$wait, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

{Update AVT
      avt_entry.mainframe_assigned := login_table_entry_p^.mainframe_assigned;
      avt_entry.logged_in_for_recovery := (recovery_status = dmc$lt_recovering);

      dmp$initialize_device_log (system_file_id, avt_index, status);

    PROCEND p$initialize_lt_entry;
?? OLDTITLE ??
?? NEWTITLE := 'LOGIN_TO_VOLUME', EJECT ??

    PROCEDURE login_to_volume
      (    avt_index: dmt$active_volume_table_index;
       VAR avt_entry: dmt$ms_active_vol_table_entry;
           login_table_p: ^dmt$ms_mainframe_login_table;
       VAR status: ost$status);

      VAR
        login_index: dmt$login_table_entries,
        login_sequence: dmt$login_table_sequence,
        login_table_entry_p: ^dmt$ms_mf_login_table_entry,
        login_type: dmt$login_table_recovery_status,
        number_of_dflt_entries_reset: integer,
        retained_mainframe: dmt$mainframe_assigned;

?? NEWTITLE := 'P$LOG_TO_CRITICAL_WINDOW', EJECT ??

      PROCEDURE p$log_to_critical_window
        (    vsn: rmt$recorded_vsn;
             number_of_dflt_entries_reset: integer);

        VAR
          i: integer,
          ignore_status: ost$status,
          message_line: string (60);

        STRINGREP (message_line, i, 'DFLT Entries reset on ', vsn, ': ', number_of_dflt_entries_reset);
        dpp$put_critical_message (message_line (1, i), ignore_status);

      PROCEND p$log_to_critical_window;
?? OLDTITLE ??
?? EJECT ??
      login_sequence := avt_entry.mainframe_assigned.log_in_sequence;
      login_index := avt_entry.mainframe_assigned.log_in_index;

      IF (login_sequence <> 0) THEN
        login_type := dmc$lt_normal_status;
        IF (login_table_p^.body [login_index].login_status <> dmc$lt_entry_available) THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$volume_already_active,
                avt_entry.recorded_vsn, status);
          RETURN; {----->
        IFEND;

      ELSE { Clean up after any failed recovery attempts.
        dmp$search_login_table (login_table_p, dmc$recovery_login_entry, login_index);

        IF (login_index <> 0) THEN
          login_table_entry_p := ^login_table_p^.body [login_index];
          dmp$return_dat_entries (login_table_entry_p^.mainframe_assigned, avt_index,
                dmc$return_specific_entry, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;

          dmp$return_dfl_entries (login_table_entry_p^.mainframe_assigned, avt_index, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;

{ Free LT Entry
          login_table_entry_p^.login_status := dmc$lt_entry_available;
          mmp$write_modified_pages (login_table_p, #SIZE (login_table_p^), osc$wait, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        IFEND;

{ Determine if recovery is required.
        dmp$search_login_table (login_table_p, dmc$production_login_entry, login_index);

        IF (login_index <> 0) THEN {recovery required}
          login_table_entry_p := ^login_table_p^.body [login_index];
          login_type := dmc$lt_recovering;
          retained_mainframe := login_table_entry_p^.mainframe_assigned;
          IF (login_table_entry_p^.recovery_status = dmc$lt_normal_status) THEN
            login_table_entry_p^.recovery_status := dmc$lt_being_recovered;
            mmp$write_modified_pages (login_table_p, #SIZE (login_table_p^), osc$wait, status);
            IF NOT status.normal THEN
              RETURN; {----->
            IFEND;
          IFEND;
        ELSE {no recovery required}
          login_type := dmc$lt_normal_status;
          retained_mainframe := avt_entry.mainframe_assigned;

{ Return DFL entries from any previous idle_system.
          p$return_all_dfl_entries (avt_index, number_of_dflt_entries_reset, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
          IF number_of_dflt_entries_reset > 0 THEN
            p$log_to_critical_window (avt_entry.recorded_vsn, number_of_dflt_entries_reset);
          IFEND;
        IFEND;

{ If no job recovery - return unused DAT entries.
        IF syv$job_recovery_option <> syc$jre_enabled THEN
          dmp$return_dat_entries (retained_mainframe, avt_index, dmc$return_all_except_entry, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        IFEND;
      IFEND;

{ Locate free login table entry.
      dmp$search_login_table (login_table_p, dmc$free_login_entry, login_index);
      IF (login_index = 0) THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$login_table_full, avt_entry.recorded_vsn,
              status);
        RETURN; {----->
      ELSE
        login_table_p^.header.sequence := login_table_p^.header.sequence + 1;
        login_sequence := login_table_p^.header.sequence;
      IFEND;

{ Login to volume.
      p$initialize_lt_entry (login_table_p, login_index, login_sequence, login_type, avt_index, avt_entry,
            status);

    PROCEND login_to_volume;
?? OLDTITLE ??
?? EJECT ??
    avt_entry_p := ^dmv$active_volume_table.table_p^ [avt_index].mass_storage;
    dmp$open_login_table (avt_entry_p^.p_login_table, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
          mmc$as_sequential, p_login_table, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    login_to_volume (avt_index, avt_entry_p^, p_login_table, status);

    IF status.normal THEN
      status_p := ^status;
    ELSE
      PUSH status_p;
    IFEND;

    dmp$close_file (p_login_table, status_p^);

  PROCEND p$login_to_volume;
?? OLDTITLE ??
?? NEWTITLE := 'P$RETURN_ALL_DFL_ENTRIES', EJECT ??

  PROCEDURE p$return_all_dfl_entries
    (    avt_index: dmt$active_volume_table_index;
     VAR number_of_dflt_entries_reset: integer;
     VAR status: ost$status);

    VAR
      able: boolean,
      avt_entry_p: ^dmt$ms_active_vol_table_entry,
      dfl_index: dmt$device_file_list_index,
      p_dflt: ^dmt$ms_device_file_list_table,
      status_p: ^ost$status;

?? NEWTITLE := 'DFL_CONDITION_HANDLER', EJECT ??

    PROCEDURE dfl_condition_handler
      (    mf: ost$monitor_fault;
           p_msa: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      VAR
        process_non_local_exit: boolean;

      p$condition_handler (avt_index, mf, p_msa, NIL, p_dflt, 'p$return_all_dfl_entries',
            process_non_local_exit, continue, status);
      IF process_non_local_exit THEN
        EXIT p$return_all_dfl_entries; {----->
      IFEND;

    PROCEND dfl_condition_handler;
?? OLDTITLE ??
?? EJECT ??
    number_of_dflt_entries_reset := 0;
    avt_entry_p := ^dmv$active_volume_table.table_p^ [avt_index].mass_storage;
    dmp$open_dflt (avt_entry_p^.p_device_file_list_table, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
          mmc$as_sequential, p_dflt, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    #SPOIL (p_dflt);

    osp$set_mainframe_sig_lock (avt_entry_p^.update_lock);

    syp$establish_condition_handler (^dfl_condition_handler);

    FOR dfl_index := 1 TO UPPERBOUND (p_dflt^.entries) DO
      IF p_dflt^.entries [dfl_index].flags = dmc$dfle_assigned_to_mainframe THEN

        {! Return all entries not belonging to the current deadstart !!!!!

        IF p_dflt^.entries [dfl_index].mainframe_assigned <> avt_entry_p^.mainframe_assigned THEN
          p_dflt^.entries [dfl_index].flags := dmc$dfle_available;
          number_of_dflt_entries_reset := number_of_dflt_entries_reset + 1;
        IFEND;
      IFEND;
    FOREND;

    syp$disestablish_cond_handler;

    osp$clear_mainframe_sig_lock (avt_entry_p^.update_lock);
    mmp$write_modified_pages (p_dflt, #SIZE (p_dflt^), osc$wait, status);

    IF status.normal THEN
      status_p := ^status;
    ELSE
      PUSH status_p;
    IFEND;

    dmp$close_file (p_dflt, status_p^);

  PROCEND p$return_all_dfl_entries;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate] DMP$ACTIVATE_VOLUME', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$activate_volume
    (    logical_unit_number: iot$logical_unit;
     VAR status: ost$status);

    CONST
      c$full_update = TRUE;

    VAR
      avt_entry_found: boolean,
      avt_entry_p: ^dmt$ms_active_vol_table_entry,
      avt_index: dmt$active_volume_table_index,
      internal_vsn: dmt$internal_vsn,
      recorded_vsn: rmt$recorded_vsn,
      set_name: stt$set_name;

    status.normal := TRUE;
    dmp$search_avt_by_lun (logical_unit_number, avt_index, avt_entry_found);
    IF NOT avt_entry_found THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$volume_not_online, 'dmp$activate_volume',
            status);
      RETURN; {----->
    IFEND;

    dmp$lock_avt_entry (avt_index);

    avt_entry_p := ^dmv$active_volume_table.table_p^ [avt_index].mass_storage;
    dmp$process_sc_flaw_commands (avt_index, avt_entry_p^.p_device_allocation_table,
          avt_entry_p^.recorded_vsn, status);

    p$login_to_volume (avt_index, status);
    IF status.normal THEN
      recorded_vsn := avt_entry_p^.recorded_vsn;
      internal_vsn := avt_entry_p^.internal_vsn;
      avt_entry_p^.disk_table_status := avt_entry_p^.disk_table_status +
            $dmt$ms_volume_table_status [dmc$dflt_update_required];
      avt_entry_p^.status := avt_entry_p^.status + $dmt$ms_volume_system_status [dmc$mainframe_mounted];
      avt_entry_p^.status := avt_entry_p^.status - $dmt$ms_volume_system_status [dmc$mainframe_dismounted];
      avt_entry_p^.allocation_allowed := TRUE;
    IFEND;

    dmp$unlock_avt_entry (avt_index);

    IF status.normal THEN
      IF NOT avt_entry_p^.logged_in_for_recovery THEN
        p$end_recovery_allocation (avt_index);
      IFEND;

      osp$disable_pico_statistics;
      dmp$volume_space_manager (avt_index, c$full_update, status);
      osp$enable_pico_statistics;
    IFEND;

    IF status.normal THEN
      IF NOT dmv$idle_system THEN
        stp$disk_volume_active (recorded_vsn, internal_vsn, avt_index, set_name, status);
        avt_entry_p^.set_name := set_name;
      IFEND;
    IFEND;

    IF dmv$volume_class_kludge THEN
      dmp$add_class_to_volume (avt_index, -$dmt$class [], status);
    IFEND;

  PROCEND dmp$activate_volume;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl] DMP$DEACTIVATE_VOLUME', EJECT ??

  PROCEDURE [XDCL] dmp$deactivate_volume
    (    avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    VAR
      avt_entry_p: ^dmt$ms_active_vol_table_entry,
      close_status: ost$status,
      login_index: dmt$login_table_entry_index,
      mainframe_assigned: dmt$mainframe_assigned,
      mat_converter: dmt$mat_converter,
      p_login_table: ^dmt$ms_mainframe_login_table;

    avt_entry_p := ^dmv$active_volume_table.table_p^ [avt_index].mass_storage;
    dmp$open_login_table (avt_entry_p^.p_login_table, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
          mmc$as_sequential, p_login_table, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    mainframe_assigned := avt_entry_p^.mainframe_assigned;
    login_index := mainframe_assigned.log_in_index;

    IF (p_login_table^.body [login_index].login_status = dmc$lt_mf_logged_in) AND
          (mainframe_assigned = p_login_table^.body [login_index].mainframe_assigned) THEN
      dmp$evacuate_active_device_log (avt_index, status);
    ELSE
      osp$set_status_abnormal (dmc$device_manager_ident, dme$mainframe_not_logged_in,
            avt_entry_p^.recorded_vsn, status);
    IFEND;

    IF status.normal THEN
      avt_entry_p^.p_device_log := gfv$null_sfid;
      avt_entry_p^.allocation_allowed := FALSE;

      p_login_table^.body [login_index].login_status := dmc$lt_entry_available;
      mmp$write_modified_pages (p_login_table, #SIZE (p_login_table^), osc$wait, status);
    IFEND;

    dmp$close_file (p_login_table, close_status);
    IF status.normal AND NOT close_status.normal THEN
      status := close_status;
    IFEND;

    IF status.normal THEN
      dmp$get_mat_pointer (avt_index, mat_converter.p_mat);
      dmp$return_mat_space (mat_converter.p_adaptable, mainframe_assigned, avt_index, status);
    IFEND;

  PROCEND dmp$deactivate_volume;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate] DMP$LOGOUT_RECOVERED_MAINFRAME', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$logout_recovered_mainframe
    (    avt_index: dmt$active_volume_table_index;
         lt_entry_index: dmt$login_table_entries;
     VAR status: ost$status);

    VAR
      p_login_table: ^dmt$ms_mainframe_login_table,
      status_p: ^ost$status;

    dmp$open_login_table (dmv$active_volume_table.table_p^ [avt_index].mass_storage.p_login_table,
          osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential, p_login_table, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    p_login_table^.body [lt_entry_index].login_status := dmc$lt_entry_available;
    mmp$write_modified_pages (p_login_table, #SIZE (p_login_table^), osc$wait, status);

    IF status.normal THEN
      status_p := ^status;
    ELSE
      PUSH status_p;
    IFEND;

    dmp$close_file (p_login_table, status_p^);

  PROCEND dmp$logout_recovered_mainframe;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate] DMP$RETURN_DAT_ENTRIES', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$return_dat_entries
    (    mainframe_assigned: dmt$mainframe_assigned;
         avt_index: dmt$active_volume_table_index;
         return_option: dmt$dat_return_option;
     VAR status: ost$status);

    VAR
      able: boolean,
      avt_entry_p: ^dmt$ms_active_vol_table_entry,
      dau_index: dmt$dau_address,
      mat_change_request: dmt$mat_change_request,
      number_of_usable_daus: dmt$dau_address,
      p_dat: ^dmt$ms_device_allocation_table,
      status_p: ^ost$status;

?? NEWTITLE := 'DAT_CONDITION_HANDLER', EJECT ??

    PROCEDURE dat_condition_handler
      (    mf: ost$monitor_fault;
           p_msa: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      VAR
        process_non_local_exit: boolean;

      p$condition_handler (avt_index, mf, p_msa, p_dat, NIL, 'dmp$return_dat_entries', process_non_local_exit,
            continue, status);
      IF process_non_local_exit THEN
        EXIT dmp$return_dat_entries; {----->
      IFEND;

    PROCEND dat_condition_handler;
?? OLDTITLE ??
?? EJECT ??
    avt_entry_p := ^dmv$active_volume_table.table_p^ [avt_index].mass_storage;
    dmp$open_dat (avt_entry_p^.p_device_allocation_table, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
          mmc$as_sequential, p_dat, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    #SPOIL (p_dat);

    osp$set_mainframe_sig_lock (avt_entry_p^.update_lock);

    syp$establish_condition_handler (^dat_condition_handler);
    number_of_usable_daus := 0;

    FOR dau_index := 0 TO UPPERBOUND (p_dat^.body) DO
      CASE p_dat^.body [dau_index].dau_status OF
      = dmc$dau_usable =
        number_of_usable_daus := number_of_usable_daus + 1;

      = dmc$dau_assigned_to_mainframe =
        IF (return_option = dmc$return_specific_entry) THEN
          IF p_dat^.body [dau_index].mainframe_id = mainframe_assigned THEN
            p_dat^.body [dau_index].dau_status := dmc$dau_usable;
            number_of_usable_daus := number_of_usable_daus + 1;
          IFEND;
        ELSE
          {Return all EXCEPT mfid specified and the current mfid
          IF (p_dat^.body [dau_index].mainframe_id <> mainframe_assigned)
{       } AND (p_dat^.body [dau_index].mainframe_id <> avt_entry_p^.mainframe_assigned) THEN
            p_dat^.body [dau_index].dau_status := dmc$dau_usable;
            number_of_usable_daus := number_of_usable_daus + 1;
          IFEND;
        IFEND;

      = dmc$dau_ass_to_mf_swr_flawed =
        IF p_dat^.body [dau_index].mainframe_id = mainframe_assigned THEN
          p_dat^.body [dau_index].dau_status := dmc$dau_software_flawed;
        IFEND;
      ELSE
      CASEND;
    FOREND;

    p_dat^.header.available := number_of_usable_daus;

{ Tell monitor to update "available_dat_space" in the MAT.
    mat_change_request.request_code := syc$rc_apply_mat_changes;
    mat_change_request.avt_index := avt_index;
    mat_change_request.mat_change_type := dmc$add_mat_space;
    mat_change_request.mat_change_count := 0;
    mat_change_request.p_mat_changes := NIL;
    mat_change_request.available_dat_space := number_of_usable_daus;

    i#call_monitor (^mat_change_request, #SIZE (mat_change_request));

    syp$disestablish_cond_handler;

    osp$clear_mainframe_sig_lock (avt_entry_p^.update_lock);
    mmp$write_modified_pages (p_dat, #SIZE (p_dat^), osc$wait, status);

    IF status.normal THEN
      status_p := ^status;
    ELSE
      PUSH status_p;
    IFEND;

    dmp$close_file (p_dat, status_p^);

  PROCEND dmp$return_dat_entries;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate]  DMP$RETURN_DFL_ENTRIES', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$return_dfl_entries
    (    mainframe_assigned: dmt$mainframe_assigned;
         avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    VAR
      able: boolean,
      dfl_index: dmt$device_file_list_index,
      p_dflt: ^dmt$ms_device_file_list_table,
      status_p: ^ost$status;

?? NEWTITLE := 'DFL_CONDITION_HANDLER', EJECT ??

    PROCEDURE dfl_condition_handler
      (    mf: ost$monitor_fault;
           p_msa: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      VAR
        process_non_local_exit: boolean;

      p$condition_handler (avt_index, mf, p_msa, NIL, p_dflt, 'dmp$return_dfl_entries',
            process_non_local_exit, continue, status);
      IF process_non_local_exit THEN
        EXIT dmp$return_dfl_entries; {----->
      IFEND;

    PROCEND dfl_condition_handler;
?? OLDTITLE ??
?? EJECT ??
    dmp$open_dflt (dmv$active_volume_table.table_p^ [avt_index].mass_storage.p_device_file_list_table,
          osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential, p_dflt, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    #SPOIL (p_dflt);

    osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

    syp$establish_condition_handler (^dfl_condition_handler);

{Note: Loop is slower with a local pointer to p_dflt^.entries [dfl_index]!
    FOR dfl_index := 1 TO UPPERBOUND (p_dflt^.entries) DO
      IF (p_dflt^.entries [dfl_index].flags = dmc$dfle_assigned_to_mainframe)
{   } AND (p_dflt^.entries [dfl_index].mainframe_assigned = mainframe_assigned) THEN
        p_dflt^.entries [dfl_index].flags := dmc$dfle_available;
      IFEND;
    FOREND;

    syp$disestablish_cond_handler;

    osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);
    mmp$write_modified_pages (p_dflt, #SIZE (p_dflt^), osc$wait, status);

    IF status.normal THEN
      status_p := ^status;
    ELSE
      PUSH status_p;
    IFEND;

    dmp$close_file (p_dflt, status_p^);

  PROCEND dmp$return_dfl_entries;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate] DMP$RETURN_MAT_SPACE', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$return_mat_space
    (    mat_pointer: cyt$adaptable_array_pointer;
         mainframe_assigned: dmt$mainframe_assigned;
         avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    TYPE
      t$daus_converter = record
        case boolean of
        = FALSE =
          p_adaptable: cyt$adaptable_array_pointer,
        = TRUE =
          p_available_daus: ^dmt$available_daus,
        casend,
      recend;

    VAR
      able: boolean,
      active_mat: boolean,
      allocation_style: dmt$allocation_styles,
      current_daus_pointer: cyt$adaptable_array_pointer,
      current_mat_pointer: cyt$adaptable_array_pointer,
      dau: dmt$dau_address,
      daus_converter: t$daus_converter,
      daus_pointer: cyt$adaptable_array_pointer,
      good_mat: boolean,
      mat_change_request: dmt$mat_change_request,
      mat_converter: dmt$mat_converter,
      p_available_daus: ^dmt$available_daus,
      p_dat: ^dmt$ms_device_allocation_table,
      p_mat: ^dmt$mainframe_allocation_table,
      position: dmt$device_position,
      returned_daus: dmt$dau_address,
      segment: ost$segment;

?? NEWTITLE := 'P$RETURN_MAT_SPACE_COND_HANDLER', EJECT ??

    PROCEDURE p$return_mat_space_cond_handler
      (    mf: ost$monitor_fault;
           p_msa: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      VAR
        process_non_local_exit: boolean;

      p$condition_handler (avt_index, mf, p_msa, p_dat, NIL, 'dmp$return_mat_space', process_non_local_exit,
            continue, status);
      IF process_non_local_exit THEN
        EXIT dmp$return_mat_space; {----->
      IFEND;

    PROCEND p$return_mat_space_cond_handler;
?? OLDTITLE ??
?? EJECT ??
    segment := #SEGMENT (mat_pointer.pointer);
    mat_converter.p_adaptable := mat_pointer;
    mat_converter.p_adaptable.pointer := #ADDRESS (1, segment, #OFFSET (mat_converter.p_adaptable.pointer));
    p_mat := mat_converter.p_mat;

    daus_converter.p_available_daus := p_mat^.p_available_daus;
    daus_converter.p_adaptable.pointer := #ADDRESS (1, segment, #OFFSET (daus_converter.p_adaptable.pointer));
    daus_pointer := daus_converter.p_adaptable;
    p_available_daus := daus_converter.p_available_daus;

    dmp$get_mat_pointer (avt_index, mat_converter.p_mat);
    active_mat := (p_mat = mat_converter.p_mat);
    current_mat_pointer := mat_converter.p_adaptable;
    daus_converter.p_available_daus := mat_converter.p_mat^.p_available_daus;
    current_daus_pointer := daus_converter.p_adaptable;

    good_mat := (mat_pointer.array_size = current_mat_pointer.array_size) AND
          (mat_pointer.lower_bound = current_mat_pointer.lower_bound) AND
          (mat_pointer.element_size = current_mat_pointer.element_size) AND
          (daus_pointer.array_size = current_daus_pointer.array_size) AND
          (daus_pointer.lower_bound = current_daus_pointer.lower_bound) AND
          (daus_pointer.element_size = current_daus_pointer.element_size);

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

    dmp$open_dat (dmv$active_volume_table.table_p^ [avt_index].mass_storage.p_device_allocation_table,
          osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential, p_dat, status);
    #SPOIL (p_dat);

    IF status.normal THEN
      osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

      syp$establish_condition_handler (^p$return_mat_space_cond_handler);

      returned_daus := 0;
      FOR dau := LOWERBOUND (p_dat^.body) TO UPPERBOUND (p_dat^.body) DO
        IF p_available_daus^ [dau] THEN
          IF (p_dat^.body [dau].dau_status = dmc$dau_assigned_to_mainframe) THEN
            IF (p_dat^.body [dau].mainframe_id = mainframe_assigned) THEN
              p_dat^.body [dau].dau_status := dmc$dau_usable;
              returned_daus := returned_daus + 1;
            IFEND;
          ELSEIF (p_dat^.body [dau].dau_status = dmc$dau_ass_to_mf_swr_flawed) THEN
            IF (p_dat^.body [dau].mainframe_id = mainframe_assigned) THEN
              p_dat^.body [dau].dau_status := dmc$dau_software_flawed;
            IFEND;
          IFEND;
        IFEND;
      FOREND;

      p_dat^.header.available := p_dat^.header.available + returned_daus;

      IF active_mat THEN
        FOR allocation_style := LOWERVALUE (allocation_style) TO UPPERVALUE (allocation_style) DO
          p_mat^.available_allocation_units [allocation_style] := 0;
          p_mat^.allocation_chains [allocation_style] := dmc$nil_position_link;
        FOREND;

        p_mat^.available_dat_space := p_mat^.available_dat_space + p_mat^.available_space +
              p_mat^.leftover_space;
        p_mat^.available_space := 0;
        p_mat^.leftover_space := 0;

        FOR dau := LOWERBOUND (p_available_daus^) TO UPPERBOUND (p_available_daus^) DO
          p_available_daus^ [dau] := FALSE;
        FOREND;

        FOR position := LOWERBOUND (p_mat^.mat_entries) TO UPPERBOUND (p_mat^.mat_entries) DO
          p_mat^.mat_entries [position].available_allocation_units := 0;
          p_mat^.mat_entries [position].backward_link := dmc$nil_position_link;
          p_mat^.mat_entries [position].forward_link := dmc$nil_position_link;
        FOREND;
      ELSE

        { Tell monitor to update "available_dat_space" in the MAT.

        mat_change_request.request_code := syc$rc_apply_mat_changes;
        mat_change_request.avt_index := avt_index;
        mat_change_request.mat_change_type := dmc$add_mat_space;
        mat_change_request.mat_change_count := 0;
        mat_change_request.p_mat_changes := NIL;
        mat_change_request.available_dat_space := p_dat^.header.available;

        i#call_monitor (^mat_change_request, #SIZE (mat_change_request));
      IFEND;

      syp$disestablish_cond_handler;
      osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

      mmp$write_modified_pages (p_dat, #SIZE (p_dat^), osc$wait, status);

      dmp$close_file (p_dat, status);
    IFEND;

  PROCEND dmp$return_mat_space;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] DMP$SEARCH_LOGIN_TABLE', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$search_login_table
    (    p_login_table: ^dmt$ms_mainframe_login_table;
         login_entry_type: dmt$login_entry_type;
     VAR lt_entry_index: dmt$login_table_entries);

    VAR
      entry_index: dmt$login_table_entry_index,
      found: boolean,
      login_table_entry_p: ^dmt$ms_mf_login_table_entry;

    lt_entry_index := 0;

    IF (login_entry_type = dmc$free_login_entry) THEN
      FOR entry_index := 1 TO UPPERBOUND (p_login_table^.body) DO
        IF p_login_table^.body [entry_index].login_status = dmc$lt_entry_available THEN
          login_table_entry_p := ^p_login_table^.body [entry_index];
          lt_entry_index := entry_index;
          RETURN; {----->
        IFEND;
      FOREND;
    ELSE
      FOR entry_index := 1 TO UPPERBOUND (p_login_table^.body) DO
        login_table_entry_p := ^p_login_table^.body [entry_index];
        IF login_table_entry_p^.login_status <> dmc$lt_entry_available THEN
          found := ((login_table_entry_p^.recovery_status = dmc$lt_recovering) AND
                (login_entry_type = dmc$recovery_login_entry)) OR
                ((login_table_entry_p^.recovery_status <> dmc$lt_recovering) AND
                (login_entry_type = dmc$production_login_entry));
          IF found THEN
            lt_entry_index := entry_index;
            RETURN; {----->
          IFEND;
        IFEND;
      FOREND;
    IFEND;

  PROCEND dmp$search_login_table;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate] DMP$START_VOLUME_PRODUCTION', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$start_volume_production
    (    avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    VAR
      avt_entry_p: ^dmt$ms_active_vol_table_entry,
      avt_locked: boolean,
      local_status: ost$status,
      login_index: dmt$login_table_entry_index,
      login_table_entry_p: ^dmt$ms_mf_login_table_entry,
      p_login_table: ^dmt$ms_mainframe_login_table,
      production_log_name: ost$name,
      production_log_sfid: gft$system_file_identifier,
      recovery_log_sfid: gft$system_file_identifier;

    avt_entry_p := ^dmv$active_volume_table.table_p^ [avt_index].mass_storage;
    login_index := avt_entry_p^.mainframe_assigned.log_in_index;
    dmp$open_login_table (avt_entry_p^.p_login_table, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
          mmc$as_sequential, p_login_table, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    login_table_entry_p := ^p_login_table^.body [login_index];
    IF (login_table_entry_p^.recovery_status <> dmc$lt_recovering) THEN
      dmp$close_file (p_login_table, status);
      RETURN; {----->
    IFEND;

    production_log_name := v$production_log_name;
    p$establish_device_log (production_log_name, avt_entry_p^, production_log_sfid, status);

    IF status.normal THEN
      dmp$evacuate_active_device_log (avt_index, status);
    IFEND;

    avt_locked := FALSE;
    IF status.normal THEN
      dmp$lock_avt_entry (avt_index);
      avt_locked := TRUE;
    IFEND;

    IF status.normal THEN
      recovery_log_sfid := avt_entry_p^.p_device_log;
      avt_entry_p^.p_device_log := gfv$null_sfid;
      avt_entry_p^.logged_in_for_recovery := FALSE;
      login_table_entry_p^.device_log_name := production_log_name;
      login_table_entry_p^.last_last_update_offset := 0;
      login_table_entry_p^.last_update_offset := 0;
      login_table_entry_p^.current_position_offset := 0;
      login_table_entry_p^.recovery_status := dmc$lt_normal_status;
    IFEND;

    dmp$close_file (p_login_table, local_status);
    IF status.normal AND NOT local_status.normal THEN
      status := local_status;
    IFEND;

    IF status.normal THEN
      dmp$initialize_device_log (production_log_sfid, avt_index, status);
    IFEND;

    IF avt_locked THEN
      dmp$unlock_avt_entry (avt_index);
    IFEND;

    IF status.normal THEN
      dmp$destroy_file (recovery_log_sfid, sfc$no_limit, status);
    IFEND;

    IF status.normal THEN
      p$end_recovery_allocation (avt_index);
    IFEND;

  PROCEND dmp$start_volume_production;
?? OLDTITLE ??
?? NEWTITLE := '[xdcl, #gate] DMP$VOLUME_IS_ACTIVE', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$volume_is_active
    (    logical_unit_number: iot$logical_unit;
     VAR volume_active: boolean);

    VAR
      avt_index: dmt$active_volume_table_index;

    dmp$search_avt_by_lun (logical_unit_number, avt_index, volume_active);
    IF NOT volume_active THEN
      RETURN; {----->
    IFEND;

    volume_active := dmv$active_volume_table.table_p^ [avt_index].mass_storage.p_device_log <> gfv$null_sfid;

  PROCEND dmp$volume_is_active;
?? OLDTITLE ??
MODEND dmm$activate_volume;
