?? RIGHT := 110 ??
?? NEWTITLE := ' NOS/VE File Server: log_side_door_port_status ', EJECT ??
MODULE dfm$log_side_door_port_status;

{
{  This module contains the processes which capture STORNET/ESM side
{  door port status and initiates generation of the system Engineering
{  Log entry.
{

?? TITLE := '    Global Definitions ', EJECT ??
*copyc cmp$execute_pp_program
*copyc cmp$get_channel_definition
*copyc cmp$get_element_information
*copyc cmp$get_iou_definition
*copyc cmp$idle_pp
*copyc cmp$release_element
*copyc cmp$reserve_element
*copyc dfe$error_condition_codes
*copyc dfi$log_display
*copyc dfp$log_sdp_data
*copyc dfp$return_esm_definition
*copyc dfp$return_esms_defined
*copyc pmp$get_mainframe_id
*copyc pmp$get_microsecond_clock
*copyc osp$await_activity_completion
*copyc osp$set_status_abnormal
*copyc osp$append_status_parameter
?? TITLE := '    Global Declarations ', EJECT ??
*copyc dfc$sdp_logging_error_codes
*copyc dft$descriptive_data_descriptor
*copyc dft$sdp_communication_buffer
*copyc dft$sdp_logging_code

?? TITLE := '    acquire_channel_for_sdpd ', EJECT ??

{
{ PURPOSE:
{ This procedure reserves the STORNET/ESM side door port channel from NOS/VE.
{

  PROCEDURE acquire_channel_for_sdpd
    (    current_port_in_definition: 1 .. cmc$max_side_door_port_number;
         stornet_esm_element_definition: cmt$esm_definition;
     VAR sdp_channel_reservation: array [1 .. 1] of cmt$element_reservation;
     VAR sdp_channel_reserved: boolean;
     VAR status: ost$status);

    sdp_channel_reserved := FALSE;

{
{ Build a channel descriptor of the STORNET/ESM side door port channel
{ element name.  This descriptor is used to acquire a channel resource
{ from NOSE/VE.
{

    sdp_channel_reservation [1].element_type := cmc$data_channel_element;
    sdp_channel_reservation [1].channel_descriptor.iou := stornet_esm_element_definition.
          side_door_port [current_port_in_definition].iou;
    sdp_channel_reservation [1].channel_descriptor.use_logical_identification := TRUE;
    sdp_channel_reservation [1].channel_descriptor.name := stornet_esm_element_definition.
          side_door_port [current_port_in_definition].element_name;
    cmp$reserve_element (sdp_channel_reservation, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    sdp_channel_reserved := TRUE;
  PROCEND acquire_channel_for_sdpd;
?? TITLE := '    acquire_pp_for_sdpd ', EJECT ??

{
{ PURPOSE:
{ This procedure reserves a PPU having access to the STORNET/ESM side door
{ port channel from NOS/VE.
{

  PROCEDURE acquire_pp_for_sdpd
    (    sdp_channel_definition: cmt$data_channel_definition;
     VAR sdp_pp_reservation: array [1 .. 1] of cmt$element_reservation;
     VAR sdp_pp_identification: cmt$pp_identification;
     VAR sdp_pp_reserved: boolean;
     VAR status: ost$status);

    sdp_pp_reserved := FALSE;

{
{ Build a channel descriptor for the STORNET/ESM side door port channel.
{ This descriptor is used to acquire a PP resource from NOSE/VE.
{

    sdp_pp_reservation [1].element_type := cmc$pp_element;
    sdp_pp_reservation [1].pp_reservation.selector := cmc$choose_pp_by_channel;
    sdp_pp_reservation [1].pp_reservation.channel.ordinal := sdp_channel_definition.ordinal;
    sdp_pp_reservation [1].pp_reservation.channel.iou := sdp_channel_definition.iou;
    cmp$reserve_element (sdp_pp_reservation, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    sdp_pp_identification := sdp_pp_reservation [1].pp_reservation.acquired_pp_identification;
    sdp_pp_reserved := TRUE;
  PROCEND acquire_pp_for_sdpd;
?? TITLE := '    await_activity_completion ', EJECT ??

{
{ Procedure AWAIT_ACTIVITY_COMPLETION is used to wait for SDPD driver
{ completion of side door port error log processing.  WAIT_LIMIT is used
{ to specify a time interval in milliseconds of how long the procedure
{ will wait before returning to its caller.  If the elapsed time during
{ which the procedure has been waiting for activity completion reaches
{ the value of this time interval, TIMEOUT is set to TRUE and the procedure
{ returns.
{
{ During the wait for activity completion, the procedure samples PP_STATUS
{ at periodic intervals.  The period of these intervals is specified in
{ milliseconds in WAIT_FIXED_QUERY_INTERVAL.  Between the queries of PP_STATUS
{ the CPU resource is released to the operating system.  If, at a given query,
{ PP_STATUS indicates that the activity is complete, the procedure returns
{ to its caller.
{
{ There are two ways an exit from the above timeout loop can occur:
{  1) condition tested is active or
{  2) timeout has occurred.
{

  PROCEDURE await_activity_completion
    (    communication_buffer_p: ^dft$sdp_communication_buffer;
     VAR descriptive_data_descriptor: dft$descriptive_data_descriptor;
     VAR status: ost$status);

    CONST
      wait_limit = 4000, { 4 seconds }
      fixed_wait_query_interval = 50; { 50 milliseconds }

    VAR
      ready_index: integer,
      running_time: integer,
      starting_time: integer,
      timeout: boolean,
      wait_list: array [1 .. 1] of ost$activity;

    wait_list [1].activity := osc$await_time;
    wait_list [1].milliseconds := fixed_wait_query_interval;
    pmp$get_microsecond_clock (starting_time, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{
{ Begin timeout of SDPD driver response to detect PP/SDPD driver hangs.
{

    timeout := FALSE;

  /timeout_loop/
    WHILE ((communication_buffer_p^.word_one.ppu_status = 0) AND (NOT timeout)) DO
      osp$await_activity_completion (wait_list, ready_index, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF communication_buffer_p^.word_one.ppu_status <> 0 THEN
        EXIT /timeout_loop/;
      IFEND;
      pmp$get_microsecond_clock (running_time, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF running_time < starting_time THEN
        starting_time := running_time;
        CYCLE /timeout_loop/;
      ELSEIF running_time - starting_time > wait_limit * 1000 THEN

{ No response from SDPD driver so assume a hang condition exits.

        descriptive_data_descriptor.symptom_code := dfc$sdp_no_sdpd_response;
        timeout := TRUE;
      IFEND;
    WHILEND /timeout_loop/;
  PROCEND await_activity_completion;
?? TITLE := '    build_descriptive_data_desc ', EJECT ??

  PROCEDURE build_descriptive_data_desc
    (    current_port_in_definition: 1 .. cmc$max_side_door_port_number;
         stornet_esm_element_definition: cmt$esm_definition;
     VAR descriptive_data_descriptor: dft$descriptive_data_descriptor);

{
{ Build a descriptive data descriptor to use in the generation of the
{ descriptive message portion in a statistic.
{

    descriptive_data_descriptor.mainframe := stornet_esm_element_definition.
          side_door_port [current_port_in_definition].mainframe_ownership;
    descriptive_data_descriptor.iou := stornet_esm_element_definition.
          side_door_port [current_port_in_definition].iou;
    descriptive_data_descriptor.pp := '0';
    descriptive_data_descriptor.ch := stornet_esm_element_definition.
          side_door_port [current_port_in_definition].element_name;
    descriptive_data_descriptor.element := stornet_esm_element_definition.element_name;
    descriptive_data_descriptor.product_id := stornet_esm_element_definition.product_id;
    descriptive_data_descriptor.symptom_code := dfc$sdp_no_initialization_error;
  PROCEND build_descriptive_data_desc;
?? TITLE := '    establish_sdpd_communications ', EJECT ??

{
{ PURPOSE:
{ This procedure is used to establish communications between the CPU and the
{ and the SDPD PP driver.  All communications are through the SDPD PP
{ Communication Buffer.
{

  PROCEDURE establish_sdpd_communications
    (    sdp_channel_definition: cmt$data_channel_definition;
         sdp_pp_identification: cmt$pp_identification;
     VAR sdpd_communications_p: ^SEQ ( * );
     VAR communication_buffer_p: ^dft$sdp_communication_buffer;
     VAR status: ost$status);

    CONST
      initialization_complete = 1;

    RESET sdpd_communications_p;
    NEXT communication_buffer_p IN sdpd_communications_p;
    IF communication_buffer_p = NIL THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$invalid_parameter_pva, 'communication_buffer_p',
            status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'establish_sdpd_communications', status);
      RETURN;
    IFEND;

{
{ Initialize the SDPD Communication Buffer used to communicate between the
{ CPU and PPU.  All data structures are explicitly reset.
{

    initialize_communication_buffer (sdp_channel_definition, sdp_pp_identification, communication_buffer_p,
          status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{
{ Inform SDPD that the CPU has completed its initialization of the SDPD
{ Communication Buffer and is ready to communicate via codes stored in
{ PPU_STATUS and is ready to receive side door port status.
{

    communication_buffer_p^.word_zero.cpu_status := initialization_complete;
  PROCEND establish_sdpd_communications;
?? TITLE := '    find_side_door_port_channel ', EJECT ??

{
{ PURPOSE:
{ Build a channel element descriptor for each STORNET/ESM channel element
{ name.  This descriptor is used to obtain side door port channel status.
{ Channel status is searched for the state of CMC$ON.
{

  PROCEDURE find_side_door_port_channel
    (    reason: dft$sdp_logging_code;
         current_port_in_definition: 1 .. cmc$max_side_door_port_number;
         host_mainframe_id: pmt$mainframe_id;
         stornet_esm_element_definition: cmt$esm_definition;
     VAR descriptive_data_descriptor: dft$descriptive_data_descriptor;
     VAR sdp_channel_definition: cmt$data_channel_definition;
     VAR side_door_port_channel_found: boolean;
     VAR status: ost$status);

    VAR
      sdp_channel_element_descriptor: cmt$element_descriptor,
      sdp_channel_element_information: array [1 .. 1] of cmt$element_info_item;

    side_door_port_channel_found := FALSE;

{
{ Build a channel element descriptor for each STORNET/ESM channel element
{ name.  This descriptor is used to obtain side door port channel status.
{

    IF ((stornet_esm_element_definition.side_door_port [current_port_in_definition].configured) AND
          (stornet_esm_element_definition.side_door_port [current_port_in_definition].mainframe_ownership =
          host_mainframe_id)) THEN
      build_descriptive_data_desc (current_port_in_definition, stornet_esm_element_definition,
            descriptive_data_descriptor);

{
{ Control is given to the following statements when a side door port channel
{ has been identified in upline connection information for the STORNET/ESM
{ element.
{

      sdp_channel_element_descriptor.element_type := cmc$data_channel_element;
      sdp_channel_element_descriptor.channel_descriptor.iou := stornet_esm_element_definition.
            side_door_port [current_port_in_definition].iou;
      sdp_channel_element_descriptor.channel_descriptor.use_logical_identification := TRUE;
      sdp_channel_element_descriptor.channel_descriptor.name :=
            stornet_esm_element_definition.side_door_port [current_port_in_definition].element_name;

{
{ Obtain channel status for each STORNET/ESM side door port channel element
{ name via a call to system interface CMP$GET_ELEMENT_INFORMATION.
{

      sdp_channel_element_information [1].selector := cmc$element_status;
      cmp$get_element_information (sdp_channel_element_descriptor, sdp_channel_element_information, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF ((sdp_channel_element_information [1].item_returned) AND
            (sdp_channel_element_information [1].element_status.state = cmc$on)) THEN
        get_sdp_channel_definition (current_port_in_definition, stornet_esm_element_definition,
              sdp_channel_definition, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        side_door_port_channel_found := TRUE;
      ELSE
        descriptive_data_descriptor.symptom_code := dfc$sdp_channel_incorrect_state;
        dfp$log_sdp_data (reason, NIL, descriptive_data_descriptor, status);
      IFEND;
    IFEND;
  PROCEND find_side_door_port_channel;
?? TITLE := '    get_pp_number ', EJECT ??

{
{ PURPOSE:
{ This procedure is used to convert a CMC$PP ordinal to a physical PP number.
{

  PROCEDURE get_pp_number
    (    sdp_pp_identification: cmt$pp_identification;
     VAR pp_number: ost$physical_pp_number;
     VAR pp_concurrent: boolean);

    CONST
      cio_pp_threshold_value = 20;

{
{ Convert a PP ordinal to a physical PP number.
{

    IF $INTEGER (sdp_pp_identification.ordinal) >= cio_pp_threshold_value + 10 THEN
      pp_number := $INTEGER (sdp_pp_identification.ordinal) - cio_pp_threshold_value + 6;
      pp_concurrent := TRUE;
    ELSEIF $INTEGER (sdp_pp_identification.ordinal) >= cio_pp_threshold_value THEN
      pp_number := $INTEGER (sdp_pp_identification.ordinal) - cio_pp_threshold_value;
      pp_concurrent := TRUE;
    ELSEIF $INTEGER (sdp_pp_identification.ordinal) > 9 THEN
      pp_number := $INTEGER (sdp_pp_identification.ordinal) + 6;
      pp_concurrent := FALSE;
    ELSE
      pp_number := $INTEGER (sdp_pp_identification.ordinal);
      pp_concurrent := FALSE;
    IFEND;
  PROCEND get_pp_number;
?? TITLE := '    get_sdp_channel_definition ', EJECT ??

{
{ PURPOSE:
{ This procedure is used to obatain a channel definition of the STORNET/ESM
{ side door port channel element name.
{

  PROCEDURE get_sdp_channel_definition
    (    current_port_in_definition: 1 .. cmc$max_side_door_port_number;
         stornet_esm_element_definition: cmt$esm_definition;
     VAR sdp_channel_definition: cmt$data_channel_definition;
     VAR status: ost$status);

    VAR
      sdp_channel_descriptor: cmt$channel_descriptor;

{
{ Build a channel descriptor of the STORNET/ESM side door port channel.
{

    sdp_channel_descriptor.iou := stornet_esm_element_definition.side_door_port [current_port_in_definition].
          iou;
    sdp_channel_descriptor.use_logical_identification := TRUE;
    sdp_channel_descriptor.name := stornet_esm_element_definition.side_door_port [current_port_in_definition].
          element_name;

{
{ Obtain a channel definition of the STORNET/ESM side door port channel
{ element name via a call to CMP$GET_CHANNEL_DEFINITION.
{

    cmp$get_channel_definition (sdp_channel_descriptor, sdp_channel_definition, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
  PROCEND get_sdp_channel_definition;
?? TITLE := '    get_stornet_esm_definition ', EJECT ??

{
{ PURPOSE:
{ This procedure is used to obtain side door port channel information for each
{ STORNET/ESM element name.
{

  PROCEDURE get_stornet_esm_definition
    (    current_element: integer;
         stornet_esm_element_names: dft$esms_defined;
     VAR stornet_esm_element_definition: cmt$esm_definition;
     VAR status: ost$status);

    VAR
      stornet_esm_element_descriptor: cmt$element_descriptor;

{
{ Build an element descriptor for each STORNET/ESM element name.  This
{ descriptor is used to obtain side door port channel information.
{

    stornet_esm_element_descriptor.element_type := cmc$communications_element;
    stornet_esm_element_descriptor.peripheral_descriptor.use_logical_identification := TRUE;
    stornet_esm_element_descriptor.peripheral_descriptor.element_name :=
          stornet_esm_element_names [current_element];

{
{ Obtain side door port channel information for each STORNET/ESM element name
{ via a call to system interface DFP$RETURN_ESM_DEFINITION.
{

    dfp$return_esm_definition (stornet_esm_element_descriptor, stornet_esm_element_definition, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
  PROCEND get_stornet_esm_definition;
?? TITLE := '    get_type_of_iou ', EJECT ??

{
{ PURPOSE:
{ This procedure is used to get the IOU definition for this mainframe.
{

  PROCEDURE get_type_of_iou
    (    sdp_pp_identification: cmt$pp_identification;
     VAR type_of_iou: 0 .. 1;
     VAR status: ost$status);

    CONST
      i0_iou = 0,
      all_other_ious = 1;

    VAR
      iou_definition: cmt$iou_definition;

    cmp$get_iou_definition (sdp_pp_identification.iou, iou_definition, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    IF iou_definition.kind = dsc$imn_i0_5x_model THEN
      type_of_iou := i0_iou;
    ELSE
      type_of_iou := all_other_ious;
    IFEND;
  PROCEND get_type_of_iou;
?? TITLE := '    initialize_communication_buffer ', EJECT ??

{
{ PURPOSE:
{ This procedure performs initialization of the SDPD Communication Buffer used
{ as the communication mechanism between the CPU and the PPU.  All data
{ structures are explicitly reset.
{

  PROCEDURE initialize_communication_buffer
    (    sdp_channel_definition: cmt$data_channel_definition;
         sdp_pp_identification: cmt$pp_identification;
     VAR communication_buffer_p: ^dft$sdp_communication_buffer;
     VAR status: ost$status);

    CONST
      iou0 = 0,
      iou1 = 1;

    VAR
      pp_concurrency: boolean,
      pp_number: ost$physical_pp_number,
      type_of_iou: 0 .. 1;

    get_pp_number (sdp_pp_identification, pp_number, pp_concurrency);
    get_type_of_iou (sdp_pp_identification, type_of_iou, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    communication_buffer_p^.word_zero.cpu_status := 0(16);
    communication_buffer_p^.word_zero.iou_type := type_of_iou;
    communication_buffer_p^.word_zero.channel_number := sdp_channel_definition.number;
    communication_buffer_p^.word_zero.reserved := 0(16);
    communication_buffer_p^.word_one.ppu_status := 0(16);
    IF pp_concurrency THEN
      communication_buffer_p^.word_one.concurrent_pp := 1;
    ELSE
      communication_buffer_p^.word_one.concurrent_pp := 0;
    IFEND;
    communication_buffer_p^.word_one.pp_number := pp_number;
    IF sdp_channel_definition.iou = 'IOU0' THEN
      communication_buffer_p^.word_one.iou_number := iou0;
    ELSE
      communication_buffer_p^.word_one.iou_number := iou1;
    IFEND;
    IF sdp_channel_definition.concurrent THEN
      communication_buffer_p^.word_one.concurrent_channel := 1;
    ELSE
      communication_buffer_p^.word_one.concurrent_channel := 0;
    IFEND;
    communication_buffer_p^.word_one.channel_number := sdp_channel_definition.number;
    communication_buffer_p^.word_two := 0(16);
    communication_buffer_p^.word_three := 0(16);
    communication_buffer_p^.word_four := 0(16);
    communication_buffer_p^.word_five := 0(16);
    communication_buffer_p^.word_six := 0(16);
    communication_buffer_p^.word_seven := 0(16);
    communication_buffer_p^.word_eight := 0(16);
    communication_buffer_p^.word_nine := 0(16);
    communication_buffer_p^.word_ten := 0(16);
    communication_buffer_p^.word_eleven := 0(16);
    communication_buffer_p^.word_twelve := 0(16);
    communication_buffer_p^.word_thirteen := 0(16);
    communication_buffer_p^.word_fourteen := 0(16);
    communication_buffer_p^.word_fifteen := 0(16);
    communication_buffer_p^.word_sixteen := 0(16);
    communication_buffer_p^.word_seventeen := 0(16);
    communication_buffer_p^.word_eighteen := 0(16);
  PROCEND initialize_communication_buffer;
?? TITLE := '    load_sdpd_into_ppu ', EJECT ??

{
{ PURPOSE:
{ This procedure is used to allocate a SDPD communication buffer and to load
{ SDPD into the acquired PPU resource.
{

  PROCEDURE load_sdpd_into_ppu
    (    sdp_pp_identification: cmt$pp_identification;
     VAR sdpd_communications_p: ^SEQ ( * );
     VAR sdpd_active: boolean;
     VAR status: ost$status);

    VAR
      sdpd_program_description: array [1 .. 1] of cmt$pp_program_description;

    sdpd_active := FALSE;

{
{ Build a SDPD driver program description for use in loading SDPD PP driver
{ into the PPU.
{

    sdpd_program_description [1].pp_identification := sdp_pp_identification;
    sdpd_program_description [1].iou_program_name := 'SDPD                           ';
    sdpd_program_description [1].pp_program := NIL;
    sdpd_program_description [1].master_pp := TRUE;
    sdpd_program_description [1].element_access := NIL;
    sdpd_program_description [1].communication_buffer_length := #SIZE (dft$sdp_communication_buffer);

{
{ Request NOS/VE to allocate a SDPD communication buffer and to load SDPD
{ into the acquired PPU and give control of the PPU to SDPD via a call
{ to system interface CMP$EXECUTE_PP_PROGRAM.
{

    cmp$execute_pp_program (sdpd_program_description, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    sdpd_communications_p := sdpd_program_description [1].communication_buffer;
    sdpd_active := TRUE;
  PROCEND load_sdpd_into_ppu;
?? TITLE := '    perform_side_door_port_clean_up ', EJECT ??

{
{ PURPOSE:
{ This procedure is used to perform SDPD PP driver clean-up for both normal
{ and abnormal cases.
{

  PROCEDURE perform_side_door_port_clean_up
    (    sdp_channel_reservation: array [1 .. 1] of cmt$element_reservation;
         sdp_pp_identification: cmt$pp_identification;
         sdp_pp_reservation: array [1 .. 1] of cmt$element_reservation;
     VAR sdpd_active: {input, output} boolean;
     VAR sdp_channel_reserved: {input, output} boolean;
     VAR sdp_pp_reserved: {input, output} boolean;
     VAR status: ost$status);

    VAR
      actual_pp_memory_size: cmt$pp_memory_length,
      ignore_status: ost$status,
      pp_registers: cmt$pp_registers,
      pp_software_idled: boolean;

{
{ Perform SDPD PP driver clean-up for both the normal and abnormal cases.
{

    IF sdpd_active THEN
      cmp$idle_pp (sdp_pp_identification, TRUE, TRUE, NIL, actual_pp_memory_size, pp_registers,
            pp_software_idled, ignore_status);
      sdpd_active := FALSE;
    IFEND;
    IF sdp_pp_reserved THEN
      cmp$release_element (sdp_pp_reservation, ignore_status);
      sdp_pp_reserved := FALSE;
    IFEND;
    IF sdp_channel_reserved THEN
      cmp$release_element (sdp_channel_reservation, ignore_status);
      sdp_channel_reserved := FALSE;
    IFEND;
  PROCEND perform_side_door_port_clean_up;
?? TITLE := '    [XDCL] dfp$log_side_door_port_status ', EJECT ??

{
{ PURPOSE:
{ This procedure is used to log STORNET/ESM side door port status to the
{ system Engineering Log.
{

  PROCEDURE [XDCL] dfp$log_side_door_port_status
    (    reason: dft$sdp_logging_code;
     VAR status: ost$status);

    VAR
      communication_buffer_p: ^dft$sdp_communication_buffer,
      current_element: integer,
      current_port_in_definition: 1 .. cmc$max_side_door_port_number,
      descriptive_data_descriptor: dft$descriptive_data_descriptor,
      host_mainframe_id: pmt$mainframe_id,
      ignore_status: ost$status,
      number_of_elements: dft$esms_defined_count,
      sdp_channel_definition: cmt$data_channel_definition,
      sdp_channel_reservation: array [1 .. 1] of cmt$element_reservation,
      sdp_channel_reserved: boolean,
      sdp_pp_identification: cmt$pp_identification,
      sdp_pp_reservation: array [1 .. 1] of cmt$element_reservation,
      sdp_pp_reserved: boolean,
      sdpd_active: boolean,
      sdpd_communications_p: ^SEQ ( * ),
      side_door_port_channel_found: boolean,
      stornet_esm_element_definition: cmt$esm_definition,
      stornet_esm_element_names: array [1 .. dfc$max_esms_defined] of cmt$element_name;

    sdp_channel_reserved := FALSE;
    sdp_pp_reserved := FALSE;
    sdpd_active := FALSE;
    side_door_port_channel_found := FALSE;

{
{ Obtain host mainframe identification.
{

    pmp$get_mainframe_id (host_mainframe_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{
{ Obtain STORNET/ESM element names.
{

    dfp$return_esms_defined (number_of_elements, stornet_esm_element_names);

{
{ Loop processing all STORNET/ESM element names on this mainframe.
{

  /process_stornet_esm_elements/
    FOR current_element := 1 TO number_of_elements DO
      get_stornet_esm_definition (current_element, stornet_esm_element_names, stornet_esm_element_definition,
            status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

{
{ Loop processing all side door port channels on this STORNET/ESM element
{ searching for a channel status state of CMC$ON.
{

    /process_side_door_port_channels/
      FOR current_port_in_definition := 1 TO cmc$max_side_door_port_number DO
        find_side_door_port_channel (reason, current_port_in_definition, host_mainframe_id,
              stornet_esm_element_definition, descriptive_data_descriptor, sdp_channel_definition,
              side_door_port_channel_found, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        IF side_door_port_channel_found THEN

{
{ Acquire the STORNET/ESM side door port channel from NOS/VE via a call to
{ system interface CMP$RESERVE_ELEMENT.
{

          acquire_channel_for_sdpd (current_port_in_definition, stornet_esm_element_definition,
                sdp_channel_reservation, sdp_channel_reserved, status);
          IF NOT status.normal THEN
            descriptive_data_descriptor.symptom_code := dfc$sdp_channel_unavailable;
            dfp$log_sdp_data (reason, NIL, descriptive_data_descriptor, ignore_status);
            CYCLE /process_side_door_port_channels/;
          IFEND;

{
{ Acquire a PP from NOS/VE such that the PP has access to the STORNET/ESM
{ side door port channel via a call to system interface CMP$RESERVE_ELEMENT.
{

          acquire_pp_for_sdpd (sdp_channel_definition, sdp_pp_reservation, sdp_pp_identification,
                sdp_pp_reserved, status);
          IF NOT status.normal THEN
            descriptive_data_descriptor.symptom_code := dfc$sdp_pp_unavailable;
            dfp$log_sdp_data (reason, NIL, descriptive_data_descriptor, ignore_status);
            perform_side_door_port_clean_up (sdp_channel_reservation, sdp_pp_identification,
                  sdp_pp_reservation, sdpd_active, sdp_channel_reserved, sdp_pp_reserved, ignore_status);
            CYCLE /process_side_door_port_channels/;
          IFEND;

{
{ Load SDPD driver into the PP acquired from NOS/VE and initiate execution
{ of SDPD.
{

          load_sdpd_into_ppu (sdp_pp_identification, sdpd_communications_p, sdpd_active, status);
          IF NOT status.normal THEN
            perform_side_door_port_clean_up (sdp_channel_reservation, sdp_pp_identification,
                  sdp_pp_reservation, sdpd_active, sdp_channel_reserved, sdp_pp_reserved, ignore_status);
            RETURN;
          IFEND;

{
{ Establish communications with SDPD via a communication protocol which
{ utilizes the SDPD Communication Buffer and involves the CPU_STATUS and
{ PPU_STATUS fields.
{

          establish_sdpd_communications (sdp_channel_definition, sdp_pp_identification, sdpd_communications_p,
                communication_buffer_p, status);
          IF NOT status.normal THEN
            perform_side_door_port_clean_up (sdp_channel_reservation, sdp_pp_identification,
                  sdp_pp_reservation, sdpd_active, sdp_channel_reserved, sdp_pp_reserved, ignore_status);
            RETURN;
          IFEND;

{
{ Wait for SDPD driver to complete side door port error log processing.
{ Begin timeout of SDPD driver to detect PP/driver hangs.
{

          await_activity_completion (communication_buffer_p, descriptive_data_descriptor, status);
          IF NOT status.normal THEN
            perform_side_door_port_clean_up (sdp_channel_reservation, sdp_pp_identification,
                  sdp_pp_reservation, sdpd_active, sdp_channel_reserved, sdp_pp_reserved, ignore_status);
            RETURN;
          IFEND;

{
{ Process SDPD driver completion status and create an entry in the System
{ Engineering Log via a call to DFP$LOG_SDP_DATA.
{

          dfp$log_sdp_data (reason, communication_buffer_p, descriptive_data_descriptor, status);
          IF NOT status.normal THEN
            perform_side_door_port_clean_up (sdp_channel_reservation, sdp_pp_identification,
                  sdp_pp_reservation, sdpd_active, sdp_channel_reserved, sdp_pp_reserved, ignore_status);
            RETURN;
          IFEND;

{
{ Perform log side door port status process clean-up (ie. idle the PP and
{ release the PPU and channel resource).
{

          perform_side_door_port_clean_up (sdp_channel_reservation, sdp_pp_identification, sdp_pp_reservation,
                sdpd_active, sdp_channel_reserved, sdp_pp_reserved, status);
        IFEND;
      FOREND /process_side_door_port_channels/;
    FOREND /process_stornet_esm_elements/;
  PROCEND dfp$log_side_door_port_status;
MODEND dfm$log_side_door_port_status;
