?? RIGHT := 110 ??
MODULE dmm$search_for_ms_label;
?? RIGHT := 110 ??

{Purpose: Try to read the Disk Label, which resides at three different locations.

?? NEWTITLE := 'Global Declarations Referenced By This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc ioe$st_errors
*copyc dmt$device_allocation_unit
*copyc dmt$error_condition_codes
*copyc dmt$minimum_allocation_unit
*copyc dmt$ms_logical_device_address
*copyc dmt$ms_volume_label
*copyc dmt$physical_device_attributes
*copyc iot$io_function
*copyc iot$logical_unit
*copyc ost$status
?? POP ??
*copyc iop$mass_storage_io
*copyc osp$append_status_integer
*copyc osp$set_status_abnormal
*copyc pmp$zero_out_table
?? OLDTITLE ??
?? NEWTITLE := 'DMP$LOCATE_VOLUME_LABEL', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$locate_volume_label
    (    logical_unit_number: iot$logical_unit;
         p_physical_attributes: ^dmt$physical_device_attributes;
     VAR ms_volume_label: dmt$ms_volume_label;
     VAR status: ost$status);

    CONST
      c$no_label = $CHAR (0) CAT $CHAR (0) CAT $CHAR (0) CAT $CHAR (0) CAT $CHAR (0) CAT $CHAR (0) CAT
            $CHAR (0) CAT $CHAR (0),
      c$nosve_label = 'nosve   ';

    VAR
      buffer_length_in_maus: dmt$maus_per_dau,
      bytes_per_mau: dmt$bytes_per_mau,
      device_address: dmt$ms_logical_device_address,
      first_foreign_label_type: string (8),
      foreign_label_read_count: integer,
      index: integer,
      last_label_type_read: string (8),
      label_size_in_bytes: ost$byte_count,
      maus_per_cylinder: dmt$maus_per_position,
      maus_per_dau: dmt$maus_per_dau,
      maus_per_label: dmt$mau_address,
      no_label_read_count: integer,
      p_completion_status: ^iot$completion_status,
      p_label_body: ^dmt$ms_label_0_0,
      p_label_buffer: ^SEQ ( * ),
      p_label_header: ^dmt$volume_label_header,
      p_ms_label: ^dmt$ms_volume_label,
      p_volume_label: ^dmt$ms_volume_label;

    status.normal := TRUE;
    foreign_label_read_count := 0;
    no_label_read_count := 0;
    last_label_type_read := '';

    p_volume_label := ^ms_volume_label;
    RESET p_volume_label;

    maus_per_cylinder := dmc$min_maus_position;
    bytes_per_mau := dmc$max_bytes_per_mau;
    maus_per_dau := dmc$min_maus_per_dau;

    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$bytes_per_mau =
          bytes_per_mau := p_physical_attributes^ [index].bytes_per_mau;
        = dmc$maus_per_cylinder =
          maus_per_cylinder := p_physical_attributes^ [index].maus_per_cylinder;
        = dmc$maus_per_dau =
          maus_per_dau := p_physical_attributes^ [index].maus_per_dau;
        ELSE
        CASEND;
      FOREND;
    IFEND;

    maus_per_label := dmc$default_label_alloc_size DIV bytes_per_mau;

    label_size_in_bytes := #SIZE (dmt$volume_label_header);
    IF label_size_in_bytes <= #SIZE (ms_volume_label) THEN
      label_size_in_bytes := #SIZE (ms_volume_label);
    IFEND;

    IF ((label_size_in_bytes + bytes_per_mau - 1) DIV bytes_per_mau) < dmc$min_maus_per_dau THEN
      buffer_length_in_maus := dmc$min_maus_per_dau;
    ELSE
      buffer_length_in_maus := (label_size_in_bytes + bytes_per_mau - 1) DIV bytes_per_mau;
    IFEND;

    PUSH p_label_buffer: [[REP (buffer_length_in_maus * bytes_per_mau) OF cell]];
    RESET p_label_buffer;
    NEXT p_label_header IN p_label_buffer;

    device_address.allocation_unit_mau_address := 0;
    device_address.maus_per_position := maus_per_cylinder;
    device_address.logical_unit_number := logical_unit_number;
    device_address.transfer_length := buffer_length_in_maus;
    device_address.transfer_mau_offset := 0;
    device_address.write_translation := FALSE;
    pmp$zero_out_table (#LOC (p_label_buffer^), #SIZE (p_label_buffer^));

  /search_for_label_header/
    REPEAT
      iop$mass_storage_io (#LOC (p_label_buffer^), label_size_in_bytes, ioc$read_mass_storage, device_address,
            TRUE, p_completion_status, status);
      IF status.normal THEN
        last_label_type_read := p_label_header^.label_type;

        IF last_label_type_read = c$nosve_label THEN
          RESET p_label_buffer;
          NEXT p_ms_label: [[REP #SIZE (ms_volume_label) OF cell]] IN p_label_buffer;
          RESET p_ms_label;
          p_volume_label^ := p_ms_label^;
          RETURN; {----->

        ELSEIF (last_label_type_read = c$no_label) OR (last_label_type_read = '') THEN
          no_label_read_count := no_label_read_count + 1;

        ELSE {we can read the label, but it's overwritten or the volume is formatted for another system.
          IF foreign_label_read_count = 0 THEN
            {Save the first unknown label for error status processing
            first_foreign_label_type := last_label_type_read;
          IFEND;
          foreign_label_read_count := foreign_label_read_count + 1;
        IFEND;

      ELSE
        CASE status.condition OF
        = dme$transient_error, ioe$requests_full =
{do we really get this? In this case we would only have to wait a little while
          ;
        = ioe$unit_disabled =
          RETURN; {----->
        = ioe$unrecovered_disk_error =
          ; {try on the next address
        ELSE {What other error could we get? Can't see one for now, so just retry on the next address ...
          ;
        CASEND;
      IFEND;

      device_address.allocation_unit_mau_address := device_address.allocation_unit_mau_address +
            maus_per_label;
    UNTIL (device_address.allocation_unit_mau_address > maus_per_label * dmc$max_label_aus);

    IF NOT status.normal THEN
      RETURN; {----->
    ELSEIF foreign_label_read_count > 0 THEN
      osp$set_status_abnormal ('DM', dme$unknown_ms_label_type, first_foreign_label_type, status);
      osp$append_status_integer (osc$status_parameter_delimiter, logical_unit_number, 10, FALSE, status);
    ELSEIF no_label_read_count > 0 THEN
      osp$set_status_abnormal ('DM', dme$no_ms_label_type, '', status);
      osp$append_status_integer (osc$status_parameter_delimiter, logical_unit_number, 10, FALSE, status);
    IFEND;

  PROCEND dmp$locate_volume_label;
?? OLDTITLE ??
MODEND dmm$search_for_ms_label;

