MODULE rmm$complete_tape_operations;
?? ROGHT := 110 ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$job_paged_literal
*copyc ame$improper_file_id
*copyc dme$tape_errors
*copyc fse$attach_validation_errors
*copyc dmt$tape_assignment_operation
*copyc dmt$tape_job_lun_table
*copyc fst$file_reference
*copyc fst$goi_object_information
*copyc ost$name
*copyc ost$status
*copyc pft$cycle_selector
*copyc pft$path
*copyc pft$usage_selections
*copyc rmt$density
*copyc rmt$volume_descriptor
*copyc rmt$write_ring
?? POP ??
*copyc amp$access_method
*copyc amp$set_file_instance_abnormal
*copyc bap$set_evaluated_file_abnormal
*copyc bap$validate_file_identifier
*copyc clp$convert_file_ref_to_string
*copyc clp$convert_integer_to_string
*copyc dmp$close_current_tape_volume
*copyc dmp$close_tape_volume
*copyc dmp$create_tape_file_sfid
*copyc dmp$get_tape_volume_information
*copyc fmp$attach_file
*copyc fmp$get_system_file_id
*copyc fsp$evaluate_file_reference
*copyc fsp$path_element
*copyc osp$generate_unique_binary_name
*copyc pfp$convert_fs_to_pft$path
*copyc pfp$get_object_information
*copyc pfp$r3_append_rem_media_vsn
*copyc pfp$r3_define_removable_media
*copyc bav$global_tape_fap_variables
*copyc fmv$default_detachment_options
*copyc iov$number_of_tape_units
*copyc pfv$write_usage

  CONST
    command_file_reference_allowed = TRUE,
    max_tape_volumes = 256;

  VAR
    goi_information_request: [oss$job_paged_literal, READ] fst$goi_information_request :=
          [[fsc$specific_depth, 1], [fsc$goi_catalog_identity, fsc$goi_catalog_device_info,
          fsc$goi_cycle_device_info]];

?? TITLE := 'rmp$complete_tape_assignment', EJECT ??

  PROCEDURE [XDCL] rmp$complete_tape_assignment (
         file_identifier: amt$file_identifier;
         file: fst$file_reference;
         density: rmt$density;
         write_ring: rmt$write_ring;
         file_label_type: amt$file_label_type;
         access_mode: pft$usage_selections;
         initial_assignment: boolean;
         next_volume: amt$volume_number;
         volume_descriptor: rmt$volume_descriptor;
         removable_media_group: ost$name;
         removable_media_location: ost$name;
     VAR operator_terminated_assignment: boolean;
     VAR status: ost$status);

    VAR
      call_block: amt$call_block,
      current_volume: amt$volume_number,
      current_vsns: rmt$volume_descriptor,
      cycle_selector: pft$cycle_selector,
      detachment_options: fmt$detachment_options,
      evaluated_file_reference: fst$evaluated_file_reference,
      file_instance: ^bat$task_file_entry,
      first_volume_descriptor: rmt$volume_descriptor,
      fs_path: fst$path,
      fs_path_size: fst$path_size,
      ignore_current_volume: amt$volume_number,
      ignore_current_vsns: rmt$volume_descriptor,
      ignore_density: rmt$density,
      ignore_device_class: rmt$device_class,
      ignore_label_type: amt$label_type,
      ignore_removable_media_req_info: ^fmt$removable_media_req_info,
      ignore_volume_attributes: iot$requested_volume_attributes,
      ignore_volume_overflow_allowed: boolean,
      ignore_write_ring: rmt$write_ring,
      label_type: amt$label_type,
      number_of_volumes: 0 .. amc$max_vol_number,
      number_of_volumes_after_assign: amt$volume_number,
      number_of_volumes_before_assign: amt$volume_number,
      open_tape_volume: ^amt$open_tape_volume,
      p_object_info_seq: ^SEQ ( * ),
      p_object_information: ^fst$goi_object_information,
      p_path: ^pft$path,
      sfid: gft$system_file_identifier,
      validation_ok: boolean,
      volume_list: ^rmt$volume_list;

    bap$validate_file_identifier (file_identifier, file_instance, validation_ok);
    IF NOT validation_ok THEN
      amp$set_file_instance_abnormal (file_identifier, ame$improper_file_id,
          LOWERVALUE (amt$last_operation), '', status);
      RETURN;
    IFEND;

{ If there is a current volume assigned to the tape file then return
{ the current tape volume before requesting the next tape volume.

    IF NOT initial_assignment THEN
      fmp$get_system_file_id (file_instance^.local_file_name, sfid, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      detachment_options := fmv$default_detachment_options;
      detachment_options.device_class := rmc$magnetic_tape_device;
      detachment_options.physical_unload := TRUE;
      dmp$close_current_tape_volume (sfid, detachment_options, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF (fsp$path_element (^evaluated_file_reference, 1)^ <> fsc$local) AND
            ((access_mode * pfv$write_usage) <> $pft$usage_selections []) AND
            ((volume_descriptor.external_vsn = rmc$unspecified_vsn) AND
            (volume_descriptor.recorded_vsn = rmc$unspecified_vsn)) THEN
        dmp$get_tape_volume_information (sfid, number_of_volumes_before_assign, ignore_current_volume,
              ignore_current_vsns, ignore_density, ignore_write_ring, ignore_volume_attributes,
              ignore_volume_overflow_allowed, ignore_label_type, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      IFEND;
    IFEND;

    fsp$evaluate_file_reference (file, command_file_reference_allowed, evaluated_file_reference, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Now ask for the next tape volume to be assigned. This request will first
{ go to the RMS fap if installed and then go to the site hook for processing.

    PUSH open_tape_volume;
    call_block.operation := amc$open_tape_volume;
    call_block.open_tape_volume := open_tape_volume;

    open_tape_volume^.tape_density := density;
    open_tape_volume^.write_ring := write_ring;
    open_tape_volume^.file_label_type := file_label_type;
    open_tape_volume^.access_mode := access_mode;
    open_tape_volume^.initial_assignment := initial_assignment;
    open_tape_volume^.opening_volume_number := next_volume;
    open_tape_volume^.opening_volume := volume_descriptor;
    open_tape_volume^.removable_media_group := removable_media_group;
    open_tape_volume^.removable_media_location := removable_media_location;
    open_tape_volume^.account := osc$null_name;
    open_tape_volume^.family := osc$null_name;
    open_tape_volume^.project := osc$null_name;
    open_tape_volume^.slot := osc$null_name;
    open_tape_volume^.source_pool := osc$null_name;
    open_tape_volume^.source_pool_location := osc$null_name;
    open_tape_volume^.user := osc$null_name;

    amp$access_method (file_identifier, call_block, global_layer_number, status);
    operator_terminated_assignment := FALSE;
    IF NOT status.normal THEN
      IF (status.condition = dme$operator_stop) OR (status.condition = dme$termination_condition) THEN
        operator_terminated_assignment := TRUE;
      IFEND;
      RETURN;
    IFEND;

    IF (fsp$path_element (^evaluated_file_reference, 1)^ <> fsc$local) AND
          (initial_assignment OR ((access_mode * pfv$write_usage) <> $pft$usage_selections [])) THEN
      IF ((volume_descriptor.external_vsn = rmc$unspecified_vsn) AND
            (volume_descriptor.recorded_vsn = rmc$unspecified_vsn)) THEN
        IF initial_assignment THEN
          fmp$get_system_file_id (file_instance^.local_file_name, sfid, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
        IFEND;
        dmp$get_tape_volume_information (sfid, number_of_volumes_after_assign, current_volume,
              current_vsns, ignore_density, ignore_write_ring, ignore_volume_attributes,
              ignore_volume_overflow_allowed, ignore_label_type, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        IF (initial_assignment AND (current_volume = 1) AND (number_of_volumes_after_assign = 1))
              OR ((NOT initial_assignment)
              AND (number_of_volumes_after_assign = (number_of_volumes_before_assign + 1))) THEN
          PUSH p_path: [1 .. evaluated_file_reference.number_of_path_elements];
          pfp$convert_fs_to_pft$path (evaluated_file_reference, p_path^);
          cycle_selector.cycle_option := pfc$specific_cycle;
          cycle_selector.cycle_number := evaluated_file_reference.cycle_reference.cycle_number;
          pfp$r3_append_rem_media_vsn (p_path^, cycle_selector, current_vsns, status);
        IFEND;
      ELSE
        clp$convert_file_ref_to_string (evaluated_file_reference, {include_open_position} FALSE,
              fs_path, fs_path_size, status);
        IF status.normal THEN
          PUSH p_object_info_seq: [[REP #SIZE(fst$goi_object_information) OF cell,
                REP fsc$max_path_size OF cell, REP #SIZE (fst$goi_object) OF cell,
                REP #SIZE (fst$device_information) OF cell,
                REP (max_tape_volumes * #SIZE (rmt$volume_descriptor)) OF cell]];

          pfp$get_object_information (fs_path(1, fs_path_size), goi_information_request,
                {p_validation_criteria} NIL, p_object_info_seq, status);
          IF status.normal THEN
            RESET p_object_info_seq;
            NEXT p_object_information IN p_object_info_seq;
            IF (p_object_information <> NIL) AND (p_object_information^.object <> NIL) AND
                  (p_object_information^.object^.cycle_device_information <> NIL) THEN
              number_of_volumes := UPPERBOUND (p_object_information^.object^.cycle_device_information^.
                    magnetic_tape_device_info.volume_list^);
              first_volume_descriptor := p_object_information^.object^.cycle_device_information^.
                      magnetic_tape_device_info.volume_list^ [1];
              IF (next_volume > number_of_volumes) OR
{
{ The first volume is being assigned.
{
                  ((next_volume = 1) AND (number_of_volumes = 1) AND
                  (first_volume_descriptor.external_vsn = rmc$unspecified_vsn) AND
                  (first_volume_descriptor.recorded_vsn = rmc$unspecified_vsn)) THEN

                PUSH p_path: [1 .. evaluated_file_reference.number_of_path_elements];
                pfp$convert_fs_to_pft$path (evaluated_file_reference, p_path^);
                cycle_selector.cycle_option := pfc$specific_cycle;
                cycle_selector.cycle_number := evaluated_file_reference.cycle_reference.cycle_number;
                pfp$r3_append_rem_media_vsn (p_path^, cycle_selector,
                      volume_descriptor, status);
              IFEND;
            IFEND;
          IFEND;
        IFEND;
      IFEND;
    IFEND;

  PROCEND rmp$complete_tape_assignment;

?? TITLE := 'rmp$complete_tape_request', EJECT ??

  PROCEDURE [XDCL] rmp$complete_tape_request
    (    file: fst$file_reference;
         density: rmt$density;
         write_ring: rmt$write_ring;
         volume_list: rmt$volume_list;
         removable_media_group: ost$name;
         volume_overflow_allowed: boolean;
         validation_ring: ost$valid_ring;
         file_password: pft$password;
         attachment_logging: boolean;
     VAR status: ost$status);

    CONST
      complete_tape_request = 'RMP$COMPLETE_TAPE_REQUEST',
      include_radix = TRUE,
      radix = 10;

    VAR
      cycle_number: fst$cycle_number,
      cycle_selector: pft$cycle_selector,
      detachment_options: fmt$detachment_options,
      evaluated_file_reference: fst$evaluated_file_reference,
      ignore_status: ost$status,
      internal_cycle_name: ost$binary_unique_name,
      limit_string: ost$string,
      local_file_name: amt$local_file_name,
      log: pft$log,
      p_path: ^pft$path,
      removable_media_req_info: fmt$removable_media_req_info,
      sfid: gft$system_file_identifier,
      share_selections: pft$share_selections,
      usage_selections: pft$usage_selections;

    fsp$evaluate_file_reference (file, command_file_reference_allowed, evaluated_file_reference, status);

    IF status.normal THEN
      IF write_ring = rmc$write_ring THEN
        usage_selections := - $pft$usage_selections [];
      ELSE
        usage_selections := $pft$usage_selections [pfc$read, pfc$execute];
      IFEND;
      share_selections := $pft$share_selections [];
      removable_media_req_info.density := density;
      removable_media_req_info.removable_media_group := removable_media_group;
      removable_media_req_info.volume_overflow_allowed := volume_overflow_allowed;
      removable_media_req_info.write_ring := write_ring;

      IF fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local THEN
        dmp$create_tape_file_sfid (^removable_media_req_info, ^volume_list, sfid, status);
        IF status.normal THEN
          osp$generate_unique_binary_name (internal_cycle_name, status);
          IF status.normal THEN
            local_file_name := osc$null_name;
            fmp$attach_file (local_file_name, internal_cycle_name, internal_cycle_name, sfid,
                  usage_selections, share_selections, validation_ring, sfc$no_limit, {p_file_label} NIL,
                  {p_pf_attachment_info} NIL, {device_class} rmc$magnetic_tape_device,
                  ^removable_media_req_info, ^volume_list, evaluated_file_reference, status);
            IF NOT status.normal THEN
              detachment_options := fmv$default_detachment_options;
              detachment_options.device_class := rmc$magnetic_tape_device;
              detachment_options.physical_unload := TRUE;
              dmp$close_tape_volume (sfid, detachment_options, ignore_status);
            IFEND;
          IFEND;
        ELSEIF status.condition = dme$tape_attach_limit_exceeded THEN
          clp$convert_integer_to_string (iov$number_of_tape_units + dmc$extra_lun_table_entries, radix,
                NOT include_radix, limit_string, ignore_status);
          bap$set_evaluated_file_abnormal (evaluated_file_reference, fse$tape_attach_limit_exceeded,
                complete_tape_request, limit_string.value, status);
        IFEND;
      ELSE
        IF evaluated_file_reference.cycle_reference.specification = fsc$cycle_number THEN
          cycle_selector.cycle_option := pfc$specific_cycle;
          cycle_selector.cycle_number := evaluated_file_reference.cycle_reference.cycle_number;
        ELSE
          cycle_selector.cycle_option := pfc$highest_cycle;
        IFEND;

        IF attachment_logging THEN
          log := pfc$log;
        ELSE
          log := pfc$no_log;
        IFEND;

        PUSH p_path: [1 .. evaluated_file_reference.number_of_path_elements];
        pfp$convert_fs_to_pft$path (evaluated_file_reference, p_path^);
        pfp$r3_define_removable_media (p_path^, cycle_selector, file_password, validation_ring,
              pfc$maximum_retention, log, {device_class} rmc$magnetic_tape_device, ^removable_media_req_info,
              ^volume_list, status);
      IFEND;
    IFEND;

  PROCEND rmp$complete_tape_request;

MODEND rmm$complete_tape_operations;
