?? NEWTITLE := 'NOSVE Device Management' ??
MODULE dmm$initialize_volume;
?? RIGHT := 110 ??

{  PURPOSE:
{    This module provides requests to initialize a mass storage volume,
{    set the force format option and issue a DAS restore command.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc i#call_monitor
*copyc oss$mainframe_paged_literal
*copyc dmc$cti_device_type_numbers
*copyc osd$virtual_address
*copyc rmd$volume_declarations
*copyc cme$manage_interface_tables
*copyc mme$condition_codes
*copyc amt$file_byte_address
*copyc cmt$logical_unit_attributes
*copyc cmt$unit_types
*copyc dmt$allocation_size
*copyc dmt$chapter_number
*copyc dmt$date
*copyc dmt$device_allocation_unit
*copyc dmt$device_file_list_index
*copyc dmt$device_file_stored_fmd
*copyc dmt$error_condition_codes
*copyc dmt$file_allocation_table
*copyc dmt$file_medium_descriptor
*copyc dmt$global_file_name
*copyc dmt$initialize_ms_vol_options
*copyc dmt$initialize_status_info
*copyc dmt$log_flaw_init_data
*copyc dmt$logical_device_attributes
*copyc dmt$logical_unit_specification
*copyc dmt$minimum_allocation_unit
*copyc dmt$ms_device_allocation_table
*copyc dmt$ms_device_file_list_entry
*copyc dmt$ms_flaw_list
*copyc dmt$ms_logical_device_address
*copyc dmt$ms_login_table
*copyc dmt$ms_physical_characteristics
*copyc dmt$ms_volume_directory
*copyc dmt$ms_volume_label
*copyc dmt$physical_device_attributes
*copyc dmt$stored_ms_fmd_header
*copyc dmt$time
*copyc dmt$volume_label_attributes
*copyc dst$deadstart_sector
*copyc gft$file_desc_entry_p
*copyc gft$system_file_identifier
*copyc iot$io_function
*copyc iot$logical_unit
*copyc ost$name
*copyc ost$status
*copyc ost$user_identification
*copyc pmt$system_time
?? POP ??
*copyc cmp$get_mass_storage_info
*copyc cmp$lock_lun_entry
*copyc cmp$unlock_lun_entry
*copyc dmp$attach_dat_from_label
*copyc dmp$attach_device_file_by_fmd
*copyc dmp$bring_volume_online
*copyc dmp$close_file
*copyc dmp$construct_sc_dau_list
*copyc dmp$create_fau_entry
*copyc dmp$detach_device_file
*copyc dmp$generate_gfn_hash
*copyc dmp$get_disk_file_descriptor_p
*copyc dmp$get_fau_entry
*copyc dmp$get_fmd_by_index
*copyc dmp$get_number_of_faus
*copyc dmp$locate_volume_label
*copyc dmp$open_file
*copyc dmp$record_sc_flaw
*copyc dmp$take_volume_offline
*copyc dsp$access_deadstart_sector
*copyc gfp$get_fde_p
*copyc iop$initialize_sectors
*copyc iop$mass_storage_io
*copyc mmp$free_pages
*copyc mmp$write_modified_pages
*copyc osp$clear_mainframe_sig_lock
*copyc osp$disable_pico_statistics
*copyc osp$enable_pico_statistics
*copyc osp$generate_unique_binary_name
*copyc osp$initialize_sig_lock
*copyc osp$set_mainframe_sig_lock
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$system_error
*copyc osp$unpack_status_condition
*copyc pmp$get_system_time
*copyc pmp$zero_out_table
*copyc syp$continue_to_cause
*copyc syp$disestablish_cond_handler
*copyc syp$display_deadstart_message
*copyc syp$establish_condition_handler
*copyc syp$trace_deadstart_message
*copyc cmv$post_deadstart
*copyc dmv$active_volume_table
*copyc dmv$p_sc_flaw_commands
*copyc dsv$mainframe_type
*copyc osv$mainframe_wired_heap
*copyc osv$page_size
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations DEclared by This Module', EJECT ??

  TYPE
    cylinder_range_type = record
      lowest_cylinder: dmt$device_position,
      highest_cylinder: dmt$device_position,
    recend,

    flawed_dau = record
      dau_address: dmt$dau_address,
      kind_of_flaw: dmt$dau_status,
    recend,

    dau_mapping = set of dmt$daus_per_position,

    dmt$hps_unit_type = cmc$ms5832_1 .. cmc$ms47444_4,
    dmt$hps_unit_types = set of dmt$hps_unit_type;

  TYPE
    t$initialize_volume_control = record
      bytes_per_mau: dmt$bytes_per_mau,
      cylinders_per_device: dmt$device_position,

      dat_user_supplied_name: ost$name,
      dat_global_file_name: dmt$global_file_name,
      dat_dfle: dmt$ms_device_file_list_entry,
      dat_stored_df_fmd: dmt$device_file_stored_fmd,

      dflt_user_supplied_name: ost$name,
      dflt_global_file_name: dmt$global_file_name,
      dflt_stored_df_fmd: dmt$device_file_stored_fmd,
      dflt_dfle: dmt$ms_device_file_list_entry,

      login_table_user_supplied_name: ost$name,
      login_table_global_file_name: dmt$global_file_name,
      login_table_stored_df_fmd: dmt$device_file_stored_fmd,

      directory_dfle: dmt$ms_device_file_list_entry,
      directory_stored_df_fmd: dmt$device_file_stored_fmd,

      daus_per_cylinder: dmt$daus_per_position,
      daus_per_device: dmt$dau_address,
      daus_per_allocation_style: array [dmt$allocation_styles] of dmt$daus_per_position,
      maus_per_cylinder: dmt$maus_per_position,
      maus_per_dau: dmt$maus_per_dau,
      sectors_per_track: iot$sectors_per_track,
      sectors_per_mau: iot$sectors_per_mau,
      max_label_size: dmt$max_volume_label_size,

      usable_daus_p: ^array [0 .. * ] of dau_mapping,
    recend;

  VAR
    v$cm3_unit_type: [READ, oss$mainframe_paged_literal] cmt$unit_types := [cmc$msfsd2_s0, cmc$msxmd_3],
    v$hps_unit_type: [READ, oss$mainframe_paged_literal] dmt$hps_unit_types := -$dmt$hps_unit_types [];

  VAR
    p_existing_flaws: [STATIC] ^array [ * ] of flawed_dau := NIL;

?? OLDTITLE ??
?? NEWTITLE := 'dmp$initialize_ms_volume', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copy dmh$initialize_ms_volume
?? POP ??

  PROCEDURE [XDCL, #GATE] dmp$initialize_ms_volume
    (    access_code: ost$name;
         owner_id: ost$user_identification;
         unit_type: cmt$unit_type;
         p_physical_attributes: ^dmt$physical_device_attributes;
         p_logical_attributes: ^dmt$logical_device_attributes;
         p_volume_label_attributes: ^dmt$volume_label_attributes;
         logical_unit_number: iot$logical_unit;
         initialization_options: dmt$initialize_ms_vol_options;
     VAR initialize_status_info: dmt$initialize_status_info;
     VAR status: ost$status);

    VAR
      control: t$initialize_volume_control,
      i: integer,
      unit_lock_cleared: boolean,
      unit_lock_set: boolean;

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

    PROCEDURE p$initialize_locked_ms_volume
      (VAR status: ost$status);

      VAR
        able_to_retain_flaws: boolean,
        applicable_flaw_count: integer,
        avt_index: dmt$active_volume_table_index,
        initialize_status: ost$status,
        label_found: boolean,
        p_label_header: ^dmt$volume_label_header,
        p_sc_dau_list: ^array [1 .. * ] of dmt$log_flaw_init_data,
        p_volume_label: ^dmt$ms_volume_label,
        volume_downed: boolean;

      avt_index := 0;
      dmp$bring_volume_online (logical_unit_number, avt_index, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

    /volume_online/
      BEGIN
        label_found := FALSE;
        IF initialization_options.format_option <> dmc$fmvo_format_at_all_costs THEN
          PUSH p_volume_label: [[REP control.max_label_size OF cell]];
          RESET p_volume_label;

          dmp$locate_volume_label (logical_unit_number, p_physical_attributes, p_volume_label^, status);
          IF status.normal THEN
            label_found := TRUE;
            RESET p_volume_label;
            NEXT p_label_header IN p_volume_label;
          ELSE
            CASE status.condition OF
            = ioe$unit_disabled =
              osp$set_status_condition (mme$volume_unavailable, status);
              EXIT /volume_online/; {----->

            = dme$unknown_ms_label_type =
              IF initialization_options.allowed_to_overwrite_volume THEN
                label_found := FALSE;
                status.normal := TRUE;
                IF NOT cmv$post_deadstart THEN
                  syp$trace_deadstart_message (
                        'unable to retain device flaws - foreign or overwritten volume label detected');
                  syp$trace_deadstart_message ('...device initialization continuing');
                IFEND;
              ELSE
                EXIT /volume_online/; {----->
              IFEND;

            = dme$no_ms_label_type =
              label_found := FALSE;
              status.normal := TRUE;

            = ioe$unrecovered_disk_error =
              label_found := FALSE;
              status.normal := TRUE;

            ELSE
{What else could it be? Return for now.
              EXIT /volume_online/; {----->
            CASEND;
          IFEND;
        IFEND;

        IF label_found AND (NOT initialization_options.allowed_to_overwrite_volume) THEN
          RESET p_volume_label;
          validate_volume_label (access_code, owner_id, p_volume_label^, initialize_status_info, status);
          IF NOT status.normal THEN
            EXIT /volume_online/; {----->
          IFEND;
        IFEND;

        able_to_retain_flaws := TRUE;
        volume_downed := FALSE;
        IF initialization_options.retain_device_flaws AND label_found THEN
          dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn := p_label_header^.
                recorded_vsn;
          remember_device_flaws (p_volume_label^, control.cylinders_per_device, avt_index, p_existing_flaws,
                able_to_retain_flaws, volume_downed);
          dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn := '      ';
          IF volume_downed THEN
            osp$set_status_condition (mme$volume_unavailable, status);
            EXIT /volume_online/; {----->
          IFEND;

          IF (NOT able_to_retain_flaws) AND (NOT cmv$post_deadstart) THEN
            syp$trace_deadstart_message ('...device initialization continuing');
          IFEND;

        ELSEIF initialization_options.retain_device_flaws AND (NOT label_found) AND
              (NOT cmv$post_deadstart) THEN
          syp$trace_deadstart_message ('unable to retain device flaws (cannot find volume label)');
          syp$trace_deadstart_message ('...device initialization continuing');
        IFEND;

        IF (unit_type = cmc$ms895_2) AND ((NOT able_to_retain_flaws) OR (NOT label_found) OR
              (initialization_options.format_option <> dmc$fmvo_no_format)) THEN
          soft_sector_895 (logical_unit_number, control, status);
          IF NOT status.normal THEN
            EXIT /volume_online/; {----->
          IFEND;

        ELSEIF unit_type IN v$cm3_unit_type THEN
          format_cm3_device (logical_unit_number, initialization_options.format_option = dmc$fmvo_no_format,
                status);
          IF NOT status.normal THEN
            EXIT /volume_online/; {----->
          IFEND;

        ELSEIF unit_type IN v$hps_unit_type THEN
          soft_sector_583x (logical_unit_number, initialization_options.format_option = dmc$fmvo_no_format,
                status);
          IF NOT status.normal THEN
            EXIT /volume_online/; {----->
          IFEND;
        IFEND;

        create_new_volume_label (p_volume_label_attributes, p_physical_attributes, p_logical_attributes,
              logical_unit_number, avt_index, control, status);

{ The following call to dmp$construct_sc_dau_list is here to mark the flaw commands as processed.  IF the
{ status returned by create_new_volume_label is not normal, there is a possiblility for the operator to
{ enter the initialize command again and the flaw commands would be lost if they were marked as processed
{ before this check.

        IF status.normal THEN
          IF dmv$p_sc_flaw_commands <> NIL THEN
            PUSH p_sc_dau_list: [1 .. UPPERBOUND (dmv$p_sc_flaw_commands^)];
            dmp$construct_sc_dau_list (dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn,
                  FALSE, p_sc_dau_list, applicable_flaw_count, status);
          IFEND;
        IFEND;

      END /volume_online/;

      dmp$take_volume_offline (logical_unit_number, initialize_status);
      IF NOT initialize_status.normal AND status.normal THEN
        status := initialize_status;
      IFEND;

    PROCEND p$initialize_locked_ms_volume;
?? OLDTITLE ??
?? EJECT ??

    status.normal := TRUE;
    initialize_status_info.recorded_vsn := ' ';
    control.cylinders_per_device := dmc$min_device_position;
    control.maus_per_cylinder := dmc$min_maus_position;
    control.bytes_per_mau := dmc$max_bytes_per_mau;
    control.maus_per_dau := dmc$min_maus_per_dau;
    control.sectors_per_track := dmc$default_sectors_per_track;
    control.sectors_per_mau := dmc$default_sectors_per_mau;
    control.max_label_size := dmc$default_volume_label_size;
    control.usable_daus_p := NIL;

    IF p_physical_attributes <> NIL THEN
      FOR i := LOWERBOUND (p_physical_attributes^) TO UPPERBOUND (p_physical_attributes^) DO
        CASE p_physical_attributes^ [i].keyword OF
        = dmc$bytes_per_mau =
          control.bytes_per_mau := p_physical_attributes^ [i].bytes_per_mau;
        = dmc$cylinders_per_device =
          control.cylinders_per_device := p_physical_attributes^ [i].cylinders_per_device;
        = dmc$maus_per_cylinder =
          control.maus_per_cylinder := p_physical_attributes^ [i].maus_per_cylinder;
        = dmc$maus_per_dau =
          control.maus_per_dau := p_physical_attributes^ [i].maus_per_dau;
        = dmc$sectors_per_track =
          control.sectors_per_track := p_physical_attributes^ [i].sectors_per_track;
        = dmc$sectors_per_mau =
          control.sectors_per_mau := p_physical_attributes^ [i].sectors_per_mau;
        = dmc$pda_max_label_size =
          control.max_label_size := p_physical_attributes^ [i].max_label_size;
        ELSE
        CASEND;
      FOREND;
    IFEND;

{logically lock the logical unit table
    cmp$lock_lun_entry (logical_unit_number, unit_lock_set);
    IF NOT unit_lock_set THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_lock_lun_entry,
            'unable to lock lun entry - dmp$initialize_ms_volume', status);
      RETURN; {----->
    IFEND;

{ Turn off PICO statistics so we don't trip over the request while
{ initializing the volume
    osp$disable_pico_statistics;

    p$initialize_locked_ms_volume (status);

    cmp$unlock_lun_entry (logical_unit_number, unit_lock_cleared);
    IF (NOT unit_lock_cleared) AND status.normal THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_release_lun_lock,
            'unable to release lun lock - dmp$initialize_ms_volume', status);
    IFEND;

    osp$enable_pico_statistics;

  PROCEND dmp$initialize_ms_volume;
?? OLDTITLE ??
?? NEWTITLE := 'dmp$process_force_format', EJECT ??

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

    VAR
      able: boolean;

{ Logically lock the logical unit table.
    cmp$lock_lun_entry (logical_unit_number, able);
    IF NOT able THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_lock_lun_entry,
            'unable to lock lun entry - dmp$' CAT 'format_reinstated_parity_unit', status);
      RETURN; {----->
    IFEND;

    send_force_format_command (logical_unit_number, force_format, status);

{ Unlock the logical unit table.
    cmp$unlock_lun_entry (logical_unit_number, able);
    IF (NOT able) AND status.normal THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_release_lun_lock,
            'unable to release lun lock - ' CAT 'dmp$format_reinstated_parity_unit', status);
      RETURN; {----->
    IFEND;

  PROCEND dmp$process_force_format;
?? OLDTITLE ??
?? NEWTITLE := 'soft_sector_895', EJECT ??

  PROCEDURE soft_sector_895
    (    logical_unit_number: iot$logical_unit;
     VAR control: t$initialize_volume_control;
     VAR status: ost$status);

    VAR
      cip_found: boolean,
      cip_cylinder: dmt$device_position,
      cylinders_to_initialize: ^array [ * ] of iot$cylinders_to_initialize;

    status.normal := TRUE;

    IF NOT cmv$post_deadstart THEN
      syp$trace_deadstart_message ('soft-sectoring volume');
    IFEND;
    find_cip_cylinder (logical_unit_number, control, cip_cylinder, cip_found);

    PUSH cylinders_to_initialize: [1 .. 1];
    cylinders_to_initialize^ [1].start_cylinder := 0;
    IF cip_found THEN { format up to but not including first CIP cylinder }
      cylinders_to_initialize^ [1].end_cylinder := cip_cylinder - 1;
    ELSE
      cylinders_to_initialize^ [1].end_cylinder := control.cylinders_per_device - 4;
      {Do not format cylinders 883 - 885.}
    IFEND;

    iop$initialize_sectors (logical_unit_number, cylinders_to_initialize^, status);
    IF status.normal AND (NOT cmv$post_deadstart) THEN
      syp$trace_deadstart_message ('soft-sectoring of volume complete');
    IFEND;

  PROCEND soft_sector_895;
?? OLDTITLE ??
?? NEWTITLE := 'format_cm3_device', EJECT ??

  PROCEDURE format_cm3_device
    (    logical_unit_number: iot$logical_unit;
         retain_device_flaws: boolean;
     VAR status: ost$status);

    VAR
      cylinders_to_initialize: array [1 .. 1] of iot$cylinders_to_initialize;

    status.normal := TRUE;

    IF NOT cmv$post_deadstart THEN
      syp$trace_deadstart_message ('checking format of volume');
    IFEND;

{
{ Formatting of the device is dependent on the value of retain_device_flaws.
{ If retain_device_flaws is true, a value of 0 is passed to IO and it will
{ decide whether formatting is necessary or not; if false, a value of 1 is
{ passed to IO, a value > than 0 will cause IO to unconditionally format
{ the device.
{

    IF retain_device_flaws THEN
      cylinders_to_initialize [1].start_cylinder := 0;
    ELSE
      cylinders_to_initialize [1].start_cylinder := 1;
    IFEND;

    iop$initialize_sectors (logical_unit_number, cylinders_to_initialize, status);
    IF status.normal AND (NOT cmv$post_deadstart) THEN
      syp$trace_deadstart_message ('volume formatted');
    IFEND;

  PROCEND format_cm3_device;
?? OLDTITLE ??
?? NEWTITLE := 'soft_sector_583x', EJECT ??

  PROCEDURE soft_sector_583x
    (    logical_unit_number: iot$logical_unit;
         retain_device_flaws: boolean;
     VAR status: ost$status);

{
{ The DAS & DVK devices do not support CIP
{

    VAR
      cylinders_to_initialize: array [1 .. 1] of iot$cylinders_to_initialize;

    status.normal := TRUE;

    IF NOT cmv$post_deadstart THEN
      syp$trace_deadstart_message ('checking format of volume');
    IFEND;

{ Formatting of the device is dependent on the value of retain_device_flaws.
{ If retain_device_flaws is true, a value of 0 is passed to IO and it will
{ decide whether formatting is necessary or not; if false, a value of 1 is
{ passed to IO, a value > than 0 will cause IO to unconditionally format
{ the device.

    IF retain_device_flaws THEN
      cylinders_to_initialize [1].start_cylinder := 0;
    ELSE
      cylinders_to_initialize [1].start_cylinder := 1;
    IFEND;

    iop$initialize_sectors (logical_unit_number, cylinders_to_initialize, status);
    IF status.normal AND (NOT cmv$post_deadstart) THEN
      syp$trace_deadstart_message ('volume formatted');
    IFEND;

  PROCEND soft_sector_583x;
?? OLDTITLE ??
?? NEWTITLE := 'send_force_format_command', EJECT ??

  PROCEDURE send_force_format_command
    (    logical_unit_number: iot$logical_unit;
         force_format: boolean;
     VAR status: ost$status);

    VAR
      cylinders_to_initialize: array [1 .. 1] of iot$cylinders_to_initialize;

    status.normal := TRUE;

{ This procedure uses the iop$initialize_sectors command to inform the
{ io driver to set or clear the 'force_format' bit located in the unit
{ interface table. A value of 2 will cause the driver to clear the bit
{ and a value of 3 will cause the driver to set the bit. Values of 0 and
{ 1 are reserved for use by the 'soft_sector_583x' procedure.

    IF force_format THEN
      cylinders_to_initialize [1].start_cylinder := 3; {set force_format bit}
    ELSE
      cylinders_to_initialize [1].start_cylinder := 2; {clear force_format bit}
    IFEND;

    iop$initialize_sectors (logical_unit_number, cylinders_to_initialize, status);

  PROCEND send_force_format_command;
?? OLDTITLE ??
?? NEWTITLE := 'dmp$process_das_restore', EJECT ??

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

    VAR
      able: boolean;

{ Logically lock the logical unit table.
    cmp$lock_lun_entry (logical_unit_number, able);
    IF NOT able THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_lock_lun_entry,
            'unable to lock lun entry - dmp$' CAT 'format_reinstated_parity_unit', status);
      RETURN; {----->
    IFEND;
    send_das_restore_command (logical_unit_number, status);
{ Unlock the logical unit table.
    cmp$unlock_lun_entry (logical_unit_number, able);
    IF (NOT able) AND status.normal THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_release_lun_lock,
            'unable to release lun lock - ' CAT 'dmp$format_reinstated_parity_unit', status);
      RETURN; {----->
    IFEND;

  PROCEND dmp$process_das_restore;
?? OLDTITLE ??
?? NEWTITLE := 'send_das_restore_command', EJECT ??

  PROCEDURE send_das_restore_command
    (    logical_unit_number: iot$logical_unit;
     VAR status: ost$status);

    VAR
      cylinders_to_initialize: array [1 .. 1] of iot$cylinders_to_initialize;

    status.normal := TRUE;

{ This procedure uses the iop$initialize_sectors command to inform the
{ io driver to run the confidence test on the specified unit. This is
{ used to provide a means of manually starting a resore operation on the
{ ibm 3.5" das drive because this drive type does not notify the driver
{ when it is powered up. A value of 5 is sent to enable running ct.

    cylinders_to_initialize [1].start_cylinder := 5; {run confidence test}

    iop$initialize_sectors (logical_unit_number, cylinders_to_initialize, status);

  PROCEND send_das_restore_command;
?? OLDTITLE ??
?? NEWTITLE := 'validate_volume_label', EJECT ??

  PROCEDURE validate_volume_label
    (    access_code: ost$name;
         owner_id: ost$user_identification;
     VAR volume_label: {input} dmt$ms_volume_label;
     VAR initialize_status_info: dmt$initialize_status_info;
     VAR status: ost$status);

    status.normal := TRUE;

    verify_label_expiration_date (volume_label, initialize_status_info, status);
    IF status.normal THEN
      verify_volume_access_code (access_code, volume_label, initialize_status_info, status);
      IF status.normal THEN
        verify_volume_owner (owner_id, volume_label, initialize_status_info, status);
      IFEND;
    IFEND;

  PROCEND validate_volume_label;
?? OLDTITLE ??
?? NEWTITLE := 'verify_label_expiration_date', EJECT ??

  PROCEDURE verify_label_expiration_date
    (VAR volume_label: {input} dmt$ms_volume_label;
     VAR initialize_status_info: dmt$initialize_status_info;
     VAR status: ost$status);

    VAR
      p_volume_label: ^dmt$ms_volume_label,
      p_volume_label_header: ^dmt$volume_label_header,
      current_date: pmt$system_time,
      label_expiration_date: dmt$date;

    status.normal := TRUE;

    p_volume_label := ^volume_label;

    RESET p_volume_label;
    NEXT p_volume_label_header IN p_volume_label;

    label_expiration_date := p_volume_label_header^.expiration_date;

    pmp$get_system_time (current_date, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF current_date.year > label_expiration_date.year THEN
      RETURN; {----->
    IFEND;

    IF current_date.year = label_expiration_date.year THEN
      IF current_date.month > label_expiration_date.month THEN
        RETURN; {----->
      IFEND;
      IF current_date.month = label_expiration_date.month THEN
        IF current_date.day > label_expiration_date.day THEN
          RETURN; {----->
        IFEND;
      IFEND;
    IFEND;

    osp$set_status_abnormal (dmc$device_manager_ident, dme$vol_label_date_not_expired,
          'volume label not expired - verify_label_expiration_date', status);

    initialize_status_info.recorded_vsn := p_volume_label_header^.recorded_vsn;
    initialize_status_info.key := dme$vol_label_date_not_expired;
    initialize_status_info.label_expiration_date := label_expiration_date;

  PROCEND verify_label_expiration_date;
?? OLDTITLE ??
?? NEWTITLE := 'verify_volume_access_code', EJECT ??

  PROCEDURE verify_volume_access_code
    (    user_access_code: ost$name;
     VAR volume_label: {input} dmt$ms_volume_label;
     VAR initialize_status_info: dmt$initialize_status_info;
     VAR status: ost$status);

    VAR
      p_volume_label: ^dmt$ms_volume_label,
      p_volume_label_header: ^dmt$volume_label_header,
      p_volume_label_0_0: ^dmt$ms_label_0_0,
      volume_label_access_code: ost$name;

    status.normal := TRUE;

    p_volume_label := ^volume_label;

    RESET p_volume_label;
    NEXT p_volume_label_header IN p_volume_label;

    CASE p_volume_label_header^.version_number OF
    = dmc$ms_label_0_0 =
      NEXT p_volume_label_0_0 IN p_volume_label;
      volume_label_access_code := p_volume_label_0_0^.access_code;
    ELSE
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unsupported_label_version,
            'label version number not suppo' CAT 'rted - verify_volume_access_code', status);

      initialize_status_info.recorded_vsn := p_volume_label_header^.recorded_vsn;
      initialize_status_info.key := dme$unsupported_label_version;

      RETURN; {----->
    CASEND;

    IF user_access_code <> volume_label_access_code THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$invalid_volume_access_code,
            'invalid volume access code - verify_volume_access_code', status);

      initialize_status_info.recorded_vsn := p_volume_label_header^.recorded_vsn;
      initialize_status_info.key := dme$invalid_volume_access_code;
      initialize_status_info.access_code := volume_label_access_code;

    IFEND;

  PROCEND verify_volume_access_code;
?? OLDTITLE ??
?? NEWTITLE := 'verify_volume_owner', EJECT ??

  PROCEDURE verify_volume_owner
    (    requesting_owner_id: ost$user_identification;
     VAR volume_label: {input} dmt$ms_volume_label;
     VAR initialize_status_info: dmt$initialize_status_info;
     VAR status: ost$status);

    VAR
      p_volume_label: ^dmt$ms_volume_label,
      p_volume_label_header: ^dmt$volume_label_header,
      p_volume_label_0_0: ^dmt$ms_label_0_0,
      label_owner_id: ost$user_identification;

    status.normal := TRUE;

    p_volume_label := ^volume_label;

    RESET p_volume_label;
    NEXT p_volume_label_header IN p_volume_label;

    CASE p_volume_label_header^.version_number OF
    = dmc$ms_label_0_0 =
      NEXT p_volume_label_0_0 IN p_volume_label;
      label_owner_id := p_volume_label_0_0^.owner_id;
    ELSE
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unsupported_label_version,
            'label version not supported - verify_volume_owner', status);

      initialize_status_info.recorded_vsn := p_volume_label_header^.recorded_vsn;
      initialize_status_info.key := dme$unsupported_label_version;

      RETURN; {----->
    CASEND;

    IF label_owner_id <> requesting_owner_id THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$invalid_vol_owner_specified,
            'illegal volume owner id - verify_volume_owner', status);

      initialize_status_info.recorded_vsn := p_volume_label_header^.recorded_vsn;
      initialize_status_info.key := dme$invalid_vol_owner_specified;
      initialize_status_info.label_owner_id := label_owner_id;
    IFEND;

  PROCEND verify_volume_owner;
?? OLDTITLE ??
?? NEWTITLE := 'CREATE_NEW_VOLUME_LABEL', EJECT ??

  PROCEDURE create_new_volume_label
    (    p_volume_label_attributes: ^dmt$volume_label_attributes;
         p_physical_attributes: ^dmt$physical_device_attributes;
         p_logical_attributes: ^dmt$logical_device_attributes;
         logical_unit_number: iot$logical_unit;
         avt_index: dmt$active_volume_table_index;
     VAR control: {input/output} t$initialize_volume_control;
     VAR status: ost$status);

    CONST
      c$init_label_user_supplied_name = 'LABEL',
      c$nosve_label_type = 'nosve   ';

    VAR
      v$default_owner_id: [READ, oss$mainframe_paged_literal] ost$user_identification :=
            ['$SYSTEM', '$SYSTEM'];

    VAR
      access_code: ost$name,
      current_date: pmt$system_time,
      dat_sfid: gft$system_file_identifier,
      daus_per_alloc: dmt$dau_address,
      dfl_sfid: gft$system_file_identifier,
      directory_sfid: gft$system_file_identifier,
      expiration_days: dmt$label_expiration_days,
      expiration_years: 0 .. 4095,
      expiration_months: 0 .. 12,
      file_already_attached: boolean,
      index: integer,
      internal_vsn: dmt$internal_vsn,
      label_allocation_size: dmt$bytes_per_allocation,
      label_body_0_0: dmt$ms_label_0_0,
      label_cylinder_range: cylinder_range_type,
      label_dfle: dmt$ms_device_file_list_entry,
      label_file_hash: dmt$file_hash,
      label_global_file_name: dmt$global_file_name,
      label_sfid: gft$system_file_identifier,
      label_size: amt$file_byte_address,
      label_stored_df_fmd: dmt$device_file_stored_fmd,
      label_transfer_size: dmt$transfer_size,
      label_user_supplied_name: ost$name,
      label_version_number: dmt$ms_label_version_number,
      local_status: ost$status,
      number_of_faus: dmt$fau_entries,
      owner_id: ost$user_identification,
      p_dat: ^dmt$ms_device_allocation_table,
      p_dat_fmd: ^dmt$file_medium_descriptor,
      p_device_allocation_table_fat: ^dmt$stored_ms_device_file_fat,
      p_dfd: ^dmt$disk_file_descriptor,
      p_dfl: ^dmt$ms_device_file_list_table,
      p_directory: ^dmt$ms_volume_directory,
      p_fau_entry: ^dmt$file_allocation_unit,
      p_fde: gft$file_desc_entry_p,
      p_file_attributes: ^array [ * ] of dmt$file_attribute,
      p_fmd_attributes: ^array [1 .. * ] of dmt$fmd_attribute,
      p_label_body_0_0: ^dmt$ms_label_0_0,
      p_label_fmd: ^dmt$file_medium_descriptor,
      p_label_header: ^dmt$volume_label_header,
      p_stored_df_fat: ^dmt$stored_ms_device_file_fat,
      p_volume_label: ^dmt$ms_volume_label,
      recorded_vsn: rmt$recorded_vsn,
      variant_size: amt$file_byte_address,
      volume_label_header: dmt$volume_label_header;

    status.normal := TRUE;

  /build_label/
    BEGIN
      access_code := dmc$default_vol_access_code;
      owner_id := v$default_owner_id;
      expiration_years := dmc$default_vol_exp_years;
      expiration_months := dmc$default_vol_exp_months;
      expiration_days := dmc$default_vol_exp_days;
      recorded_vsn := '    ';
      label_version_number := dmc$ms_label_0_0;
      label_cylinder_range.lowest_cylinder := 0;
      label_cylinder_range.highest_cylinder := 0;
      label_allocation_size := dmc$default_label_alloc_size;
      label_transfer_size := dmc$default_label_transfer_size;

      IF p_volume_label_attributes <> NIL THEN
        FOR index := LOWERBOUND (p_volume_label_attributes^) TO UPPERBOUND (p_volume_label_attributes^) DO
          CASE p_volume_label_attributes^ [index].keyword OF
          = dmc$label_access_code =
            access_code := p_volume_label_attributes^ [index].access_code;
          = dmc$label_expiration_days =
            expiration_days := p_volume_label_attributes^ [index].expiration_days;
          = dmc$label_owner_id =
            owner_id := p_volume_label_attributes^ [index].owner_id;
          = dmc$label_recorded_vsn =
            recorded_vsn := p_volume_label_attributes^ [index].recorded_vsn;
          ELSE
          CASEND;
        FOREND;
      IFEND;

      preset_cylinder_0 (logical_unit_number, control.maus_per_cylinder);

      label_user_supplied_name := c$init_label_user_supplied_name;
      label_user_supplied_name (6, rmc$recorded_vsn_size) := recorded_vsn;

      volume_label_header.version_number := label_version_number;

      volume_label_header.label_type := c$nosve_label_type;

      pmp$get_system_time (current_date, status);
      IF NOT status.normal THEN
        EXIT /build_label/; {----->
      IFEND;

      volume_label_header.creation_date.year := current_date.year;
      volume_label_header.creation_date.month := current_date.month;
      volume_label_header.creation_date.day := current_date.day;

      expiration_years := expiration_days DIV 365;
      expiration_days := expiration_days - (expiration_years * 365);
      expiration_months := expiration_days DIV 30;
      expiration_days := expiration_days - (expiration_months * 30);
      volume_label_header.expiration_date.year := current_date.year + expiration_years;
      volume_label_header.expiration_date.month := expiration_months;
      volume_label_header.expiration_date.day := expiration_days;

      volume_label_header.bytes_per_dau := control.maus_per_dau * control.bytes_per_mau;
      volume_label_header.bytes_per_mau := control.bytes_per_mau;
      volume_label_header.positions_per_device := control.cylinders_per_device;
      volume_label_header.recorded_vsn := recorded_vsn;

      osp$generate_unique_binary_name (internal_vsn, status);
      IF NOT status.normal THEN
        EXIT /build_label/; {----->
      IFEND;
      volume_label_header.internal_vsn := internal_vsn;

{Initialize deadstart files to empty
      volume_label_header.primary_deadstart_file := 0;
      volume_label_header.secondary_deadstart_file := 0;
      volume_label_header.image_file := 0;
      volume_label_header.spare_file := 0;

      CASE label_version_number OF
      = dmc$ms_label_0_0 =
        variant_size := #SIZE (label_body_0_0);
        label_body_0_0.access_code := access_code;
        label_body_0_0.owner_id := owner_id;
        label_body_0_0.class := -$dmt$class [];

      /build_vol_device_files/
        BEGIN

{create device allocation table
          PUSH control.usable_daus_p: [0 .. control.cylinders_per_device - 1];
          build_device_allocation_table (logical_unit_number, avt_index, recorded_vsn, internal_vsn,
                dmc$dat_0_0, p_logical_attributes, p_physical_attributes, control, dat_sfid, p_dat, status);
          IF NOT status.normal THEN
            EXIT /build_label/; {----->
          IFEND;

        /dat_created/
          BEGIN
            label_body_0_0.device_allocation_table_fmd := control.dat_stored_df_fmd;
            label_body_0_0.dat_dfl_entry := control.dat_dfle;

{create device file list table
            build_device_file_list (avt_index, recorded_vsn, internal_vsn, dmc$dflt_0_0, p_logical_attributes,
                  p_dat, dfl_sfid, p_dfl, control, status);
            IF NOT status.normal THEN
              EXIT /dat_created/; {----->
            IFEND;

          /dfl_created/
            BEGIN
              label_body_0_0.device_file_list_fmd := control.dflt_stored_df_fmd;
              label_body_0_0.device_file_list_dfl_entry := control.dflt_dfle;

{create login table
              build_login_table (avt_index, recorded_vsn, internal_vsn, p_dat, p_dfl, control, status);
              IF NOT status.normal THEN
                EXIT /dfl_created/; {----->
              IFEND;

            /login_table_created/
              BEGIN

{create volume directory
                build_volume_directory (avt_index, recorded_vsn, internal_vsn, p_logical_attributes, p_dat,
                      p_dfl, directory_sfid, p_directory, control, status);
                IF NOT status.normal THEN
                  EXIT /login_table_created/; {----->
                IFEND;

              /directory_created/
                BEGIN
                  label_body_0_0.directory_fmd := control.directory_stored_df_fmd;
                  label_body_0_0.directory_dfl_entry := control.directory_dfle;

{create stored device file fats
                  gfp$get_fde_p (dat_sfid, p_fde);
                  dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
                  dmp$get_number_of_faus (p_dfd, number_of_faus);
                  PUSH p_device_allocation_table_fat: [1 .. number_of_faus];
                  variant_size := variant_size + #SIZE (p_device_allocation_table_fat^);
                  dmp$get_fmd_by_index (p_dfd, 1, p_dat_fmd);
                  build_stored_df_fat (p_fde, p_dfd, p_dat_fmd, p_device_allocation_table_fat, status);

                  IF status.normal THEN {leave files attached}
                    EXIT /build_vol_device_files/; {----->
                  IFEND;

                END /directory_created/;
                detach_file (p_directory, directory_sfid, local_status);

              END /login_table_created/;

            END /dfl_created/;
            detach_file (p_dfl, dfl_sfid, local_status);

          END /dat_created/;
          detach_file (p_dat, dat_sfid, local_status);

          EXIT /build_label/; {----->
        END /build_vol_device_files/;
      ELSE
        osp$set_status_abnormal (dmc$device_manager_ident, dme$unsupported_label_version,
              'label version not supported - DMMIVOL', status);
        EXIT /build_label/; {----->
      CASEND;

    /volume_device_files_created/
      BEGIN
        label_size := #SIZE (dmt$volume_label_header) + variant_size;

        PUSH p_volume_label: [[REP label_size OF cell]];
        RESET p_volume_label;

        NEXT p_label_header IN p_volume_label;

        p_label_header^ := volume_label_header;

        CASE label_version_number OF
        = dmc$ms_label_0_0 =
          NEXT p_label_body_0_0 IN p_volume_label;
          p_label_body_0_0^ := label_body_0_0;
          NEXT p_stored_df_fat: [1 .. UPPERBOUND (p_device_allocation_table_fat^.file_allocation_units)] IN
                p_volume_label;
          p_stored_df_fat^ := p_device_allocation_table_fat^;
        CASEND;

        label_global_file_name := internal_vsn;

        dmp$generate_gfn_hash (label_global_file_name, label_file_hash);

        PUSH p_file_attributes: [1 .. 12];

        p_file_attributes^ [1].keyword := dmc$file_kind;
        p_file_attributes^ [1].file_kind := gfc$fk_device_file;
        p_file_attributes^ [2].keyword := dmc$overflow;
        p_file_attributes^ [2].overflow_allowed := FALSE;
        p_file_attributes^ [3].keyword := dmc$requested_allocation_size;
        p_file_attributes^ [3].requested_allocation_size := label_allocation_size;
        p_file_attributes^ [4].keyword := dmc$requested_transfer_size;
        p_file_attributes^ [4].requested_transfer_size := label_transfer_size;
        p_file_attributes^ [5].keyword := dmc$requested_volume;
        p_file_attributes^ [5].requested_volume.recorded_vsn := recorded_vsn;
        p_file_attributes^ [5].requested_volume.setname := '    ';
        p_file_attributes^ [6].keyword := dmc$clear_space;
        p_file_attributes^ [6].required := TRUE;
        p_file_attributes^ [7].keyword := dmc$preset_value;
        p_file_attributes^ [7].preset_value := 0;
        p_file_attributes^ [8].keyword := dmc$locked_file;
        p_file_attributes^ [8].file_lock.required := FALSE;
        p_file_attributes^ [9].keyword := dmc$file_limit;
        p_file_attributes^ [9].limit := ((label_size + label_allocation_size - 1) DIV label_allocation_size) *
              label_allocation_size;
        p_file_attributes^ [10].keyword := dmc$file_hash;
        p_file_attributes^ [10].file_hash := label_file_hash;
        p_file_attributes^ [11].keyword := dmc$class;
        p_file_attributes^ [11].class := dmc$default_class;
        p_file_attributes^ [12].keyword := dmc$class_ordinal;
        p_file_attributes^ [12].ordinal := dmc$default_class_ordinal;

        build_stored_df_fmd_header (p_file_attributes, label_stored_df_fmd, status);
        IF NOT status.normal THEN
          EXIT /volume_device_files_created/; {----->
        IFEND;

        PUSH p_fmd_attributes: [1 .. 3];

        p_fmd_attributes^ [1].keyword := dmc$recorded_vsn;
        p_fmd_attributes^ [1].recorded_vsn := recorded_vsn;
        p_fmd_attributes^ [2].keyword := dmc$internal_vsn;
        p_fmd_attributes^ [2].internal_vsn := internal_vsn;
        p_fmd_attributes^ [3].keyword := dmc$device_file_list_index;
        p_fmd_attributes^ [3].device_file_list_index := dmc$label_dfl_index;

        build_stored_df_fmd_subfile (p_fmd_attributes, label_stored_df_fmd, status);
        IF NOT status.normal THEN
          EXIT /volume_device_files_created/; {----->
        IFEND;

        dmp$attach_device_file_by_fmd (label_global_file_name, label_stored_df_fmd, file_already_attached,
              label_sfid, status);
        IF NOT status.normal THEN
          EXIT /volume_device_files_created/; {----->
        IFEND;
        IF file_already_attached THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$duplicate_device_file_gfn,
                'label gfn already attached', status);
          EXIT /volume_device_files_created/; {----->
        IFEND;

        gfp$get_fde_p (label_sfid, p_fde);
        dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
        dmp$get_fmd_by_index (p_dfd, 1, p_label_fmd);

        p_label_fmd^.fmd_allocated_length := ((label_size + label_allocation_size) DIV
              label_allocation_size) * label_allocation_size;
        p_label_fmd^.avt_index := avt_index;

        daus_per_alloc := dmc$default_label_alloc_size DIV control.bytes_per_mau DIV control.maus_per_dau;

      /allocate_label_and_write_it/
        WHILE TRUE DO

          build_faus (label_cylinder_range, label_size, label_allocation_size, label_transfer_size,
                label_sfid, control, status);
          dmp$get_fau_entry (p_dfd, 0, p_fau_entry);
          IF NOT status.normal OR ((p_fau_entry^.dau_address DIV daus_per_alloc) > dmc$max_label_aus) THEN
            osp$set_status_abnormal (dmc$device_manager_ident, dme$no_contig_space_for_label,
                  'no contiguous daus for label', status);
            EXIT /volume_device_files_created/; {----->
          IFEND;

          write_label_to_disk (logical_unit_number, p_label_fmd, p_dfd, p_fau_entry, p_volume_label,
                label_size, control, status);
          IF status.normal THEN
            EXIT /allocate_label_and_write_it/; {----->
          IFEND;

          free_faus_flaw_daus (p_dat, p_dfd);

        WHILEND /allocate_label_and_write_it/;

{ update dat to reflect allocation of label daus
        update_dat_entries (p_dat, dmc$label_dfl_index, p_dfd, avt_index);

{ create label dfle
        label_dfle.pad := 0;
        label_dfle.flags := dmc$dfle_assigned_to_file;
        label_dfle.daus_per_allocation_unit := p_label_fmd^.daus_per_allocation_unit;
        label_dfle.dau_chain_status := dmc$dau_chain_linked;
        label_dfle.end_of_file := ((label_size + osv$page_size - 1) DIV osv$page_size) * osv$page_size;
        label_dfle.end_of_information := ((label_size + osv$page_size - 1) DIV osv$page_size) * osv$page_size;
        label_dfle.file_byte_address := 0;
        label_dfle.file_hash := label_sfid.file_hash;
        label_dfle.file_kind := gfc$fk_device_file;
        label_dfle.first_dau_address := p_fau_entry^.dau_address;
        label_dfle.global_file_name := label_global_file_name;
        label_dfle.logical_length := ((label_size + osv$page_size - 1) DIV osv$page_size) * osv$page_size;
        label_dfle.fmd_length := ((label_size + label_allocation_size - 1) DIV label_allocation_size) *
              label_allocation_size;
        label_dfle.login_set := $dmt$dfl_login_set [];

{update dfl to reflect label dfle.

        p_dfl^.entries [dmc$label_dfl_index] := label_dfle;

{create directory entry for label

        p_directory^.entries [dmc$label_directory_index].global_file_name := label_global_file_name;
        p_directory^.entries [dmc$label_directory_index].user_supplied_name := label_user_supplied_name;
        p_directory^.entries [dmc$label_directory_index].stored_df_fmd := label_stored_df_fmd;

      END /volume_device_files_created/;

      detach_file (p_directory, directory_sfid, local_status);
      IF status.normal AND NOT local_status.normal THEN
        status := local_status;
      IFEND;

      detach_file (p_dfl, dfl_sfid, local_status);
      IF status.normal AND NOT local_status.normal THEN
        status := local_status;
      IFEND;

      detach_file (p_dat, dat_sfid, local_status);
      IF status.normal AND NOT local_status.normal THEN
        status := local_status;
      IFEND;

      detach_file ({p_file =} NIL, label_sfid, local_status);
      IF status.normal AND NOT local_status.normal THEN
        status := local_status;
      IFEND;

    END /build_label/;

  PROCEND create_new_volume_label;
?? OLDTITLE ??
?? NEWTITLE := 'build_device_allocation_table', EJECT ??

  PROCEDURE build_device_allocation_table
    (    logical_unit_number: iot$logical_unit;
         avt_index: dmt$active_volume_table_index;
         recorded_vsn: rmt$recorded_vsn;
         internal_vsn: dmt$internal_vsn;
         dat_version_number: dmt$ms_dat_version_number;
         p_logical_attributes: ^dmt$logical_device_attributes;
         p_physical_attributes: ^dmt$physical_device_attributes;
     VAR control: t$initialize_volume_control;
     VAR dat_sfid: gft$system_file_identifier;
     VAR p_dat: ^dmt$ms_device_allocation_table;
     VAR status: ost$status);

    CONST
      c$init_dat_user_supplied_name = 'DAT';

    VAR
      allocation_size: dmt$allocation_size,
      allocation_style: dmt$allocation_styles,
      applicable_flaw_count: integer,
      bytes_per_dau: dmt$bytes_per_dau,
      cylinder: integer, { can be temporarly bigger than dmt$device_position during flaw calculation
      dat_cylinder_range: cylinder_range_type,
      dat_file_hash: dmt$file_hash,
      dat_length_in_bytes: amt$file_byte_address,
      dau_index: dmt$dau_address,
      daus_per_allocation_unit: dmt$daus_per_allocation,
      device_flaws_specified: boolean,
      file_already_attached: boolean,
      flaw_index: integer,
      index: integer,
      local_status: ost$status,
      logical_flaws: array [1 .. dmc$max_logical_flaws] of dmt$flaw_list_entry,
      logical_flaws_specified: boolean,
      number_of_logical_flaws: dmt$dau_address,
      p_device_flaw_list: ^dmt$ms_flaw_list,
      p_ds_sector_flaw_list: ^dmt$ms_flaw_list,
      p_dat_fmd: ^dmt$file_medium_descriptor,
      p_dfd: ^dmt$disk_file_descriptor,
      p_fde: gft$file_desc_entry_p,
      p_fau_entry: ^dmt$file_allocation_unit,
      p_sc_dau_list: ^array [1 .. * ] of dmt$log_flaw_init_data,
      p_dat_seq: ^SEQ ( * ),
      p_flaw_locations: ^array [1 .. * ] of dmt$flaw_map_address,
      powers_of_two: 1 .. 1024,
      p_file_attributes: ^array [ * ] of dmt$file_attribute,
      p_fmd_attributes: ^array [1 .. * ] of dmt$fmd_attribute,
      segment_pointer: mmt$segment_pointer,
      transfer_size: dmt$transfer_size,
      unusable_daus: dmt$dau_address;

    status.normal := TRUE;
    allocation_size := 0;
    transfer_size := 0;
    p_dat := NIL;

    applicable_flaw_count := 0;
    number_of_logical_flaws := 0;
    control.dat_user_supplied_name := c$init_dat_user_supplied_name;
    control.dat_user_supplied_name (4, rmc$recorded_vsn_size) := recorded_vsn;

    osp$generate_unique_binary_name (control.dat_global_file_name, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    dmp$generate_gfn_hash (control.dat_global_file_name, dat_file_hash);

    control.daus_per_cylinder := control.maus_per_cylinder DIV control.maus_per_dau;
    bytes_per_dau := control.maus_per_dau * control.bytes_per_mau;
    control.daus_per_device := control.daus_per_cylinder * control.cylinders_per_device;
    dat_length_in_bytes := control.daus_per_device * #SIZE (dmt$ms_device_allocation_unit) +
          #SIZE (dmt$ms_device_alloc_table_head);
    device_flaws_specified := FALSE;
    logical_flaws_specified := FALSE;

    IF p_physical_attributes <> NIL THEN
      FOR index := LOWERBOUND (p_physical_attributes^) TO UPPERBOUND (p_physical_attributes^) DO
        CASE p_physical_attributes^ [index].keyword OF
        = dmc$flaw_map_locations =
          PUSH p_flaw_locations: [1 .. UPPERBOUND (p_physical_attributes^ [index].flaw_locations)];
          p_flaw_locations^ := p_physical_attributes^ [index].flaw_locations;
          device_flaws_specified := p_flaw_locations^ [1].device_flaws_specified;
        ELSE
        CASEND;
      FOREND;
    IFEND;

{create allocation map for the device
    FOR cylinder := 0 TO control.cylinders_per_device - 1 DO
      control.usable_daus_p^ [cylinder] := -$dau_mapping [];
      FOR dau_index := control.daus_per_cylinder TO dmc$max_daus_position DO
        control.usable_daus_p^ [cylinder] := control.usable_daus_p^ [cylinder] - $dau_mapping [dau_index];
      FOREND;
    FOREND;

{compute allocation style dau values
    powers_of_two := 1;

    FOR allocation_style := LOWERVALUE (dmt$allocation_styles) TO UPPERVALUE (dmt$allocation_styles) DO
      IF control.daus_per_cylinder > powers_of_two THEN
        control.daus_per_allocation_style [allocation_style] := powers_of_two;
      ELSE
        control.daus_per_allocation_style [allocation_style] := control.daus_per_cylinder;
      IFEND;
      powers_of_two := powers_of_two * 2;
    FOREND;

    IF p_logical_attributes <> NIL THEN
      FOR index := LOWERBOUND (p_logical_attributes^) TO UPPERBOUND (p_logical_attributes^) DO
        CASE p_logical_attributes^ [index].keyword OF
        = dmc$logical_flaws =
          number_of_logical_flaws := p_logical_attributes^ [index].number_of_flaw_entries;
          logical_flaws := p_logical_attributes^ [index].flaw_locations;
          logical_flaws_specified := (number_of_logical_flaws > 0);
        = dmc$volume_default_alloc_sz =
          allocation_size := p_logical_attributes^ [index].volume_default_allocation_size;
        = dmc$volume_default_transfer_sz =
          transfer_size := p_logical_attributes^ [index].volume_default_transfer_size;
        ELSE
        CASEND;
      FOREND;
    IFEND;

{ build the stored device file fmd
    PUSH p_file_attributes: [1 .. 12];
    p_file_attributes^ [1].keyword := dmc$file_kind;
    p_file_attributes^ [1].file_kind := gfc$fk_device_file;
    p_file_attributes^ [2].keyword := dmc$overflow;
    p_file_attributes^ [2].overflow_allowed := FALSE;
    p_file_attributes^ [3].keyword := dmc$requested_allocation_size;
    p_file_attributes^ [3].requested_allocation_size := dmc$dat_allocation_size;
    p_file_attributes^ [4].keyword := dmc$requested_transfer_size;
    p_file_attributes^ [4].requested_transfer_size := dmc$dat_transfer_size;
    p_file_attributes^ [5].keyword := dmc$requested_volume;
    p_file_attributes^ [5].requested_volume.recorded_vsn := recorded_vsn;
    p_file_attributes^ [5].requested_volume.setname := '    ';
    p_file_attributes^ [6].keyword := dmc$clear_space;
    p_file_attributes^ [6].required := TRUE;
    p_file_attributes^ [7].keyword := dmc$preset_value;
    p_file_attributes^ [7].preset_value := 0;
    p_file_attributes^ [8].keyword := dmc$locked_file;
    p_file_attributes^ [8].file_lock.required := FALSE;
    p_file_attributes^ [9].keyword := dmc$file_limit;
    p_file_attributes^ [9].limit := ((dat_length_in_bytes + dmc$dat_allocation_size - 1) DIV
          dmc$dat_allocation_size) * dmc$dat_allocation_size;
    p_file_attributes^ [10].keyword := dmc$file_hash;
    p_file_attributes^ [10].file_hash := dat_file_hash;
    p_file_attributes^ [11].keyword := dmc$class;
    p_file_attributes^ [11].class := dmc$default_class;
    p_file_attributes^ [12].keyword := dmc$class_ordinal;
    p_file_attributes^ [12].ordinal := dmc$default_class_ordinal;

    build_stored_df_fmd_header (p_file_attributes, control.dat_stored_df_fmd, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    PUSH p_fmd_attributes: [1 .. 3];

    p_fmd_attributes^ [1].keyword := dmc$recorded_vsn;
    p_fmd_attributes^ [1].recorded_vsn := recorded_vsn;
    p_fmd_attributes^ [2].keyword := dmc$internal_vsn;
    p_fmd_attributes^ [2].internal_vsn := internal_vsn;
    p_fmd_attributes^ [3].keyword := dmc$device_file_list_index;
    p_fmd_attributes^ [3].device_file_list_index := dmc$dat_dfl_index;

    build_stored_df_fmd_subfile (p_fmd_attributes, control.dat_stored_df_fmd, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

{ attach the device allocation table
    dmp$attach_device_file_by_fmd (control.dat_global_file_name, control.dat_stored_df_fmd,
          file_already_attached, dat_sfid, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF file_already_attached THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$duplicate_device_file_gfn,
            'dat gfn already attached', status);
      RETURN; {----->
    IFEND;

    gfp$get_fde_p (dat_sfid, p_fde);
    dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
    dmp$get_fmd_by_index (p_dfd, 1, p_dat_fmd);

    p_dat_fmd^.fmd_allocated_length := ((dat_length_in_bytes + dmc$dat_allocation_size - 1) DIV
          dmc$dat_allocation_size) * dmc$dat_allocation_size;
    p_dat_fmd^.avt_index := avt_index;

  /dat_file_attached/
    BEGIN

      unusable_daus := 0;
      get_deadstart_sector_flaws (logical_unit_number, control, p_ds_sector_flaw_list);
      IF (p_ds_sector_flaw_list <> NIL) THEN
        FOR flaw_index := 1 TO UPPERBOUND (p_ds_sector_flaw_list^) DO
          dau_index := p_ds_sector_flaw_list^ [flaw_index].dau_address;

          FOR index := 1 TO p_ds_sector_flaw_list^ [flaw_index].number_flawed_daus DO
            cylinder := dau_index DIV control.daus_per_cylinder;
            IF cylinder < control.cylinders_per_device THEN
              IF (dau_index MOD control.daus_per_cylinder) IN control.usable_daus_p^ [cylinder] THEN
                control.usable_daus_p^ [cylinder] := control.usable_daus_p^ [cylinder] -
                      $dau_mapping [dau_index MOD control.daus_per_cylinder];
                unusable_daus := unusable_daus + 1;
              IFEND;
            IFEND;
            dau_index := dau_index + 1;
          FOREND;
        FOREND;
      IFEND;

      IF device_flaws_specified THEN
        get_device_flaws (logical_unit_number, p_flaw_locations^, p_device_flaw_list, control, status);
        IF NOT status.normal THEN
          EXIT /dat_file_attached/; {----->
        IFEND;
        device_flaws_specified := (p_device_flaw_list <> NIL);
      IFEND;
      IF device_flaws_specified THEN
        FOR flaw_index := 1 TO UPPERBOUND (p_device_flaw_list^) DO
          dau_index := p_device_flaw_list^ [flaw_index].dau_address;

          FOR index := 1 TO p_device_flaw_list^ [flaw_index].number_flawed_daus DO
            cylinder := dau_index DIV control.daus_per_cylinder;
            IF cylinder < control.cylinders_per_device THEN
              IF (dau_index MOD control.daus_per_cylinder) IN control.usable_daus_p^ [cylinder] THEN
                control.usable_daus_p^ [cylinder] := control.usable_daus_p^ [cylinder] -
                      $dau_mapping [dau_index MOD control.daus_per_cylinder];
                unusable_daus := unusable_daus + 1;
              IFEND;
            IFEND;
            dau_index := dau_index + 1;
          FOREND;
        FOREND;
      IFEND;

      IF logical_flaws_specified THEN
        FOR flaw_index := 1 TO number_of_logical_flaws DO
          dau_index := logical_flaws [flaw_index].dau_address;

          FOR index := 1 TO logical_flaws [flaw_index].number_flawed_daus DO
            cylinder := dau_index DIV control.daus_per_cylinder;
            IF cylinder < control.cylinders_per_device THEN
              IF (dau_index MOD control.daus_per_cylinder) IN control.usable_daus_p^ [cylinder] THEN
                control.usable_daus_p^ [cylinder] := control.usable_daus_p^ [cylinder] -
                      $dau_mapping [dau_index MOD control.daus_per_cylinder];
                unusable_daus := unusable_daus + 1;
              IFEND;
            IFEND;
            dau_index := dau_index + 1;
          FOREND;
        FOREND;
      IFEND;

      IF (p_existing_flaws <> NIL) THEN
        FOR flaw_index := LOWERBOUND (p_existing_flaws^) TO UPPERBOUND (p_existing_flaws^) DO
          dau_index := p_existing_flaws^ [flaw_index].dau_address;
          cylinder := dau_index DIV control.daus_per_cylinder;
          IF cylinder < control.cylinders_per_device THEN
            IF (dau_index MOD control.daus_per_cylinder) IN control.usable_daus_p^ [cylinder] THEN
              control.usable_daus_p^ [cylinder] := control.usable_daus_p^ [cylinder] -
                    $dau_mapping [dau_index MOD control.daus_per_cylinder];
              unusable_daus := unusable_daus + 1;
            IFEND;
          IFEND;
        FOREND;
      IFEND;

{ Procedure dmp$convert_to_dau_address called by dmp$construct_sc_dau_list needs the RVSN to
{ be set in the active_volume_table before it is executed.

      dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn := recorded_vsn;

{ Create an array of system core flaws that pertain to this device and clear the correct bit in the bit map.
{ NOTE: The number of available DAUs will be adjusted in dmp$record_sc_flaw called later.
{       Also, the system core flaws will not be marked as processed until normal status is received at the
{       completion of creating the label.  Otherwise, if another iniatialize command is entered for the same
{       device after a failed attempt, all flaws would be lost.

      IF dmv$p_sc_flaw_commands <> NIL THEN
        PUSH p_sc_dau_list: [1 .. UPPERBOUND (dmv$p_sc_flaw_commands^)];
        dmp$construct_sc_dau_list (recorded_vsn, TRUE, p_sc_dau_list, applicable_flaw_count, status);

        FOR index := 1 TO applicable_flaw_count DO
          cylinder := p_sc_dau_list^ [index].first_dau DIV control.daus_per_cylinder;
          IF cylinder < control.cylinders_per_device THEN

            FOR dau_index := p_sc_dau_list^ [index].first_dau TO p_sc_dau_list^ [index].last_dau DO
              IF (dau_index MOD control.daus_per_cylinder) IN control.usable_daus_p^ [cylinder] THEN
                control.usable_daus_p^ [cylinder] := control.usable_daus_p^ [cylinder] -
                      $dau_mapping [dau_index MOD control.daus_per_cylinder];
              IFEND;
            FOREND;

          IFEND;
        FOREND;

      IFEND;

      dat_cylinder_range.lowest_cylinder := 1;
      dat_cylinder_range.highest_cylinder := control.cylinders_per_device - 1;

      build_faus (dat_cylinder_range, dat_length_in_bytes, dmc$dat_allocation_size, dmc$dat_transfer_size,
            dat_sfid, control, status);
      IF NOT status.normal THEN
        EXIT /dat_file_attached/; {----->
      IFEND;

      daus_per_allocation_unit := p_dat_fmd^.daus_per_allocation_unit;
      segment_pointer.kind := mmc$sequence_pointer;

      dmp$open_file (dat_sfid, osc$os_ring_1, osc$os_ring_1, mmc$sar_write_extend, mmc$as_sequential,
            segment_pointer, status);
      IF NOT status.normal THEN
        EXIT /dat_file_attached/; {----->
      IFEND;

      p_dat_seq := segment_pointer.seq_pointer;
      RESET p_dat_seq;
      NEXT p_dat: [dmc$min_dau_address .. dmc$min_dau_address + control.daus_per_device - 1] IN p_dat_seq;

{build device allocation table header
      osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

    /dat_locked/
      BEGIN
        p_dat^.header.default_transfer_size := transfer_size;
        p_dat^.header.default_allocation_size := allocation_size;
        p_dat^.header.bytes_per_dau := bytes_per_dau;
        p_dat^.header.bytes_per_mau := control.bytes_per_mau;
        p_dat^.header.daus_per_position := control.daus_per_cylinder;
        p_dat^.header.maus_per_dau := control.maus_per_dau;
        p_dat^.header.number_of_entries := control.daus_per_device;
        p_dat^.header.positions_per_device := control.cylinders_per_device;
        p_dat^.header.version_number := dat_version_number;
        CASE dat_version_number OF
        = dmc$dat_0_0 =
          p_dat^.header.daus_per_allocation_style := control.daus_per_allocation_style;
          p_dat^.header.available := control.daus_per_device - unusable_daus;

          { Recovery threshold = 2% of device to the nearest 100 DAU's }

          p_dat^.header.recovery_threshold := ((control.daus_per_device + 2500) DIV 5000) * 100;

          { Warning threshold = 10% of device to the nearest 100 DAU's }

          p_dat^.header.warning_threshold := ((control.daus_per_device + 500) DIV 1000) * 100;

          p_dat^.header.pad1 [1] := 0;
          p_dat^.header.pad1 [2] := 0; { this used to be "commitment level"
          p_dat^.header.pad1 [3] := 0;
          p_dat^.header.pad1 [4] := 0;
          p_dat^.header.pad1 [5] := 0;

{build device allocation table body

          FOR dau_index := dmc$min_dau_address TO dmc$min_dau_address + control.daus_per_device - 1 DO
            p_dat^.body [dau_index].dau_status := dmc$dau_usable;
          FOREND;

{flaw dat entries that are in the device flaw list

          IF device_flaws_specified THEN
            FOR flaw_index := 1 TO UPPERBOUND (p_device_flaw_list^) DO
              dau_index := p_device_flaw_list^ [flaw_index].dau_address;

              FOR index := 1 TO p_device_flaw_list^ [flaw_index].number_flawed_daus DO
                IF dau_index < control.daus_per_device THEN
                  p_dat^.body [dau_index].dau_status := dmc$dau_hardware_flawed;
                IFEND;
                dau_index := dau_index + 1;
              FOREND;
            FOREND;

            FREE p_device_flaw_list IN osv$mainframe_wired_heap^;
          IFEND;

{flaw entries in deadstart sector

          IF (p_ds_sector_flaw_list <> NIL) THEN
            FOR flaw_index := 1 TO UPPERBOUND (p_ds_sector_flaw_list^) DO
              dau_index := p_ds_sector_flaw_list^ [flaw_index].dau_address;

              FOR index := 1 TO p_ds_sector_flaw_list^ [flaw_index].number_flawed_daus DO
                IF dau_index < control.daus_per_device THEN
                  IF (p_dat^.body [dau_index].dau_status = dmc$dau_usable) THEN
                    p_dat^.body [dau_index].dau_status := dmc$dau_hardware_flawed;
                  IFEND;
                IFEND;
                dau_index := dau_index + 1;
              FOREND;
            FOREND;

            FREE p_ds_sector_flaw_list IN osv$mainframe_wired_heap^;
          IFEND;

{flaw logical flaws
          IF logical_flaws_specified THEN
            FOR flaw_index := 1 TO number_of_logical_flaws DO
              dau_index := logical_flaws [flaw_index].dau_address;

              FOR index := 1 TO logical_flaws [flaw_index].number_flawed_daus DO
                IF dau_index < control.daus_per_device THEN
                  IF (p_dat^.body [dau_index].dau_status = dmc$dau_usable) THEN
                    p_dat^.body [dau_index].dau_status := dmc$dau_hardware_flawed;
                  IFEND;
                IFEND;
                dau_index := dau_index + 1;
              FOREND;
            FOREND;
          IFEND;

{retain flaws from previous production run on this device ******************************** }
          IF (p_existing_flaws <> NIL) THEN
            FOR index := LOWERBOUND (p_existing_flaws^) TO UPPERBOUND (p_existing_flaws^) DO
              dau_index := p_existing_flaws^ [index].dau_address;
              IF (p_dat^.body [dau_index].dau_status = dmc$dau_usable) THEN
                CASE p_existing_flaws^ [index].kind_of_flaw OF

                = dmc$dau_hardware_flawed, dmc$dau_software_flawed =
                  p_dat^.body [dau_index].dau_status := p_existing_flaws^ [index].kind_of_flaw;

                = dmc$dau_ass_to_mf_swr_flawed, dmc$dau_ass_to_file_swr_flawed =
                  p_dat^.body [dau_index].dau_status := dmc$dau_software_flawed;

                ELSE
                CASEND;
              IFEND;
            FOREND;

            FREE p_existing_flaws IN osv$mainframe_wired_heap^;
          IFEND;

{Flaw DAUs selected by the system core flaw commands.

          IF applicable_flaw_count <> 0 THEN
            dmp$record_sc_flaw (applicable_flaw_count, p_dat, p_sc_dau_list);
          IFEND;

        ELSE
          osp$set_status_abnormal (dmc$device_manager_ident, dme$unsupported_dat_version,
                'unsupported dat version number', status);
        CASEND;
      END /dat_locked/;

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

{set dat entries,which are used to describe the dat, to reflect allocated status
      update_dat_entries (p_dat, dmc$dat_dfl_index, p_dfd, avt_index);

    /build_device_file_list_entry/
      BEGIN
        dmp$get_fau_entry (p_dfd, 0, p_fau_entry);
        control.dat_dfle.pad := 0;
        control.dat_dfle.flags := dmc$dfle_assigned_to_file;
        control.dat_dfle.dau_chain_status := dmc$dau_chain_linked;
        control.dat_dfle.daus_per_allocation_unit := daus_per_allocation_unit;
        control.dat_dfle.end_of_file := ((dat_length_in_bytes + osv$page_size - 1) DIV osv$page_size) *
              osv$page_size;
        control.dat_dfle.end_of_information := ((dat_length_in_bytes + osv$page_size - 1) DIV osv$page_size) *
              osv$page_size;
        control.dat_dfle.file_byte_address := 0;
        control.dat_dfle.file_hash := dat_sfid.file_hash;
        control.dat_dfle.file_kind := gfc$fk_device_file;
        control.dat_dfle.first_dau_address := p_fau_entry^.dau_address;
        control.dat_dfle.global_file_name := control.dat_global_file_name;
        control.dat_dfle.logical_length := ((dat_length_in_bytes + osv$page_size - 1) DIV osv$page_size) *
              osv$page_size;
        control.dat_dfle.fmd_length := ((dat_length_in_bytes + dmc$dat_allocation_size - 1) DIV
              dmc$dat_allocation_size) * dmc$dat_allocation_size;
        control.dat_dfle.login_set := $dmt$dfl_login_set [];

      END /build_device_file_list_entry/;

    END /dat_file_attached/;
    IF NOT status.normal THEN
      detach_file (p_dat, dat_sfid, local_status);
    IFEND;

  PROCEND build_device_allocation_table;
?? OLDTITLE ??
?? NEWTITLE := 'build_faus', EJECT ??

  PROCEDURE build_faus
    (    cylinder_range: cylinder_range_type;
         length_in_bytes: amt$file_byte_address;
         allocation_size: dmt$bytes_per_allocation;
         transfer_size: dmt$transfer_size;
         sfid: gft$system_file_identifier;
     VAR control: {input/output} t$initialize_volume_control;
     VAR status: ost$status);

    VAR
      able_to_allocate_aus: boolean,
      allocation_style: dmt$allocation_styles,
      allocation_style_found: boolean,
      allocation_unit_dau_address: dmt$dau_address,
      byte_address: amt$file_byte_address,
      bytes_per_dau: dmt$bytes_per_dau,
      daus_per_allocation_unit: dmt$daus_per_allocation,
      fau_index: dmt$fau_entries,
      length_in_daus: dmt$dau_address,
      maus_per_allocation_unit: dmt$maus_per_allocation,
      maus_per_transfer_unit: dmt$maus_per_transfer,
      next_au_index_in_cylinder: dmt$daus_per_position,
      number_faus: dmt$fau_entries,
      p_fau: ^dmt$file_allocation_unit,
      p_dfd: ^dmt$disk_file_descriptor,
      p_fde: gft$file_desc_entry_p,
      p_fmd: ^dmt$file_medium_descriptor;

    status.normal := TRUE;

    bytes_per_dau := control.bytes_per_mau * control.maus_per_dau;
    maus_per_allocation_unit := (allocation_size + control.bytes_per_mau - 1) DIV control.bytes_per_mau;
    daus_per_allocation_unit := (maus_per_allocation_unit + control.maus_per_dau - 1) DIV
          control.maus_per_dau;
    maus_per_transfer_unit := (transfer_size + control.bytes_per_mau - 1) DIV control.bytes_per_mau;

  /compute_allocation_style/
    FOR allocation_style := dmc$a0 TO dmc$acyl DO
      allocation_style_found := (control.daus_per_allocation_style [allocation_style] =
            daus_per_allocation_unit);
      IF allocation_style_found THEN
        EXIT /compute_allocation_style/; {----->
      IFEND;
    FOREND /compute_allocation_style/;

    IF NOT allocation_style_found THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$no_allocation_style_found,
            'unable to compute allocation style', status);
      RETURN; {----->
    IFEND;

    length_in_daus := (length_in_bytes + bytes_per_dau - 1) DIV bytes_per_dau;
    number_faus := (length_in_daus + daus_per_allocation_unit - 1) DIV daus_per_allocation_unit;

    gfp$get_fde_p (sfid, p_fde);
    dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
    dmp$get_fmd_by_index (p_dfd, 1, p_fmd);

    p_fmd^.bytes_per_mau := control.bytes_per_mau;
    p_fmd^.daus_per_allocation_unit := daus_per_allocation_unit;
    p_fmd^.daus_per_cylinder := control.daus_per_cylinder;
    p_fmd^.maus_per_dau := control.maus_per_dau;
    p_fmd^.allocation_style := allocation_style;
    p_fmd^.maus_per_transfer_unit := maus_per_transfer_unit;
    p_dfd^.bytes_per_allocation := control.maus_per_dau * control.bytes_per_mau * daus_per_allocation_unit;
    p_fde^.allocation_unit_size := control.maus_per_dau * control.bytes_per_mau * daus_per_allocation_unit;

    IF (dmc$bytes_per_level_2 MOD p_dfd^.bytes_per_allocation) <> 0 THEN
      {Round up to next allocation unit
      p_dfd^.bytes_per_level_2 := (dmc$bytes_per_level_2 + p_dfd^.bytes_per_allocation - 1) DIV
            p_dfd^.bytes_per_allocation * p_dfd^.bytes_per_allocation;
    ELSE
      p_dfd^.bytes_per_level_2 := dmc$bytes_per_level_2;
    IFEND;
    p_fmd^.system_file_id := sfid;
    p_dfd^.current_fmd_index := 1;

    allocation_unit_dau_address := cylinder_range.lowest_cylinder * control.daus_per_cylinder;

    dmp$create_fau_entry (p_dfd, 0, number_faus * p_dfd^.bytes_per_allocation);

  /allocate_space/
    BEGIN
      get_consecutive_alloc_units (number_faus, daus_per_allocation_unit, cylinder_range,
            allocation_unit_dau_address, control, able_to_allocate_aus);
      IF able_to_allocate_aus THEN
        byte_address := 0;
        FOR fau_index := 1 TO number_faus DO
          dmp$get_fau_entry (p_dfd, byte_address, p_fau);
          p_fau^.dau_address := allocation_unit_dau_address;
          p_fau^.state := dmc$fau_invalid_data;
          p_fau^.fmd_index := 1;
          next_au_index_in_cylinder := ((allocation_unit_dau_address + daus_per_allocation_unit) -
                ((allocation_unit_dau_address + daus_per_allocation_unit) DIV control.daus_per_cylinder) *
                control.daus_per_cylinder) DIV daus_per_allocation_unit;
          IF next_au_index_in_cylinder <= ((control.daus_per_cylinder DIV daus_per_allocation_unit) - 1) THEN
            allocation_unit_dau_address := allocation_unit_dau_address + daus_per_allocation_unit;
          ELSE
            allocation_unit_dau_address := ((allocation_unit_dau_address DIV control.daus_per_cylinder) + 1) *
                  control.daus_per_cylinder;
          IFEND;
          byte_address := byte_address + p_dfd^.bytes_per_allocation;
        FOREND;
      IFEND;

    END /allocate_space/;
    IF NOT able_to_allocate_aus THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_allocate_aus,
            'unable to allocate consecutive aus - DMMIVOL', status);
      RETURN; {----->
    IFEND;

    p_fmd^.volume_assigned := TRUE;
    p_dfd^.highest_offset_allocated := byte_address;

  PROCEND build_faus;
?? OLDTITLE ??
?? NEWTITLE := 'free_faus_flaw_daus', EJECT ??

  PROCEDURE free_faus_flaw_daus
    (    p_dat: ^dmt$ms_device_allocation_table;
         p_dfd: ^dmt$disk_file_descriptor);

    VAR
      byte_address: amt$file_byte_address,
      fau_index: dmt$fau_entries,
      number_of_faus: dmt$fau_entries,
      p_fau_entry: ^dmt$file_allocation_unit;

    dmp$get_number_of_faus (p_dfd, number_of_faus);

    byte_address := 0;
    FOR fau_index := 1 TO number_of_faus DO
      dmp$get_fau_entry (p_dfd, byte_address, p_fau_entry);
      IF (p_fau_entry^.state <> dmc$fau_free) THEN
        p_dat^.body [p_fau_entry^.dau_address].dau_status := dmc$dau_software_flawed;
        p_fau_entry^.state := dmc$fau_free;
      IFEND;
      byte_address := byte_address + p_dfd^.bytes_per_allocation;
    FOREND;

  PROCEND free_faus_flaw_daus;
?? OLDTITLE ??
?? NEWTITLE := 'get_consecutive_alloc_units', EJECT ??

  PROCEDURE get_consecutive_alloc_units
    (    number_of_consecutive_aus: dmt$fau_entries;
         daus_per_allocation_unit: dmt$daus_per_allocation;
         cylinder_range: cylinder_range_type;
     VAR allocation_unit_address: dmt$dau_address;
     VAR control: {input/output} t$initialize_volume_control;
     VAR able_to_allocate_aus: boolean);

    VAR
      cylinder: dmt$device_position,
      au_address: 0 .. dmc$max_daus_position + dmc$max_daus_allocation,
      last_au_address_in_cylinder: dmt$daus_per_position,
      consecutive_aus: dmt$dau_address,
      consecutive_au_address: dmt$dau_address,
      dau_index: dmt$daus_per_position,
      consecutive_au_found: boolean;

    able_to_allocate_aus := FALSE;
    consecutive_aus := number_of_consecutive_aus;
    consecutive_au_address := allocation_unit_address;
    last_au_address_in_cylinder := ((control.daus_per_cylinder DIV daus_per_allocation_unit) - 1) *
          daus_per_allocation_unit;

    REPEAT
      cylinder := consecutive_au_address DIV control.daus_per_cylinder;
      au_address := ((consecutive_au_address - (cylinder * control.daus_per_cylinder)) DIV
            daus_per_allocation_unit) * daus_per_allocation_unit;

    /consecutive_au_loop/
      WHILE au_address <= last_au_address_in_cylinder DO

      /consecutive_dau_loop/
        FOR dau_index := 0 TO daus_per_allocation_unit - 1 DO
          consecutive_au_found := (au_address + dau_index) IN control.usable_daus_p^ [cylinder];
          IF NOT consecutive_au_found THEN
            EXIT /consecutive_au_loop/; {----->
          IFEND;
        FOREND /consecutive_dau_loop/;
        consecutive_aus := consecutive_aus - 1;
        IF consecutive_aus <= 0 THEN
          EXIT /consecutive_au_loop/; {----->
        IFEND;
        au_address := au_address + daus_per_allocation_unit;
      WHILEND /consecutive_au_loop/;
      IF consecutive_aus <= 0 THEN
        cylinder := allocation_unit_address DIV control.daus_per_cylinder;
        au_address := ((allocation_unit_address - (cylinder * control.daus_per_cylinder)) DIV
              daus_per_allocation_unit) * daus_per_allocation_unit;
        consecutive_aus := 1;
        WHILE consecutive_aus <= number_of_consecutive_aus DO
          consecutive_aus := consecutive_aus + 1;
          FOR dau_index := 0 TO daus_per_allocation_unit - 1 DO
            control.usable_daus_p^ [cylinder] := control.usable_daus_p^ [cylinder] -
                  $dau_mapping [au_address + dau_index];
          FOREND;
          IF (au_address + daus_per_allocation_unit) <= last_au_address_in_cylinder THEN
            au_address := au_address + daus_per_allocation_unit;
          ELSE
            cylinder := cylinder + 1;
            au_address := 0;
          IFEND;
        WHILEND;
        able_to_allocate_aus := TRUE;
        RETURN; {----->
      IFEND;
      IF consecutive_au_found THEN
        consecutive_au_address := (cylinder + 1) * control.daus_per_cylinder;
      ELSE
        consecutive_aus := number_of_consecutive_aus;
        IF au_address < last_au_address_in_cylinder THEN
          consecutive_au_address := (au_address + daus_per_allocation_unit) +
                (control.daus_per_cylinder * cylinder);
        ELSE
          consecutive_au_address := (cylinder + 1) * control.daus_per_cylinder;
        IFEND;
        allocation_unit_address := consecutive_au_address;
      IFEND;
    UNTIL (consecutive_au_address > (cylinder_range.highest_cylinder *
          control.daus_per_cylinder + last_au_address_in_cylinder));

  PROCEND get_consecutive_alloc_units;
?? OLDTITLE ??
?? NEWTITLE := 'build_device_file_list', EJECT ??

  PROCEDURE build_device_file_list
    (    avt_index: dmt$active_volume_table_index;
         recorded_vsn: rmt$recorded_vsn;
         internal_vsn: dmt$internal_vsn;
         dflt_version_number: dmt$ms_dflt_version_number;
         p_logical_attributes: ^dmt$logical_device_attributes;
         p_dat: ^dmt$ms_device_allocation_table;
     VAR dfl_sfid: gft$system_file_identifier;
     VAR p_dfl: ^dmt$ms_device_file_list_table;
     VAR control: {input/output} t$initialize_volume_control;
     VAR status: ost$status);

    CONST
      c$init_dflt_user_supplied_name = 'DFLT';

    VAR
      dfl_length_in_bytes: amt$file_byte_address,
      dflt_file_hash: dmt$file_hash,
      dflt_cylinder_range: cylinder_range_type,
      entry_index: dmt$device_file_list_index,
      file_already_attached: boolean,
      index: integer,
      local_status: ost$status,
      number_dfl_entries: dmt$device_file_list_index,
      p_dfd: ^dmt$disk_file_descriptor,
      p_dflt_fmd: ^dmt$file_medium_descriptor,
      p_dflt_seq: ^SEQ ( * ),
      p_fmd_attributes: ^array [1 .. * ] of dmt$fmd_attribute,
      p_fau_entry: ^dmt$file_allocation_unit,
      p_fde: gft$file_desc_entry_p,
      p_file_attributes: ^array [1 .. * ] of dmt$file_attribute,
      segment_pointer: mmt$segment_pointer;

    status.normal := TRUE;
    p_dfl := NIL;

  /build_dfl/
    BEGIN
      control.dflt_user_supplied_name := c$init_dflt_user_supplied_name;
      control.dflt_user_supplied_name (5, rmc$recorded_vsn_size) := recorded_vsn;

      osp$generate_unique_binary_name (control.dflt_global_file_name, status);
      IF NOT status.normal THEN
        EXIT /build_dfl/; {----->
      IFEND;

      dmp$generate_gfn_hash (control.dflt_global_file_name, dflt_file_hash);

      number_dfl_entries := dmc$default_volume_dfl_entries;
      dflt_cylinder_range.lowest_cylinder := 1;
      dflt_cylinder_range.highest_cylinder := control.cylinders_per_device - 1;

      IF p_logical_attributes <> NIL THEN
        FOR index := LOWERBOUND (p_logical_attributes^) TO UPPERBOUND (p_logical_attributes^) DO
          CASE p_logical_attributes^ [index].keyword OF
          = dmc$volume_dfl_entries =
            number_dfl_entries := p_logical_attributes^ [index].number_dfl_entries;
          ELSE
          CASEND;
        FOREND;
      IFEND;

      dfl_length_in_bytes := number_dfl_entries * #SIZE (dmt$ms_device_file_list_entry) +
            #SIZE (dmt$ms_device_file_list_header);

      PUSH p_file_attributes: [1 .. 12];
      p_file_attributes^ [1].keyword := dmc$file_kind;
      p_file_attributes^ [1].file_kind := gfc$fk_device_file;
      p_file_attributes^ [2].keyword := dmc$overflow;
      p_file_attributes^ [2].overflow_allowed := FALSE;
      p_file_attributes^ [3].keyword := dmc$requested_allocation_size;
      p_file_attributes^ [3].requested_allocation_size := dmc$dfl_allocation_size;
      p_file_attributes^ [4].keyword := dmc$requested_transfer_size;
      p_file_attributes^ [4].requested_transfer_size := dmc$dfl_transfer_size;
      p_file_attributes^ [5].keyword := dmc$requested_volume;
      p_file_attributes^ [5].requested_volume.recorded_vsn := recorded_vsn;
      p_file_attributes^ [5].requested_volume.setname := '    ';
      p_file_attributes^ [6].keyword := dmc$clear_space;
      p_file_attributes^ [6].required := TRUE;
      p_file_attributes^ [7].keyword := dmc$preset_value;
      p_file_attributes^ [7].preset_value := 0;
      p_file_attributes^ [8].keyword := dmc$locked_file;
      p_file_attributes^ [8].file_lock.required := FALSE;
      p_file_attributes^ [9].keyword := dmc$file_limit;
      p_file_attributes^ [9].limit := (dfl_length_in_bytes + dmc$dfl_allocation_size - 1) DIV
            dmc$dfl_allocation_size * dmc$dfl_allocation_size;
      p_file_attributes^ [10].keyword := dmc$file_hash;
      p_file_attributes^ [10].file_hash := dflt_file_hash;
      p_file_attributes^ [11].keyword := dmc$class;
      p_file_attributes^ [11].class := dmc$default_class;
      p_file_attributes^ [12].keyword := dmc$class_ordinal;
      p_file_attributes^ [12].ordinal := dmc$default_class_ordinal;

      build_stored_df_fmd_header (p_file_attributes, control.dflt_stored_df_fmd, status);
      IF NOT status.normal THEN
        EXIT /build_dfl/; {----->
      IFEND;

      PUSH p_fmd_attributes: [1 .. 3];

      p_fmd_attributes^ [1].keyword := dmc$recorded_vsn;
      p_fmd_attributes^ [1].recorded_vsn := recorded_vsn;
      p_fmd_attributes^ [2].keyword := dmc$internal_vsn;
      p_fmd_attributes^ [2].internal_vsn := internal_vsn;
      p_fmd_attributes^ [3].keyword := dmc$device_file_list_index;
      p_fmd_attributes^ [3].device_file_list_index := dmc$device_file_list_dfl_index;

      build_stored_df_fmd_subfile (p_fmd_attributes, control.dflt_stored_df_fmd, status);
      IF NOT status.normal THEN
        EXIT /build_dfl/; {----->
      IFEND;

{attach device file list table
      dmp$attach_device_file_by_fmd (control.dflt_global_file_name, control.dflt_stored_df_fmd,
            file_already_attached, dfl_sfid, status);
      IF NOT status.normal THEN
        EXIT /build_dfl/; {----->
      IFEND;

      IF file_already_attached THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$duplicate_device_file_gfn,
              'dfl gfn already attached', status);
        EXIT /build_dfl/; {----->
      IFEND;

      gfp$get_fde_p (dfl_sfid, p_fde);
      dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
      dmp$get_fmd_by_index (p_dfd, 1, p_dflt_fmd);

      p_dflt_fmd^.fmd_allocated_length := ((dfl_length_in_bytes + dmc$dfl_allocation_size - 1) DIV
            dmc$dfl_allocation_size) * dmc$dfl_allocation_size;
      p_dflt_fmd^.avt_index := avt_index;

    /dfl_file_attached/
      BEGIN
        build_faus (dflt_cylinder_range, dfl_length_in_bytes, dmc$dfl_allocation_size, dmc$dfl_transfer_size,
              dfl_sfid, control, status);
        IF NOT status.normal THEN
          EXIT /dfl_file_attached/; {----->
        IFEND;

{build_device_file_list_entry
        dmp$get_fau_entry (p_dfd, 0, p_fau_entry);
        control.dflt_dfle.pad := 0;
        control.dflt_dfle.flags := dmc$dfle_assigned_to_file;
        control.dflt_dfle.dau_chain_status := dmc$dau_chain_linked;
        control.dflt_dfle.daus_per_allocation_unit := p_dflt_fmd^.daus_per_allocation_unit;
        control.dflt_dfle.end_of_file := ((dfl_length_in_bytes + osv$page_size - 1) DIV osv$page_size) *
              osv$page_size;
        control.dflt_dfle.end_of_information := ((dfl_length_in_bytes + osv$page_size - 1) DIV
              osv$page_size) * osv$page_size;
        control.dflt_dfle.file_byte_address := 0;
        control.dflt_dfle.file_hash := dfl_sfid.file_hash;
        control.dflt_dfle.file_kind := gfc$fk_device_file;
        control.dflt_dfle.first_dau_address := p_fau_entry^.dau_address;
        control.dflt_dfle.global_file_name := control.dflt_global_file_name;
        control.dflt_dfle.logical_length := ((dfl_length_in_bytes + osv$page_size - 1) DIV osv$page_size) *
              osv$page_size;
        control.dflt_dfle.fmd_length := ((dfl_length_in_bytes + dmc$dfl_allocation_size - 1) DIV
              dmc$dfl_allocation_size) * dmc$dfl_allocation_size;
        control.dflt_dfle.login_set := $dmt$dfl_login_set [];

        segment_pointer.kind := mmc$sequence_pointer;
        dmp$open_file (dfl_sfid, osc$os_ring_1, osc$os_ring_1, mmc$sar_write_extend, mmc$as_sequential,
              segment_pointer, status);
        IF NOT status.normal THEN
          EXIT /dfl_file_attached/; {----->
        IFEND;

        p_dflt_seq := segment_pointer.seq_pointer;
        RESET p_dflt_seq;
        NEXT p_dfl: [1 .. number_dfl_entries] IN p_dflt_seq;

{build device file list header
        osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

      /dflt_locked/
        BEGIN
          p_dfl^.header.version_number := dflt_version_number;
          p_dfl^.header.number_of_entries := number_dfl_entries;
          CASE dflt_version_number OF
          = dmc$dflt_0_0 =
            {
            { build device file list entries
            {
            FOR entry_index := 1 TO number_dfl_entries DO
              p_dfl^.entries [entry_index].pad := 0;
              p_dfl^.entries [entry_index].flags := dmc$dfle_available;
            FOREND;
            {
            { build device file list dfle
            {
            p_dfl^.entries [dmc$device_file_list_dfl_index] := control.dflt_dfle;
            {
            { build device allocation table dfle
            {
            p_dfl^.entries [dmc$dat_dfl_index] := control.dat_dfle;
          ELSE
            osp$set_status_abnormal (dmc$device_manager_ident, dme$unsupported_dflt_version,
                  'unsupported dflt version number', status);
          CASEND;
        END /dflt_locked/;

{unlock device file list table
        osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

{update dat entries to reflect dflt file allocation units
        update_dat_entries (p_dat, dmc$device_file_list_dfl_index, p_dfd, avt_index);

      END /dfl_file_attached/;
      IF NOT status.normal THEN
        detach_file (p_dfl, dfl_sfid, local_status);
      IFEND;

    END /build_dfl/;

  PROCEND build_device_file_list;
?? OLDTITLE ??
?? NEWTITLE := 'build_volume_directory', EJECT ??

  PROCEDURE build_volume_directory
    (    avt_index: dmt$active_volume_table_index;
         recorded_vsn: rmt$recorded_vsn;
         internal_vsn: dmt$internal_vsn;
         p_logical_attributes: ^dmt$logical_device_attributes;
         p_dat: ^dmt$ms_device_allocation_table;
         p_dfl: ^dmt$ms_device_file_list_table;
     VAR directory_sfid: gft$system_file_identifier;
     VAR p_directory: ^dmt$ms_volume_directory;
     VAR control: {input/output} t$initialize_volume_control;
     VAR status: ost$status);

    CONST
      c$init_dir_user_supplied_name = 'DIRECTORY';

    VAR
      directory_cylinder_range: cylinder_range_type,
      directory_file_hash: dmt$file_hash,
      directory_global_file_name: dmt$global_file_name,
      directory_index: dmt$directory_index,
      directory_length_in_bytes: amt$file_byte_address,
      directory_user_supplied_name: ost$name,
      index: integer,
      file_already_attached: boolean,
      local_status: ost$status,
      number_directory_entries: dmt$directory_index,
      p_dfd: ^dmt$disk_file_descriptor,
      p_directory_fmd: ^dmt$file_medium_descriptor,
      p_directory_seq: ^SEQ ( * ),
      p_fmd_attributes: ^array [1 .. * ] of dmt$fmd_attribute,
      p_fau_entry: ^dmt$file_allocation_unit,
      p_fde: gft$file_desc_entry_p,
      p_file_attributes: ^array [1 .. * ] of dmt$file_attribute,
      segment_pointer: mmt$segment_pointer;

    status.normal := TRUE;
    p_directory := NIL;

  /build_directory/
    BEGIN
      directory_user_supplied_name := c$init_dir_user_supplied_name;
      directory_user_supplied_name (10, rmc$recorded_vsn_size) := recorded_vsn;

      osp$generate_unique_binary_name (directory_global_file_name, status);
      IF NOT status.normal THEN
        EXIT /build_directory/; {----->
      IFEND;

      dmp$generate_gfn_hash (directory_global_file_name, directory_file_hash);

      number_directory_entries := dmc$default_vol_dir_entries;
      directory_cylinder_range.lowest_cylinder := 1;
      directory_cylinder_range.highest_cylinder := control.cylinders_per_device - 1;

      IF p_logical_attributes <> NIL THEN
        FOR index := LOWERBOUND (p_logical_attributes^) TO UPPERBOUND (p_logical_attributes^) DO
          CASE p_logical_attributes^ [index].keyword OF
          = dmc$volume_directory_entries =
            number_directory_entries := p_logical_attributes^ [index].number_directory_entries;
          ELSE
          CASEND;
        FOREND;
      IFEND;

      PUSH p_file_attributes: [1 .. 12];
      p_file_attributes^ [1].keyword := dmc$file_kind;
      p_file_attributes^ [1].file_kind := gfc$fk_device_file;
      p_file_attributes^ [2].keyword := dmc$overflow;
      p_file_attributes^ [2].overflow_allowed := FALSE;
      p_file_attributes^ [3].keyword := dmc$requested_allocation_size;
      p_file_attributes^ [3].requested_allocation_size := dmc$directory_allocation_size;
      p_file_attributes^ [4].keyword := dmc$requested_transfer_size;
      p_file_attributes^ [4].requested_transfer_size := dmc$directory_transfer_size;
      p_file_attributes^ [5].keyword := dmc$requested_volume;
      p_file_attributes^ [5].requested_volume.recorded_vsn := recorded_vsn;
      p_file_attributes^ [5].requested_volume.setname := '    ';
      p_file_attributes^ [6].keyword := dmc$clear_space;
      p_file_attributes^ [6].required := TRUE;
      p_file_attributes^ [7].keyword := dmc$preset_value;
      p_file_attributes^ [7].preset_value := 0;
      p_file_attributes^ [8].keyword := dmc$locked_file;
      p_file_attributes^ [8].file_lock.required := FALSE;
      p_file_attributes^ [9].keyword := dmc$file_limit;
      p_file_attributes^ [9].limit := dmc$max_directory_length_bytes;
      p_file_attributes^ [10].keyword := dmc$file_hash;
      p_file_attributes^ [10].file_hash := directory_file_hash;
      p_file_attributes^ [11].keyword := dmc$class;
      p_file_attributes^ [11].class := dmc$default_class;
      p_file_attributes^ [12].keyword := dmc$class_ordinal;
      p_file_attributes^ [12].ordinal := dmc$default_class_ordinal;

      build_stored_df_fmd_header (p_file_attributes, control.directory_stored_df_fmd, status);
      IF NOT status.normal THEN
        EXIT /build_directory/; {----->
      IFEND;

      PUSH p_fmd_attributes: [1 .. 3];

      directory_length_in_bytes := #SIZE (dmt$ms_volume_directory_head) +
            number_directory_entries * #SIZE (dmt$ms_volume_directory_entry);

      IF directory_length_in_bytes > dmc$max_directory_length_bytes THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$max_dir_length_exceeded,
              'directory byte length > max', status);
        EXIT /build_directory/; {----->
      IFEND;

      p_fmd_attributes^ [1].keyword := dmc$recorded_vsn;
      p_fmd_attributes^ [1].recorded_vsn := recorded_vsn;
      p_fmd_attributes^ [2].keyword := dmc$internal_vsn;
      p_fmd_attributes^ [2].internal_vsn := internal_vsn;
      p_fmd_attributes^ [3].keyword := dmc$device_file_list_index;
      p_fmd_attributes^ [3].device_file_list_index := dmc$directory_dfl_index;

      build_stored_df_fmd_subfile (p_fmd_attributes, control.directory_stored_df_fmd, status);
      IF NOT status.normal THEN
        EXIT /build_directory/; {----->
      IFEND;

      dmp$attach_device_file_by_fmd (directory_global_file_name, control.directory_stored_df_fmd,
            file_already_attached, directory_sfid, status);
      IF NOT status.normal THEN
        EXIT /build_directory/; {----->
      IFEND;

      IF file_already_attached THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$duplicate_device_file_gfn,
              'directory gfn already attached', status);
        EXIT /build_directory/; {----->
      IFEND;

      gfp$get_fde_p (directory_sfid, p_fde);
      dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
      dmp$get_fmd_by_index (p_dfd, 1, p_directory_fmd);

      p_directory_fmd^.fmd_allocated_length := ((directory_length_in_bytes + dmc$directory_allocation_size -
            1) DIV dmc$directory_allocation_size) * dmc$directory_allocation_size;
      p_directory_fmd^.avt_index := avt_index;

    /directory_file_attached/
      BEGIN
        build_faus (directory_cylinder_range, directory_length_in_bytes, dmc$directory_allocation_size,
              dmc$directory_transfer_size, directory_sfid, control, status);
        IF NOT status.normal THEN
          EXIT /directory_file_attached/; {----->
        IFEND;

{ build_device_file_list_entry/
        dmp$get_fau_entry (p_dfd, 0, p_fau_entry);
        control.directory_dfle.pad := 0;
        control.directory_dfle.flags := dmc$dfle_assigned_to_file;
        control.directory_dfle.dau_chain_status := dmc$dau_chain_linked;
        control.directory_dfle.daus_per_allocation_unit := p_directory_fmd^.daus_per_allocation_unit;
        control.directory_dfle.end_of_file := ((directory_length_in_bytes + osv$page_size - 1) DIV
              osv$page_size) * osv$page_size;
        control.directory_dfle.end_of_information := ((directory_length_in_bytes + osv$page_size - 1) DIV
              osv$page_size) * osv$page_size;
        control.directory_dfle.file_byte_address := 0;
        control.directory_dfle.file_hash := directory_sfid.file_hash;
        control.directory_dfle.file_kind := gfc$fk_device_file;
        control.directory_dfle.first_dau_address := p_fau_entry^.dau_address;
        control.directory_dfle.global_file_name := directory_global_file_name;
        control.directory_dfle.logical_length := ((directory_length_in_bytes + osv$page_size - 1) DIV
              osv$page_size) * osv$page_size;
        control.directory_dfle.fmd_length := ((directory_length_in_bytes + dmc$directory_allocation_size -
              1) DIV dmc$directory_allocation_size) * dmc$directory_allocation_size;
        control.directory_dfle.login_set := $dmt$dfl_login_set [];

{put device file list entry into dfl.
        p_dfl^.entries [dmc$directory_dfl_index] := control.directory_dfle;

        segment_pointer.kind := mmc$sequence_pointer;
        dmp$open_file (directory_sfid, osc$os_ring_1, osc$os_ring_1, mmc$sar_write_extend, mmc$as_sequential,
              segment_pointer, status);
        IF NOT status.normal THEN
          EXIT /directory_file_attached/; {----->
        IFEND;

        p_directory_seq := segment_pointer.seq_pointer;
        RESET p_directory_seq;
        NEXT p_directory: [1 .. number_directory_entries] IN p_directory_seq;

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

        p_directory^.header.number_of_entries := number_directory_entries;
        FOR directory_index := 1 TO number_directory_entries DO
          p_directory^.entries [directory_index].entry_available := TRUE;
          p_directory^.entries [directory_index].user_supplied_name := osc$null_name;
        FOREND;

{ create entry for dat
        p_directory^.entries [dmc$dat_directory_index].entry_available := FALSE;
        p_directory^.entries [dmc$dat_directory_index].global_file_name := control.dat_global_file_name;
        p_directory^.entries [dmc$dat_directory_index].user_supplied_name := control.dat_user_supplied_name;
        p_directory^.entries [dmc$dat_directory_index].stored_df_fmd := control.dat_stored_df_fmd;

{ create entry for dflt
        p_directory^.entries [dmc$dflt_directory_index].entry_available := FALSE;
        p_directory^.entries [dmc$dflt_directory_index].global_file_name := control.dflt_global_file_name;
        p_directory^.entries [dmc$dflt_directory_index].user_supplied_name := control.dflt_user_supplied_name;
        p_directory^.entries [dmc$dflt_directory_index].stored_df_fmd := control.dflt_stored_df_fmd;

{ create entry for login table
        p_directory^.entries [dmc$login_table_dfl_index].entry_available := FALSE;
        p_directory^.entries [dmc$login_table_dfl_index].global_file_name :=
              control.login_table_global_file_name;
        p_directory^.entries [dmc$login_table_dfl_index].user_supplied_name :=
              control.login_table_user_supplied_name;
        p_directory^.entries [dmc$login_table_dfl_index].stored_df_fmd := control.login_table_stored_df_fmd;

{ create entry for directory
        p_directory^.entries [dmc$directory_directory_index].entry_available := FALSE;
        p_directory^.entries [dmc$directory_directory_index].global_file_name := directory_global_file_name;
        p_directory^.entries [dmc$directory_directory_index].user_supplied_name :=
              directory_user_supplied_name;
        p_directory^.entries [dmc$directory_directory_index].stored_df_fmd := control.directory_stored_df_fmd;

{ reserve entry for label
        p_directory^.entries [dmc$label_directory_index].entry_available := FALSE;

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

{ update dat to reflect directory file allocation units
        update_dat_entries (p_dat, dmc$directory_dfl_index, p_dfd, avt_index);

      END /directory_file_attached/;
      IF NOT status.normal THEN
        detach_file (p_directory, directory_sfid, local_status);
      IFEND;

    END /build_directory/;

  PROCEND build_volume_directory;
?? OLDTITLE ??
?? NEWTITLE := 'build_login_table', EJECT ??

  PROCEDURE build_login_table
    (    avt_index: dmt$active_volume_table_index;
         recorded_vsn: rmt$recorded_vsn;
         internal_vsn: dmt$internal_vsn;
         p_dat: ^dmt$ms_device_allocation_table;
         p_dfl: ^dmt$ms_device_file_list_table;
     VAR control: {input/output} t$initialize_volume_control;
     VAR status: ost$status);

    CONST
      c$init_login_table_name = 'LOGIN_TABLE';

    VAR
      file_already_attached: boolean,
      local_status: ost$status,
      login_cylinder_range: cylinder_range_type,
      login_table_dfle: dmt$ms_device_file_list_entry,
      login_table_file_hash: dmt$file_hash,
      login_table_index: dmt$login_table_entry_index,
      login_table_length_in_bytes: amt$file_byte_address,
      login_table_sfid: gft$system_file_identifier,
      p_dfd: ^dmt$disk_file_descriptor,
      p_fmd_attributes: ^array [1 .. * ] of dmt$fmd_attribute,
      p_fau_entry: ^dmt$file_allocation_unit,
      p_fde: gft$file_desc_entry_p,
      p_file_attributes: ^array [1 .. * ] of dmt$file_attribute,
      p_login_table: ^dmt$ms_mainframe_login_table,
      p_login_table_fmd: ^dmt$file_medium_descriptor,
      p_login_table_seq: ^SEQ ( * ),
      segment_pointer: mmt$segment_pointer;

    status.normal := TRUE;
    p_login_table := NIL;

  /create_login_table/
    BEGIN
      control.login_table_user_supplied_name := c$init_login_table_name;
      control.login_table_user_supplied_name (12, rmc$recorded_vsn_size) := recorded_vsn;

      osp$generate_unique_binary_name (control.login_table_global_file_name, status);
      IF NOT status.normal THEN
        EXIT /create_login_table/; {----->
      IFEND;

      dmp$generate_gfn_hash (control.login_table_global_file_name, login_table_file_hash);

      login_cylinder_range.lowest_cylinder := 1;
      login_cylinder_range.highest_cylinder := control.cylinders_per_device - 1;

      PUSH p_file_attributes: [1 .. 12];

      p_file_attributes^ [1].keyword := dmc$file_kind;
      p_file_attributes^ [1].file_kind := gfc$fk_device_file;
      p_file_attributes^ [2].keyword := dmc$overflow;
      p_file_attributes^ [2].overflow_allowed := FALSE;
      p_file_attributes^ [3].keyword := dmc$requested_allocation_size;
      p_file_attributes^ [3].requested_allocation_size := dmc$login_table_allocation_size;
      p_file_attributes^ [4].keyword := dmc$requested_transfer_size;
      p_file_attributes^ [4].requested_transfer_size := dmc$login_table_transfer_size;
      p_file_attributes^ [5].keyword := dmc$requested_volume;
      p_file_attributes^ [5].requested_volume.recorded_vsn := recorded_vsn;
      p_file_attributes^ [5].requested_volume.setname := '    ';
      p_file_attributes^ [6].keyword := dmc$clear_space;
      p_file_attributes^ [6].required := TRUE;
      p_file_attributes^ [7].keyword := dmc$preset_value;
      p_file_attributes^ [7].preset_value := 0;
      p_file_attributes^ [8].keyword := dmc$locked_file;
      p_file_attributes^ [8].file_lock.required := FALSE;
      p_file_attributes^ [9].keyword := dmc$file_limit;
      p_file_attributes^ [9].limit := dmc$max_login_table_lngth_bytes;
      p_file_attributes^ [10].keyword := dmc$file_hash;
      p_file_attributes^ [10].file_hash := login_table_file_hash;
      p_file_attributes^ [11].keyword := dmc$class;
      p_file_attributes^ [11].class := dmc$default_class;
      p_file_attributes^ [12].keyword := dmc$class_ordinal;
      p_file_attributes^ [12].ordinal := dmc$default_class_ordinal;

      build_stored_df_fmd_header (p_file_attributes, control.login_table_stored_df_fmd, status);
      IF NOT status.normal THEN
        EXIT /create_login_table/; {----->
      IFEND;

      PUSH p_fmd_attributes: [1 .. 3];

      login_table_length_in_bytes := #SIZE (dmt$ms_mf_login_table_header) +
            dmc$default_login_table_entries * #SIZE (dmt$ms_mf_login_table_entry);

      p_fmd_attributes^ [1].keyword := dmc$recorded_vsn;
      p_fmd_attributes^ [1].recorded_vsn := recorded_vsn;
      p_fmd_attributes^ [2].keyword := dmc$internal_vsn;
      p_fmd_attributes^ [2].internal_vsn := internal_vsn;
      p_fmd_attributes^ [3].keyword := dmc$device_file_list_index;
      p_fmd_attributes^ [3].device_file_list_index := dmc$login_table_dfl_index;

      build_stored_df_fmd_subfile (p_fmd_attributes, control.login_table_stored_df_fmd, status);
      IF NOT status.normal THEN
        EXIT /create_login_table/; {----->
      IFEND;

      dmp$attach_device_file_by_fmd (control.login_table_global_file_name, control.login_table_stored_df_fmd,
            file_already_attached, login_table_sfid, status);
      IF NOT status.normal THEN
        EXIT /create_login_table/; {----->
      IFEND;

      IF file_already_attached THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$duplicate_device_file_gfn,
              'login table gfn already atttached', status);
        EXIT /create_login_table/; {----->
      IFEND;

      gfp$get_fde_p (login_table_sfid, p_fde);
      dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
      dmp$get_fmd_by_index (p_dfd, 1, p_login_table_fmd);

      p_login_table_fmd^.fmd_allocated_length := ((login_table_length_in_bytes +
            dmc$login_table_allocation_size - 1) DIV dmc$login_table_allocation_size) *
            dmc$login_table_allocation_size;
      p_login_table_fmd^.avt_index := avt_index;

    /login_table_attached/
      BEGIN
        build_faus (login_cylinder_range, login_table_length_in_bytes, dmc$login_table_allocation_size,
              dmc$login_table_transfer_size, login_table_sfid, control, status);
        IF NOT status.normal THEN
          EXIT /login_table_attached/; {----->
        IFEND;

{ build_device_file_list_entry
        dmp$get_fau_entry (p_dfd, 0, p_fau_entry);
        login_table_dfle.pad := 0;
        login_table_dfle.flags := dmc$dfle_assigned_to_file;
        login_table_dfle.dau_chain_status := dmc$dau_chain_linked;
        login_table_dfle.daus_per_allocation_unit := p_login_table_fmd^.daus_per_allocation_unit;
        login_table_dfle.end_of_file := ((login_table_length_in_bytes + osv$page_size - 1) DIV
              osv$page_size) * osv$page_size;
        login_table_dfle.end_of_information := ((login_table_length_in_bytes + osv$page_size - 1) DIV
              osv$page_size) * osv$page_size;
        login_table_dfle.file_byte_address := 0;
        login_table_dfle.file_hash := login_table_sfid.file_hash;
        login_table_dfle.file_kind := gfc$fk_device_file;
        login_table_dfle.first_dau_address := p_fau_entry^.dau_address;
        login_table_dfle.global_file_name := control.login_table_global_file_name;
        login_table_dfle.logical_length := ((login_table_length_in_bytes + osv$page_size - 1) DIV
              osv$page_size) * osv$page_size;
        login_table_dfle.fmd_length := ((login_table_length_in_bytes + dmc$login_table_allocation_size -
              1) DIV dmc$login_table_allocation_size) * dmc$login_table_allocation_size;
        login_table_dfle.login_set := $dmt$dfl_login_set [];

{put device file list entry into dfl.
        p_dfl^.entries [dmc$login_table_dfl_index] := login_table_dfle;

        segment_pointer.kind := mmc$sequence_pointer;
        dmp$open_file (login_table_sfid, osc$os_ring_1, osc$os_ring_1, mmc$sar_write_extend,
              mmc$as_sequential, segment_pointer, status);
        IF NOT status.normal THEN
          EXIT /login_table_attached/; {----->
        IFEND;

        p_login_table_seq := segment_pointer.seq_pointer;
        RESET p_login_table_seq;
        NEXT p_login_table: [1 .. dmc$default_login_table_entries] IN p_login_table_seq;

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

{login_table_locked
        p_login_table^.header.lower_bound := 1;
        p_login_table^.header.upper_bound := dmc$default_login_table_entries;
        p_login_table^.header.sequence := 0;

{initialize the login table entries.
        FOR login_table_index := 1 TO dmc$default_login_table_entries DO
          p_login_table^.body [login_table_index].login_status := dmc$lt_entry_available;
        FOREND;

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

{update dat to reflect login table allocation units
        update_dat_entries (p_dat, dmc$login_table_dfl_index, p_dfd, avt_index);

      END /login_table_attached/;
      detach_file (p_login_table, login_table_sfid, local_status);
      IF status.normal AND NOT local_status.normal THEN
        status := local_status;
      IFEND;

    END /create_login_table/;

  PROCEND build_login_table;
?? OLDTITLE ??
?? NEWTITLE := '  build_stored_df_fat', EJECT ??

  PROCEDURE build_stored_df_fat
    (    p_fde: ^gft$file_descriptor_entry;
         p_dfd: ^dmt$disk_file_descriptor;
         p_fmd: ^dmt$file_medium_descriptor;
     VAR p_stored_fat: ^dmt$stored_ms_device_file_fat;
     VAR status: ost$status);

    VAR
      byte_address: amt$file_byte_address,
      fau_index: dmt$fau_entries,
      flag_usage: pmt$initialization_value,
      p_fau_entry: ^dmt$file_allocation_unit;

    status.normal := TRUE;

    p_stored_fat^.header.allocation_style := p_fmd^.allocation_style;
    p_stored_fat^.header.byte_address := 0;
    p_stored_fat^.header.bytes_per_mau := p_fmd^.bytes_per_mau;
    p_stored_fat^.header.clear_space := TRUE;
    p_stored_fat^.header.daus_per_allocation_unit := p_fmd^.daus_per_allocation_unit;
    p_stored_fat^.header.daus_per_cylinder := p_fmd^.daus_per_cylinder;
    p_stored_fat^.header.daus_per_transfer_unit := dmc$min_daus_transfer;
    p_stored_fat^.header.global_file_name := p_fde^.global_file_name;
    p_stored_fat^.header.maus_per_allocation_unit := p_dfd^.bytes_per_allocation DIV p_fmd^.bytes_per_mau;
    p_stored_fat^.header.maus_per_dau := p_fmd^.maus_per_dau;
    p_stored_fat^.header.maus_per_transfer_unit := p_fmd^.maus_per_transfer_unit;
{ Flag_usage is used here only to make others aware that this value must not be changed in the future.
{ As the stored fat is wriiten to disk, changing its type will cause incompatibility with other disks
{ already initialized with previous versions.
    flag_usage := pmc$initialize_to_zero;
    p_stored_fat^.header.preset_value := 0;

    {Assume sequential allocation

    byte_address := 0;
    fau_index := LOWERBOUND (p_stored_fat^.file_allocation_units);
    p_stored_fat^.header.number_faus := 0;

    WHILE byte_address < p_fmd^.fmd_allocated_length DO
      dmp$get_fau_entry (p_dfd, byte_address, p_fau_entry);
      p_stored_fat^.file_allocation_units [fau_index].dau_address := p_fau_entry^.dau_address;
      p_stored_fat^.file_allocation_units [fau_index].state := dmc$fau_initialized;
      p_stored_fat^.file_allocation_units [fau_index].status := dmc$no_change_required;
      p_stored_fat^.header.number_faus := p_stored_fat^.header.number_faus + 1;
      byte_address := byte_address + p_dfd^.bytes_per_allocation;
      fau_index := fau_index + 1;
    WHILEND;

  PROCEND build_stored_df_fat;
?? OLDTITLE ??
?? NEWTITLE := '  build_stored_df_fmd_header', EJECT ??

  PROCEDURE build_stored_df_fmd_header
    (    p_file_attributes: ^array [ * ] of dmt$file_attribute;
     VAR df_fmd: dmt$device_file_stored_fmd;
     VAR status: ost$status);

    VAR
      p_df_fmd: ^dmt$device_file_stored_fmd,
      header_index: integer,
      p_stored_fmd_version_number: ^dmt$stored_ms_version_number,
      p_df_fmd_header: ^dmt$stored_ms_fmd_header,
      keyword: dmt$file_attribute_keywords;

    status.normal := TRUE;
    status.condition := 0;

    p_df_fmd := ^df_fmd;

    RESET p_df_fmd;

    NEXT p_stored_fmd_version_number IN p_df_fmd;
    IF p_stored_fmd_version_number = NIL THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_too_small,
            'FMD too small - dmp$build_stored_df_fmd_header.', status);
      RETURN; {----->
    IFEND;

    p_stored_fmd_version_number^ := dmc$current_fmd_version;

    NEXT p_df_fmd_header: [dmc$current_fmd_version] IN p_df_fmd;
    IF p_df_fmd_header = NIL THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_too_small,
            'FMD too small - dmp$build_stored_df_fmd_header.', status);
      RETURN; {----->
    IFEND;

    p_df_fmd_header^.version_0_0.number_fmds := 1;

    FOR header_index := LOWERBOUND (p_file_attributes^) TO UPPERBOUND (p_file_attributes^) DO
      keyword := p_file_attributes^ [header_index].keyword;
      CASE keyword OF
      = dmc$clear_space =
        p_df_fmd_header^.version_0_0.clear_space := p_file_attributes^ [header_index].required;
      = dmc$file_hash =
        p_df_fmd_header^.version_0_0.file_hash := p_file_attributes^ [header_index].file_hash;
      = dmc$file_limit =
        p_df_fmd_header^.version_0_0.file_limit := p_file_attributes^ [header_index].limit;
      = dmc$file_kind =
        p_df_fmd_header^.version_0_0.file_kind := p_file_attributes^ [header_index].file_kind;
      = dmc$locked_file =
        p_df_fmd_header^.version_0_0.locked_file := p_file_attributes^ [header_index].file_lock;
      = dmc$overflow =
        p_df_fmd_header^.version_0_0.overflow_allowed := p_file_attributes^ [header_index].overflow_allowed;
      = dmc$preset_value =
        p_df_fmd_header^.version_0_0.preset_value := p_file_attributes^ [header_index].preset_value;
      = dmc$requested_allocation_size =
        p_df_fmd_header^.version_0_0.requested_allocation_size :=
              p_file_attributes^ [header_index].requested_allocation_size;
      = dmc$class =
        p_df_fmd_header^.version_0_0.requested_class := p_file_attributes^ [header_index].class;
      = dmc$class_ordinal =
        p_df_fmd_header^.version_0_0.requested_class_ordinal := p_file_attributes^ [header_index].ordinal;
      = dmc$requested_transfer_size =
        p_df_fmd_header^.version_0_0.requested_transfer_size :=
              p_file_attributes^ [header_index].requested_transfer_size;
      = dmc$requested_volume =
        p_df_fmd_header^.version_0_0.requested_volume := p_file_attributes^ [header_index].requested_volume;
      ELSE
      CASEND;
    FOREND;

  PROCEND build_stored_df_fmd_header;
?? OLDTITLE ??
?? NEWTITLE := '  build_stored_df_fmd_subfile', EJECT ??

  PROCEDURE build_stored_df_fmd_subfile
    (    p_fmd_attributes: ^array [1 .. * ] of dmt$fmd_attribute;
     VAR df_fmd: dmt$device_file_stored_fmd;
     VAR status: ost$status);

    VAR
      p_stored_fmd_version_number: ^dmt$stored_ms_version_number,
      p_df_fmd_header: ^dmt$stored_ms_fmd_header,
      p_df_fmd: ^dmt$device_file_stored_fmd,
      p_df_fmd_subfile: ^dmt$stored_ms_fmd_subfile,
      keyword: dmt$file_attribute_keywords,
      attribute_index: integer;

    status.normal := TRUE;
    status.condition := 0;

    p_df_fmd := ^df_fmd;

    RESET p_df_fmd;

    NEXT p_stored_fmd_version_number IN p_df_fmd;
    IF p_stored_fmd_version_number = NIL THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_too_small,
            'FMD too small - dmp$build_stored_df_fmd_subfile.', status);
      RETURN; {----->
    IFEND;

    NEXT p_df_fmd_header: [dmc$current_fmd_version] IN p_df_fmd;
    IF p_df_fmd_header = NIL THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_too_small,
            'FMD too small - dmp$build_stored_df_fmd_subfile.', status);
      RETURN; {----->
    IFEND;

    NEXT p_df_fmd_subfile: [dmc$current_fmd_version] IN p_df_fmd;
    IF p_df_fmd_subfile = NIL THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$fmd_too_small,
            'FMD too small - dmp$build_stored_df_fmd_subfile.', status);
      RETURN; {----->
    IFEND;

    p_df_fmd_subfile^.version_0_0.stored_byte_address := 0;

    FOR attribute_index := LOWERBOUND (p_fmd_attributes^) TO UPPERBOUND (p_fmd_attributes^) DO
      keyword := p_fmd_attributes^ [attribute_index].keyword;
      CASE keyword OF
      = dmc$device_file_list_index =
        p_df_fmd_subfile^.version_0_0.device_file_list_index :=
              p_fmd_attributes^ [attribute_index].device_file_list_index;
      = dmc$internal_vsn =
        p_df_fmd_subfile^.version_0_0.internal_vsn := p_fmd_attributes^ [attribute_index].internal_vsn;
      = dmc$recorded_vsn =
        p_df_fmd_subfile^.version_0_0.recorded_vsn := p_fmd_attributes^ [attribute_index].recorded_vsn;
      ELSE
      CASEND;
    FOREND;

  PROCEND build_stored_df_fmd_subfile;
?? OLDTITLE ??
?? NEWTITLE := ' detach_file', EJECT ??

{   The purpose of this procedure is to optionally (p_file <> NIL) write
{ modified pages to disk and close the file and then to detach the file.  If
{ modified pages can't be written to disk, they are removed from memory.  This
{ is done to bypass the fault tolerant feature of dmp$detach_file which keeps a
{ file table entry around for any file whose pages can't be written to disk.
{ Since the initialize volume process always deletes the AVT entry after it
{ completes, bad things will happen later if a file table entry is kept around
{ pointing to an AVT entry that is not.  Memory Manager periodically tries to
{ flush modified pages to disk which will cause access to the file table entry
{ left pointing to the unused (or possibly reused) AVT entry.

  PROCEDURE detach_file
    (    p_file: ^cell;
         sfid: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      file_modified: boolean,
      fmd_modified: boolean,
      local_status: ost$status;

    status.normal := TRUE;

    IF (p_file <> NIL) THEN
      mmp$write_modified_pages (p_file, UPPERVALUE (ost$byte_count), osc$wait, status);

      IF NOT status.normal THEN
        mmp$free_pages (p_file, UPPERVALUE (ost$byte_count), osc$wait, local_status);
      IFEND;

      dmp$close_file (p_file, local_status);

      IF status.normal AND NOT local_status.normal THEN
        status := local_status;
      IFEND;
    IFEND;

    dmp$detach_device_file (sfid, file_modified, fmd_modified, local_status);

    IF status.normal AND NOT local_status.normal THEN
      status := local_status;
    IFEND;

  PROCEND detach_file;
?? OLDTITLE ??
?? NEWTITLE := 'get_device_flaws', EJECT ??

  PROCEDURE get_device_flaws
    (    logical_unit_number: iot$logical_unit;
         flaw_map_locations: array [1 .. * ] of dmt$flaw_map_address;
     VAR p_device_flaw_list: ^dmt$ms_flaw_list;
     VAR control: t$initialize_volume_control;
     VAR status: ost$status);

    VAR
      v$termination_flaw_map_entry: [READ, oss$mainframe_paged_literal] dmt$flaw_map_entry :=
            [FALSE, FALSE, 0, 0, 0];

    VAR
      flaw_map_location_index: integer,
      flaw_map_address: dmt$flaw_map_address,
      p_flawed_daus: ^array [1 .. 120] of dmt$flaw_list_entry,
      flawed_daus_index: 0 .. 120,
      starting_flawed_dau_address: dmt$dau_address,
      number_consecutive_flawed_daus: dmt$dau_address,
      number_consecutive_flawed_maus: dmt$mau_address,
      number_consecutive_flawed_sect: integer,
      flawed_mau_address: dmt$mau_address,
      flawed_sector_address: integer,
      mau_address: dmt$mau_address,
      mau_byte_offset: dmt$bytes_per_mau,
      p_bytes: ^array [1 .. * ] of cell,
      p_flaw_map: ^array [1 .. * ] of dmt$flaw_map_entry,
      read_length_in_bytes: ost$byte_count,
      flaw_map_index: 1 .. 120,
      flaw_map_entry: dmt$flaw_map_entry,
      p_buffer: ^SEQ ( * ),
      device_address: dmt$ms_logical_device_address,
      number_flaw_map_entries: integer,
      read_status: ost$status,
      p_completion_status: ^iot$completion_status;

    status.normal := TRUE;

    p_device_flaw_list := NIL;

    PUSH p_flawed_daus;

    flawed_daus_index := 0;

    PUSH p_buffer: [[REP control.bytes_per_mau OF cell]];
    RESET p_buffer;

    device_address.maus_per_position := control.maus_per_cylinder;
    device_address.logical_unit_number := logical_unit_number;
    device_address.transfer_length := 1;
    device_address.transfer_mau_offset := 0;
    device_address.write_translation := FALSE;
    read_length_in_bytes := control.bytes_per_mau;

  /flaw_map_addresses/
    FOR flaw_map_location_index := 1 TO UPPERBOUND (flaw_map_locations) DO
      flaw_map_address := flaw_map_locations [flaw_map_location_index];
      mau_address := flaw_map_address.mau_address;
      mau_byte_offset := flaw_map_address.mau_byte_offset;

    /flaw_map_processing/
      BEGIN
        device_address.allocation_unit_mau_address := mau_address;
        iop$mass_storage_io (#LOC (p_buffer^), read_length_in_bytes, ioc$read_uft, device_address, TRUE,
              p_completion_status, read_status);
        IF NOT read_status.normal THEN
          status := read_status;
          EXIT /flaw_map_processing/; {----->
        IFEND;
        NEXT p_bytes: [1 .. mau_byte_offset] IN p_buffer;
        IF p_bytes = NIL THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$flaw_map_positioning_error,
                'p_bytes = NIL - DMMIVOL', status);
          RETURN; {----->
        IFEND;
        number_flaw_map_entries := (read_length_in_bytes - mau_byte_offset) DIV #SIZE (dmt$flaw_map_entry);
        IF number_flaw_map_entries > 120 THEN
          number_flaw_map_entries := 120;
        IFEND;
        NEXT p_flaw_map: [1 .. number_flaw_map_entries] IN p_buffer;
        IF p_flaw_map = NIL THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_process_flaw_map,
                'p_flaw_map = NIL - DMMIVOL', status);
          RETURN; {----->
        IFEND;

      /process_flaw_map_entries/
        FOR flaw_map_index := 1 TO number_flaw_map_entries DO
          flaw_map_entry := p_flaw_map^ [flaw_map_index];
          IF flaw_map_entry = v$termination_flaw_map_entry THEN
            EXIT /process_flaw_map_entries/; {----->
          IFEND;
          flawed_daus_index := flawed_daus_index + 1;

{compute dau address
          starting_flawed_dau_address := flaw_map_entry.cylinder * control.daus_per_cylinder;
          flawed_sector_address := flaw_map_entry.track * control.sectors_per_track;
          number_consecutive_flawed_sect := 1;
          IF flaw_map_entry.sector_flaw_entry THEN
            IF flaw_map_entry.sector = 0 THEN
              number_consecutive_flawed_sect := control.sectors_per_track;
            ELSE
              flawed_sector_address := flawed_sector_address + flaw_map_entry.sector;
            IFEND;
          IFEND;
          flawed_mau_address := flawed_sector_address DIV control.sectors_per_mau;
          number_consecutive_flawed_maus := (number_consecutive_flawed_sect + control.sectors_per_mau - 1) DIV
                control.sectors_per_mau;
          starting_flawed_dau_address := starting_flawed_dau_address +
                (flawed_mau_address DIV control.maus_per_dau);
          number_consecutive_flawed_daus := (number_consecutive_flawed_maus + control.maus_per_dau - 1) DIV
                control.maus_per_dau;
          p_flawed_daus^ [flawed_daus_index].dau_address := starting_flawed_dau_address;
          p_flawed_daus^ [flawed_daus_index].number_flawed_daus := number_consecutive_flawed_daus;
        FOREND /process_flaw_map_entries/;
      END /flaw_map_processing/;
    FOREND /flaw_map_addresses/;

    IF flawed_daus_index > 0 THEN
      ALLOCATE p_device_flaw_list: [1 .. flawed_daus_index] IN osv$mainframe_wired_heap^;
      p_device_flaw_list^ := p_flawed_daus^;
    IFEND;

  PROCEND get_device_flaws;
?? OLDTITLE ??
?? NEWTITLE := ' find_cip_cylinder', EJECT ??

{  PURPOSE:
{    This procedure determines whether a cip exists on the given device.

  PROCEDURE find_cip_cylinder
    (    logical_unit_number: iot$logical_unit;
     VAR control: t$initialize_volume_control;
     VAR cip_cylinder: dmt$device_position;
     VAR cip_found: boolean);

    VAR
      ds_sector: dst$deadstart_sector,
      ds_sector_device_path: dst$ds_sector_device_path,
      ds_sector_seq_p: ^SEQ ( * ),
      identifier: ost$status_identifier,
      msi: cmt$mass_storage_information,
      number: ost$status_condition_number,
      status: ost$status,
      str: string (100),
      str_size: integer;

    cip_found := FALSE;
    status.normal := TRUE;

    CASE dsv$mainframe_type OF
    = dsc$mt_962_972_mainframe, dsc$mt_992_mainframe, dsc$mt_2000_mainframe =
      RETURN; {----->
    ELSE
    CASEND;

    cmp$get_mass_storage_info (logical_unit_number, msi, status);
    IF NOT status.normal THEN
      IF (NOT cmv$post_deadstart) THEN
        IF status.condition = cme$it_not_cip_device THEN
          syp$trace_deadstart_message ('device does not support cip');
        ELSEIF (status.condition = cme$it_no_cip_access) OR
              (status.condition = cme$it_unusable_cip_access) THEN
          syp$trace_deadstart_message ('device as configured does not support cip');
        ELSE
          syp$trace_deadstart_message ('unable to retrieve mass storage info');
          osp$unpack_status_condition (status.condition, identifier, number);
          STRINGREP (str, str_size, 'status condition = ', identifier, number, ' status text = ',
                status.text.value (1, status.text.size));
          syp$trace_deadstart_message (str (1, str_size));
        IFEND;
      IFEND;
      RETURN; {----->
    IFEND;

    ds_sector_device_path.iou_number := msi.iou_number;
    ds_sector_device_path.channel_number := msi.channel.number;
    ds_sector_device_path.unit_number := msi.unit_number;
    ds_sector_device_path.access_type := dsc$read_ds_sector;
    ds_sector_device_path.maus_per_cylinder := control.maus_per_cylinder;
    ds_sector_device_path.logical_unit_number := logical_unit_number;
    ds_sector_device_path.deadstart_sector_mau := (control.cylinders_per_device - 1) *
          control.maus_per_cylinder;

{Retrieve the correct device path number and the disk type for the given device.
    CASE msi.unit_type OF
    = cmc$ms844_4x =
      ds_sector_device_path.device_type := dmc$844_double_density;
      ds_sector_device_path.disk_type := dsc$small_sector_disk;
    = cmc$ms885_1x =
      ds_sector_device_path.device_type := dmc$885;
      ds_sector_device_path.disk_type := dsc$small_sector_disk;
    = cmc$ms885_4x =
      ds_sector_device_path.device_type := dmc$885;
      ds_sector_device_path.disk_type := dsc$small_sector_disk;
    = cmc$ms834_2 =
      ds_sector_device_path.device_type := dmc$834_isd1;
      ds_sector_device_path.unit_number := msi.control_module * 8 + msi.unit_number;
      ds_sector_device_path.disk_type := dsc$small_sector_disk;
    = cmc$ms895_2 =
      ds_sector_device_path.device_type := dmc$895;
      ds_sector_device_path.disk_type := dsc$small_sector_disk;
      IF (msi.storage_director_address > 1) OR (msi.head_of_string_controller > 1) THEN
        IF NOT cmv$post_deadstart THEN
          syp$trace_deadstart_message ('device does not support cip');
        IFEND;
        RETURN; {----->
      IFEND;
      ds_sector_device_path.unit_number := (msi.storage_director_address * 100000(2)) +
            (msi.head_of_string_controller * 10000(2)) + ds_sector_device_path.unit_number;
    = cmc$msfsd_2 =
      ds_sector_device_path.device_type := dmc$836_isd2;
      ds_sector_device_path.unit_number := msi.control_module * 8 + msi.unit_number;
      ds_sector_device_path.disk_type := dsc$small_sector_disk;
    = cmc$msxmd_3 =
      ds_sector_device_path.device_type := dmc$xmd3;
      ds_sector_device_path.unit_number := msi.control_module * 8 + msi.unit_number;

{ Large sector disk indicates that the NOS/VE driver will determine
{ presence of CIP. For small sector disk, go through DFT and 2AP.

      ds_sector_device_path.disk_type := dsc$large_sector_disk;
    = cmc$msfsd2_s0 =
      ds_sector_device_path.device_type := dmc$9836_s0;
      ds_sector_device_path.disk_type := dsc$large_sector_disk;
    ELSE
      IF NOT cmv$post_deadstart THEN
        syp$trace_deadstart_message ('device does not support cip');
      IFEND;
      RETURN; {----->
    CASEND;

    STRINGREP (str, str_size, 'attempting to read cip on device_type:', ds_sector_device_path.device_type,
          ' iou:', ds_sector_device_path.iou_number, ' channel:', ds_sector_device_path.channel_number,
          ' unit:', ds_sector_device_path.unit_number);
    IF NOT cmv$post_deadstart THEN
      syp$trace_deadstart_message (str (1, str_size));
    IFEND;
    {Read the deadstart sector on the given device.

    ds_sector_seq_p := #SEQ (ds_sector);
    RESET ds_sector_seq_p;
    dsp$access_deadstart_sector (ds_sector_device_path, ds_sector_seq_p, status);
    IF NOT status.normal THEN
      IF NOT cmv$post_deadstart THEN
        syp$display_deadstart_message ('WARNING -- Error attempting to access the deadstart sector');
      IFEND;
      RETURN; {----->
    IFEND;

    { Determine if the deadstart sector is present on
    { this device.  If the deadstart sector is not present
    { then CIP is not installed on the device.

    IF (ds_sector.v1 <> dsc$special_cti_constant_1) OR (ds_sector.v2 <> dsc$special_cti_constant_2) OR
          (ds_sector.v4 <> dsc$special_cti_ipl_constant) THEN
      IF NOT cmv$post_deadstart THEN
        syp$trace_deadstart_message ('cip is not present on device');
      IFEND;
      RETURN; {----->
    IFEND;

    { If the following addresses have a zero for the cylinder
    { value then the CIP installed is not a valid CIP.  The
    { following addresses must be checked in the following order.

    cip_cylinder := 0;
    IF ds_sector.msl <> 0 THEN
      cip_cylinder := ds_sector.msl;
    ELSEIF ds_sector.hvs_address.cylinder <> 0 THEN
      cip_cylinder := ds_sector.hvs_address.cylinder;
    ELSEIF ds_sector.cda_address.cylinder <> 0 THEN
      cip_cylinder := ds_sector.cda_address.cylinder;
    IFEND;

    IF cip_cylinder <> 0 THEN
      cip_found := TRUE;
    ELSE
      IF NOT cmv$post_deadstart THEN
        syp$trace_deadstart_message ('cip is not present on device');
      IFEND;
    IFEND;

  PROCEND find_cip_cylinder;
?? OLDTITLE ??
?? NEWTITLE := 'get_deadstart_sector_flaws', EJECT ??

  PROCEDURE get_deadstart_sector_flaws
    (    logical_unit_number: iot$logical_unit;
     VAR control: t$initialize_volume_control;
     VAR p_ds_sector_flaw_list: ^dmt$ms_flaw_list);

    VAR
      cip_found: boolean,
      msg: string (60),
      l: integer,
      starting_cylinder: dmt$device_position;

    p_ds_sector_flaw_list := NIL;

    find_cip_cylinder (logical_unit_number, control, starting_cylinder, cip_found);

    IF cip_found THEN
      ALLOCATE p_ds_sector_flaw_list: [1 .. 1] IN osv$mainframe_wired_heap^;
      p_ds_sector_flaw_list^ [1].dau_address := starting_cylinder * control.daus_per_cylinder;
      p_ds_sector_flaw_list^ [1].number_flawed_daus := control.daus_per_cylinder *
            (control.cylinders_per_device - starting_cylinder);
      IF NOT cmv$post_deadstart THEN
        STRINGREP (msg, l, 'cip present on device at cylinder ', starting_cylinder);
        syp$trace_deadstart_message (msg (1, l));
      IFEND;
    IFEND;

  PROCEND get_deadstart_sector_flaws;
?? OLDTITLE ??
?? NEWTITLE := 'update_dat_entries', EJECT ??

  PROCEDURE update_dat_entries
    (    p_dat: ^dmt$ms_device_allocation_table;
         dfl_index: dmt$device_file_list_index;
         p_dfd: ^dmt$disk_file_descriptor;
         avt_index: dmt$active_volume_table_index);

    VAR
      allocation_chain_position: dmt$allocation_chain_position,
      allocation_unit_dau_address: dmt$dau_address,
      byte_address: amt$file_byte_address,
      dau_index: dmt$dau_address,
      daus_per_allocation_unit: dmt$daus_per_allocation,
      fau_lower_bound: dmt$fau_entries,
      fau_upper_bound: dmt$fau_entries,
      fau_index: dmt$fau_entries,
      next_allocation_unit_dau: dmt$dau_address,
      p_fmd: ^dmt$file_medium_descriptor,
      p_fau_entry: ^dmt$file_allocation_unit;

    dmp$get_fmd_by_index (p_dfd, 1, p_fmd);
    daus_per_allocation_unit := p_fmd^.daus_per_allocation_unit;
    dmp$get_number_of_faus (p_dfd, fau_upper_bound);
    fau_lower_bound := 1;

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

    p_dat^.header.available := p_dat^.header.available - ((fau_upper_bound - fau_lower_bound + 1) *
          daus_per_allocation_unit);

    IF fau_upper_bound = fau_lower_bound THEN
      allocation_chain_position := dmc$first_and_last_allocation;
    ELSE
      allocation_chain_position := dmc$last_allocation;
    IFEND;
    next_allocation_unit_dau := 0;
    fau_index := fau_upper_bound;
    byte_address := p_dfd^.highest_offset_allocated;

    IF (byte_address DIV p_dfd^.bytes_per_allocation) <> (fau_upper_bound - fau_lower_bound + 1) THEN
      osp$system_error (' Initialize allocation failure', NIL);
    IFEND;

    REPEAT
      byte_address := byte_address - p_dfd^.bytes_per_allocation;
      dmp$get_fau_entry (p_dfd, byte_address, p_fau_entry);
      allocation_unit_dau_address := p_fau_entry^.dau_address;
      dau_index := allocation_unit_dau_address;
      IF p_fau_entry^.state = dmc$fau_free THEN
        osp$system_error (' Initialize allocation failure', #LOC (p_fau_entry));
      IFEND;

      REPEAT
        p_dat^.body [dau_index].dau_status := dmc$dau_assigned_to_file;
        p_dat^.body [dau_index].file_hash := p_fmd^.system_file_id.file_hash;
        p_dat^.body [dau_index].data_status := dmc$dau_data_initialized;
        p_dat^.body [dau_index].allocation_chain_position := allocation_chain_position;
        CASE allocation_chain_position OF
        = dmc$first_and_last_allocation, dmc$last_allocation =
          p_dat^.body [dau_index].high_dfl_index := dfl_index DIV dmc$dfl_index_converter;
          p_dat^.body [dau_index].low_dfl_index := dfl_index MOD dmc$dfl_index_converter;
        = dmc$first_allocation, dmc$middle_allocation =
          p_dat^.body [dau_index].next_allocation_unit_dau := next_allocation_unit_dau;
        ELSE
        CASEND;
        dau_index := dau_index + 1;
        allocation_chain_position := dmc$part_of_allocation_unit;
      UNTIL (dau_index >= (allocation_unit_dau_address + daus_per_allocation_unit));

      fau_index := fau_index - 1;
      IF fau_index = fau_lower_bound THEN
        allocation_chain_position := dmc$first_allocation;
      ELSE
        allocation_chain_position := dmc$middle_allocation;
      IFEND;
      next_allocation_unit_dau := allocation_unit_dau_address;
    UNTIL (fau_index < fau_lower_bound);

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

  PROCEND update_dat_entries;
?? OLDTITLE ??
?? NEWTITLE := 'preset_cylinder_0', EJECT ??

  PROCEDURE preset_cylinder_0
    (    logical_unit_number: iot$logical_unit;
         maus_per_cylinder: dmt$maus_per_position);

    VAR
      status: ost$status,
      buffer: integer,
      device_address: dmt$ms_logical_device_address,
      p_completion_status: ^iot$completion_status;

    buffer := 0;
    device_address.preset_value := 0;
    device_address.transfer_mau_offset := 0;
    device_address.write_translation := TRUE;
    device_address.allocation_unit_mau_address := 0;
    device_address.au_was_previously_written := FALSE;
    device_address.maus_per_position := maus_per_cylinder;
    device_address.logical_unit_number := logical_unit_number;
    device_address.transfer_length := maus_per_cylinder;
    device_address.maus_per_allocation_unit := maus_per_cylinder;

    iop$mass_storage_io (#LOC (buffer), 0, ioc$write_mass_storage, device_address, TRUE, p_completion_status,
          status);

  PROCEND preset_cylinder_0;
?? OLDTITLE ??
?? NEWTITLE := 'write_label_to_disk', EJECT ??

  PROCEDURE write_label_to_disk
    (    logical_unit_number: iot$logical_unit;
         p_fmd: ^dmt$file_medium_descriptor;
         p_dfd: ^dmt$disk_file_descriptor;
         p_fau_entry: ^dmt$file_allocation_unit;
         p_p_data_buffer: ^SEQ ( * );
         number_bytes_to_write: amt$file_byte_address;
     VAR control: t$initialize_volume_control;
     VAR status: ost$status);

    VAR
      device_address: dmt$ms_logical_device_address,
      flag_usage: pmt$initialization_value,
      p_buffer: ^array [1 .. * ] of cell,
      p_completion_status: ^iot$completion_status,
      p_data_buffer: ^SEQ ( * ),
      p_read_buffer: ^SEQ ( * );

    status.normal := TRUE;
    IF number_bytes_to_write > p_dfd^.bytes_per_allocation THEN
      osp$system_error ('volume label size > allocation unit', #LOC (number_bytes_to_write));
    IFEND;

    p_data_buffer := p_p_data_buffer;
    RESET p_data_buffer;
    NEXT p_buffer: [1 .. number_bytes_to_write] IN p_data_buffer;

    PUSH p_read_buffer: [[REP p_dfd^.bytes_per_allocation OF cell]];
    pmp$zero_out_table (#LOC (p_read_buffer^), #SIZE (p_read_buffer^));

    device_address.maus_per_position := control.maus_per_cylinder;
    device_address.logical_unit_number := logical_unit_number;
    device_address.transfer_length := p_fmd^.maus_per_transfer_unit;
    device_address.transfer_mau_offset := 0;
    device_address.write_translation := TRUE;
    device_address.au_was_previously_written := FALSE;
    device_address.maus_per_allocation_unit := p_fmd^.daus_per_allocation_unit * p_fmd^.maus_per_dau;
{ Flag_usage is used here only to make others aware that this value must not be changed in the future.
{ As the stored fat is wriiten to disk, changing its type will cause incompatibility with other disks
{ already initialized with previous versions.
    flag_usage := pmc$initialize_to_zero;
    device_address.preset_value := 0;
    device_address.allocation_unit_mau_address := p_fau_entry^.dau_address * p_fmd^.maus_per_dau;

    iop$mass_storage_io (#LOC (p_buffer^), number_bytes_to_write, ioc$write_mass_storage, device_address,
          TRUE, p_completion_status, status);
    IF status.normal THEN { attempt read of allocation unit
      p_fau_entry^.state := dmc$fau_initialized;
      device_address.write_translation := FALSE;
      iop$mass_storage_io (#LOC (p_read_buffer^), p_dfd^.bytes_per_allocation, ioc$read_mass_storage,
            device_address, TRUE, p_completion_status, status);
      IF NOT status.normal THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_read_verify_data,
              'unable to read verify data - write_label_to_disk', status);
      IFEND;
    IFEND;

  PROCEND write_label_to_disk;
?? OLDTITLE ??
?? NEWTITLE := 'remember_device_flaws', EJECT ??

  PROCEDURE remember_device_flaws
    (VAR volume_label: {input} dmt$ms_volume_label;
         cylinders_per_device: dmt$device_position;
         avt_index: dmt$active_volume_table_index;
     VAR p_existing_flaws: ^array [ * ] of flawed_dau;
     VAR able_to_retain_flaws: boolean;
     VAR volume_downed: boolean);

    VAR
      dat_attached: boolean,
      dat_open: boolean,
      status: ost$status,
      dat_sfid: gft$system_file_identifier,
      segment_pointer: mmt$segment_pointer,
      p_dat_seq: ^SEQ ( * ),
      p_dat: ^dmt$ms_device_allocation_table,
      p_dat_header: ^dmt$ms_device_alloc_table_head,
      number_of_daus: dmt$dau_address,
      number_of_flaws: dmt$dau_address,
      flaw_index: dmt$dau_address,
      index: dmt$dau_address,
      file_modified: boolean,
      fmd_modified: boolean;

?? 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
        p_sac: ^mmt$segment_access_condition,
        p_scc: ^syt$system_core_condition;

      IF mf.identifier = mmc$segment_fault_processor_id THEN
        p_sac := #LOC (mf.contents);
        CASE p_sac^.identifier OF
        = mmc$sac_io_read_error =
          IF NOT cmv$post_deadstart THEN
            syp$trace_deadstart_message ('unable to retain device flaws (I/O error on old DAT)');
          IFEND;
          IF p_existing_flaws <> NIL THEN
            FREE p_existing_flaws IN osv$mainframe_wired_heap^;
          IFEND;
          able_to_retain_flaws := FALSE;
          EXIT remember_device_flaws; {----->
        ELSE
        CASEND;

      ELSEIF mf.identifier = syc$system_core_condition THEN
        p_scc := #LOC (mf.system_core_condition);
        CASE p_scc^.condition OF
        = syc$user_defined_condition =
          IF p_scc^.user_defined_condition = syc$udc_volume_unavailable THEN
            volume_downed := TRUE;
            #SPOIL (volume_downed);
            able_to_retain_flaws := FALSE;
            IF NOT cmv$post_deadstart THEN
              syp$trace_deadstart_message ('Volume downed by IO error.');
            IFEND;
            IF p_existing_flaws <> NIL THEN
              FREE p_existing_flaws IN osv$mainframe_wired_heap^;
            IFEND;
            EXIT remember_device_flaws; {----->
          IFEND;
        ELSE
        CASEND;
      IFEND;

      syp$continue_to_cause (mf, p_msa, syc$condition_ignored, continue);

    PROCEND dat_condition_handler;
?? OLDTITLE ??
?? EJECT ??

    dat_attached := FALSE;
    dat_open := FALSE;
    number_of_flaws := 0;
    able_to_retain_flaws := FALSE;
    volume_downed := FALSE;
    segment_pointer.kind := mmc$sequence_pointer;

    dmp$attach_dat_from_label (volume_label, avt_index, dat_sfid, status);
    IF status.normal THEN
      dat_attached := TRUE;
      dmp$open_file (dat_sfid, osc$os_ring_1, osc$os_ring_1, mmc$sar_read, mmc$as_sequential, segment_pointer,
            status);
      IF status.normal THEN
        p_dat_seq := segment_pointer.seq_pointer;
        dat_open := TRUE;
      ELSE
        IF NOT cmv$post_deadstart THEN
          syp$trace_deadstart_message ('unable to retain device flaws (cannot open old DAT)');
        IFEND;
      IFEND;
    ELSE
      IF NOT cmv$post_deadstart THEN
        syp$trace_deadstart_message ('unable to retain device flaws (cannot attach old DAT)');
      IFEND;
    IFEND;

    IF status.normal THEN
      syp$establish_condition_handler (^dat_condition_handler);
      RESET p_dat_seq;
      NEXT p_dat_header IN p_dat_seq;

      IF p_dat_header = NIL THEN
        IF NOT cmv$post_deadstart THEN
          syp$trace_deadstart_message ('unable to retain device flaws (received NIL pointer)');
        IFEND;
      ELSEIF p_dat_header^.positions_per_device <> cylinders_per_device THEN
        IF NOT cmv$post_deadstart THEN
          syp$trace_deadstart_message ('unable to retain device flaws (# of cylinders mismatch)');
        IFEND;
      ELSE {  this is likely the old DAT

        CASE p_dat_header^.version_number OF
        = dmc$dat_0_0 =

          number_of_daus := p_dat_header^.positions_per_device * p_dat_header^.daus_per_position;
          RESET p_dat_seq;
          NEXT p_dat: [dmc$min_dau_address .. number_of_daus - 1] IN p_dat_seq;
          IF p_dat <> NIL THEN

          /count_flaws_validate_dau_status/
            FOR index := LOWERBOUND (p_dat^.body) TO UPPERBOUND (p_dat^.body) DO
              CASE p_dat^.body [index].dau_status OF
              = dmc$dau_hardware_flawed, dmc$dau_software_flawed, dmc$dau_ass_to_mf_swr_flawed,
                    dmc$dau_ass_to_file_swr_flawed =
                number_of_flaws := number_of_flaws + 1;
              = dmc$dau_usable, dmc$dau_assigned_to_mainframe, dmc$dau_assigned_to_file =
                ;
              ELSE {  we've run into a dau status that is out of bounds
                IF NOT cmv$post_deadstart THEN
                  syp$trace_deadstart_message ('unable to retain device flaws (old DAT is damaged)');
                IFEND;
                number_of_flaws := 0;
                EXIT /count_flaws_validate_dau_status/; {----->
              CASEND;
            FOREND /count_flaws_validate_dau_status/;

            IF number_of_flaws > 0 THEN
              ALLOCATE p_existing_flaws: [1 .. number_of_flaws] IN osv$mainframe_wired_heap^;

              flaw_index := 1;
              FOR index := LOWERBOUND (p_dat^.body) TO UPPERBOUND (p_dat^.body) DO
                CASE p_dat^.body [index].dau_status OF
                = dmc$dau_hardware_flawed, dmc$dau_software_flawed, dmc$dau_ass_to_mf_swr_flawed,
                      dmc$dau_ass_to_file_swr_flawed =

                  p_existing_flaws^ [flaw_index].dau_address := index;
                  p_existing_flaws^ [flaw_index].kind_of_flaw := p_dat^.body [index].dau_status;
                  flaw_index := flaw_index + 1;

                ELSE
                CASEND;
              FOREND;
            IFEND;
          ELSE
            IF NOT cmv$post_deadstart THEN
              syp$trace_deadstart_message ('unable to retain device flaws (NIL pointer returned)');
            IFEND;
          IFEND;
        ELSE
          IF NOT cmv$post_deadstart THEN
            syp$trace_deadstart_message ('unable to retain device flaws (invalid DAT version number)');
          IFEND;
        CASEND;
      IFEND;

      syp$disestablish_cond_handler;
    IFEND;

    IF p_existing_flaws <> NIL THEN
      able_to_retain_flaws := TRUE;
    IFEND;

    IF dat_open THEN
      dmp$close_file (p_dat_seq, status);
    IFEND;

    IF dat_attached THEN
      dmp$detach_device_file (dat_sfid, file_modified, fmd_modified, status);
    IFEND;

  PROCEND remember_device_flaws;
?? OLDTITLE ??
MODEND dmm$initialize_volume;
