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

{ PURPOSE:
{   The purpose of this module is to provide physical IO with information
{   pertaining to files on disk.
{ DESIGN:
{   All address translation is performed here. In addition physical IO
{   is informed whether a write is a write/initialize.

?? NEWTITLE := 'Global Declarations Referenced By This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$mainframe_wired
*copyc mtc$job_fixed_segment
*copyc amt$file_byte_address
*copyc dmt$active_volume_table
*copyc dmt$allocation_size
*copyc dmt$disk_file_descriptor
*copyc dmt$error_condition_codes
*copyc dmt$file_allocation_descriptor
*copyc dmt$file_attributes
*copyc dmt$file_descriptor_entry
*copyc dmt$file_table_lock
*copyc dmt$minimum_allocation_unit
*copyc dmt$monitor_request_blocks
*copyc dmt$ms_logical_device_address
*copyc gft$locked_file_desc_entry_p
*copyc gft$system_file_identifier
*copyc iot$io_function
*copyc iot$logical_unit
*copyc jmt$ijl_ordinal
*copyc ost$hardware_subranges
*copyc pmt$initialization_value
*copyc syt$monitor_request_code
?? POP ??
*copyc dmp$get_disk_file_descriptor_p
*copyc dmp$get_fau_entry_and_fmd
*copyc dmp$get_fmd_by_index
*copyc dmp$get_mat_pointer
*copyc dmp$preset_conversion
*copyc mtp$error_stop
*copyc mtp$set_status_abnormal
*copyc osp$fetch_locked_variable
*copyc dmv$active_volume_table
*copyc dmv$allocation_log
*copyc jmv$system_ijl_ordinal
*copyc osv$page_size
*copyc syv$test_jr_system
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared By This Module', EJECT ??

  VAR
    dmv$last_fde_rejected: [XDCL, STATIC, oss$mainframe_wired] gft$locked_file_desc_entry_p,
    dmv$transient_errors: [XDCL, STATIC, oss$mainframe_wired] integer := 0,
    dmv$job_mode_fix_reqs: [XDCL, STATIC, oss$mainframe_wired] integer := 0;

?? OLDTITLE ??
?? NEWTITLE := '  dmp$build_device_address', EJECT ??
*copy dmh$build_device_address

  PROCEDURE [INLINE] dmp$build_device_address
    (    p_fde: gft$locked_file_desc_entry_p;
         p_dfd: ^dmt$disk_file_descriptor;
         p_fmd: ^dmt$file_medium_descriptor;
         p_fau: ^dmt$file_allocation_unit;
         preset_value: pmt$initialization_value;
         byte_address: amt$file_byte_address;
         number_bytes: amt$file_byte_address;
     VAR device_address: dmt$ms_logical_device_address;
     VAR status: syt$monitor_status);

    VAR
      allocation_unit_mau_address: dmt$mau_address,
      allocation_unit_write_status: boolean,
      byte_offset_within_au: dmt$byte_offset_within_au,
      bytes_per_allocation: dmt$bytes_per_allocation,
      bytes_per_mau: dmt$bytes_per_mau,
      mau_offset_within_au: dmt$mau_offset_within_au,
      maus_per_allocation: dmt$maus_per_allocation,
      maus_per_dau: dmt$maus_per_dau,
      maus_per_position: dmt$maus_per_position,
      maus_per_transfer_unit: dmt$maus_per_transfer,
      last_mau_offset_within_au: dmt$mau_offset_within_au,
      logical_unit_number: iot$logical_unit,
      transfer_length: dmt$maus_per_transfer,
      transfer_length_in_maus: dmt$maus_per_transfer,
      transfer_mau_address: dmt$mau_address,
      transfer_mau_offset: dmt$mau_offset_within_tu;

    logical_unit_number := dmv$active_volume_table.table_p^ [p_fmd^.avt_index].logical_unit_number;
    maus_per_dau := p_fmd^.maus_per_dau;
    maus_per_position := p_fmd^.daus_per_cylinder * maus_per_dau;
    bytes_per_allocation := p_dfd^.bytes_per_allocation;
    maus_per_transfer_unit := p_fmd^.maus_per_transfer_unit;
    bytes_per_mau := p_fmd^.bytes_per_mau;
    maus_per_allocation := bytes_per_allocation DIV bytes_per_mau;

    IF p_fau^.state = dmc$fau_initialization_in_prog THEN
      mtp$set_status_abnormal (dmc$device_manager_ident, dme$transient_error, status);
      dmv$transient_errors := dmv$transient_errors + 1;
      dmv$last_fde_rejected := p_fde;
      RETURN; {----->
    IFEND;

    byte_offset_within_au := byte_address MOD bytes_per_allocation;
    mau_offset_within_au := byte_offset_within_au DIV bytes_per_mau;
    last_mau_offset_within_au := (byte_offset_within_au + number_bytes - 1 + bytes_per_mau - 1) DIV
          bytes_per_mau;
    transfer_length_in_maus := last_mau_offset_within_au - mau_offset_within_au;

    IF transfer_length_in_maus > maus_per_allocation THEN
      transfer_length_in_maus := maus_per_allocation;
    IFEND;

    allocation_unit_mau_address := p_fau^.dau_address * maus_per_dau;

    IF device_address.write_translation AND ((p_fau^.state = dmc$fau_invalid_data) OR
          (p_fau^.state = dmc$fau_invalid_and_flawed)) THEN
      transfer_mau_address := allocation_unit_mau_address;
      transfer_mau_offset := mau_offset_within_au;
      allocation_unit_write_status := FALSE;
    ELSE
      transfer_mau_address := (mau_offset_within_au DIV maus_per_transfer_unit) *
            maus_per_transfer_unit + allocation_unit_mau_address;
      transfer_mau_offset := mau_offset_within_au MOD maus_per_transfer_unit;
      allocation_unit_write_status := TRUE;
    IFEND;

    device_address.logical_unit_number := logical_unit_number;
    device_address.allocation_unit_mau_address := transfer_mau_address;
    device_address.transfer_length := transfer_length_in_maus;
    device_address.transfer_mau_offset := transfer_mau_offset;
    device_address.maus_per_position := maus_per_position;
    IF device_address.write_translation THEN
      device_address.au_was_previously_written := allocation_unit_write_status;
      device_address.maus_per_allocation_unit := maus_per_allocation;
      device_address.preset_value := dmp$preset_conversion (preset_value);
    IFEND;

  PROCEND dmp$build_device_address;
?? OLDTITLE ??
?? NEWTITLE := '  dmp$write', EJECT ??
*copy dmh$write

  PROCEDURE [XDCL] dmp$write
    (    p_fde: gft$locked_file_desc_entry_p;
         byte_address: amt$file_byte_address;
         length: amt$file_byte_address;
         io_function: iot$io_function;
     VAR device_address: dmt$ms_logical_device_address;
     VAR status: syt$monitor_status);

    VAR
      allocate_request_block: dmt$monitor_rb_allocate_space,
      dmv$allocation_log_rejects: [XDCL] integer := 0,
      logging_required_for_file: boolean,
      new_fmd_length: ost$byte_count,
      number: integer,
      p_dfd: ^dmt$disk_file_descriptor,
      p_fmd: ^dmt$file_medium_descriptor,
      p_fau: ^dmt$file_allocation_unit,
      transfer_size: ost$byte_count;

*if $true(syv$allow_jr_test)
    VAR
      syv$allow_jr_test: [XREF] boolean,
*ifend

    status.normal := TRUE;
    device_address.write_translation := TRUE;

    dmp$get_disk_file_descriptor_p (p_fde, p_dfd);

    dmp$get_fau_entry_and_fmd (p_dfd, byte_address, p_fau, p_fmd);
    IF (p_fau = NIL) OR (p_fmd = NIL) OR (p_fau^.state = dmc$fau_free) THEN
      mtp$set_status_abnormal (dmc$device_manager_ident, dme$job_mode_allocate_required, status);
      RETURN; {----->
    IFEND;

    IF dmv$active_volume_table.table_p^ [p_fmd^.avt_index].mass_storage.volume_unavailable THEN
      mtp$set_status_abnormal (dmc$device_manager_ident, dme$volume_unavailable, status);
      RETURN; {----->
    IFEND;

    dmp$build_device_address (p_fde, p_dfd, p_fmd, p_fau, p_fde^.preset_value, byte_address, length,
          device_address, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    transfer_size := length DIV p_fmd^.bytes_per_mau;

    IF (transfer_size > device_address.transfer_length) OR (length MOD p_fmd^.bytes_per_mau <> 0) OR
          (length = 0) THEN
      mtp$error_stop ('bad length in write request (dmp$write)');
    IFEND;

    {Commit allocation log entry for initialize if required and available
    IF NOT device_address.au_was_previously_written THEN
      logging_required_for_file := (p_fde^.file_kind <= gfc$fk_last_permanent_file);
      IF logging_required_for_file THEN
        osp$fetch_locked_variable (dmv$allocation_log.number, number);
        IF (number + dmv$allocation_log.committed_initialize_count) >= dmc$max_allocation_log_entries THEN
          dmv$allocation_log_rejects := dmv$allocation_log_rejects + 1;
          dmv$last_fde_rejected := p_fde;
          mtp$set_status_abnormal (dmc$device_manager_ident, dme$transient_error, status);
          RETURN; {----->
        ELSE
          dmv$allocation_log.committed_initialize_count := dmv$allocation_log.committed_initialize_count + 1;
        IFEND;
      IFEND;
    IFEND;

    IF (p_fau^.state = dmc$fau_invalid_data) OR (p_fau^.state = dmc$fau_invalid_and_flawed) THEN
      IF (#SEGMENT (p_fde) > 1) AND ((io_function = ioc$write_page) OR (io_function = ioc$write_locked_page))
            THEN
        p_fau^.state := dmc$fau_initialized;
      ELSE
        p_fau^.state := dmc$fau_initialization_in_prog;
      IFEND;
    IFEND;

    IF (#SEGMENT (p_fde) = 1) OR ((io_function <> ioc$write_page) AND (io_function <> ioc$write_locked_page))
          THEN
      p_dfd^.read_write_count := p_dfd^.read_write_count + 1;
    IFEND;

*if $true(syv$allow_jr_test)
    IF syv$allow_jr_test THEN
      IF syc$tjr_crash_in_dmwrite IN syv$test_jr_system THEN
        IF (#SEGMENT (p_fde) > mtc$job_fixed_segment) THEN
          mtp$error_stop ('JOB RECOVERY TEST');
        IFEND;
      IFEND;
    IFEND;
*ifend

  PROCEND dmp$write;
?? OLDTITLE ??
?? NEWTITLE := '  dmp$read', EJECT ??
*copy dmh$read

  PROCEDURE [XDCL] dmp$read
    (    p_fde: gft$locked_file_desc_entry_p;
         byte_address: amt$file_byte_address;
         length_in_bytes: amt$file_byte_address;
     VAR device_address: dmt$ms_logical_device_address;
     VAR status: syt$monitor_status);

    VAR
      p_dfd: ^dmt$disk_file_descriptor,
      p_fau: ^dmt$file_allocation_unit,
      p_fmd: ^dmt$file_medium_descriptor,
      read_status: syt$monitor_status;

*if $true(syv$allow_jr_test)
    VAR
      syv$allow_jr_test: [XREF] boolean;
*ifend

    status.normal := TRUE;
    device_address.write_translation := FALSE;

    dmp$get_disk_file_descriptor_p (p_fde, p_dfd);

    dmp$get_fau_entry_and_fmd (p_dfd, byte_address, p_fau, p_fmd);
    IF (p_fau = NIL) OR (p_fmd = NIL) OR (p_fau^.state = dmc$fau_free) THEN
      mtp$error_stop (' attempt to read unallocated area - dmp$read');
    IFEND;

    IF dmv$active_volume_table.table_p^ [p_fmd^.avt_index].mass_storage.volume_unavailable THEN
      mtp$set_status_abnormal (dmc$device_manager_ident, dme$volume_unavailable, status);
      RETURN; {----->
    IFEND;

    dmp$build_device_address (p_fde, p_dfd, p_fmd, p_fau, p_fde^.preset_value, byte_address, length_in_bytes,
          device_address, status);
    IF status.normal THEN
      p_dfd^.read_write_count := p_dfd^.read_write_count + 1;
*if $true(syv$allow_jr_test)
      IF syv$allow_jr_test THEN
        IF syc$tjr_crash_in_dmread IN syv$test_jr_system THEN
          IF (#SEGMENT (p_fde) > 14(16)) THEN
            mtp$error_stop ('JOB RECOVERY TEST');
          IFEND;
        IFEND;
      IFEND;
*ifend
    IFEND;

  PROCEND dmp$read;
?? OLDTITLE ??
MODEND dmm$build_device_address;
