?? RIGHT := 110 ??
?? NEWTITLE := 'Configuration interface (13D)' ??
MODULE cmm$configuration_interface_13d;

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cme$logical_configuration_mgr
*copyc cme$physical_configuration_mgr
*copyc cmt$element_descriptor
*copyc cmt$physical_identification
*copyc oss$mainframe_pageable
*copyc oss$mainframe_paged_literal
?? POP ??
*copyc clp$convert_integer_to_string
*copyc cmp$convert_channel_number
*copyc cmp$convert_iou_name
*copyc cmp$convert_iou_number
*copyc cmp$get_logical_pp_index
*copyc cmp$get_logical_unit_number
*copyc cmp$pc_get_element
*copyc cmp$pc_get_logical_unit
*copyc cmp$retrieve_logical_pp_index
*copyc cmp$search_active_volume_table
*copyc dsp$retrieve_channel_type
*copyc dsp$retrieve_iou_information
*copyc osp$append_status_integer
*copyc osp$set_status_abnormal
*copyc cmv$configuration_activated
*copyc cmv$logical_pp_table_p
*copyc cmv$logical_unit_table
*copyc cmv$physical_configuration
*copyc cmv$state_info_table
*copyc iov$tusl_p
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  VAR
    v$cip_driver_name: [STATIC, READ, oss$mainframe_paged_literal] ARRAY [cmt$controller_type] OF
          ARRAY [boolean] OF dst$driver_name :=
          { NIO driver, CIO driver }
          [['DSK7154', 'DSK7154'], ['DSK55A ', 'DSK55C7'], ['DSK55A ', 'DSK55C7'], ['D895   ', 'D895CIO'],
           ['DSKI   ', 'E9P9853'], ['       ', 'HYD    '], ['E5P5831', 'E9P5831'], ['TAPE   ', 'TAPE   '],
           ['TAPE   ', 'TAPE   '], ['ISD    ', '       '], ['ISD    ', '       '], ['TAPB   ', '       '],
           ['E2X5680', 'E2X5680'], ['TAPE   ', '       '], ['TAPE   ', 'TAPE   '], ['TAPC   ', 'TAPD   '],
           ['VM5B   ', 'VM5B   '], ['E1C2629', '       '], ['E1C380 ', 'E1A380 '], ['E1C2620', 'E1A2620'],
           ['E1C2620', 'E1A2620'], ['E1C5380', 'E1A5380'], ['E5P4000', 'E9P4000'], ['E5PNTDD', 'E9PNTDD'],
           ['E5PPICO', 'E9PPICO'], ['       ', '       ']],

    v$iou_program_name: [STATIC, READ, oss$mainframe_paged_literal] ARRAY [cmt$controller_type] OF
          ARRAY [boolean] OF dst$driver_name :=
          { NIO driver, CIO driver }
          [['DSKE   ', 'DSKE   '], ['E1C7155', 'E1A7155'], ['E1C7155', 'E1A7155'], ['E2C7165', 'E9A7165'],
           ['E5P9836', 'E9P9853'], ['       ', 'E9S887 '], ['E5P5831', 'E9P5831'], ['E1C7021', 'E1A7021'],
           ['E1C7021', 'E1A7021'], ['E1I7255', '       '], ['E1I7255', '       '], ['E5I9639', '       '],
           ['E2C5680', 'E2A5680'], ['E1C7021', '       '], ['E1C7021', 'E1A7021'], ['E5P5698', 'E9P5698'],
           ['E1C6535', 'E1A6535'], ['E1C2629', '       '], ['E1C380 ', 'E1A380 '], ['E1C2620', 'E1A2620'],
           ['E1C2620', 'E1A2620'], ['E1C5380', 'E1A5380'], ['E5P4000', 'E9P4000'], ['E5PNTDD', 'E9PNTDD'],
           ['E5PPICO', 'E9PPICO'], ['       ', '       ']];

  VAR
    cmv$post_deadstart: [XDCL, #GATE, oss$mainframe_pageable] boolean := FALSE,

{ 20 physical pps in octal   : 0..7, 10, 11, 20..27, 30, 31.
{                    decimal : 0..7,  8,  9, 16..23, 24, 25.

    cmv$valid_pp_names: { Array must be sorted }
          [STATIC, READ, oss$mainframe_paged_literal] array [1 .. 40] of cmt$element_name :=
          ['CPP0                           ', 'CPP1                           ',
          'CPP16                          ', 'CPP17                          ',
          'CPP18                          ', 'CPP19                          ',
          'CPP2                           ', 'CPP20                          ',
          'CPP21                          ', 'CPP22                          ',
          'CPP23                          ', 'CPP24                          ',
          'CPP25                          ', 'CPP3                           ',
          'CPP4                           ', 'CPP5                           ',
          'CPP6                           ', 'CPP7                           ',
          'CPP8                           ', 'CPP9                           ',
          'PP0                            ', 'PP1                            ',
          'PP16                           ', 'PP17                           ',
          'PP18                           ', 'PP19                           ',
          'PP2                            ', 'PP20                           ',
          'PP21                           ', 'PP22                           ',
          'PP23                           ', 'PP24                           ',
          'PP25                           ', 'PP3                            ',
          'PP4                            ', 'PP5                            ',
          'PP6                            ', 'PP7                            ',
          'PP8                            ', 'PP9                            '],

{ Array of channel names must be sorted

    cmv$default_channel_names: [STATIC, READ, oss$mainframe_paged_literal] array [1 .. 96] of
          cmt$element_name := ['CCH0                      ', 'CCH0A                     ',
          'CCH0B                     ', 'CCH1                      ', 'CCH10                     ',
          'CCH11                     ', 'CCH12                     ', 'CCH13                     ',
          'CCH14                     ', 'CCH15                     ', 'CCH16                     ',
          'CCH16A                    ', 'CCH16B                    ', 'CCH17                     ',
          'CCH17A                    ', 'CCH17B                    ', 'CCH18                     ',
          'CCH18A                    ', 'CCH18B                    ', 'CCH19                     ',
          'CCH19A                    ', 'CCH19B                    ', 'CCH1A                     ',
          'CCH1B                     ', 'CCH2                      ', 'CCH20                     ',
          'CCH20A                    ', 'CCH20B                    ', 'CCH21             ',
          'CCH21A            ', 'CCH21B            ', 'CCH22             ', 'CCH22A            ',
          'CCH22B            ', 'CCH23             ', 'CCH23A            ', 'CCH23B            ',
          'CCH24             ', 'CCH24A            ', 'CCH24B            ', 'CCH25             ',
          'CCH25A            ', 'CCH25B            ', 'CCH26             ', 'CCH27             ',
          'CCH2A             ', 'CCH2B             ', 'CCH3              ', 'CCH3A             ',
          'CCH3B             ', 'CCH4              ', 'CCH4A             ', 'CCH4B             ',
          'CCH5              ', 'CCH5A             ', 'CCH5B             ', 'CCH6              ',
          'CCH6A             ', 'CCH6B             ', 'CCH7              ', 'CCH7A             ',
          'CCH7B             ', 'CCH8              ', 'CCH8A             ', 'CCH8B             ',
          'CCH9              ', 'CCH9A             ', 'CCH9B             ', 'CH0               ',
          'CH1               ', 'CH10              ', 'CH11              ', 'CH12              ',
          'CH13              ', 'CH14              ', 'CH15              ', 'CH16              ',
          'CH17              ', 'CH18              ', 'CH19              ', 'CH2               ',
          'CH20              ', 'CH21              ', 'CH22              ', 'CH23              ',
          'CH24              ', 'CH25              ', 'CH26              ', 'CH27              ',
          'CH3               ', 'CH4               ', 'CH5               ', 'CH6               ',
          'CH7               ', 'CH8               ', 'CH9               '];


?? OLDTITLE ??
?? NEWTITLE := '[xref] CMF$PHYSICAL_CONFIG_ACTIVATED', EJECT ??

  FUNCTION [XDCL, #GATE] cmf$physical_config_activated: boolean;

    cmf$physical_config_activated := cmv$configuration_activated;

  FUNCEND cmf$physical_config_activated;
?? TITLE := '  cmp$valid_channel_name', EJECT ??

  FUNCTION [XDCL, #GATE] cmp$valid_channel_name
    (    channel_name: cmt$element_name): boolean;

    VAR
      temp: integer,
      found: boolean,
      index: integer,
      high: integer,
      low: integer,
      middle: integer;

    found := FALSE;
    low := LOWERBOUND (cmv$default_channel_names);
    high := UPPERBOUND (cmv$default_channel_names);
    WHILE (low <= high) AND NOT found DO
      temp := low + high;
      middle := temp DIV 2;
      IF cmv$default_channel_names [middle] = channel_name THEN
        found := TRUE;
      ELSEIF channel_name < cmv$default_channel_names [middle] THEN
        high := middle - 1;
      ELSEIF channel_name > cmv$default_channel_names [middle] THEN
        low := middle + 1;
      IFEND;
    WHILEND;
    cmp$valid_channel_name := found;
  FUNCEND cmp$valid_channel_name;


?? TITLE := '  valid_pp_name', EJECT ??

  FUNCTION valid_pp_name
    (    pp_name: cmt$element_name): boolean;

    VAR
      temp: integer,
      found: boolean,
      index: integer,
      high: integer,
      low: integer,
      middle: integer;

    found := FALSE;
    low := LOWERBOUND (cmv$valid_pp_names);
    high := UPPERBOUND (cmv$valid_pp_names);
    WHILE (low <= high) AND NOT found DO
      temp := low + high;
      middle := temp DIV 2;
      IF cmv$valid_pp_names [middle] = pp_name THEN
        found := TRUE;
      ELSEIF pp_name < cmv$valid_pp_names [middle] THEN
        high := middle - 1;
      ELSEIF pp_name > cmv$valid_pp_names [middle] THEN
        low := middle + 1;
      IFEND;
    WHILEND;
    valid_pp_name := found;
  FUNCEND valid_pp_name;

?? TITLE := '  cmp$convert_channel_ordinal', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$convert_channel_ordinal
    (    channel_ordinal: cmt$channel_ordinal;
     VAR channel_name: cmt$element_name;
     VAR channel_number: ost$physical_channel_number;
     VAR concurrent: boolean;
     VAR channel_port: cmt$channel_port;
     VAR status: ost$status);

    VAR
      port: string (1),
      str: ost$string;

{ PURPOSE : This procedure convert the internal CM type channel ordinal
{   Into the equivalent channel name, channel number.

    status.normal := TRUE;
    concurrent := TRUE;
    port := ' ';
    channel_port := cmc$unspecified_port;
    CASE channel_ordinal OF
    = cmc$channel0 .. cmc$channel27 =
      concurrent := FALSE;
      channel_number := $INTEGER (channel_ordinal);
    = cmc$cio_channel0_porta .. cmc$cio_channel9_portb =
      channel_number := ($INTEGER (channel_ordinal) - $INTEGER (cmc$cio_channel0_porta)) DIV 2;
      IF ($INTEGER (channel_ordinal) - $INTEGER (cmc$cio_channel0_porta)) MOD 2 = 1 THEN
        port := 'B';
      ELSE
        port := 'A';
      IFEND;
    = cmc$cio_channel16_porta .. cmc$cio_channel25_portb =
      channel_number := ($INTEGER (channel_ordinal) - 16) DIV 2;
      IF ($INTEGER (channel_ordinal) - 16) MOD 2 = 1 THEN
        port := 'B';
      ELSE
        port := 'A';
      IFEND;

    = cmc$cio_channel0 .. cmc$cio_channel27 =
      channel_number := $INTEGER (channel_ordinal) - $INTEGER (cmc$cio_channel0);
    ELSE
      osp$set_status_abnormal (cmc$configuration_management_id, cme$cm_end_case_error,
            'CMP$CONVERT_CHANNEL_ORDINAL', status);
    CASEND;

    clp$convert_integer_to_string (channel_number, 10, FALSE, str, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF concurrent THEN
      channel_name := 'CCH';
      channel_name (4, str.size) := str.value;
      IF port <> ' ' THEN
        channel_name (str.size + 4, 1) := port;
        IF port = 'A' THEN
          channel_port := cmc$port_a;
        ELSE
          channel_port := cmc$port_b;
        IFEND;
      IFEND;
    ELSE
      channel_name := 'CH';
      channel_name (3, str.size) := str.value;
    IFEND;

  PROCEND cmp$convert_channel_ordinal;

?? TITLE := '   cmp$determine_active_path', EJECT ??

{ PURPOSE:
{   This procedure determines if a given channel, controller and mass storage
{   unit are currently active. This is determined by checking for a non-zero
{   UIT RMA in the unit descriptor entry of the PP interface table.
{   This interface expects all three elements to be of the correct type and
{   that they are members of a valid path.


  PROCEDURE [XDCL, #GATE] cmp$determine_active_path
    (    channel_element: cmt$element_definition;
         controller_element: cmt$element_definition;
         unit_element: cmt$element_definition;
     VAR active: boolean;
     VAR status: ost$status);

    VAR
      controller_number: cmt$physical_equipment_number,
      logical_pp_index: iot$pp_number,
      logical_unit: iot$logical_unit,
      ppit_p: ^iot$pp_interface_table;

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

    cmp$get_logical_pp_index (channel_element, logical_pp_index, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    ppit_p := cmv$logical_pp_table_p^ [logical_pp_index].pp_info.pp_interface_table_p;

    controller_number := controller_element.controller.physical_equipment_number;

    cmp$get_logical_unit_number (unit_element.element_name, logical_unit, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    active := (ppit_p^.unit_descriptors [logical_unit].unit_interface_table <> NIL) AND
          (ppit_p^.unit_descriptors [logical_unit].physical_path.controller_number = controller_number) AND
          (ppit_p^.unit_descriptors [logical_unit].unit_interface_table_rma <> 0);

  PROCEND cmp$determine_active_path;

?? TITLE := '  cmp$format_error_message', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$format_error_message
    (    element_descriptor: cmt$element_descriptor;
         physical_id: cmt$physical_identification;
         specified_physical_id: boolean;
         condition: integer;
     VAR status: ost$status);

    VAR
      local_status: ost$status,
      str: ost$string,
      text: string (255),
      concurrent: boolean,
      channel_name: cmt$element_name,
      channel_port: cmt$channel_port,
      channel_number: ost$physical_channel_number,
      index: integer;

{ PURPOSE: This procedure format the error message to include the
{   physical path of the form IOU # CH # EQ # UN #.


    text := '           ';

    IF specified_physical_id THEN
      IF physical_id.product_identification.product_number <> '      ' THEN
        text (1, 6) := physical_id.product_identification.product_number;
        text (7, 1) := physical_id.product_identification.underscore;
        text (8, 3) := physical_id.product_identification.model_number;
        text (12, 6) := physical_id.serial_number;

        osp$set_status_abnormal (cmc$configuration_management_id, condition, text (1, 18), status);

      ELSE
        text (1, 5) := physical_id.hardware_address.iou (1, 5);
        IF (cmc$channel IN physical_id.hardware_address.physical_address_specifier) AND
              (cmc$channel_address IN physical_id.hardware_address.physical_address_specifier) AND
              (cmc$unit_address IN physical_id.hardware_address.physical_address_specifier) THEN
          cmp$convert_channel_ordinal (physical_id.hardware_address.channel.ordinal, channel_name,
                channel_number, concurrent, channel_port, local_status);
          text (6, 6) := channel_name (1, 6);
          index := 12;
          clp$convert_integer_to_string (physical_id.hardware_address.channel_address, 10, FALSE, str,
                local_status);
          text (index, 3) := ' EQ';
          text (index + 3, str.size) := str.value (1, str.size);
          index := index + str.size + 4;
          clp$convert_integer_to_string (physical_id.hardware_address.unit_address, 10, FALSE, str,
                local_status);
          text (index, 3) := ' UN';
          text (index + 3, str.size) := str.value (1, str.size);
          index := index + str.size + 3;

        ELSEIF (cmc$channel IN physical_id.hardware_address.physical_address_specifier) AND
              (cmc$channel_address IN physical_id.hardware_address.physical_address_specifier) THEN
          cmp$convert_channel_ordinal (physical_id.hardware_address.channel.ordinal, channel_name,
                channel_number, concurrent, channel_port, local_status);
          text (6, 6) := channel_name (1, 6);
          index := 12;
          clp$convert_integer_to_string (physical_id.hardware_address.channel_address, 10, FALSE, str,
                local_status);
          text (index, 3) := ' EQ';
          text (index + 3, str.size) := str.value (1, str.size);
          index := index + str.size + 3;

        ELSEIF (cmc$channel IN physical_id.hardware_address.physical_address_specifier) THEN
          cmp$convert_channel_ordinal (physical_id.hardware_address.channel.ordinal, channel_name,
                channel_number, concurrent, channel_port, local_status);
          text (6, 6) := channel_name (1, 6);
          index := 12;

        ELSE
        IFEND;

        osp$set_status_abnormal (cmc$configuration_management_id, condition, text (1, index), status);

      IFEND;

    ELSE

      CASE element_descriptor.element_type OF

      = cmc$data_channel_element =
        text (1, 5) := element_descriptor.channel_descriptor.iou (1, 5);
        IF element_descriptor.channel_descriptor.use_logical_identification THEN
          text (6, * ) := element_descriptor.channel_descriptor.name;
        ELSE
          cmp$convert_channel_ordinal (element_descriptor.channel_descriptor.channel_ordinal, channel_name,
                channel_number, concurrent, channel_port, local_status);
          text (6, * ) := channel_name;
        IFEND;
        index := 37;

      = cmc$controller_element, cmc$storage_device_element, cmc$external_processor_element,
            cmc$channel_adapter_element, cmc$communications_element =

        CASE element_descriptor.peripheral_descriptor.use_logical_identification OF

        = TRUE =
          text (1, * ) := element_descriptor.peripheral_descriptor.element_name;
          index := 31;
        = FALSE =
          text (1, 5) := element_descriptor.peripheral_descriptor.hardware_address.iou (1, 5);
          IF (cmc$channel IN element_descriptor.peripheral_descriptor.hardware_address.
                physical_address_specifier) AND (cmc$channel_address IN
                element_descriptor.peripheral_descriptor.hardware_address.physical_address_specifier) AND
                (cmc$unit_address IN element_descriptor.peripheral_descriptor.hardware_address.
                physical_address_specifier) THEN
            cmp$convert_channel_ordinal (element_descriptor.peripheral_descriptor.hardware_address.channel.
                  ordinal, channel_name, channel_number, concurrent, channel_port, local_status);
            text (6, 6) := channel_name (1, 6);
            index := 12;
            clp$convert_integer_to_string (element_descriptor.peripheral_descriptor.hardware_address.
                  channel_address, 10, FALSE, str, local_status);
            text (index, 3) := ' EQ';
            text (index + 3, str.size) := str.value (1, str.size);
            index := index + str.size + 4;
            clp$convert_integer_to_string (element_descriptor.peripheral_descriptor.hardware_address.
                  unit_address, 10, FALSE, str, local_status);
            text (index, 3) := ' UN';
            text (index + 3, str.size) := str.value (1, str.size);
            index := index + str.size + 3;

          ELSEIF (cmc$channel IN element_descriptor.peripheral_descriptor.hardware_address.
                physical_address_specifier) AND (cmc$channel_address IN
                element_descriptor.peripheral_descriptor.hardware_address.physical_address_specifier) THEN
            cmp$convert_channel_ordinal (element_descriptor.peripheral_descriptor.hardware_address.channel.
                  ordinal, channel_name, channel_number, concurrent, channel_port, local_status);
            text (6, 6) := channel_name (1, 6);
            index := 12;
            clp$convert_integer_to_string (element_descriptor.peripheral_descriptor.hardware_address.
                  channel_address, 10, FALSE, str, local_status);
            text (index, 3) := ' EQ';
            text (index + 3, str.size) := str.value (1, str.size);
            index := index + str.size + 3;

          ELSEIF (cmc$channel IN element_descriptor.peripheral_descriptor.hardware_address.
                physical_address_specifier) THEN
            cmp$convert_channel_ordinal (element_descriptor.peripheral_descriptor.hardware_address.channel.
                  ordinal, channel_name, channel_number, concurrent, channel_port, local_status);
            text (6, 6) := channel_name (1, 6);
            index := 12;

          ELSE
          IFEND;

        CASEND;

      ELSE
      CASEND;

      osp$set_status_abnormal (cmc$configuration_management_id, condition, text (1, index), status);

    IFEND;

  PROCEND cmp$format_error_message;

?? TITLE := '   cmp$get_channel_def', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$get_channel_def
    (    channel_identification: cmt$channel_descriptor;
     VAR channel_definition: cmt$data_channel_definition;
     VAR status: ost$status);

    VAR
      found: boolean,
      ch_name: cmt$element_name,
      ch_number: ost$physical_channel_number,
      ch_ordinal: cmt$channel_ordinal,
      ch_port: cmt$channel_port,
      concurrent: boolean,
      element_descriptor: cmt$element_descriptor,
      error_string: string (80),
      exact_match: boolean,
      i: integer,
      iou_definition: cmt$iou_definition,
      iou_information_table: dst$iou_information_table,
      iou_name: cmt$element_name,
      iou_number: dst$iou_number,
      number: integer,
      number_of_ious: dst$number_of_ious,
      number_string: string (4),
      physical_id: cmt$physical_identification,
      string_index: 0 .. 31,
      string_length: integer,
      val: integer,
      valid: boolean;

    status.normal := TRUE;
    iou_name := 'IOU0';

    dsp$retrieve_iou_information (number_of_ious, iou_information_table);
    IF number_of_ious > 1 THEN
      iou_name := channel_identification.iou;
    IFEND;

    cmp$retrieve_iou_definition (iou_name, iou_definition, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cmp$convert_iou_name (iou_name, iou_number, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF channel_identification.use_logical_identification THEN

      { Determine physical channel number from channel name.

      IF NOT cmp$valid_channel_name (channel_identification.name) THEN
        error_string := iou_name;
        error_string (7, * ) := channel_identification.name;
        osp$set_status_abnormal (cmc$configuration_management_id, cme$invalid_channel_name, error_string,
              status);
        RETURN;
      IFEND;

      i := 1;
      number_string := ' ';
      string_index := 0;
      WHILE (channel_identification.name (i) <> ' ') AND (i <= osc$max_name_size) DO
        IF (channel_identification.name (i) >= '0') AND (channel_identification.name (i) <= '9') THEN
          string_index := string_index + 1;
          number_string (string_index) := channel_identification.name (i);
        IFEND;
        i := i + 1;
      WHILEND;
      IF number_string = ' ' THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$invalid_channel_name,
              channel_identification.name, status);
        RETURN;
      IFEND;

      number := 0;
      val := 1;
      FOR i := string_index DOWNTO 1 DO
        IF number_string (i) <> ' ' THEN
          number := (number + (($INTEGER (number_string (i)) - $INTEGER ('0')) * val));
          val := val * 10;
        IFEND;
      FOREND;
      IF (number >= 0) AND (number <= 27) THEN
        ch_number := number;
      ELSE
        osp$set_status_abnormal (cmc$configuration_management_id, cme$illegal_channel_number,
              number_string, status);
        osp$append_status_integer (osc$status_parameter_delimiter, 0, 10, TRUE, status);
        osp$append_status_integer (osc$status_parameter_delimiter, 27, 10, TRUE, status);
        RETURN;
      IFEND;

      concurrent := channel_identification.name (1, 2) = 'CC';
      ch_port := cmc$unspecified_port;
      IF concurrent THEN
        IF (channel_identification.name (5) = 'A') OR (channel_identification.name (6) = 'A') THEN
          ch_port := cmc$port_a;
        ELSEIF (channel_identification.name (5) = 'B') OR (channel_identification.name (6) = 'B') THEN
          ch_port := cmc$port_b;
        IFEND;
      IFEND;

      cmp$convert_channel_number (ch_number, concurrent, ch_port, ch_ordinal, ch_name, valid);
      IF NOT valid THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$illegal_channel_number,
              number_string, status);
        osp$append_status_integer (osc$status_parameter_delimiter, 0, 10, TRUE, status);
        osp$append_status_integer (osc$status_parameter_delimiter, 27, 10, TRUE, status);
        RETURN;
      IFEND;
    ELSE

      ch_number := channel_identification.number;
      ch_ordinal := channel_identification.channel_ordinal;
      concurrent := channel_identification.concurrent;
      CASE ch_ordinal OF
      = cmc$cio_channel0_porta .. cmc$cio_channel9_portb =
        IF ($INTEGER (ch_ordinal) - $INTEGER (cmc$cio_channel0_porta)) MOD 2 = 1 THEN
          ch_port := cmc$port_b;
        ELSE
          ch_port := cmc$port_a;
        IFEND;
      = cmc$cio_channel16_porta .. cmc$cio_channel25_portb =
        IF ($INTEGER (ch_ordinal) - 16) MOD 2 = 1 THEN
          ch_port := cmc$port_b;
        ELSE
          ch_port := cmc$port_a;
        IFEND;
      ELSE
        ch_port := cmc$unspecified_port;
      CASEND;
      number_string := ' ';
      STRINGREP (number_string, string_length, ch_number);
    IFEND;

    found := FALSE;

    IF cmv$post_deadstart AND (cmv$physical_configuration <> NIL) THEN

     /pc_loop/
      FOR i := LOWERBOUND (cmv$physical_configuration^) TO UPPERBOUND (cmv$physical_configuration^) DO
        IF cmv$physical_configuration^ [i].element_type = cmc$data_channel_element THEN
          exact_match := (ch_port = cmv$physical_configuration^ [i].data_channel.port) AND
                (ch_number = cmv$physical_configuration^ [i].data_channel.number) AND
                (concurrent = cmv$physical_configuration^ [i].data_channel.concurrent) AND
                (iou_name = cmv$physical_configuration^ [i].data_channel.iou);
          IF exact_match THEN
            found := TRUE;
            EXIT /pc_loop/;
          ELSE
            IF (ch_number = cmv$physical_configuration^ [i].data_channel.number) AND
                  (concurrent = cmv$physical_configuration^ [i].data_channel.concurrent) AND
                  (iou_name = cmv$physical_configuration^ [i].data_channel.iou) THEN
              found := TRUE;
              channel_definition := cmv$physical_configuration^ [i].data_channel;
            IFEND;
          IFEND;
        IFEND;
      FOREND /pc_loop/;
    IFEND;

    { If no exact match is found then the CIO channel no port will be returned.

    IF found THEN
      IF exact_match THEN
        channel_definition := cmv$physical_configuration^ [i].data_channel;
      ELSE
        channel_definition.port := cmc$unspecified_port;
        cmp$convert_channel_number (channel_definition.number, concurrent, cmc$unspecified_port,
              channel_definition.ordinal, ch_name, valid);
      IFEND;
      RETURN;
    IFEND;

    { The channel was not found in the physical configuration table.

    channel_definition.number := ch_number;
    channel_definition.concurrent := concurrent;
    channel_definition.port := ch_port;
    channel_definition.ordinal := ch_ordinal;

    cmp$convert_channel_number (ch_number, concurrent, ch_port, ch_ordinal, ch_name, valid);
    IF NOT valid THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$illegal_channel_number,
            number_string, status);
      osp$append_status_integer (osc$status_parameter_delimiter, 0, 10, TRUE, status);
      osp$append_status_integer (osc$status_parameter_delimiter, 27, 10, TRUE, status);
      RETURN;
    IFEND;

    FOR i := LOWERVALUE (ost$physical_pp_number) TO UPPERVALUE (ost$physical_pp_number) DO
      channel_definition.pps_capable_of_access [i] := FALSE;
    FOREND;
    CASE iou_definition.kind OF
    = dsc$imn_i0_5x_model =
      IF channel_definition.number <= 5 THEN
        FOR i := 0 TO 4 DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      ELSE
        FOR i := 20(8) TO 24(8) DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      IFEND;

    = dsc$imn_i4_40_model =
      IF channel_definition.concurrent THEN
        IF channel_definition.number <= 4 THEN
          FOR i := 0 TO 4 DO
            channel_definition.pps_capable_of_access [i] := TRUE;
          FOREND;
        ELSE
          FOR i := 5 TO 9 DO
            channel_definition.pps_capable_of_access [i] := TRUE;
          FOREND;
        IFEND;
      ELSE
        FOR i := LOWERVALUE (ost$physical_pp_number) TO UPPERVALUE (ost$physical_pp_number) DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      IFEND;

    = dsc$imn_i4_44_model, dsc$imn_i4_46_model =
      IF (channel_definition.number >= 2) AND (channel_definition.number <= 4) THEN
        FOR i := 0 TO 4 DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      ELSEIF (channel_definition.number >= 5) AND (channel_definition.number <= 11(8)) THEN
        FOR i := 5 TO 11(8) DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      ELSEIF (channel_definition.number >= 12(8)) AND (channel_definition.number <= 17(8)) THEN
        FOR i := LOWERVALUE (ost$physical_pp_number) TO UPPERVALUE (ost$physical_pp_number) DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      ELSEIF (channel_definition.number >= 20(8)) AND (channel_definition.number <= 24(8)) THEN
        FOR i := 20(8) TO 24(8) DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      ELSEIF (channel_definition.number >= 25(8)) AND (channel_definition.number <= 31(8)) THEN
        FOR i := 25(8) TO 31(8) DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      ELSEIF (iou_definition.kind = dsc$imn_i4_46_model) AND
            ((channel_definition.number = 32(8)) OR (channel_definition.number = 33(8))) THEN
        FOR i := 0 TO 11(8) DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      IFEND;

    = dsc$imn_i4_42_model =
      IF channel_definition.concurrent THEN
        IF (channel_definition.number > 3) THEN
          osp$set_status_abnormal (cmc$configuration_management_id, cme$illegal_channel_number,
                number_string, status);
          osp$append_status_integer (osc$status_parameter_delimiter, 0, 10, TRUE, status);
          osp$append_status_integer (osc$status_parameter_delimiter, 3, 10, TRUE, status);
          RETURN;
        IFEND;
        FOR i := 0 TO 4 DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      ELSE
        IF (channel_definition.number > 24(8)) THEN
          osp$set_status_abnormal (cmc$configuration_management_id, cme$illegal_channel_number,
                number_string, status);
          osp$append_status_integer (osc$status_parameter_delimiter, 0, 10, TRUE, status);
          osp$append_status_integer (osc$status_parameter_delimiter, 20, 10, TRUE, status);
          RETURN;
        IFEND;
        FOR i := 0 TO 11(8) DO
          channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
        FOR i := 20(8) TO 24(8) DO
         channel_definition.pps_capable_of_access [i] := TRUE;
        FOREND;
      IFEND;

    ELSE { I1, I2 model }
      FOR i := LOWERVALUE (ost$physical_pp_number) TO UPPERVALUE (ost$physical_pp_number) DO
        channel_definition.pps_capable_of_access [i] := TRUE;
      FOREND;
    CASEND;

    channel_definition.iou := iou_name;
    FOR i := LOWERVALUE (cmt$physical_equipment_number) TO UPPERVALUE (cmt$physical_equipment_number) DO
      channel_definition.connection.equipment [i].configured := FALSE;
    FOREND;
    cmp$get_channel_type (iou_number, channel_definition.number, channel_definition.concurrent,
          channel_definition.kind, status);
    IF NOT status.normal THEN
      error_string := iou_name;
      error_string (7, * ) := ch_name;
      osp$set_status_abnormal (cmc$configuration_management_id, cme$unknown_channel_type,
            error_string, status);
      RETURN;
    IFEND;

    channel_definition.direct_memory_access := ((channel_definition.concurrent OR
          (iou_definition.kind = dsc$imn_i0_5x_model)) AND (channel_definition.kind = cmc$170_channel)) OR
          (channel_definition.kind = cmc$ipi_channel) OR
          ((channel_definition.kind = cmc$ici_channel) AND
          (iou_definition.kind = dsc$imn_i0_5x_model)) OR (channel_definition.kind = cmc$isi_channel);

    { Return abnormal status indicating that the channel is not in the active configuration.

    IF cmv$post_deadstart AND status.normal THEN
      element_descriptor.element_type := cmc$data_channel_element;
      element_descriptor.channel_descriptor := channel_identification;
      cmp$format_error_message (element_descriptor, physical_id, FALSE, cme$lcm_element_not_found, status);
    IFEND;

  PROCEND cmp$get_channel_def;

?? TITLE := '    cmp$get_channel_type ', EJECT ??

  PROCEDURE [XDCL] cmp$get_channel_type
    (    iou_number: dst$iou_number;
         channel_number: ost$physical_channel_number;
         concurrent: boolean;
     VAR channel_type: cmt$channel_type;
     VAR status: ost$status);

    VAR
      channel: dst$iou_resource,
      channel_type_found: boolean;

    status.normal := TRUE;
    channel_type := cmc$170_channel;
    channel.iou_number := iou_number;
    IF NOT concurrent THEN
      channel.channel_protocol := dsc$cpt_nio;
    ELSE
      channel.channel_protocol := dsc$cpt_cio;
    IFEND;
    channel.number := channel_number;

    dsp$retrieve_channel_type (channel, channel_type, channel_type_found);
    IF NOT channel_type_found THEN
      status.normal := FALSE;
    IFEND;

  PROCEND cmp$get_channel_type;
?? TITLE := '   cmp$get_driver_by_controller', EJECT ??

{ PURPOSE:
{   This procedure retrieves the driver name given the controller type.

  PROCEDURE [XDCL, #GATE] cmp$get_driver_by_controller
    (    controller: cmt$controller_type;
         concurrent: boolean;
         iou: dst$iou_number;
     VAR driver_name: dst$driver_name;
     VAR alternate_driver_name: dst$driver_name);

    VAR
      index: dst$number_of_ious,
      iou_information_table: dst$iou_information_table,
      number_of_ious: dst$number_of_ious;

    driver_name := ' ';
    alternate_driver_name := ' ';

    driver_name := v$iou_program_name [controller] [concurrent];

    CASE controller OF
    = cmc$mt7021_3x, cmc$mt7021_4x, cmc$mt698_xx =
      IF concurrent THEN
        alternate_driver_name := 'E2A7021';
      ELSE
        alternate_driver_name := 'E2C7021';
      IFEND;
    = cmc$mt7221_1 =
      IF NOT concurrent THEN
        alternate_driver_name := 'E2C7021';
      IFEND;
    = cmc$lcn380_170 =
      IF NOT concurrent THEN
        alternate_driver_name := 'E1I380';
      IFEND;
    ELSE
    CASEND;

  PROCEND cmp$get_driver_by_controller;
?? TITLE := '   cmp$get_driver_info', EJECT ??

{ PURPOSE:
{   This procedure returns the CIP driver name, given the IOU program name used at PCU and the channel
{   type (CIO or NIO). It also tells whether or not the current driver is a Dual PP.

  PROCEDURE [XDCL, #GATE] cmp$get_driver_info
    (    iou_program_name: pmt$program_name;
         concurrent: boolean;
     VAR cip_driver_name: dst$driver_name;
     VAR dual_pp: boolean;
     VAR status: ost$status);

    VAR
      controller: cmt$controller_type,
      temp_iou_program_name: pmt$program_name;

    status.normal := TRUE;

    { The following programs are carefully handled to insure that the case where one controller is being
    { accessed from both NIO and CIO channels is being properly handled.  In this situation the
    { iou_program_name will reflect whichever access was declared first, so an explicit NIO/CIO check is
    { required to determine the correct cip_driver_name and PP requirements.

    IF (iou_program_name = 'E9A7165') OR (iou_program_name = 'E2C7165') THEN
      IF concurrent THEN
        temp_iou_program_name := 'E9A7165';
      ELSE
        temp_iou_program_name := 'E2C7165';
      IFEND;
    ELSEIF (iou_program_name = 'E1C7155') OR (iou_program_name = 'E1A7155') THEN
      IF concurrent THEN
        temp_iou_program_name := 'E1A7155';
      ELSE
        temp_iou_program_name := 'E1C7155';
      IFEND;
    ELSE
      temp_iou_program_name := iou_program_name;
    IFEND;

    FOR controller := LOWERVALUE (cmt$controller_type) TO UPPERVALUE (cmt$controller_type) DO
      IF temp_iou_program_name = v$iou_program_name [controller] [concurrent] THEN
        cip_driver_name := v$cip_driver_name [controller] [concurrent];
        dual_pp := (temp_iou_program_name (2) = '2');
        RETURN;
      IFEND;
    FOREND;

    IF (temp_iou_program_name = 'E2A7021') OR (temp_iou_program_name = 'E2C7021') THEN
      cip_driver_name := 'TAPE';
      dual_pp := TRUE;
      RETURN;
    ELSEIF (temp_iou_program_name = 'E9Q5698') OR (temp_iou_program_name = 'E1I380') THEN
      cip_driver_name := temp_iou_program_name;
      dual_pp := FALSE;
      RETURN;
    IFEND;

    osp$set_status_abnormal (cmc$configuration_management_id, cme$invalid_iou_program_name, iou_program_name,
          status);

  PROCEND cmp$get_driver_info;
?? TITLE := '  cmp$get_driver_state', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$get_driver_state
    (    channel_name: cmt$element_name;
         iou_name: cmt$element_name;
     VAR driver_present: boolean;
     VAR status: ost$status);

    VAR
      channel: dst$iou_resource,
      channel_definition: cmt$data_channel_definition,
      channel_identification: cmt$channel_descriptor,
      index: iot$pp_number;

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

    channel_identification.iou := iou_name;
    channel_identification.name := channel_name;
    channel_identification.use_logical_identification := TRUE;
    cmp$get_channel_def (channel_identification, channel_definition, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    channel.number := channel_definition.number;

    cmp$convert_iou_name (iou_name, channel.iou_number, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF channel_definition.concurrent THEN
      channel.channel_protocol := dsc$cpt_cio;
    ELSE
      channel.channel_protocol := dsc$cpt_nio;
    IFEND;

    FOR index := LOWERBOUND (cmv$logical_pp_table_p^) TO UPPERBOUND (cmv$logical_pp_table_p^) DO
      IF cmv$logical_pp_table_p^ [index].flags.configured AND
            (cmv$logical_pp_table_p^ [index].flags.entry_reserved_by_nosve OR
            cmv$logical_pp_table_p^ [index].flags.entry_reserved_by_other) AND
            (cmv$logical_pp_table_p^ [index].pp_info.channel = channel) THEN
        driver_present := TRUE;
        RETURN;
      IFEND;
    FOREND;

  PROCEND cmp$get_driver_state;

?? TITLE := '    cmp$get_element_state', EJECT ??

{  PURPOSE: Return the current state associated with the given element name.

  PROCEDURE [XDCL, #GATE] cmp$get_element_state
    (    element_name: cmt$element_name;
         iou_name: cmt$element_name;
     VAR state: cmt$element_state;
     VAR status: ost$status);

    VAR
      found: boolean,
      index: integer,
      text: string (80);

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

    IF cmv$state_info_table = NIL THEN
      IF NOT cmv$post_deadstart THEN

{ Default state to ON because state table is not built during
{ Boot or System Core time.

        state := cmc$on;
      ELSE
        osp$set_status_abnormal (cmc$configuration_management_id, cme$pc_nil_cm_table, 'Nil state info table',
              status);
      IFEND;
      RETURN; {----->
    IFEND;

    IF cmp$valid_channel_name (element_name) THEN
      text (1, 5) := iou_name;
      text (7, * ) := element_name;
    ELSE
      text := element_name;
    IFEND;

    FOR index := 1 TO UPPERBOUND (cmv$state_info_table^) DO
      IF (cmv$state_info_table^ [index].element_type = cmc$data_channel_element) THEN

        found := (element_name = cmv$state_info_table^ [index].element_name) AND
              (iou_name = cmv$state_info_table^ [index].iou);
      ELSE
        found := (element_name = cmv$state_info_table^ [index].element_name);
      IFEND;

      IF found THEN
        state := cmv$state_info_table^ [index].status.state;
        RETURN; {----->
      IFEND;
    FOREND;

    osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_element_not_found, text, status);

  PROCEND cmp$get_element_state;
?? TITLE := '   cmp$get_pp_def', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$get_pp_def
    (    pp_identification: cmt$pp_descriptor;
     VAR pp_definition: cmt$pp_definition;
     VAR status: ost$status);

    VAR
      ch_number: ost$physical_channel_number,
      iou_definition: cmt$iou_definition,
      iou_information_table: dst$iou_information_table,
      iou_name: cmt$element_name,
      number_of_ious: dst$number_of_ious,
      pp_number: ost$physical_pp_number;

    status.normal := TRUE;
    iou_name := 'IOU0';
    dsp$retrieve_iou_information (number_of_ious, iou_information_table);
    IF number_of_ious > 1 THEN
      iou_name := pp_identification.iou;
    IFEND;
    cmp$retrieve_iou_definition (iou_name, iou_definition, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    FOR ch_number := LOWERVALUE (ost$physical_channel_number) TO UPPERVALUE (ost$physical_channel_number) DO
      pp_definition.accessible_channels [ch_number] := FALSE;
    FOREND;

    IF pp_identification.use_logical_identification THEN
      IF NOT valid_pp_name (pp_identification.pp_name) THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$invalid_pp_name,
              pp_identification.pp_name, status);
        RETURN;
      IFEND;
      pp_definition.concurrent := (pp_identification.pp_name (1, 3) = 'CPP');
      IF pp_definition.concurrent THEN
        IF pp_identification.pp_name (5) <> ' ' THEN
          pp_number := (($INTEGER (pp_identification.pp_name (4)) - $INTEGER ('0')) * 10) +
                ($INTEGER (pp_identification.pp_name (5)) - $INTEGER ('0'));
        ELSE
          pp_number := $INTEGER (pp_identification.pp_name (4)) - $INTEGER ('0');
        IFEND;
      ELSE
        IF pp_identification.pp_name (4) <> ' ' THEN
          pp_number := (($INTEGER (pp_identification.pp_name (3)) - $INTEGER ('0')) * 10) +
                ($INTEGER (pp_identification.pp_name (4)) - $INTEGER ('0'));
        ELSE
          pp_number := $INTEGER (pp_identification.pp_name (3)) - $INTEGER ('0');
        IFEND;
      IFEND;
      pp_definition.number := pp_number;
    ELSE
      pp_definition.concurrent := pp_identification.concurrent;
      pp_definition.number := pp_identification.pp_number;
    IFEND;

    IF (pp_definition.number > 25) OR ((pp_definition.number > 9) AND (pp_definition.number < 16)) THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$invalid_pp_number,
            'PP number must be in range 0..9 or 16..25.', status);
      RETURN;
    IFEND;

    pp_definition.direct_memory_access := FALSE;
    pp_definition.iou := iou_name;

    CASE iou_definition.kind OF
    = dsc$imn_i0_5x_model =
      pp_definition.size := 16384;
      pp_definition.direct_memory_access := TRUE;
      IF pp_definition.number <= 4 THEN
        FOR ch_number := 0 TO 5 DO
          pp_definition.accessible_channels [ch_number] := TRUE;
        FOREND;
      ELSE
        FOR ch_number := 21(8) TO 26(8) DO
          pp_definition.accessible_channels [ch_number] := TRUE;
        FOREND;
      IFEND;

    = dsc$imn_i4_40_model =
      IF pp_definition.concurrent THEN
        pp_definition.size := 8192;
        pp_definition.direct_memory_access := TRUE;
        IF pp_definition.number <= 4 THEN
          FOR ch_number := 0 TO 4 DO
            pp_definition.accessible_channels [ch_number] := TRUE;
          FOREND;
        ELSE
          FOR ch_number := 5 TO 11(8) DO
            pp_definition.accessible_channels [ch_number] := TRUE;
          FOREND;
        IFEND;
      ELSE
        pp_definition.size := 4096;
        FOR ch_number := LOWERVALUE (ost$physical_channel_number)
              TO UPPERVALUE (ost$physical_channel_number) DO
          pp_definition.accessible_channels [ch_number] := TRUE;
        FOREND;
      IFEND;

    = dsc$imn_i4_44_model, dsc$imn_i4_46_model =
      pp_definition.size := 8192;
      pp_definition.direct_memory_access := TRUE;
      FOR ch_number := LOWERVALUE (ost$physical_channel_number)
            TO UPPERVALUE (ost$physical_channel_number) DO
        pp_definition.accessible_channels [ch_number] := TRUE;
      FOREND;

    = dsc$imn_i4_42_model =
      IF pp_definition.concurrent THEN
        pp_definition.size := 8192;
        pp_definition.direct_memory_access := TRUE;
        FOR ch_number := 0 TO 4 DO
          pp_definition.accessible_channels [ch_number] := TRUE;
        FOREND;
      ELSE
        pp_definition.size := 4096;
        FOR ch_number := LOWERVALUE (ost$physical_channel_number) TO 24(8) DO
          pp_definition.accessible_channels [ch_number] := TRUE;
        FOREND;
      IFEND;

    ELSE  { dsc$imn_i1_10_model .. dsc$imn_i2_20_model
      pp_definition.size := 4096;
      FOR ch_number := LOWERVALUE (ost$physical_channel_number)
            TO UPPERVALUE (ost$physical_channel_number) DO
        pp_definition.accessible_channels [ch_number] := TRUE;
      FOREND;
    CASEND;

  PROCEND cmp$get_pp_def;

?? TITLE := '  cmp$retrieve_iou_definition', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$retrieve_iou_definition
    (    iou_name: cmt$element_name;
     VAR iou_definition: cmt$iou_definition;
     VAR status: ost$status);

    VAR
      iou_information_table: dst$iou_information_table,
      iou_index: dst$number_of_ious,
      iou_number: dst$iou_number,
      number_of_ious: dst$number_of_ious;

    status.normal := TRUE;
    cmp$convert_iou_name (iou_name, iou_number, status);
    IF NOT status.normal THEN
      RETURN;
    ELSE
      dsp$retrieve_iou_information (number_of_ious, iou_information_table);

      FOR iou_index := 1 TO number_of_ious DO
        IF iou_information_table [iou_index].physical_iou_number = iou_number THEN
          iou_definition.kind := iou_information_table [iou_index].model_type;
          RETURN;
        IFEND;
      FOREND;
      osp$set_status_abnormal (cmc$configuration_management_id, cme$iou_not_configured, iou_name, status);
    IFEND;
  PROCEND cmp$retrieve_iou_definition;

?? TITLE := '  cmp$return_descriptor_data', EJECT ??

*copy cmh$return_descriptor_data

  PROCEDURE [XDCL, #GATE] cmp$return_descriptor_data
    (    channel: cmt$physical_channel;
         iou_number: dst$iou_number;
         physical_equipment_number: cmt$physical_equipment_number;
         logical_unit_number: iot$logical_unit;
     VAR descriptor_data: ost$string;
     VAR pp_number: 0 .. 0ff(16));

?? NEWTITLE := '  append_string_data', EJECT ??

    PROCEDURE [INLINE] append_string_data
      (    string_data: string ( * <= 31));

      descriptor_data.value (index, * ) := string_data;

      WHILE (descriptor_data.value (index, 1) <> ' ') DO
        index := index + 1;
      WHILEND;

    PROCEND append_string_data;
?? OLDTITLE ??

    CONST
      null_name = '$NULL';

    VAR
      channel_type: dst$channel_protocol_type,
      channel_ordinal: cmt$channel_ordinal,
      pp_string: string (10),
      search_key: dmt$avt_search_key,
      recorded_vsn: rmt$recorded_vsn,
      avt_entry_not_found: boolean,
      all_elements_found: boolean,
      build_pp_string: boolean,
      length,
      index: integer,
      vsn: rmt$recorded_vsn,
      status: ost$status,
      channel_element,
      controller_element,
      logical_unit_element: ^cmt$element_definition,
      logical_pp_index: iot$pp_number,
      mainframe_name,
      channel_name,
      controller_name,
      iou_name: cmt$element_name,
      logical_unit_name: cmt$element_name,
      ct_port: cmt$controller_port_number,
      un_port: cmt$data_storage_port_number,
      valid: boolean;

    all_elements_found := FALSE;
    controller_name := osc$null_name;
    PUSH logical_unit_element;
    PUSH controller_element;
    PUSH channel_element;
    vsn := ' ';
    descriptor_data.value := ' ';
    descriptor_data.size := 0;

    cmp$convert_iou_number (iou_number, iou_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cmp$retrieve_logical_pp_index (channel, iou_number, cmv$logical_pp_table_p, logical_pp_index, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    cmp$pc_get_logical_unit (logical_unit_number, logical_unit_element, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    logical_unit_name := logical_unit_element^.element_name;

    /logical_unit_port_loop/
      FOR un_port := LOWERVALUE (un_port) TO UPPERVALUE (un_port) DO
        IF logical_unit_element^.storage_device.connection.port [un_port].configured THEN
          controller_name := logical_unit_element^.storage_device.connection.port [un_port].element_name;

          cmp$pc_get_element (controller_name, iou_name, controller_element, status);
          IF NOT status.normal THEN
            CYCLE /logical_unit_port_loop/;
          IFEND;
          IF controller_element^.element_type = cmc$controller_element THEN
            IF controller_element^.controller.physical_equipment_number = physical_equipment_number THEN

            /controller_port_loop/
              FOR ct_port := LOWERVALUE (ct_port) TO UPPERVALUE (ct_port) DO
                IF controller_element^.controller.connection.port [ct_port].configured THEN
                  channel_name := controller_element^.controller.connection.port [ct_port].element_name;
                  cmp$pc_get_element (channel_name, iou_name, channel_element, status);
                  IF NOT status.normal THEN
                    CYCLE /controller_port_loop/;
                  IFEND;
                  IF (channel_element^.data_channel.number = channel.number) AND
                        (channel_element^.data_channel.port = channel.port) AND
                        (channel_element^.data_channel.concurrent = channel.concurrent) THEN
                    mainframe_name := channel_element^.data_channel.mainframe_ownership;
                    all_elements_found := TRUE;
                    EXIT /logical_unit_port_loop/;
                  IFEND;
                IFEND;
              FOREND /controller_port_loop/;
            IFEND;
          ELSE { controller_element is in fact a Channel }
            controller_name := osc$null_name;
            channel_name := controller_element^.element_name;
            mainframe_name := controller_element^.data_channel.mainframe_ownership;
            all_elements_found := TRUE;
            IF (controller_element^.data_channel.number = channel.number) AND
                  (controller_element^.data_channel.port = channel.port) AND
                  (controller_element^.data_channel.concurrent = channel.concurrent) THEN
              EXIT /logical_unit_port_loop/;
            ELSE
              CYCLE /logical_unit_port_loop/;
            IFEND;
          IFEND;
        IFEND;
      FOREND /logical_unit_port_loop/;
      IF all_elements_found THEN
        IF (cmv$logical_unit_table^ [logical_unit_number].unit_interface_table^.unit_type >=
              ioc$lowest_disk_unit) AND (cmv$logical_unit_table^ [logical_unit_number].
              unit_interface_table^.unit_type <= ioc$highest_disk_unit) THEN  { element is a disk
          search_key.value := dmc$search_avt_by_lun;
          search_key.logical_unit_number := logical_unit_number;

          cmp$search_active_volume_table (search_key, recorded_vsn, avt_entry_not_found);
          IF NOT avt_entry_not_found THEN
            vsn := recorded_vsn;
          IFEND;
        ELSE {element is a tape
         /search_tusl_for_evsn/
          FOR index := LOWERBOUND (iov$tusl_p^) TO UPPERBOUND (iov$tusl_p^) DO
            IF (iov$tusl_p^ [index].element_name = logical_unit_name) AND
                  (iov$tusl_p^ [index].assignment_state <> ioc$not_assigned) THEN
              vsn := iov$tusl_p^ [index].evsn;
              EXIT /search_tusl_for_evsn/;
            IFEND;
          FOREND /search_tusl_for_evsn/;
        IFEND;
      ELSE
        logical_unit_name := null_name;
        cmp$convert_channel_number (channel.number, channel.concurrent, channel.port, channel_ordinal,
              channel_name, valid);
        cmp$pc_get_element (channel_name, iou_name, channel_element, status);
        IF status.normal THEN
          mainframe_name := channel_element^.data_channel.mainframe_ownership;
          IF channel_element^.data_channel.connection.equipment [physical_equipment_number].configured THEN
            controller_name := channel_element^.data_channel.connection.equipment [physical_equipment_number].
                  element_name;
          ELSE
            controller_name := null_name;
          IFEND;
        ELSE
          mainframe_name := null_name;
        IFEND;
      IFEND;
      index := 1;
      append_string_data (mainframe_name);
      append_string_data ('.');
      append_string_data (iou_name);
      build_pp_string := TRUE;
      IF channel.concurrent THEN
        channel_type := dsc$cpt_cio;
      ELSE
        channel_type := dsc$cpt_nio;
      IFEND;
      IF cmv$logical_pp_table_p^ [logical_pp_index].flags.resources_acquired THEN
        pp_number := cmv$logical_pp_table_p^ [logical_pp_index].pp_info.physical_pp.number;
      ELSE
        build_pp_string := FALSE;
      IFEND;

      IF build_pp_string THEN
        pp_string := '   ';
        STRINGREP (pp_string, length, pp_number);
        IF NOT channel.concurrent THEN
          append_string_data ('.PP ');
        ELSE
          append_string_data ('.CPP ');
        IFEND;
        append_string_data (pp_string (2, * ));
      ELSE
        append_string_data ('. ');
      IFEND;
      append_string_data ('. ');
      append_string_data (channel_name);
      IF controller_name <> osc$null_name THEN
        append_string_data ('. ');
        append_string_data (controller_name);
      IFEND;
      append_string_data ('. ');
      append_string_data (logical_unit_name);
      append_string_data ('* ');
      append_string_data (vsn);
      descriptor_data.size := index - 1;

  PROCEND cmp$return_descriptor_data;

MODEND cmm$configuration_interface_13d;
