?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Deadstart : System Messages Logger' ??
MODULE dsm$log_system_messages;

{ PURPOSE:
{   This module contains procedures that log messages from the System Message buffer to the engineering log,
{   log errors from the DFT control block to the engineering log and it contains procedures that various
{   parts of the operating system call to log messages to the engineering log.
{
{ NOTES:
{   Different areas of the operating system have procedures in this module to log the data.  Each area has a
{   unique identifier at the beginning of the procedure name so that the different area's procedures can be
{   identified easily.  For example, all the code that deals with DFT has the identifier 'dft_', all the code
{   that deals with configuration management statistics has the identifier 'cm_'.  Follow this convention when
{   adding new procedures to this module.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cmc$logical_unit_constants
*copyc cml$channel_identification
*copyc cml$cm_identification
*copyc cml$connection_disabled
*copyc cml$cp_identification
*copyc cml$cpu_failure_data
*copyc cml$dft_cpu_failure_data
*copyc cml$dft_critical_failure_data
*copyc cml$dft_cyber_2000_error
*copyc cml$dft_hour_element_counters
*copyc cml$dft_hour_secded_id
*copyc cml$dft_iou_failure_data
*copyc cml$dft_memory_failure_data
*copyc cml$dft_non_crit_failure_data
*copyc cml$dft_page_map_failure_data
*copyc cml$dft_power_failure_data
*copyc cml$dft_top_of_hour
*copyc cml$element_disabled
*copyc cml$element_state_change
*copyc cml$environment_failure_data
*copyc cml$iou_failure_data
*copyc cml$iou_identification
*copyc cml$job_recovery_failure
*copyc cml$job_recovery_totals
*copyc cml$memory_failure_data
*copyc cml$ms_media_flaw_change
*copyc cml$ms_volume_initialization
*copyc cml$page_map_failure_data
*copyc cml$peripheral_identification
*copyc cml$pm_identification
*copyc cml$pp_hung
*copyc cml$pp_timed_out
*copyc cml$system_continuation
*copyc cml$system_deadstart_status
*copyc cml$system_error
*copyc cml$system_informative_message
*copyc cml$system_termination
*copyc cml$system_termination_init
*copyc cml$top_of_hour_counters
*copyc cml$top_of_hour_secded_id
*copyc cmt$physical_channel
*copyc dmt$flaw_dau_definition
*copyc dmt$log_flaw_init_data
*copyc dst$dft_analysis_code_constants
*copyc dst$log_ele_state_change
*copyc dst$log_hung_pp_data
*copyc dst$log_ms_volume_init
*copyc dst$log_pp_timed_out
*copyc dst$rb_logging_request
*copyc dst$signal_contents
*copyc dst$system_message_types
*copyc oss$mainframe_paged_literal
*copyc oss$task_shared
*copyc ost$cpu_definitions
*copyc ost$date_time
*copyc ost$global_task_id
*copyc ost$system_error_statistic
*copyc ost$system_flag
*copyc ost$terminate_continue_stats
*copyc pmt$signal
*copyc syt$180_idle_code
?? POP ??
*copyc clp$convert_integer_to_string
*copyc clp$put_job_command_response
*copyc cmp$convert_channel_number
*copyc cmp$convert_iou_number
*copyc cmp$get_element_state
*copyc cmp$pc_get_element
*copyc cmp$pc_get_logical_unit
*copyc dfp$any_sdp_defined
*copyc dfp$log_esm_data
*copyc dfp$log_side_door_port_status
*copyc dmp$get_logical_unit_number
*copyc dmp$get_physical_attributes
*copyc dsp$clear_sys_msg_buffer_in_rdf
*copyc dsp$close_rdf
*copyc dsp$get_integer_from_rdf
*copyc dsp$get_rdf_entry_seq_pointer
*copyc dsp$lock_unlock_window_from_mtr
*copyc dsp$log_sys_msg_help
*copyc dsp$manage_dftb_space_in_mfw
*copyc dsp$open_rdf
*copyc dsp$retrieve_mf_element_entry
*copyc dsp$retrieve_iou_information
*copyc dsp$retrieve_system_ds_status
*copyc dsp$set_record_errors_flag
*copyc dsp$store_integer_in_rdf
*copyc i#call_monitor
*copyc i#current_sequence_position
*copyc iop$log_disk_data
*copyc iop$log_tape_data
*copyc nap$reload_network_pp
*copyc ofp$send_operator_message_v1
*copyc osp$log_unformatted_status
*copyc pmp$cycle
*copyc pmp$format_compact_date
*copyc pmp$format_compact_time
*copyc pmp$get_mainframe_id
*copyc pmp$log_ascii
*copyc sfp$activate_system_statistic
*copyc sfp$emit_statistic
?? EJECT ??
*copyc cmv$logical_pp_table_p
*copyc cmv$physical_configuration
*copyc dsv$actual_deadstart_phase
*copyc dsv$automatic_pp_reload
*copyc dsv$cpu_pp_communication_block
*copyc dsv$dftb_data
*copyc dsv$record_errors
*copyc dsv$turn_dft_logging_off
*copyc jmv$executing_within_system_job
*copyc osv$180_memory_limits
*copyc osv$cpus_physically_configured
*copyc osv$page_size
*copyc osv$task_private_heap
*copyc syv$debug_job_recovery
*copyc syv$failure_reason_p
*copyc syv$file_rcv_failure_count
*copyc syv$recovery_failure_count
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
  CONST
    c$eid_register_number = 10(16),
    c$log_message_size = 62,

    { These constants describe the size of the variable 'dft_log_message'.  "NON" describes the non-specific
    { elements.

    c$number_of_iou = 0D(16),
    c$number_of_memory = 09(16),
    c$number_of_cpu = 32(16),
    c$number_of_page_map = 02(16),
    c$number_of_bad_requests = 09(16),
    c$number_of_packet = 07(16),
    c$number_of_software = 2C(16),
    c$number_of_non = 0A(16),
    c$number_of_dft_log_messages = c$number_of_iou + c$number_of_memory + c$number_of_cpu +
          c$number_of_page_map + c$number_of_bad_requests + c$number_of_packet + c$number_of_software +
          c$number_of_non,

    c$number_of_idle_log_messages = 11;

  TYPE
    t$dft_buffer_data = RECORD
      mrb_seq_p: ^SEQ ( * ),
      ssb_seq_p: ^SEQ ( * ),
      mdb_seq_p: ^SEQ ( * ),
      nrb_seq_p: ^SEQ ( * ),
    RECEND,

    t$hung_pp_message_type = (c$hpmt_null, c$hpmt_bad_status, c$hpmt_invalid_channel,
          c$hpmt_no_handshaking, c$hpmt_no_reload),

    { This is the type declaration for the constant messages for the log.

    t$ic_log_message_type = RECORD
      idle_code: syt$180_idle_code,
      value: string (c$log_message_size),
    RECEND,

    t$log_message_type = RECORD
      dft_analysis_code: dst$dftb_dft_analysis_code,
      value: string (c$log_message_size),
    RECEND,

    t$mainframe_name_type = RECORD
      size: 0 .. 31,
      value: string (31),
    RECEND,

    t$post_operator_actions = RECORD
      size: 0 .. ofc$max_operator_message_size,
      value: string (ofc$max_operator_message_size),
    RECEND,

    { This is the type declaration for the constant state messages for the log.  This information can be
    { obtained from the deck cml$element_state_change.

    t$state_counter_value = 0 .. 6,

    t$state_log_message_type = RECORD
      value: string (c$log_message_size),
      counter_value: t$state_counter_value,
    RECEND;
?? EJECT ??

  VAR

    { This variable contains the constant log messages for the messages created from the dft errors and from
    { system detected errors that have a dft analysis code described in dst$dft_analysis_code_constants.  IF
    { new error codes are added, the following decks must be changed.  This deck and CTI$DFT_ANALYSIS_CODES
    { and DST$DFT_ANALYSIS_CODE_CONSTANTS and DUM$PROCESS_DFT_BUFFER_COMMAND.

    v$dft_log_message: [READ, oss$mainframe_paged_literal] ARRAY [1 .. c$number_of_dft_log_messages]
          OF t$log_message_type :=
      { IOU }
          [[dsc$dftb_dac_iou_001, '*DEADSTART ERROR LOG IOU ERROR'],
           [dsc$dftb_dac_iou_002, '*EXPRESS DEADSTART DUMP IOU ERROR'],
           [dsc$dftb_dac_iou_003, '*CORRECTED IOU ERROR'],
           [dsc$dftb_dac_iou_004, '*UNCORRECTED IOU ERROR (PP HALT)'],
           [dsc$dftb_dac_iou_005, '*12/16 IOU CONVERSION ERROR'],
           [dsc$dftb_dac_iou_006, '*FATAL IOU ERROR (NOT PP HALT)'],
           [dsc$dftb_dac_iou_007, '*IOU CHANNEL ERROR'],
           [dsc$dftb_dac_iou_008, '*FATAL IOU ERROR (NOT PP HALT)'],
           [dsc$dftb_dac_iou_009, '*UNCORRECTED IOU ERROR (PP HALT)'],
           [dsc$dftb_dac_iou_00A, '*12/16 IOU CONVERSION ERROR'],
           [dsc$dftb_dac_iou_00B, '*IOU CHANNEL ERROR'],
           [dsc$dftb_dac_iou_00C, '*IOU SS BIT 57 CONDITION'],
           [dsc$dftb_dac_iou_0FF, '*HARDWARE ERROR'],
      { MEMORY }
           [dsc$dftb_dac_mem_101, '*DEADSTART ERROR LOG MEMORY ERROR'],
           [dsc$dftb_dac_mem_102, '*EXPRESS DEADSTART DUMP MEMORY ERROR'],
           [dsc$dftb_dac_mem_103, '*CORRECTED MEMORY ERROR'],
           [dsc$dftb_dac_mem_104, '*UNCORRECTED MEMORY ERROR'],
           [dsc$dftb_dac_mem_105, '*FATAL CM ERROR (MULTIPLE ODD BIT ERROR)'],
           [dsc$dftb_dac_mem_106, '*FATAL CM ERROR (PARTIAL WRITE PARITY ERROR)'],
           [dsc$dftb_dac_mem_107, '*RESERVED FOR FUTURE USE'],
           [dsc$dftb_dac_mem_108, '*UNCORRECTED MEMORY BOARD LEVEL ERROR'],
           [dsc$dftb_dac_mem_109, '*UNCORRECTED MEMORY INTERFACE ERROR'],
      { CPU }
           [dsc$dftb_dac_cpu_201, '*DEADSTART ERROR LOG PROCESSOR ERROR'],
           [dsc$dftb_dac_cpu_202, '*EXPRESS DEADSTART DUMP PROCESSOR ERROR'],
           [dsc$dftb_dac_cpu_203, '*CORRECTED PROCESSOR ERROR'],
           [dsc$dftb_dac_cpu_204, '*UNCORRECTED PROCESSOR ERROR'],
           [dsc$dftb_dac_cpu_205, '*RETRY IN PROGRESS'],
           [dsc$dftb_dac_cpu_206, '*SOFT CONTROL MEMORY RELOAD'],
           [dsc$dftb_dac_cpu_207, '*UNSUCCESSFUL SOFT CONTROL MEMORY RELOAD'],
           [dsc$dftb_dac_cpu_208, '*FATAL CPU HALT CLASS 1'],
           [dsc$dftb_dac_cpu_209, '*CPU ERROR EXIT MODE 20'],
           [dsc$dftb_dac_cpu_20A, '*CPU ERROR EXIT MODE 67'],
           [dsc$dftb_dac_cpu_20B, '*FATAL CPU RECOVERY ERROR'],
           [dsc$dftb_dac_cpu_20C, '*CORRECTED PROCESSOR ERROR WITH CACHE RELOAD'],
           [dsc$dftb_dac_cpu_20D, '*FATAL CPU UNCORRECTED ERROR'],
           [dsc$dftb_dac_cpu_20E, '*FATAL CPU ERROR (DUE THRESHOLD EXCEEDED)'],
           [dsc$dftb_dac_cpu_20F, '*FATAL C170 STATE DUE'],
           [dsc$dftb_dac_cpu_210, '*FATAL C170 STATE EXIT MODE HALT'],
           [dsc$dftb_dac_cpu_211, '*FATAL MONITOR DUE'],
           [dsc$dftb_dac_cpu_212, '*FATAL MONITOR ERROR'],
           [dsc$dftb_dac_cpu_213, '*FATAL MONITOR MCR'],
           [dsc$dftb_dac_cpu_214, '*FATAL EI DUE'],
           [dsc$dftb_dac_cpu_215, '*FATAL MCH ERROR'],
           [dsc$dftb_dac_cpu_216, '*FATAL JOB ERROR'],
           [dsc$dftb_dac_cpu_217, '*FATAL JOB MCR'],
           [dsc$dftb_dac_cpu_218, '*FATAL CPU N ERROR'],
           [dsc$dftb_dac_cpu_219, '*FORCED UNCORRECTED ERROR'],
           [dsc$dftb_dac_cpu_21A, '*FATAL CPU HALT CLASS 2'],
           [dsc$dftb_dac_cpu_21B, '*RETRY CONVERTED TO UNCORRECTED ERROR'],
           [dsc$dftb_dac_cpu_21C, '*RETRY EXHAUSTED'],
           [dsc$dftb_dac_cpu_21D, '*HOURLY RETRY THRESHOLD EXCEEDED'],
           [dsc$dftb_dac_cpu_21E, '*PARTIAL WRITE ADDRESS PARITY ERROR'],
           [dsc$dftb_dac_cpu_21F, '*FATAL CPU ERROR (UNABLE TO EXCHANGE OR TRAP)'],
           [dsc$dftb_dac_cpu_220, '*FATAL CPU ERROR (PROCESS DAMAGED IN MTR MODE)'],
           [dsc$dftb_dac_cpu_221, '*FATAL CPU ERROR (DUE WITH MICROCODE HALT)'],
           [dsc$dftb_dac_cpu_222, '*FATAL CPU ERROR (NO ERROR BITS PRESENT IN STATUS SUMMARY)'],
           [dsc$dftb_dac_cpu_223, '*FATAL CPU ERROR (CONTROL STORE RELOAD FAILED)'],
           [dsc$dftb_dac_cpu_224, '*FATAL CPU ERROR (RETRIES EXHAUSTED)'],
           [dsc$dftb_dac_cpu_225, '*FATAL CPU ERROR (HALT TIMEOUT)'],
           [dsc$dftb_dac_cpu_226, '*FATAL CPU ERROR (UNEXPECTED MICROCODE HALT ADDRESS)'],
           [dsc$dftb_dac_cpu_227, '*UNCORRECTED CPU ERROR (EXCHANGE VECTOR)'],
           [dsc$dftb_dac_cpu_228, '*UNCORRECTED CPU ERROR (TRAP VECTOR)'],
           [dsc$dftb_dac_cpu_229, '*UNCORRECTED CPU ERROR (HALT VECTOR)'],
           [dsc$dftb_dac_cpu_22A, '*CLOCK ERROR'],
           [dsc$dftb_dac_cpu_22B, '*FATAL CONTROL STORE ERROR (JOB MODE)'],
           [dsc$dftb_dac_cpu_22C, '*FATAL CONTROL STORE ERROR (MONITOR MODE)'],
           [dsc$dftb_dac_cpu_22D, '*CORRECTED CPU ERROR (RETRY SUCCESSFUL)'],
           [dsc$dftb_dac_cpu_22E, '*FATAL CPU MICROCODE PARITY ERROR'],
           [dsc$dftb_dac_cpu_22F, '*NEGATIVE SIT CONDITION'],
           [dsc$dftb_dac_cpu_230, '*CPU MAC HANG'],
           [dsc$dftb_dac_cpu_231, '*CPU/MEM DEADMAN TIMEOUT'],
           [dsc$dftb_dac_cpu_232, '*CPU VECTOR DEGRADE'],
      { PAGE MAP }
           [dsc$dftb_dac_map_301, '*CORRECTED PAGE MAP ERROR'],
           [dsc$dftb_dac_map_302, '*UNCORRECTED PAGE MAP ERROR'],
      { BAD REQUESTS TO DFT }
           [dsc$dftb_dac_req_401, '*BAD RESPONSE TO AN OS REQUEST'],
           [dsc$dftb_dac_req_402, '*DFT LOGGED PROCESSOR FAILURE MESSAGE'],
           [dsc$dftb_dac_req_403, '*ERROR UPDATING THE ECR RECORD'],
           [dsc$dftb_dac_req_404, '*ERRONEOUS BIT 59 SET AND NO ERROR DETECTED'],
           [dsc$dftb_dac_req_405, '*TRANSIENT BIT 59 CONDITION'],
           [dsc$dftb_dac_req_406, '*ERROR PROCESSING THE ECR RECORD IN AN ERROR CONDITION'],
           [dsc$dftb_dac_req_407, '*EPM BOARD ERROR DATA'],
           [dsc$dftb_dac_req_408, '*EPM SYSTEM ERROR DATA'],
           [dsc$dftb_dac_req_40A, '*NEGATIVE SIT CONDITION'],
      { PACKET COMMUNICATION }
           [dsc$dftb_dac_pac_501, '*BAD PACKET RESPONSE'],
           [dsc$dftb_dac_pac_502, '*PACKET SEQUENCE NUMBER MISMATCH'],
           [dsc$dftb_dac_pac_503, '*BAD PACKET PHASE IN DFT'],
           [dsc$dftb_dac_pac_504, '*DFT/2AP INTERFACE ERROR'],
           [dsc$dftb_dac_pac_505, '*PACKET TIMEOUT CONDITION'],
           [dsc$dftb_dac_pac_507, '*PACKET REQUEST QUEUE FULL REQUEST IGNORED'],
           [dsc$dftb_dac_pac_5FF, '*SERVICE PROCESSOR INTERNAL ERROR'],
      { SOFTWARE }
           [dsc$dftb_dac_sof_601, '*SCI NOT RESPONDING'],
           [dsc$dftb_dac_sof_602, '*DFT NOT RESPONDING'],
           [dsc$dftb_dac_sof_603, '*CHANNEL 17 PARITY ERROR'],
           [dsc$dftb_dac_sof_604, '*CHANNEL 17 INTERLOCK ERROR'],
           [dsc$dftb_dac_sof_605, '*CHANNEL 17 ACTIVE'],
           [dsc$dftb_dac_sof_606, '*RESERVED'],
           [dsc$dftb_dac_sof_607, '*DFT REGISTER NUMBER NOT IN THE MRB'],
           [dsc$dftb_dac_sof_608, '*DFT MAINFRAME IDENTIFICATION ERROR'],
           [dsc$dftb_dac_sof_609, '*DFT PROCESSOR TYPE ERROR'],
           [dsc$dftb_dac_sof_60A, '*DFT FATAL STACK'],
           [dsc$dftb_dac_sof_60B, '*DFT BUILD REGISTER LIST SIZE ERROR'],
           [dsc$dftb_dac_sof_60C, '*PP LOAD ERROR'],
           [dsc$dftb_dac_sof_60D, '*170 MTR MCR FAULT - DETECTED BY EI'],
           [dsc$dftb_dac_sof_60E, '*BAD SYSTEM REQUEST - DETECTED BY EI'],
           [dsc$dftb_dac_sof_60F, '*CHANNEL 17 INACTIVE'],
           [dsc$dftb_dac_sof_610, '*SCI PRESET FAILURE'],
           [dsc$dftb_dac_sof_611, '*SCI LOADED IN PP 0'],
           [dsc$dftb_dac_sof_612, '*DFT ELEMENT DESCRIPTOR NOT IN MRT'],
           [dsc$dftb_dac_sof_613, '*DFT COMM FAILURE'],
           [dsc$dftb_dac_sof_614, '*DFT INCOMPATIBLE VERSION'],
           [dsc$dftb_dac_sof_615, '*SCI TABLE SIZE TOO SMALL'],
           [dsc$dftb_dac_sof_616, '*WALL CLOCK CHIP READ ERROR'],
           [dsc$dftb_dac_sof_617, '*NOS/VE MONITOR NOT RESPONDING'],
           [dsc$dftb_dac_sof_618, '*NO PP AVAILABLE FOR DFT'],
           [dsc$dftb_dac_sof_619, '*REGISTER LIST LENGTH GREATER THEN POINTER VALUE'],
           [dsc$dftb_dac_sof_61A, '*DFT IOU FIELD PROCESSING ERROR'],
           [dsc$dftb_dac_sof_61B, '*DFT NOT FOUND IN CIP DIRECTORY'],
           [dsc$dftb_dac_sof_61C, '*DFT SECONDARY BUFFER ERROR'],
           [dsc$dftb_dac_sof_61D, '*PRIMARY BUFFER ALLOCATION ERROR'],
           [dsc$dftb_dac_sof_61E, '*DFT INTERNAL ERROR'],
           [dsc$dftb_dac_sof_61F, '*DFT CANNOT FIND COUNTER VALUE'],
           [dsc$dftb_dac_sof_620, '*DFT CANNOT FIND THRESHOLD VALUE'],
           [dsc$dftb_dac_sof_621, '*DFT DISK STATUS LENGTH EXCEEDED'],
           [dsc$dftb_dac_sof_622, '*SCI DETECTED DFT ERROR WHILE LOADING SSR'],
           [dsc$dftb_dac_sof_623, '*SCI DETECTED DFT ERROR WHILE LOADING VCB'],
           [dsc$dftb_dac_sof_624, '*SCI DETECTED DFT ERROR WHILE HALTING 170 PROCESSOR'],
           [dsc$dftb_dac_sof_625, '*SCI DETECTED DFT ERROR WHILE STARTING VIRTUAL CPU'],
           [dsc$dftb_dac_sof_626, '*SCI DETECTED DFT ERROR WHILE IDLING SECONDARY IOU'],
           [dsc$dftb_dac_sof_627, '*SCI DETECTED DFT ERROR WHILE HALTING VIRTUAL CPU'],
           [dsc$dftb_dac_sof_628, '*SCI DETECTED DFT ERROR WHILE STARTING 170 CPU'],
           [dsc$dftb_dac_sof_629, '*SCI DETECTED DFT ERROR WHILE GETTING ELEMENT DESCR'],
           [dsc$dftb_dac_sof_62A, '*SCI DETECTED DFT NEVER SET VERIFIED FLAG'],
           [dsc$dftb_dac_sof_62B, '*SCI DETECTED DFT SET BUFFER REJECT FLAG'],
           [dsc$dftb_dac_sof_6FF, '*SERVICE PROCESSOR EXECUTIVE ERROR'],
      { OTHER }
           [dsc$dftb_dac_non_701, '*ENVIRONMENT WARNING'],
           [dsc$dftb_dac_non_702, '*LONG POWER WARNING'],
           [dsc$dftb_dac_non_703, '*SHORT POWER WARNING'],
           [dsc$dftb_dac_non_704, '*ENVIRONMENT WARNING CLEAR'],
           [dsc$dftb_dac_non_705, '*LONG POWER WARNING CLEAR'],
           [dsc$dftb_dac_non_706, '*SHORT POWER WARNING CLEAR'],
           [dsc$dftb_dac_non_707, '*TOP OF HOUR MAINFRAME ELEMENT COUNTERS BUFFER'],
           [dsc$dftb_dac_non_708, '*TOP OF HOUR SECDED ID TABLE'],
           [dsc$dftb_dac_non_709, '*LONG POWER WARNING'],
           [dsc$dftb_dac_non_70A, '*LONG POWER WARNING CLEAR']],

    { This variable contains the constant log messages for the system commands: IDLE_SYSTEM, RESUME_SYSTEM,
    { STEP_SYSTEM, UNSTEP_SYSTEM, TERMINATE_SYSTEM.

    v$ic_log_message: [READ, oss$mainframe_paged_literal] ARRAY [1 .. c$number_of_idle_log_messages]
          OF t$ic_log_message_type :=
          [[syc$ic_null,                 ''],
           [syc$ic_system_terminated,    '*Reason: System TERMINATED via OPERATOR COMMAND'],
           [syc$ic_fatal_hardware_error, '*Reason: System ABORTED due to HARDWARE FAILURE'],
           [syc$ic_fatal_software_error, '*Reason: System ABORTED due to SOFTWARE FAILURE'],
           [syc$ic_long_power,           '*Reason: System IDLED due to LONG POWER WARNING'],
           [syc$ic_hardware_idle,        '*Reason: System IDLED due to HARDWARE_IDLE'],
           [syc$ic_idle_command,         '*Reason: System IDLED via OPERATOR COMMAND'],
           [syc$ic_step_command,         '*Reason: System STEPPED via OPERATOR COMMAND'],
           [syc$ic_short_power,          '*Reason: System STEPPED due to SHORT POWER WARNING'],
           [syc$ic_disk_error,           '*Reason: System STEPPED due to DISK ERROR'],
           [syc$ic_software_breakpoint,  '*Reason: System STEPPED due to SOFTWARE SELECTED BREAKPOINT']],

    v$mainframe_name: [STATIC, oss$task_shared] t$mainframe_name_type := [0, ''],

    v$post_operator_actions: [READ, oss$mainframe_paged_literal] ARRAY [dst$signal_poa_kinds] OF
          t$post_operator_actions :=
          [[37, ' The Service Processor has timed out.'],
           [61, ' A change has occurred in the mainframe hardware environment.'],
           [54, ' The System has downed a CPU due to hardware problems.']],

    v$post_operator_actions_part_2: [READ, oss$mainframe_paged_literal] t$post_operator_actions :=
          [90, '  Please contact a CDC Customer Engineer to determine if a maintenance action is required.'],

    { This variable contains the constant log messages for the message created when an element
    { state change occurs.  This information can be obtained from the deck cml$element_state_change.

    v$state_log_message: [READ, oss$mainframe_paged_literal] ARRAY [cmt$element_state] OF
          ARRAY [cmt$element_state] OF t$state_log_message_type :=
     {cmc$on to cmc$on}    [[['*STATE CHANGED FROM ON TO ON',     0],
     {cmc$on to cmc$off}     ['*STATE CHANGED FROM ON TO OFF',    2],
     {cmc$on to cmc$down}    ['*STATE CHANGED FROM ON TO DOWN',   1]],

     {cmc$off to cmc$on}    [['*STATE CHANGED FROM OFF TO ON',    5],
     {cmc$off to cmc$off}    ['*STATE CHANGED FROM OFF TO OFF',   0],
     {cmc$off to cmc$down}   ['*STATE CHANGED FROM OFF TO DOWN',  6]],

     {cmc$down to cmc$on}   [['*STATE CHANGED FROM DOWN TO ON',   3],
     {cmc$down to cmc$off}   ['*STATE CHANGED FROM DOWN TO OFF',  4],
     {cmc$down to cmc$down}  ['*STATE CHANGED FROM DOWN TO DOWN', 0]]];
?? OLDTITLE ??
?? NEWTITLE := 'access_logging_routines', EJECT ??

{ PURPOSE:
{   This procedure calls the appropriate logging routine.

  PROCEDURE access_logging_routines
    (    message_header: dst$system_message_header;
     VAR message_data_p: ^SEQ ( * ));

    VAR
      ignore_status: ost$status,
      message_type_p: ^integer,
      msg_to_log_size: integer,
      sys_msg_to_log_p: ^SEQ ( * );

    RESET message_data_p;
    CASE message_header.message_type OF
    = dsc$disk_errors =
      iop$log_disk_data (message_data_p, ignore_status);
    = dsc$tape_errors =
      iop$log_tape_data (message_data_p, ignore_status);
    = dsc$fs_stornet_errors =
      dfp$log_esm_data (message_data_p, ignore_status);
    = dsc$system_continuation, dsc$system_termination =
      dsp$log_system_message (cml$system_continuation, message_data_p, ignore_status);
    = dsc$general_system_message, dsc$general_du_error =
      IF #SIZE (message_data_p^) > 8 THEN
        NEXT message_type_p IN message_data_p;
        msg_to_log_size := message_header.message_size - #SIZE (message_type_p^);
        IF msg_to_log_size > 0 THEN
          NEXT sys_msg_to_log_p: [[REP msg_to_log_size OF cell]] IN message_data_p;
          dsp$log_system_message (message_type_p^, sys_msg_to_log_p, ignore_status);
        IFEND;
      IFEND;
    ELSE
    CASEND;

  PROCEND access_logging_routines;
?? OLDTITLE ??
?? NEWTITLE := 'cm_channel_identification', EJECT ??

{ PURPOSE:
{   This procedure is called to log the identity of a channel on the mainframe being initialized.
{   The format of the log message is described in the deck cml$channel_identification.

  PROCEDURE cm_channel_identification
    (VAR status: ost$status);

    VAR
      channel: cmt$physical_channel,
      counters_p: sft$counters,
      ignore_status: ost$status,
      message: ost$string,
      number_string: ost$string,
      pc_index: integer,
      temp_string: ost$string;

    status.normal := TRUE;
    PUSH counters_p: [1 .. 2];

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

        { If the physical configuration is a channel then log the data.

        message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
        message.size := v$mainframe_name.size;

        { Retrieve the IOU name associated with the channel.

        message.value ((message.size + 1), 1) := '.';
        message.size := message.size + 1;
        temp_string.value := cmv$physical_configuration^ [pc_index].data_channel.iou;
        set_string_length (temp_string);
        message.value ((message.size + 1), temp_string.size) := temp_string.value;
        message.size := message.size + temp_string.size;

        { Retrieve the channel name.

        channel.number := cmv$physical_configuration^ [pc_index].data_channel.number;
        channel.concurrent := cmv$physical_configuration^ [pc_index].data_channel.concurrent;
        channel.port := cmv$physical_configuration^ [pc_index].data_channel.port;
        clp$convert_integer_to_string (channel.number, 10, FALSE, number_string, ignore_status);

        IF NOT channel.concurrent THEN

          { The channel is a non-concurrent channel.

          message.value ((message.size + 1), 3) := '.CH';
          message.size := message.size + 3;
          message.value ((message.size + 1), number_string.size) := number_string.value;
          message.size := message.size + number_string.size;
          counters_p^ [1] := channel.number;

        ELSE

          { The channel is a concurrent channel.

          message.value ((message.size + 1), 4) := '.CCH';
          message.size := message.size + 4;
          message.value ((message.size + 1), number_string.size) := number_string.value;
          message.size := message.size + number_string.size;
          counters_p^ [1] := channel.number + 100(8);   { Set bit 57 to indicate concurrent channel

          IF channel.port = cmc$port_a THEN

            { The port of the concurrent channel is port A.

            message.value ((message.size + 1), 1) := 'A';
            message.size := message.size + 1;

          ELSEIF channel.port = cmc$port_b THEN

            { The port of the concurrent channel is port B.

            message.value ((message.size + 1), 1) := 'B';
            message.size := message.size + 1;

          IFEND;

        IFEND;

        { Retrieve the type of channel.

        message.value ((message.size + 1), 1) := '*';
        message.size := message.size + 1;
        CASE cmv$physical_configuration^ [pc_index].data_channel.kind OF
        = cmc$170_channel =
          message.value ((message.size + 1), 3) := '170';
          message.size := message.size + 3;
          counters_p^ [2] := 1;
        = cmc$isi_channel =
          message.value ((message.size + 1), 3) := 'ISI';
          message.size := message.size + 3;
          counters_p^ [2] := 2;
        = cmc$ici_channel =
          message.value ((message.size + 1), 3) := 'ICI';
          message.size := message.size + 3;
          counters_p^ [2] := 3;
        = cmc$ipi_channel =
          message.value ((message.size + 1), 3) := 'IPI';
          message.size := message.size + 3;
          counters_p^ [2] := 4;
        ELSE
          message.value ((message.size + 1), 7) := 'UNKNOWN';
          message.size := message.size + 7;
          counters_p^ [2] := 0;
        CASEND;

        { Log the message to the engineering log.

        sfp$emit_statistic (cml$channel_identification, message.value (1, message.size), counters_p, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      IFEND;
    FOREND;

  PROCEND cm_channel_identification;
?? OLDTITLE ??
?? NEWTITLE := 'cm_cm_identification', EJECT ??

{ PURPOSE:
{   This procedure is called to log the identity of central memory on the mainframe being
{   initialized.  The format of the log message is described in the deck cml$cm_identification.

  PROCEDURE cm_cm_identification
    (VAR status: ost$status);

    VAR
      counters_p: sft$counters,
      element_entry: dst$mf_element_table_entry,
      message: ost$string;

    status.normal := TRUE;
    PUSH counters_p: [1 .. 4];

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;
    message.value ((message.size + 1), 15) := '.CENTRAL_MEMORY';
    message.size := message.size + 15;

{ Retrieve the Memory element entry.
    dsp$retrieve_mf_element_entry (0, dsc$dftb_eid_memory_element, element_entry, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Construct the statistic from the mainframe element information.
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), element_entry.model_number_string.size) :=
          element_entry.model_number_string.value;
    message.size := message.size + element_entry.model_number_string.size;

    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), element_entry.serial_number_string.size) :=
          element_entry.serial_number_string.value;
    message.size := message.size + element_entry.serial_number_string.size;

{Build the Counters
    counters_p^ [1] := osv$180_memory_limits.lower;
    counters_p^ [2] := osv$180_memory_limits.deadstart_upper;
    counters_p^ [3] := osv$180_memory_limits.upper;
    counters_p^ [4] := osv$page_size;

{ Log the message to the engineering log.
    sfp$emit_statistic (cml$cm_identification, message.value (1, message.size), counters_p, status);

  PROCEND cm_cm_identification;
?? OLDTITLE ??
?? NEWTITLE := 'cm_cp_identification', EJECT ??

{ PURPOSE:
{   This procedure is called to log the identity of a central processor on the mainframe being
{   initialized.  The format of the log message is described in the deck cml$cp_identification.

  PROCEDURE cm_cp_identification
    (VAR status: ost$status);

    VAR
      cpu_index: ost$logical_processor_id,
      element_entry: dst$mf_element_table_entry,
      ignore_status: ost$status,
      message: ost$string,
      number_string: ost$string;

    status.normal := TRUE;

    FOR cpu_index := 0 TO (osv$cpus_physically_configured - 1) DO

      message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
      message.size := v$mainframe_name.size;
      message.value ((message.size + 1), 3) := '.CP';
      message.size := message.size + 3;
      clp$convert_integer_to_string (cpu_index, 10, FALSE, number_string, ignore_status);
      message.value ((message.size + 1), number_string.size) := number_string.value;
      message.size := message.size + number_string.size;

      { Retrieve the CPU element entry.

      dsp$retrieve_mf_element_entry (cpu_index, dsc$dftb_eid_cpu0_element, element_entry, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      { Construct the statistic from the mainframe element information.

      message.value ((message.size + 1), 1) := '*';
      message.size := message.size + 1;
      message.value ((message.size + 1), element_entry.model_number_string.size) :=
            element_entry.model_number_string.value;
      message.size := message.size + element_entry.model_number_string.size;

      message.value ((message.size + 1), 1) := '*';
      message.size := message.size + 1;
      message.value ((message.size + 1), element_entry.serial_number_string.size) :=
            element_entry.serial_number_string.value;
      message.size := message.size + element_entry.serial_number_string.size;

      { Log the message to the engineering log.

      sfp$emit_statistic (cml$cp_identification, message.value (1, message.size), NIL, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    FOREND;

  PROCEND cm_cp_identification;
?? OLDTITLE ??
?? NEWTITLE := 'cm_element_state_change', EJECT ??

{ PURPOSE:
{   This procedure is called to log the change in the state of a system hardware element.
{   The format of the log message is described in the deck cml$element_state_change.

  PROCEDURE cm_element_state_change
    (VAR log_data_p: ^SEQ( * );
     VAR status: ost$status);

    VAR
      counters_p: sft$counters,
      message: ost$string,
      message_data_p: ^dst$log_ele_state_change,
      temp_string: ost$string;

    status.normal := TRUE;
    RESET log_data_p;
    NEXT message_data_p IN log_data_p;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;

    { Retrieve the name of the mainframe or peripheral hardware
    { element which was the object of the system action.

    temp_string.value := message_data_p^.element_name;
    set_string_length (temp_string);
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    { Retrieve the identification of the element specified in the active configuration.

    temp_string.value := message_data_p^.product_id.product_number;
    set_string_length (temp_string);
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;
    IF message_data_p^.product_id.model_number <> ' ' THEN
      temp_string.value := message_data_p^.product_id.underscore;
      set_string_length (temp_string);
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;
      temp_string.value := message_data_p^.product_id.model_number;
      set_string_length (temp_string);
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;
    IFEND;

    { Retrieve the unique identity of the element relative to its
    { product family as specified in the active configuration (in decimal).

    temp_string.value := message_data_p^.serial_number;
    set_string_length (temp_string);
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    { Retrieve the message string that describes the state change.

    temp_string.value := v$state_log_message [message_data_p^.old_state] [message_data_p^.new_state].value;
    set_string_length (temp_string);
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    PUSH counters_p: [1 .. 2];
    counters_p^ [1] :=
          v$state_log_message [message_data_p^.old_state] [message_data_p^.new_state].counter_value;

    IF message_data_p^.initiator = 'fail' THEN
      counters_p^ [2] := 1;
    ELSEIF message_data_p^.initiator = 'op' THEN
      counters_p^ [2] := 2;
    ELSEIF message_data_p^.initiator = 'ce' THEN
      counters_p^ [2] := 3;
    ELSE
      counters_p^ [2] := 0;
    IFEND;

    { Log the message to the engineering log.

    sfp$emit_statistic (cml$element_state_change, message.value (1, message.size), counters_p, status);

  PROCEND cm_element_state_change;
?? OLDTITLE ??
?? NEWTITLE := 'cm_iou_identification', EJECT ??

{ PURPOSE:
{   This procedure is called to log the identity of an IOU on the mainframe being initialized.
{   The format of the log message is described in the deck cml$iou_identification.

  PROCEDURE cm_iou_identification
    (VAR status: ost$status);

    VAR
      element_entry: dst$mf_element_table_entry,
      ignore_status: ost$status,
      iou_index: dst$number_of_ious,
      iou_information_table: dst$iou_information_table,
      message: ost$string,
      number_of_ious: dst$number_of_ious,
      number_string: ost$string;

    status.normal := TRUE;

    dsp$retrieve_iou_information (number_of_ious, iou_information_table);

    FOR iou_index := 1 TO number_of_ious DO

      message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
      message.size := v$mainframe_name.size;

      clp$convert_integer_to_string (iou_information_table [iou_index].physical_iou_number,
            10, FALSE, number_string, ignore_status);
      message.value ((message.size + 1), 4) := '.IOU';
      message.size := message.size + 4;
      message.value ((message.size + 1), number_string.size) := number_string.value;
      message.size := message.size + number_string.size;

      { Retrieve the IOU element entry.

      dsp$retrieve_mf_element_entry (iou_information_table [iou_index].physical_iou_number,
            dsc$dftb_eid_iou0_element, element_entry, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      { Construct the statistic from the mainframe element information.

      message.value ((message.size + 1), 1) := '*';
      message.size := message.size + 1;
      message.value ((message.size + 1), element_entry.model_number_string.size) :=
            element_entry.model_number_string.value;
      message.size := message.size + element_entry.model_number_string.size;

      message.value ((message.size + 1), 1) := '*';
      message.size := message.size + 1;
      message.value ((message.size + 1), element_entry.serial_number_string.size) :=
            element_entry.serial_number_string.value;
      message.size := message.size + element_entry.serial_number_string.size;

      { Log the message to the engineering log.

      sfp$emit_statistic (cml$iou_identification, message.value (1, message.size), NIL, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    FOREND;

  PROCEND cm_iou_identification;
?? OLDTITLE ??
?? NEWTITLE := 'cm_ms_media_flaw_change', EJECT ??

{ PURPOSE:
{   This procedure is called to log flaw changes on a peripheral storage device.
{   The format of the statistic is described in the deck cml$ms_media_flaw_change.

  PROCEDURE cm_ms_media_flaw_change
    (VAR log_data_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      counters_p: sft$counters,
      daus_per_cylinder: integer,
      element_def_p: ^cmt$element_definition,
      first_phys_adrs: dmt$physical_flaw_address,
      last_phys_adrs: dmt$physical_flaw_address,
      lun: iot$logical_unit,
      message: ost$string,
      message_data_p: ^dmt$log_flaw_init_data,
      physical_attributes_p: ^dmt$physical_device_attributes,
      sector_offset_within_cylinder: integer,
      str_el_1: string (2),
      str_el_2: string (2),
      str_el_3: string (7),
      str_el_4: string (1),
      str: string (80),
      str_length: integer,
      temp_string: ost$string;

    status.normal := TRUE;
    RESET log_data_p;
    NEXT message_data_p IN log_data_p;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;

    { Obtain the element of the device that the flaw change is on.

    dmp$get_logical_unit_number (message_data_p^.recorded_vsn, lun, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH element_def_p;

    cmp$pc_get_logical_unit (lun, element_def_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { Place vsn and element name in the statistic.

    message.value ((message.size + 1), 1) := '.';
    message.size := message.size + 1;
    temp_string.value := element_def_p^.element_name;
    set_string_length (temp_string);
    message.value  ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), 6) := message_data_p^.recorded_vsn;
    message.size := message.size + 6;
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;

    { Set first half of the "MESSAGE" portion of statistic.

    IF message_data_p^.operation_code = dmc$oc_flaw_define THEN
      message.value  ((message.size +1), 21) := 'MEDIA FLAW DEFINED (C';
    ELSE
      message.value  ((message.size +1), 21) := 'MEDIA FLAW REMOVED (C';
    IFEND;
    message.size := message.size + 21;

    { Obtain the starting and ending cylinder, track, and sector address of the flaw from the first and last
    { dau address.

    PUSH physical_attributes_p: [1 .. 4];
    physical_attributes_p^[1].keyword := dmc$maus_per_cylinder;
    physical_attributes_p^[2].keyword := dmc$sectors_per_mau;
    physical_attributes_p^[3].keyword := dmc$sectors_per_track;
    physical_attributes_p^[4].keyword := dmc$maus_per_dau;

    dmp$get_physical_attributes (element_def_p^.product_id, physical_attributes_p, status);

    daus_per_cylinder := physical_attributes_p^[1].maus_per_cylinder DIV
          physical_attributes_p^[4].maus_per_dau;

    { Determine and set first cylinder, track and sector.

    first_phys_adrs.cylinder := message_data_p^.first_dau DIV daus_per_cylinder;
    sector_offset_within_cylinder := (message_data_p^.first_dau MOD daus_per_cylinder) *
          physical_attributes_p^[2].sectors_per_mau * physical_attributes_p^[4].maus_per_dau;
    first_phys_adrs.track := sector_offset_within_cylinder DIV physical_attributes_p^[3].sectors_per_track;
    first_phys_adrs.sector := sector_offset_within_cylinder MOD physical_attributes_p^[3].sectors_per_track;

    { Determine and set last cylinder, track and sector.

    last_phys_adrs.cylinder := message_data_p^.last_dau DIV daus_per_cylinder;
    sector_offset_within_cylinder := ((message_data_p^.last_dau MOD daus_per_cylinder) *
          physical_attributes_p^[2].sectors_per_mau * physical_attributes_p^[4].maus_per_dau) +
          (physical_attributes_p^[4].maus_per_dau * physical_attributes_p^[2].sectors_per_mau) - 1;
    last_phys_adrs.track := sector_offset_within_cylinder DIV physical_attributes_p^[3].sectors_per_track;
    last_phys_adrs.sector := sector_offset_within_cylinder MOD physical_attributes_p^[3].sectors_per_track;

    { Transfer the starting and ending cylinder, track, and sector data into the remainder of the "MESSAGE"
    { portion of statistic.

    str_el_1 (1, 2) := ' T';
    str_el_2 (1, 2) := ' S';
    str_el_3 (1, 7) := ') .. (C';
    str_el_4 (1, 1) := ')';
    STRINGREP (str, str_length, first_phys_adrs.cylinder, str_el_1, first_phys_adrs.track,
         str_el_2, first_phys_adrs.sector, str_el_3, last_phys_adrs.cylinder, str_el_1,
         last_phys_adrs.track, str_el_2,  last_phys_adrs.sector, str_el_4);

    message.value  ((message.size + 1), str_length) := str;
    message.size := message.size + str_length;

    { Set all values for the counter portion of statistic.

    PUSH counters_p: [1 .. 8];
    counters_p^ [1] := message_data_p^.operation_code;
    counters_p^ [2] := message_data_p^.initiator_code;
    counters_p^ [3] := first_phys_adrs.cylinder;
    counters_p^ [4] := first_phys_adrs.track;
    counters_p^ [5] := first_phys_adrs.sector;
    counters_p^ [6] := last_phys_adrs.cylinder;
    counters_p^ [7] := last_phys_adrs.track;
    counters_p^ [8] := last_phys_adrs.sector;

    { Log the message to the engineering log.

    sfp$emit_statistic (cml$ms_media_flaw_change, message.value (1, message.size), counters_p, status);

  PROCEND cm_ms_media_flaw_change;
?? OLDTITLE ??
?? NEWTITLE := 'cm_ms_volume_initialization', EJECT ??

{ PURPOSE:
{   This procedure is called to log the identity of a peripheral storage device which has been
{   initialized.  The format of the log message is described in the deck cml$ms_volume_initialization.

  PROCEDURE cm_ms_volume_initialization
    (VAR log_data_p: ^SEQ( * );
     VAR status: ost$status);

    VAR
      counters_p: sft$counters,
      message: ost$string,
      message_data_p: ^dst$log_ms_volume_init,
      temp_string: ost$string;

    status.normal := TRUE;
    RESET log_data_p;
    NEXT message_data_p IN log_data_p;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;

    { Retrieve the name of the element specified in the active configuration.

    temp_string.value := message_data_p^.element_name;
    set_string_length (temp_string);
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    { Retrieve the site_supplied name of the mass storage volume.

    temp_string.value := message_data_p^.recorded_vsn;
    set_string_length (temp_string);
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    { Retrieve the physical unit number of the storage device on which the volume is currently mounted.

    PUSH counters_p: [1 .. 1];
    counters_p^ [1] := message_data_p^.physical_unit_number;

    { Log the message to the engineering log.

    sfp$emit_statistic (cml$ms_volume_initialization, message.value (1, message.size), counters_p, status);

  PROCEND cm_ms_volume_initialization;
?? OLDTITLE ??
?? NEWTITLE := 'cm_peripheral_identification', EJECT ??

{ PURPOSE:
{   This procedure is called to log the identity of a peripheral in NOS/VE's active configuration.
{   The format of the log message is described in the deck cml$peripheral_identification.

  PROCEDURE cm_peripheral_identification
    (VAR status: ost$status);

    VAR
      counters_p: sft$counters,
      element_state: cmt$element_state,
      iou_name: cmt$element_name,
      message: ost$string,
      pc_index: integer,
      temp_string: ost$string;

    status.normal := TRUE;
    PUSH counters_p: [1 .. 3];

  /channel_loop/
    FOR pc_index := 1 TO UPPERBOUND(cmv$physical_configuration^) DO
      CASE cmv$physical_configuration^ [pc_index].element_type OF
      = cmc$channel_adapter_element =
        counters_p^ [1] := 1;
        counters_p^ [3] := 0;
      = cmc$controller_element =
        counters_p^ [1] := 2;
        counters_p^ [3] := 0;
      = cmc$communications_element, cmc$external_processor_element =
        counters_p^ [1] := 1;
        counters_p^ [3] := 0;
      = cmc$storage_device_element =
        counters_p^ [1] := 3;
        counters_p^ [3] := cmv$physical_configuration^ [pc_index].storage_device.physical_unit_number;
      ELSE
        CYCLE /channel_loop/;
      CASEND;

      { Retrieve the element state of the peripheral.

      iou_name := 'IOU0';
      cmp$get_element_state (cmv$physical_configuration^ [pc_index].element_name, iou_name,
            element_state, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      CASE element_state OF
      = cmc$on =
        counters_p^ [2] := 1;
      = cmc$down =
        counters_p^ [2] := 2;
      = cmc$off =
        counters_p^ [2] := 3;
      CASEND;

      message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
      message.size := v$mainframe_name.size;

      { Retrieve the name of the element specified in the active configuration.

      temp_string.value := cmv$physical_configuration^ [pc_index].element_name;
      set_string_length (temp_string);
      message.value ((message.size + 1), 1) := '.';
      message.size := message.size + 1;
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;

      { Retrieve the identification of the element specified in the active configuration.

      temp_string.value := cmv$physical_configuration^ [pc_index].product_id.product_number;
      set_string_length (temp_string);
      message.value ((message.size + 1), 1) := '*';
      message.size := message.size + 1;
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;
      temp_string.value := cmv$physical_configuration^ [pc_index].product_id.underscore;
      set_string_length (temp_string);
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;
      temp_string.value := cmv$physical_configuration^ [pc_index].product_id.model_number;
      set_string_length (temp_string);
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;

      { Retrieve the unique identity of the element relative to its product family as specified in the active
      { configuration (in decimal).

      temp_string.value := cmv$physical_configuration^ [pc_index].serial_number;
      set_string_length (temp_string);
      message.value ((message.size + 1), 1) := '*';
      message.size := message.size + 1;
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;

      { Log the message to the engineering log.

      sfp$emit_statistic (cml$peripheral_identification, message.value (1, message.size), counters_p, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    FOREND /channel_loop/;

  PROCEND cm_peripheral_identification;
?? OLDTITLE ??
?? NEWTITLE := 'cm_pm_identification', EJECT ??

{ PURPOSE:
{   This procedure is called to log the identity of a page map on the mainframe being
{   initialized.  The format of the log message is described in the deck cml$pm_identification.

  PROCEDURE cm_pm_identification
    (VAR status: ost$status);

    VAR
      element_entry: dst$mf_element_table_entry,
      message: ost$string;

    status.normal := TRUE;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;
    message.value ((message.size + 1), 9) := '.PAGE_MAP';
    message.size := message.size + 9;

    { Retrieve the PAGE_MAP element entry.

    dsp$retrieve_mf_element_entry (0, dsc$dftb_eid_page_map_element, element_entry, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { Construct the statistic from the mainframe element information.

    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), element_entry.model_number_string.size) :=
          element_entry.model_number_string.value;
    message.size := message.size + element_entry.model_number_string.size;

    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), element_entry.serial_number_string.size) :=
          element_entry.serial_number_string.value;
    message.size := message.size + element_entry.serial_number_string.size;

    { Log the message to the engineering log.

    sfp$emit_statistic (cml$pm_identification, message.value (1, message.size), NIL, status);

  PROCEND cm_pm_identification;
?? OLDTITLE ??
?? NEWTITLE := 'cm_system_deadstart_status', EJECT ??

{ PURPOSE:
{   This procedure is called to log the System Deadstart Status Data from the SSR.

  PROCEDURE cm_system_deadstart_status
    (VAR status: ost$status);

    CONST
      c$number_of_blocks = 4,

      c$information_words = 1,
      c$disk_errors = 2,
      c$mainframe_errors = 3,
      c$nos_or_nbe_words = 4;

    TYPE
      t$mf_error = RECORD
        data: dst$ssr_sds_mf_error_entry,
        link_p: ^t$mf_error,
      RECEND,

      t$header_word = RECORD
        id: 0 .. 0ff(16),
        rfu: 0 .. 0ffffff(16),
        number_of_errors: 0 .. 0ffff(16),
        words_per_block: 0 .. 0ffff(16),
      RECEND;

    VAR
      before_p: ^t$mf_error,
      counters_p: sft$counters,
      data_p: ^t$mf_error,
      disk_error_entry_p: ^dst$ssr_sds_disk_error_entry,
      disk_index: 1 .. dsc$ssr_sds_number_of_disk_errs,
      disk_valid_entries: 0 .. dsc$ssr_sds_number_of_disk_errs,
      entry: 1 .. dsc$ssr_sds_number_of_disk_errs,
      general_info_p: ^dst$ssr_sds_general_info,
      header_word_p: ^t$header_word,
      mainframe_error_entry_p: ^dst$ssr_sds_mf_error_entry,
      message: ost$string,
      mf_errors_p: ^t$mf_error,
      mf_index: 1 .. dsc$ssr_sds_number_of_mf_errors,
      mf_valid_entries: 0 .. dsc$ssr_sds_number_of_mf_errors,
      nos_nbe_words_p: ^dst$ssr_sds_nos_nbe_words,
      possible_counter_size: integer,
      real_counter_size: integer,
      search_p: ^t$mf_error,
      statistic_data_seq_p: ^SEQ ( * ),
      system_deadstart_status: dst$ssr_system_deadstart_status,
      temp_string: ost$string,
      top_mf_errors_p: ^t$mf_error;

    status.normal := TRUE;

    { Retrieve the data from the SSR.

    dsp$retrieve_system_ds_status (system_deadstart_status);

    { Move the top line message and the DFT message to the descriptive data message.

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    temp_string.value := system_deadstart_status.top_line_message;
    set_string_length (temp_string);
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    temp_string.value := system_deadstart_status.dft_message;
    set_string_length (temp_string);
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    { Decide the possible size of each part of the statistic.

    possible_counter_size := #SIZE (dst$ssr_system_deadstart_status) + (#SIZE (t$header_word) *
          c$number_of_blocks);

    { Create a sequence to use to build the data to place in the counters.

    PUSH statistic_data_seq_p: [[REP possible_counter_size OF cell]];
    RESET statistic_data_seq_p;
    real_counter_size := 0;

    { Add the general information and its header to the sequence.

    NEXT header_word_p IN statistic_data_seq_p;
    real_counter_size := real_counter_size + #SIZE (header_word_p^);
    header_word_p^.id := c$information_words;
    header_word_p^.rfu := 0;
    header_word_p^.number_of_errors := 0;
    header_word_p^.words_per_block := #SIZE (dst$ssr_sds_general_info) DIV 8;
    NEXT general_info_p IN statistic_data_seq_p;
    real_counter_size := real_counter_size + #SIZE (general_info_p^);
    general_info_p^ := system_deadstart_status.general_info;
    convert_date_time_format (system_deadstart_status.general_info.timestamp_of_crash,
          general_info_p^.timestamp_of_crash);

    { Add any valid disk errors and a header to the sequence.  If no errors exists, nothing is added to the
    { sequence.

    IF system_deadstart_status.disk_errors.number_of_valid_entries > 0 THEN
      disk_valid_entries := system_deadstart_status.disk_errors.number_of_valid_entries;
      NEXT header_word_p IN statistic_data_seq_p;
      real_counter_size := real_counter_size + #SIZE (header_word_p^);
      header_word_p^.id := c$disk_errors;
      header_word_p^.rfu := 0;
      header_word_p^.number_of_errors := disk_valid_entries;
      header_word_p^.words_per_block := disk_valid_entries * (#SIZE (dst$ssr_sds_disk_error_entry) DIV 8);
      IF system_deadstart_status.disk_errors.next_available_entry = 1 THEN
        entry := dsc$ssr_sds_number_of_disk_errs;
      ELSE
        entry := system_deadstart_status.disk_errors.next_available_entry - 1;
      IFEND;
      FOR disk_index := 1 TO disk_valid_entries DO
        NEXT disk_error_entry_p IN statistic_data_seq_p;
        real_counter_size := real_counter_size + #SIZE (disk_error_entry_p^);
        disk_error_entry_p^ := system_deadstart_status.disk_errors.entry [entry];
        convert_date_time_format (system_deadstart_status.disk_errors.entry [entry].timestamp,
              disk_error_entry_p^.timestamp);
        IF entry = 1 THEN
          entry := dsc$ssr_sds_number_of_disk_errs;
        ELSE
          entry := entry - 1;
        IFEND;
      FOREND;
    IFEND;

    { Add any valid mainframe errors and a header to the sequence.  If no errors exists, nothing is added to
    { the sequence.

    IF system_deadstart_status.mainframe_errors.number_of_valid_entries > 0 THEN

      { Create a list of the valid mainframe errors, ordering them from top to bottom with the most recent
      { time first.

      PUSH top_mf_errors_p;
      top_mf_errors_p^.link_p := NIL;
      mf_valid_entries := 0;
      FOR mf_index := 1 TO dsc$ssr_sds_number_of_mf_errors DO
        IF system_deadstart_status.mainframe_errors.data [mf_index].valid THEN
          PUSH mf_errors_p;
          mf_valid_entries := mf_valid_entries + 1;
          mf_errors_p^.data := system_deadstart_status.mainframe_errors.data [mf_index].entry;
          before_p := top_mf_errors_p;
          search_p := top_mf_errors_p^.link_p;

         /search_error_links/
          WHILE search_p <> NIL DO
            IF mf_errors_p^.data.timestamp.data >= search_p^.data.timestamp.data THEN
              EXIT /search_error_links/;
            ELSE
              before_p := search_p;
              search_p := search_p^.link_p;
            IFEND;
          WHILEND /search_error_links/;
          mf_errors_p^.link_p := before_p^.link_p;
          before_p^.link_p := mf_errors_p;
        IFEND;
      FOREND;

      IF mf_valid_entries > 0 THEN
        NEXT header_word_p IN statistic_data_seq_p;
        real_counter_size := real_counter_size + #SIZE (header_word_p^);
        header_word_p^.id := c$mainframe_errors;
        header_word_p^.rfu := 0;
        header_word_p^.number_of_errors := mf_valid_entries;
        header_word_p^.words_per_block := mf_valid_entries * (#SIZE (dst$ssr_sds_mf_error_entry) DIV 8);
        data_p := top_mf_errors_p^.link_p;
        WHILE data_p <> NIL DO
          NEXT mainframe_error_entry_p IN statistic_data_seq_p;
          real_counter_size := real_counter_size + #SIZE (mainframe_error_entry_p^);
          mainframe_error_entry_p^ := data_p^.data;
          data_p := data_p^.link_p;
        WHILEND;
      IFEND;
    IFEND;

    { Add the NOS or NBE words and a header to the sequence.

    NEXT header_word_p IN statistic_data_seq_p;
    real_counter_size := real_counter_size + #SIZE (header_word_p^);
    header_word_p^.id := c$nos_or_nbe_words;
    header_word_p^.rfu := 0;
    header_word_p^.number_of_errors := 0;
    header_word_p^.words_per_block := #SIZE (dst$ssr_sds_nos_nbe_words) DIV 8;
    NEXT nos_nbe_words_p IN statistic_data_seq_p;
    real_counter_size := real_counter_size + #SIZE (nos_nbe_words_p^);
    nos_nbe_words_p^ := system_deadstart_status.nos_nbe_words;

    RESET statistic_data_seq_p;
    NEXT counters_p: [1 .. (real_counter_size DIV 8)] IN statistic_data_seq_p;

    { Log the message to the engineering log.

    sfp$emit_statistic (cml$system_deadstart_status, message.value (1, message.size), counters_p, status);

  PROCEND cm_system_deadstart_status;
?? OLDTITLE ??
?? NEWTITLE := 'convert_date_time_format', EJECT ??

{ PURPOSE:
{   This procedure converts a date and time from the OS format of OST$DATE_TIME to the DFT date/time format.

  PROCEDURE convert_date_time_format
    (    input_date_time: dst$ssr_sds_timestamp;
     VAR output_date_time: dst$ssr_sds_timestamp);

    IF input_date_time.word = 0 THEN
      output_date_time.word := 0;
      RETURN;
    IFEND;

    output_date_time.dft.rfu_1 := 0;
    output_date_time.dft.lost_integrity := FALSE;
    output_date_time.dft.tens_of_years := input_date_time.os.year DIV 10;
    output_date_time.dft.units_of_years := input_date_time.os.year MOD 10;
    output_date_time.dft.tens_of_months := input_date_time.os.month DIV 10;
    output_date_time.dft.units_of_months := input_date_time.os.month MOD 10;
    output_date_time.dft.tens_of_days := input_date_time.os.day DIV 10;
    output_date_time.dft.units_of_days := input_date_time.os.day MOD 10;
    output_date_time.dft.tens_of_hours := input_date_time.os.hour DIV 10;
    output_date_time.dft.units_of_hours := input_date_time.os.hour MOD 10;
    output_date_time.dft.tens_of_minutes := input_date_time.os.minute DIV 10;
    output_date_time.dft.units_of_minutes := input_date_time.os.minute MOD 10;
    output_date_time.dft.tens_of_seconds := input_date_time.os.second DIV 10;
    output_date_time.dft.units_of_seconds := input_date_time.os.second MOD 10;
    output_date_time.dft.rfu_2 := 0;

  PROCEND convert_date_time_format;
?? OLDTITLE ??
?? NEWTITLE := 'convert_timestamp_to_string', EJECT ??

{ PURPOSE:
{   This procedure converts a given timestamp into a string.

  PROCEDURE convert_timestamp_to_string
    (    date_time: ost$date_time;
     VAR converted_time: ost$string);

    VAR
      date: ost$date,
      status: ost$status,
      time: ost$time;

    { Format the time part of the time stamp.

    pmp$format_compact_time (date_time, osc$millisecond_time, time, status);
    IF NOT status.normal THEN
      converted_time.value := '';
      converted_time.size := 0;
      RETURN;
    IFEND;

    { Format the date part of the time stamp.

    pmp$format_compact_date (date_time, osc$mdy_date, date, status);
    IF NOT status.normal THEN
      converted_time.value := '';
      converted_time.size := 0;
      RETURN;
    IFEND;

    converted_time.value := 'at              on         ';
    converted_time.value (4, 12) := time.millisecond;
    converted_time.value (20, 8) := date.mdy;
    set_string_length (converted_time);

  PROCEND convert_timestamp_to_string;
?? OLDTITLE ??
?? NEWTITLE := 'dft_add_element_id_information', EJECT ??

{ PURPOSE:
{   This procedure adds the element id information to the message string.

  PROCEDURE dft_add_element_id_information
    (    element_number: dst$dftb_structure_length;
     VAR message: ost$string);

    VAR
      element_entry: dst$mf_element_table_entry,
      element_number_string: ost$string,
      status: ost$status;

    IF element_number <> dsc$dftb_eid_no_known_element THEN
      dsp$retrieve_mf_element_entry ((element_number DIV 16), (element_number MOD 16), element_entry, status);
      IF status.normal THEN
        dft_convert_element_number (element_number, element_number_string);
        message.value ((message.size + 1), element_number_string.size) := element_number_string.value;
        message.size := message.size + element_number_string.size;
        message.value ((message.size + 1), 1) := '*';
        message.size := message.size + 1;
        message.value ((message.size + 1), element_entry.model_number_string.size) :=
              element_entry.model_number_string.value;
        message.size := message.size + element_entry.model_number_string.size;
        message.value ((message.size + 1), 1) := '*';
        message.size := message.size + 1;
        message.value ((message.size + 1), element_entry.serial_number_string.size) :=
              element_entry.serial_number_string.value;
        message.size := message.size + element_entry.serial_number_string.size;
      IFEND;
    IFEND;

  PROCEND dft_add_element_id_information;
?? OLDTITLE ??
?? NEWTITLE := 'dft_convert_element_number', EJECT ??

{ PURPOSE:
{   This procedure converts the element number into a string that HPA/VE expects.

  PROCEDURE dft_convert_element_number
    (    element_number: dst$mf_element_number;
     VAR element_number_string: ost$string);

    CASE element_number OF
    = dsc$dftb_eid_cpu0_element =
      element_number_string.value (1, 4) := '.CP0';
      element_number_string.size := 4;
    = dsc$dftb_eid_cpu1_element =
      element_number_string.value (1, 4) := '.CP1';
      element_number_string.size := 4;
    = dsc$dftb_eid_memory_element =
      element_number_string.value (1, 15) := '.CENTRAL_MEMORY';
      element_number_string.size := 15;
    = dsc$dftb_eid_iou0_element =
      element_number_string.value (1, 5) := '.IOU0';
      element_number_string.size := 5;
    = dsc$dftb_eid_iou1_element =
      element_number_string.value (1, 5) := '.IOU1';
      element_number_string.size := 5;
    = dsc$dftb_eid_page_map_element =
      element_number_string.value (1, 9) := '.PAGE_MAP';
      element_number_string.size := 9;
    ELSE
      element_number_string.value (1, 16) := '.UNKNOWN_ELEMENT';
      element_number_string.size := 16;
    CASEND;

  PROCEND dft_convert_element_number;
?? OLDTITLE ??
?? NEWTITLE := 'dft_log_data', EJECT ??

{ PURPOSE:
{   This procedure builds the statistics and emits them to the engineering log.
{   HPA requires that the counter field does not exceed 255.

  PROCEDURE dft_log_data
    (    control_word: dst$dftb_buffer_control_word;
         standard_dft_analysis_code: dst$dftb_dft_analysis_code;
         statistic_code: sft$statistic_code;
     VAR buffer_data: t$dft_buffer_data);

    CONST
      c$hpa_required_max_counters = 255,

      c$available_counters = (c$hpa_required_max_counters - 2),
      c$counter_block_size = c$hpa_required_max_counters;

    VAR
      block_index: dst$dftb_element_size,
      buffer_data_seq_p: ^SEQ ( * ),
      code_string: ost$string,
      counter_block_header_p: ^dst$dftb_stat_block_header,
      counter_data_seq_p: ^SEQ ( * ),
      counter_seq_p: ^SEQ ( * ),
      counters_p: sft$counters,
      date_and_time: dst$dftb_date_and_time,
      date_and_time_p: ^dst$dftb_date_and_time,
      data_size: 1 .. c$hpa_required_max_counters,
      element_entry: dst$mf_element_table_entry,
      element_number_string: ost$string,
      error_msg: ost$string,
      global_length: dst$dftb_element_size,
      ignore_status: ost$status,
      mdb_data_length_to_log: dst$dftb_element_size,
      mdb_iw_p: ^dst$dftb_mdb_information_word,
      message: ost$string,
      message_index: 1 .. c$number_of_dft_log_messages,
      mrb_group_length_needed: dst$dftb_element_size,
      mrb_type: dst$dftb_structure_length,
      nrb_iw_p: ^dst$dftb_nrb_information_word,
      nrb_data_length_to_log: dst$dftb_element_size,
      number_of_blocks: dst$dftb_element_size,
      skip_cw_p: ^dst$dftb_buffer_control_word,
      ssb_data_length_to_log: dst$dftb_element_size,
      ssb_iw_p: ^dst$dftb_ssb_information_word,
      statistic_block_header: dst$dftb_stat_block_header,
      statistic_buffer_header_p: ^dst$dftb_stat_buffer_header,
      statistic_data_seq_p: ^SEQ ( * ),
      statistic_seq_p: ^SEQ ( * ),
      status: ost$status,
      temp_string: ost$string;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;

    { Retrieve the global length of the statistic and the date and time for the statistic.

    date_and_time.data := 0;
    global_length := 0;
    IF buffer_data.mrb_seq_p <> NIL THEN

      { The data contains a MRB and possibly a SSB and a MDB.  Round up the actual MRB length to a group size.

      RESET buffer_data.mrb_seq_p;
      IF buffer_data.ssb_seq_p <> NIL THEN
        RESET buffer_data.ssb_seq_p;
        NEXT ssb_iw_p IN buffer_data.ssb_seq_p;
        mrb_type := ssb_iw_p^.mrb_type;
        NEXT date_and_time_p IN buffer_data.ssb_seq_p;
        date_and_time := date_and_time_p^;
        mrb_group_length_needed := ((ssb_iw_p^.logged_mrb_size + dsc$dftb_mr_number_of_registers) DIV
              dsc$dftb_mr_group_size) * dsc$dftb_mr_group_size;
        IF dsv$dftb_data.revision_level <= dsc$dftb_revision_level_4 THEN
          ssb_data_length_to_log := ssb_iw_p^.data_length_to_log - 1;
        ELSE
          ssb_data_length_to_log := ssb_iw_p^.data_length_to_log + 1;
        IFEND;
        global_length := mrb_group_length_needed + 1 + ssb_data_length_to_log + 1;
        dft_add_element_id_information (ssb_iw_p^.element_number, message);
      ELSE
        mrb_type := dsc$dftb_sbt_mrb;
        mrb_group_length_needed := dsv$dftb_data.mrb_length;
        global_length := mrb_group_length_needed + 1;
      IFEND;
      IF buffer_data.mdb_seq_p <> NIL THEN
        RESET buffer_data.mdb_seq_p;
        NEXT mdb_iw_p IN buffer_data.mdb_seq_p;
        mdb_data_length_to_log := mdb_iw_p^.data_length_to_log - 1;
        global_length := global_length + mdb_data_length_to_log + 1;
      IFEND;

    ELSEIF buffer_data.nrb_seq_p <> NIL THEN

      { The data contains a NRB.

      RESET buffer_data.nrb_seq_p;
      NEXT skip_cw_p IN buffer_data.nrb_seq_p;
      NEXT nrb_iw_p IN buffer_data.nrb_seq_p;
      mrb_type := nrb_iw_p^.mrb_type;
      NEXT date_and_time_p IN buffer_data.nrb_seq_p;
      date_and_time := date_and_time_p^;
      IF dsv$dftb_data.revision_level <= dsc$dftb_revision_level_4 THEN
        nrb_data_length_to_log := nrb_iw_p^.data_length_to_log - 2;
      ELSE
        nrb_data_length_to_log := nrb_iw_p^.data_length_to_log + 1;
      IFEND;
      global_length := nrb_data_length_to_log + 1;
      dft_add_element_id_information (nrb_iw_p^.element_number, message);
    IFEND;
    IF global_length = 0 THEN
      RETURN;
    IFEND;

    { Add the message that corresponds to the DFT analysis code to the log message.

   /retrieve_log_message/
    FOR message_index := 1 TO c$number_of_dft_log_messages DO
      IF v$dft_log_message [message_index].dft_analysis_code = standard_dft_analysis_code THEN
        temp_string.value := v$dft_log_message [message_index].value;
        set_string_length (temp_string);
        message.value ((message.size + 1), temp_string.size) := temp_string.value;
        message.size := message.size + temp_string.size;
        EXIT /retrieve_log_message/;
      IFEND;
    FOREND /retrieve_log_message/;

    { Build the statistic block header.

    statistic_block_header.date_and_time := date_and_time.data;
    statistic_block_header.linked_block_follows := FALSE;
    statistic_block_header.block_number := 1;
    statistic_block_header.global_length := global_length;
    statistic_block_header.dft_code_version_number := 0;
    statistic_block_header.dft_interface_version_number := dsv$dftb_data.revision_level;
    statistic_block_header.rfu := 0;
    statistic_block_header.dft_analysis_code := control_word.dft_analysis_code;
    statistic_block_header.sequence_number := control_word.sequence_number;

    { Determine the number of statistic blocks needed to log the message.

    number_of_blocks := (global_length + (c$available_counters - 1)) DIV c$available_counters;
    PUSH statistic_seq_p: [[REP (number_of_blocks * c$available_counters) OF integer]];
    RESET statistic_seq_p;

    { Build the counter data.

    IF buffer_data.mrb_seq_p <> NIL THEN
      NEXT statistic_buffer_header_p IN statistic_seq_p;
      statistic_buffer_header_p^.buffer_length := mrb_group_length_needed + 1;
      statistic_buffer_header_p^.rfu := 0;
      statistic_buffer_header_p^.buffer_type := mrb_type;
      IF mrb_group_length_needed > 0 THEN
        NEXT buffer_data_seq_p: [[REP mrb_group_length_needed OF integer]] IN buffer_data.mrb_seq_p;
        NEXT statistic_data_seq_p: [[REP mrb_group_length_needed OF integer]] IN statistic_seq_p;
        statistic_data_seq_p^ := buffer_data_seq_p^;
      IFEND;

      IF buffer_data.ssb_seq_p <> NIL THEN
        NEXT statistic_buffer_header_p IN statistic_seq_p;
        statistic_buffer_header_p^.buffer_length := ssb_data_length_to_log + 1;
        statistic_buffer_header_p^.rfu := 0;
        statistic_buffer_header_p^.buffer_type := dsc$dftb_sbt_ssb;
        IF ssb_data_length_to_log > 0 THEN
          IF dsv$dftb_data.revision_level > dsc$dftb_revision_level_4 THEN
            RESET buffer_data.ssb_seq_p;
          IFEND;
          NEXT buffer_data_seq_p: [[REP ssb_data_length_to_log OF integer]] IN buffer_data.ssb_seq_p;
          NEXT statistic_data_seq_p: [[REP ssb_data_length_to_log OF integer]] IN statistic_seq_p;
          statistic_data_seq_p^ := buffer_data_seq_p^;
        IFEND;
      IFEND;

      IF buffer_data.mdb_seq_p <> NIL THEN
        NEXT statistic_buffer_header_p IN statistic_seq_p;
        statistic_buffer_header_p^.buffer_length := mdb_data_length_to_log + 1;
        statistic_buffer_header_p^.rfu := 0;
        statistic_buffer_header_p^.buffer_type := dsc$dftb_sbt_mdb;
        IF mdb_data_length_to_log > 0 THEN
          NEXT buffer_data_seq_p: [[REP mdb_data_length_to_log OF integer]] IN buffer_data.mdb_seq_p;
          NEXT statistic_data_seq_p: [[REP mdb_data_length_to_log OF integer]] IN statistic_seq_p;
          statistic_data_seq_p^ := buffer_data_seq_p^;
        IFEND;
      IFEND;

    ELSEIF buffer_data.nrb_seq_p <> NIL THEN
      NEXT statistic_buffer_header_p IN statistic_seq_p;
      statistic_buffer_header_p^.buffer_length := nrb_data_length_to_log + 1;
      statistic_buffer_header_p^.rfu := 0;
      statistic_buffer_header_p^.buffer_type := mrb_type;
      IF nrb_data_length_to_log > 0 THEN
        IF dsv$dftb_data.revision_level > dsc$dftb_revision_level_4 THEN
          RESET buffer_data.nrb_seq_p;
        IFEND;
        NEXT buffer_data_seq_p: [[REP nrb_data_length_to_log OF integer]] IN buffer_data.nrb_seq_p;
        NEXT statistic_data_seq_p: [[REP nrb_data_length_to_log OF integer]] IN statistic_seq_p;
        statistic_data_seq_p^ := buffer_data_seq_p^;
      IFEND;
    ELSE
      RETURN;
    IFEND;

    { Log the registers.

    RESET statistic_seq_p;

    PUSH counter_seq_p: [[REP c$counter_block_size OF integer]];
    FOR block_index := 1 TO number_of_blocks DO
      RESET counter_seq_p;
      NEXT counter_block_header_p IN counter_seq_p;
      counter_block_header_p^ := statistic_block_header;
      counter_block_header_p^.linked_block_follows := (block_index <> number_of_blocks);
      counter_block_header_p^.block_number := block_index;
      IF c$available_counters <= global_length THEN
        data_size := c$available_counters;
        global_length := global_length - c$available_counters;
      ELSE
        data_size := global_length;
      IFEND;
      NEXT statistic_data_seq_p: [[REP data_size OF integer]] IN statistic_seq_p;
      NEXT counter_data_seq_p: [[REP data_size OF integer]] IN counter_seq_p;
      counter_data_seq_p^ := statistic_data_seq_p^;
      RESET counter_seq_p;
      NEXT counters_p: [1 .. (data_size + 2)] IN counter_seq_p;
      sfp$emit_statistic (statistic_code, message.value (1, message.size), counters_p, ignore_status);
      IF NOT ignore_status.normal THEN
        clp$convert_integer_to_string (control_word.dft_analysis_code, 16, FALSE, code_string, ignore_status);
        error_msg.value := ' Not able to log DFT error: ';
        error_msg.value (29, *) := code_string.value;
        error_msg.size := 29 + code_string.size;
        sfp$emit_statistic (cml$system_informative_message, error_msg.value (1, error_msg.size), NIL,
              ignore_status);
      IFEND;
    FOREND;

  PROCEND dft_log_data;
?? OLDTITLE ??
?? NEWTITLE := 'dft_log_failure_data', EJECT ??

{ PURPOSE:
{   This procedure writes information about DFT failure data into the engineering log.

  PROCEDURE dft_log_failure_data
    (    mrb_length: dst$dftb_element_size;
     VAR rb: dst$rb_logging_request);

    VAR
      buffer_data: t$dft_buffer_data,
      hardware_element: dst$dftb_dft_analysis_code,
      standard_dft_analysis_code: dst$dftb_dft_analysis_code,
      statistic_code: sft$statistic_code;

    { The first digit of the dft analysis code describes the hardware element on which the error occurred
    { (IOU, MEMORY, PROCESSOR, NON).  If DFT had detected multiple errors occurring then the leftmost bit
    { of the dft analysis code is set to indicate that multiple errors occur.  This bit is cleared to get
    { the standard DFT analysis code and retrieve the hardware element type.

    hardware_element := rb.dftb_control_word.dft_analysis_code DIV 100(16);
    IF hardware_element > dsc$dftb_mrb_non THEN
      hardware_element := hardware_element - 8;
      standard_dft_analysis_code := rb.dftb_control_word.dft_analysis_code - 800(16);
    ELSE
      standard_dft_analysis_code := rb.dftb_control_word.dft_analysis_code;
    IFEND;

    dft_retrieve_statistic_code (hardware_element, rb.dftb_control_word, statistic_code);

    { Retrieve any existing buffers from the sequence.

    RESET rb.dftb_seq_p;
    buffer_data.mrb_seq_p := NIL;
    buffer_data.ssb_seq_p := NIL;
    buffer_data.mdb_seq_p := NIL;
    buffer_data.nrb_seq_p := NIL;

    { Retrieve the Maintenance Register Buffer from the sequence.

    IF dsc$dds_mrb IN rb.dftb_data_structures THEN
      NEXT buffer_data.mrb_seq_p: [[REP mrb_length OF integer]] IN rb.dftb_seq_p;
      RESET buffer_data.mrb_seq_p;
    IFEND;

    { Retrieve the Supportive Status Buffer from the sequence.

    IF dsc$dds_ssb IN rb.dftb_data_structures THEN
      NEXT buffer_data.ssb_seq_p: [[REP dsv$dftb_data.ssb_length OF integer]] IN rb.dftb_seq_p;
      RESET buffer_data.ssb_seq_p;
    IFEND;

    { Retrieve the Model Dependent Buffer from the sequence.

    IF dsc$dds_mdb IN rb.dftb_data_structures THEN
      NEXT buffer_data.mdb_seq_p: [[REP dsv$dftb_data.mdb_length OF integer]] IN rb.dftb_seq_p;
      RESET buffer_data.mdb_seq_p;
    IFEND;

    { Retrieve the Non Register Buffer from the sequence.

    IF dsc$dds_nrb IN rb.dftb_data_structures THEN
      NEXT buffer_data.nrb_seq_p: [[REP dsv$dftb_data.nrb_length OF integer]] IN rb.dftb_seq_p;
      RESET buffer_data.nrb_seq_p;
    IFEND;

    { Log the counter part of the statistic.

    IF dsv$dftb_data.revision_level <= dsc$dftb_revision_level_3 THEN
      dft_version_3_log_data (mrb_length, rb.dftb_control_word, standard_dft_analysis_code,
            statistic_code, buffer_data);
    ELSE
      dft_log_data (rb.dftb_control_word, standard_dft_analysis_code, statistic_code, buffer_data);
    IFEND;

  PROCEND dft_log_failure_data;
?? OLDTITLE ??
?? NEWTITLE := 'dft_read_eid_register', EJECT ??

{ PURPOSE:
{   This procedure retrieves information from the element identification register (EID).  This information
{   is used on most of the DFT messages written into the engineering log.  The element identification register
{   is described in the 'Maintenance Register Codes Booklet'.

  PROCEDURE dft_read_eid_register
    (    eid_register_input: integer;
     VAR element_message: ost$string);

    VAR
      eid_register: integer,
      element_number: 0 .. 0ff(16),
      ignore_status: ost$status,
      model_number: 0 .. 0ff(16),
      number_string: ost$string,
      serial_number: 0 .. 0ffff(16);

    { Remove the serial number, model number, and element number from the EID register.

    eid_register := eid_register_input;
    serial_number := eid_register MOD 10000(16);
    eid_register := eid_register DIV 10000(16);
    model_number := eid_register MOD 100(16);
    eid_register := eid_register DIV 100(16);
    element_number := eid_register MOD 100(16);

    { Build the log message from the EID register parts.

    dft_convert_element_number (element_number, element_message);

    element_message.value ((element_message.size + 1), 1) := '*';
    element_message.size := element_message.size + 1;
    clp$convert_integer_to_string (model_number, 16, FALSE, number_string, ignore_status);
    element_message.value ((element_message.size + 1), number_string.size) := number_string.value;
    element_message.size := element_message.size + number_string.size;

    element_message.value ((element_message.size + 1), 1) := '*';
    element_message.size := element_message.size + 1;
    clp$convert_integer_to_string (serial_number, 16, FALSE, number_string, ignore_status);
    element_message.value ((element_message.size + 1), number_string.size) := number_string.value;
    element_message.size := element_message.size + number_string.size;

  PROCEND dft_read_eid_register;
?? OLDTITLE ??
?? NEWTITLE := 'dft_retrieve_statistic_code', EJECT ??

{ PURPOSE:
{   This procedure retrieves the statistic code which is based on the DFT analysis code.

  PROCEDURE dft_retrieve_statistic_code
    (    hardware_element: dst$dftb_dft_analysis_code;
         control_word: dst$dftb_buffer_control_word;
     VAR statistic_code: sft$statistic_code);

    IF dsv$dftb_data.revision_level <= dsc$dftb_revision_level_3 THEN
      CASE control_word.dft_analysis_code OF
      = dsc$dftb_dac_non_707 =
        statistic_code := cml$top_of_hour_counters;
      = dsc$dftb_dac_non_708 =
        statistic_code := cml$top_of_hour_secded_id;
      ELSE
        CASE hardware_element OF
        = dsc$dftb_mrb_iou_error =
          statistic_code := cml$iou_failure_data;
        = dsc$dftb_mrb_memory_error =
          statistic_code := cml$memory_failure_data;
        = dsc$dftb_mrb_cpu_error =
          statistic_code := cml$cpu_failure_data;
        = dsc$dftb_mrb_page_map_error =
          statistic_code := cml$page_map_failure_data;
        ELSE
          statistic_code := cml$environment_failure_data;
        CASEND;
      CASEND;
    ELSE
      CASE control_word.dft_analysis_code OF
      = dsc$dftb_dac_non_707 =
        statistic_code := cml$dft_hour_element_counters;
      = dsc$dftb_dac_non_708 =
        statistic_code := cml$dft_hour_secded_id;
      = dsc$dftb_dac_iou_0FF, dsc$dftb_dac_pac_5FF, dsc$dftb_dac_sof_6FF, dsc$dftb_dac_non_709,
            dsc$dftb_dac_non_70A =
        statistic_code := cml$dft_cyber_2000_error;
      ELSE
        CASE hardware_element OF
        = dsc$dftb_mrb_iou_error =
          statistic_code := cml$dft_iou_failure_data;
        = dsc$dftb_mrb_memory_error =
          statistic_code := cml$dft_memory_failure_data;
        = dsc$dftb_mrb_cpu_error =
          statistic_code := cml$dft_cpu_failure_data;
        = dsc$dftb_mrb_page_map_error =
          statistic_code := cml$dft_page_map_failure_data;
        = dsc$dftb_mrb_bad_requests =
          statistic_code := cml$dft_non_crit_failure_data;
        = dsc$dftb_mrb_packet_error, dsc$dftb_mrb_software_error =
          statistic_code := cml$dft_critical_failure_data;
        ELSE
          statistic_code := cml$dft_power_failure_data;
        CASEND;
      CASEND;
    IFEND;

  PROCEND dft_retrieve_statistic_code;
?? OLDTITLE ??
?? NEWTITLE := 'dft_version_3_log_data', EJECT ??

{ PURPOSE:
{   This procedure uses the version 3 statistics to log the data to the engineering log.

  PROCEDURE dft_version_3_log_data
    (    mrb_length: dst$dftb_element_size;
         control_word: dst$dftb_buffer_control_word;
         standard_dft_analysis_code: dst$dftb_dft_analysis_code;
         statistic_code: sft$statistic_code;
     VAR buffer_data: t$dft_buffer_data);

    VAR
      counters_p: sft$counters,
      eid_register_p: ^integer,
      ignore_status: ost$status,
      iou_information_table: dst$iou_information_table,
      message: ost$string,
      message_index: 1 .. c$number_of_dft_log_messages,
      mrb_buffer_index: dst$dftb_structure_length,
      mrb_buffer_word_p: ^integer,
      number_of_ious: dst$number_of_ious,
      register_count: dst$dftb_structure_length,
      register_group_index: dst$dftb_structure_length,
      register_group_p: ^dst$dftb_maintenance_registers,
      register_index: 1 .. dsc$dftb_mr_number_of_registers,
      skip_word_p: ^integer,
      temp_string: ost$string;

    IF buffer_data.mrb_seq_p = NIL THEN
      RETURN;
    IFEND;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;

    { Retrieve the element identification information from the EID register.

    CASE control_word.dft_analysis_code OF
    = dsc$dftb_dac_non_707 =

    = dsc$dftb_dac_non_708 =

    { The EID register is the second word in the MRB for the SECDED id table.

      NEXT skip_word_p IN buffer_data.mrb_seq_p;
      NEXT eid_register_p IN buffer_data.mrb_seq_p;
      dft_read_eid_register (eid_register_p^, temp_string);
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;

    ELSE

      { Search for the EID register in the MRB.

     /retrieve_eid_information/
      FOR register_group_index := 1 TO (mrb_length DIV dsc$dftb_mr_group_size) DO
        NEXT register_group_p IN buffer_data.mrb_seq_p;
        FOR register_index := 1 TO dsc$dftb_mr_number_of_registers DO
          IF (register_group_p^.register_header [register_index].register_number = c$eid_register_number) THEN
            dft_read_eid_register (register_group_p^.register_list [register_index], temp_string);
            message.value ((message.size + 1), temp_string.size) := temp_string.value;
            message.size := message.size + temp_string.size;
            EXIT /retrieve_eid_information/;
          IFEND;
        FOREND;
      FOREND /retrieve_eid_information/;

    CASEND;
    RESET buffer_data.mrb_seq_p;

    { Add the constant message to the log message.

   /retrieve_log_message/
    FOR message_index := 1 TO c$number_of_dft_log_messages DO
      IF v$dft_log_message [message_index].dft_analysis_code = standard_dft_analysis_code THEN
        temp_string.value := v$dft_log_message [message_index].value;
        set_string_length (temp_string);
        message.value ((message.size + 1), temp_string.size) := temp_string.value;
        message.size := message.size + temp_string.size;
        EXIT /retrieve_log_message/;
      IFEND;
    FOREND /retrieve_log_message/;

    { Count the number of mrb buffer words to log.

    CASE control_word.dft_analysis_code OF

    = dsc$dftb_dac_non_707 =

      dsp$retrieve_iou_information (number_of_ious, iou_information_table);
      IF iou_information_table [1].model_type = dsc$imn_i0_5x_model THEN
        register_count := dsc$dftb_mec_s0_counters;
      ELSE
        register_count := dsc$dftb_mec_non_s0_counters;
      IFEND;

    = dsc$dftb_dac_non_708 =
      register_count := dsv$dftb_data.secded_id_table_length + 2;

    ELSE

      { The entire buffer is searched for the last non-zero buffer word.

      RESET buffer_data.mrb_seq_p;
      register_count := 0;
      FOR mrb_buffer_index := 1 TO mrb_length DO
        NEXT mrb_buffer_word_p IN buffer_data.mrb_seq_p;
        IF mrb_buffer_word_p^ <> 0 THEN
          register_count := mrb_buffer_index;
        IFEND;
      FOREND;

      { Round up the register count to the size of the group.

      register_count := ((register_count + dsc$dftb_mr_number_of_registers) DIV
            dsc$dftb_mr_group_size) * dsc$dftb_mr_group_size;
    CASEND;

    { Log the registers.

    PUSH counters_p: [1 .. (register_count + 2)];
    counters_p^ [1] := control_word.os_action_code;
    counters_p^ [2] := (control_word.dft_analysis_code * 100(16)) + control_word.sequence_number;
    RESET buffer_data.mrb_seq_p;
    FOR mrb_buffer_index := 1 TO register_count DO
      NEXT mrb_buffer_word_p IN buffer_data.mrb_seq_p;
      counters_p^ [mrb_buffer_index + 2] := mrb_buffer_word_p^;
    FOREND;

    { Log the message to the engineering log.

    sfp$emit_statistic (statistic_code, message.value (1, message.size), counters_p, ignore_status);

  PROCEND dft_version_3_log_data;
?? OLDTITLE ??
?? NEWTITLE := 'establish_sys_msgs_stats', EJECT ??

{ PURPOSE:
{   This procedure is called right before logging is allowed during deadstart to establish
{   the system message statistics.

  PROCEDURE establish_sys_msgs_stats;

    CONST
      c$number_of_statistics = 40;

    VAR
      ignore_status: ost$status,
      statistics: array [1 .. c$number_of_statistics] of sft$statistic_code,
      statistic_index: 1 .. c$number_of_statistics;

    { Set up the statistic codes for the DFT messages.

    statistics [01] := cml$cpu_failure_data;
    statistics [02] := cml$environment_failure_data;
    statistics [03] := cml$iou_failure_data;
    statistics [04] := cml$memory_failure_data;
    statistics [05] := cml$page_map_failure_data;
    statistics [06] := cml$dft_top_of_hour;
    statistics [07] := cml$top_of_hour_counters;
    statistics [08] := cml$top_of_hour_secded_id;

    statistics [09] := cml$dft_cpu_failure_data;
    statistics [10] := cml$dft_critical_failure_data;
    statistics [11] := cml$dft_cyber_2000_error;
    statistics [12] := cml$dft_hour_element_counters;
    statistics [13] := cml$dft_hour_secded_id;
    statistics [14] := cml$dft_iou_failure_data;
    statistics [15] := cml$dft_memory_failure_data;
    statistics [16] := cml$dft_non_crit_failure_data;
    statistics [17] := cml$dft_page_map_failure_data;
    statistics [18] := cml$dft_power_failure_data;
    statistics [19] := cml$dft_top_of_hour;

    { Set up the statistic codes for the Configuration Management messages.

    statistics [20] := cml$channel_identification;
    statistics [21] := cml$cm_identification;
    statistics [22] := cml$connection_disabled;
    statistics [23] := cml$cp_identification;
    statistics [24] := cml$element_disabled;
    statistics [25] := cml$element_state_change;
    statistics [26] := cml$iou_identification;
    statistics [27] := cml$ms_volume_initialization;
    statistics [28] := cml$ms_media_flaw_change;
    statistics [29] := cml$peripheral_identification;
    statistics [30] := cml$pm_identification;
    statistics [31] := cml$system_deadstart_status;

    { Set up the statistic code for the system informative message.

    statistics [32] := cml$system_informative_message;

    { Set up the statistic code for the system termination and continuation messages.

    statistics [33] := cml$system_termination;
    statistics [34] := cml$system_continuation;
    statistics [35] := cml$system_termination_init;

    { Set up the statistic code for the PP timed out message.

    statistics [36] := cml$pp_timed_out;

    { Set up the job recovery statistics and the system error statistic.

    statistics [37] := cml$system_error;
    statistics [38] := cml$job_recovery_totals;
    statistics [39] := cml$job_recovery_failure;

    { Set up the statistic code for the PP hung message.

    statistics [40] := cml$pp_hung;

    FOR statistic_index := 1 TO c$number_of_statistics DO
      sfp$activate_system_statistic (statistics [statistic_index], $sft$binary_logset [pmc$engineering_log],
            ignore_status);
    FOREND;

  PROCEND establish_sys_msgs_stats;
?? OLDTITLE ??
?? NEWTITLE := 'get_mainframe_name', EJECT ??

{ PURPOSE:
{   This procedure retrieves the name of the mainframe.

  PROCEDURE get_mainframe_name;

    VAR
      mainframe_id: pmt$mainframe_id,
      status: ost$status;

    pmp$get_mainframe_id (mainframe_id, status);
    IF NOT status.normal THEN
      v$mainframe_name.value := 'UNKNOWN MAINFRAME NAME';
    ELSE
      v$mainframe_name.value := mainframe_id;
    IFEND;
    v$mainframe_name.size := STRLENGTH (v$mainframe_name.value);
    WHILE v$mainframe_name.value (v$mainframe_name.size) = ' ' DO
      v$mainframe_name.size := v$mainframe_name.size - 1;
    WHILEND;

  PROCEND get_mainframe_name;
?? OLDTITLE ??
?? NEWTITLE := 'os_log_system_control_data', EJECT ??

{ PURPOSE:
{   This procedure logs a message to the engineering log for the following system commands: IDLE_SYSTEM,
{   RESUME_SYSTEM, STEP_SYSTEM, UNSTEP_SYSTEM, TERMINATE_SYSTEM.  The message states whether the system
{   was terminated or continued.  The format of the log messages are described in the decks
{   cml$system_continuation and cml$system_termination.

  PROCEDURE os_log_system_control_data
    (VAR data_to_log_p: ^SEQ( * );
     VAR status: ost$status);

    VAR
      message: ost$string,
      message_index: 1 .. c$number_of_idle_log_messages,
      statistic_code: sft$statistic_code,
      temp_string: ost$string,
      terminate_continue_message_p: ^ost$terminate_continue_record;

    status.normal := TRUE;
    IF NOT jmv$executing_within_system_job THEN
      RETURN;
    IFEND;

    RESET data_to_log_p;
    NEXT terminate_continue_message_p IN data_to_log_p;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    message.value ((message.size + 1), terminate_continue_message_p^.log_message.size) :=
          terminate_continue_message_p^.log_message.value;
    message.size := message.size + terminate_continue_message_p^.log_message.size;

    convert_timestamp_to_string (terminate_continue_message_p^.date_time, temp_string);
    message.value ((message.size + 1), 1) := ' ';
    message.size := message.size + 1;
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    { Retrieve the associated log message for the log reason.

    IF terminate_continue_message_p^.log_reason <> syc$ic_null THEN

     /retrieve_log_message/
      FOR message_index := 1 TO c$number_of_idle_log_messages DO
        IF v$ic_log_message [message_index].idle_code = terminate_continue_message_p^.log_reason THEN
          temp_string.value := v$ic_log_message [message_index].value;
          set_string_length (temp_string);
          message.value ((message.size + 1), temp_string.size) := temp_string.value;
          message.size := message.size + temp_string.size;
          EXIT /retrieve_log_message/;
        IFEND;
      FOREND /retrieve_log_message/;
    IFEND;

    { Get the correct statistic code for the log message.

    CASE terminate_continue_message_p^.log_statistic OF
    = osc$idle_statistic, osc$step_statistic, osc$terminate_statistic =
      statistic_code := cml$system_termination;
    = osc$unstep_statistic, osc$resume_statistic =
      statistic_code := cml$system_continuation;
    ELSE
    CASEND;

    { Log the message to the engineering log.

    sfp$emit_statistic (statistic_code, message.value (1, message.size), NIL, status);

  PROCEND os_log_system_control_data;
?? OLDTITLE ??
?? NEWTITLE := 'os_log_system_error', EJECT ??

{ PURPOSE:
{   This procedure logs a message from a call to osp$system_error.

  PROCEDURE os_log_system_error
    (VAR data_to_log_p: ^SEQ( * );
     VAR status: ost$status);

    CONST
      c$p_address_information = 1;

    TYPE
      t$header_word = RECORD
        id: 0 .. 0ff(16),
        rfu: 0 .. 0ffffffffff(16),
        words_per_block: 0 .. 0ffff(16),
      RECEND;

    VAR
      counters_p: sft$counters,
      header_word_p: ^t$header_word,
      message: ost$string,
      p_address_index: 1 .. osc$stacks_to_display,
      p_address_p: ^integer,
      statistic_data_seq_p: ^SEQ ( * ),
      system_error_data_p: ^ost$system_error_statistic,
      temp_string: ost$string;

    status.normal := TRUE;

    RESET data_to_log_p;
    NEXT system_error_data_p IN data_to_log_p;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    temp_string.value := system_error_data_p^.text;
    set_string_length (temp_string);
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    PUSH statistic_data_seq_p: [[REP (#SIZE (system_error_data_p^) + #SIZE (t$header_word)) OF cell]];
    RESET statistic_data_seq_p;

    NEXT header_word_p IN statistic_data_seq_p;
    header_word_p^.id := c$p_address_information;
    header_word_p^.rfu := 0;
    header_word_p^.words_per_block := osc$stacks_to_display;

    FOR p_address_index := 1 TO osc$stacks_to_display DO
      NEXT p_address_p IN statistic_data_seq_p;
      p_address_p^ := system_error_data_p^.counter [p_address_index];
    FOREND;

    { Log the message to the engineering log.

    RESET statistic_data_seq_p;
    NEXT counters_p: [1 .. (osc$stacks_to_display + 1)] IN statistic_data_seq_p;
    sfp$emit_statistic (cml$system_error, message.value (1, message.size), counters_p, status);

  PROCEND os_log_system_error;
?? OLDTITLE ??
?? NEWTITLE := 'os_pp_hung', EJECT ??

{ PURPOSE:
{   This procedure logs a message to the engineering log when monitor detects that a PP has hung.
{   The message states which PP has hung.

  PROCEDURE os_pp_hung
    (VAR data_to_log_p: ^SEQ( * ));

    VAR
      counters_p: sft$counters,
      data_string: ost$string,
      hung_pp_data_p: ^dst$log_hung_pp_data,
      ignore_status: ost$status,
      message: ost$string;

    IF (data_to_log_p = NIL) OR (#SIZE (dst$log_hung_pp_data) > #SIZE (data_to_log_p^)) THEN
      RETURN;
    IFEND;
    RESET data_to_log_p;
    NEXT hung_pp_data_p IN data_to_log_p;
    IF hung_pp_data_p = NIL THEN
      RETURN;
    IFEND;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;
    message.value ((message.size + 1), 4) := '.IOU';
    message.size := message.size + 4;
    clp$convert_integer_to_string (hung_pp_data_p^.pp.iou_number, 10, FALSE, data_string, ignore_status);
    message.value ((message.size + 1), data_string.size) := data_string.value;
    message.size := message.size + data_string.size;

    IF hung_pp_data_p^.channel.channel_protocol = dsc$cpt_cio THEN
      message.value ((message.size + 1), 4) := '.CCH';
      message.size := message.size + 4;
    ELSE
      message.value ((message.size + 1), 3) := '.CH';
      message.size := message.size + 3;
    IFEND;
    clp$convert_integer_to_string (hung_pp_data_p^.channel.number, 8, TRUE, data_string, ignore_status);
    message.value ((message.size + 1), data_string.size) := data_string.value;
    message.size := message.size + data_string.size;

    IF hung_pp_data_p^.pp.channel_protocol = dsc$cpt_cio THEN
      message.value ((message.size + 1), 4) := '.CPP';
      message.size := message.size + 4;
    ELSE
      message.value ((message.size + 1), 3) := '.PP';
      message.size := message.size + 3;
    IFEND;
    clp$convert_integer_to_string (hung_pp_data_p^.pp.number, 8, TRUE, data_string, ignore_status);
    message.value ((message.size + 1), data_string.size) := data_string.value;
    message.size := message.size + data_string.size;

    message.value ((message.size + 1), 22) := ' HUNG - RELOAD OF PP (';
    message.size := message.size + 22;
    data_string.value := hung_pp_data_p^.driver_name;
    set_string_length (data_string);
    message.value ((message.size + 1), data_string.size) := data_string.value;
    message.size := message.size + data_string.size;
    message.value ((message.size + 1), 11) := ') INITIATED';
    message.size := message.size + 11;

    PUSH counters_p: [1 .. 6];
    IF counters_p = NIL THEN
      RETURN;
    IFEND;
    IF hung_pp_data_p^.pp_hung_on_one_instruction THEN
      counters_p^ [1] := 1;
    ELSE
      counters_p^ [1] := 2;
    IFEND;
    counters_p^ [2] := hung_pp_data_p^.pp_registers.p_register;
    counters_p^ [3] := hung_pp_data_p^.pp_registers.k_register;
    counters_p^ [4] := hung_pp_data_p^.pp_registers.q_register;
    counters_p^ [5] := hung_pp_data_p^.pp_registers.a_register;
    counters_p^ [6] := hung_pp_data_p^.r_register;

    { Log the message to the engineering log.

    sfp$emit_statistic (cml$pp_hung, message.value (1, message.size), counters_p, ignore_status);

  PROCEND os_pp_hung;
?? OLDTITLE ??
?? NEWTITLE := 'os_pp_timed_out', EJECT ??

{ PURPOSE:
{   This procedure logs a message to the engineering log when monitor detects that a PP has timed
{   out (ie. no longer responding to CPU/PP handshaking).  The message states which PP has timed
{   out.  The format of the log message is described in the deck cml$pp_timed_out.

  PROCEDURE os_pp_timed_out
    (VAR data_to_log_p: ^SEQ( * ));

    VAR
      converted_time: ost$string,
      local_status: ost$status,
      message: ost$string,
      pp_timed_out_p: ^dst$log_pp_timed_out;

    RESET data_to_log_p;
    NEXT pp_timed_out_p IN data_to_log_p;

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;
    message.value ((message.size + 1), 11) := '*VE0S6000- ';
    message.size := message.size + 11;
    message.value ((message.size + 1), #SIZE (pp_timed_out_p^.pp_name)) := pp_timed_out_p^.pp_name;
    message.size := message.size + #SIZE (pp_timed_out_p^.pp_name);
    message.value ((message.size + 1), 10) := ' TIMED OUT';
    message.size := message.size + 10;

    { Convert the saved timestamp to a string that can be added to the log message.

    convert_timestamp_to_string (pp_timed_out_p^.date_time, converted_time);
    message.value ((message.size + 1), 1) := ' ';
    message.size := message.size + 1;
    message.value ((message.size + 1), converted_time.size) := converted_time.value;
    message.size := message.size + converted_time.size;
    message.value ((message.size + 1), 1) := '.';
    message.size := message.size + 1;

    { Log the message to the engineering log.

    sfp$emit_statistic (cml$pp_timed_out, message.value (1, message.size), NIL, local_status);

  PROCEND os_pp_timed_out;
?? OLDTITLE ??
?? NEWTITLE := 'post_operator_action', EJECT ??

{ PURPOSE:
{   This procedure puts a message in the operator action window.

  PROCEDURE post_operator_action
    (    signal_entry: dst$signal_contents_entry);

    VAR
      date: ost$date,
      local_status: ost$status,
      message: string (ofc$max_operator_message_size),
      message_size: 0 .. ofc$max_operator_message_size,
      response: ost$string,
      time: ost$time;

    message := ' ';
    message_size := 0;

    pmp$format_compact_time (signal_entry.poa_data.date_time, osc$hms_time, time, local_status);
    IF local_status.normal THEN
      message ((message_size + 1), 8) := time.hms;
      message_size := message_size + 9;
    IFEND;

    pmp$format_compact_date (signal_entry.poa_data.date_time, osc$mdy_date, date, local_status);
    IF local_status.normal THEN
      message ((message_size + 1), 8) := date.mdy;
      message_size := message_size + 9;
    IFEND;

    message ((message_size + 1), v$post_operator_actions [signal_entry.poa_data.kind].size) :=
          v$post_operator_actions [signal_entry.poa_data.kind].value;
    message_size := message_size + v$post_operator_actions [signal_entry.poa_data.kind].size;
    pmp$log_ascii (message (1, message_size), $pmt$ascii_logset [pmc$system_log, pmc$job_log],
          pmc$msg_origin_system, local_status);
    message ((message_size + 1), v$post_operator_actions_part_2.size) := v$post_operator_actions_part_2.value;
    message_size := message_size + v$post_operator_actions_part_2.size;
    ofp$send_operator_message_v1 (message (1, message_size), ofc$system_operator, TRUE, TRUE, local_status);

  PROCEND post_operator_action;
?? OLDTITLE ??
?? NEWTITLE := 'process_hung_pp', EJECT ??

{ PURPOSE:
{   This procedure processes the hung PPs that are not processed in monitor.  If the detected hung PP does
{   not support handshaking or reload then a message is sent to the operator action window.  Otherwise the
{   correct routine is called.

  PROCEDURE process_hung_pp
    (    pp_entry: cmt$logical_pp_table_entry;
         input_message: ost$string);

    VAR
      channel_element_p: ^cmt$element_definition,
      channel_name: cmt$element_name,
      channel_ordinal: cmt$channel_ordinal,
      concurrent: boolean,
      element_name: cmt$element_name,
      element_p: ^cmt$element_definition,
      iou_name: cmt$element_name,
      index: cmt$physical_equipment_number,
      local_status: ost$status,
      state: cmt$element_state,
      valid: boolean;

    IF NOT pp_entry.flags.pp_handshaking_supported THEN
      process_hung_pp_message (c$hpmt_no_handshaking, pp_entry, input_message, local_status);
      RETURN;
    IFEND;
    IF NOT pp_entry.flags.pp_reload_supported THEN
      process_hung_pp_message (c$hpmt_no_reload, pp_entry, input_message, local_status);
      RETURN;
    IFEND;

    IF pp_entry.pp_info.pp_type = cmc$lpt_network_pp_type THEN
      concurrent := (pp_entry.pp_info.channel.channel_protocol = dsc$cpt_cio);
      cmp$convert_channel_number (pp_entry.pp_info.channel.number, concurrent, pp_entry.pp_info.channel_port,
            channel_ordinal, channel_name, valid);
      IF NOT valid THEN
        process_hung_pp_message (c$hpmt_invalid_channel, pp_entry, input_message, local_status);
        RETURN;
      IFEND;
      cmp$convert_iou_number (pp_entry.pp_info.channel.iou_number, iou_name, local_status);
      IF NOT local_status.normal THEN
        process_hung_pp_message (c$hpmt_bad_status, pp_entry, input_message, local_status);
        RETURN;
      IFEND;
      cmp$pc_get_element (channel_name, iou_name, channel_element_p, local_status);
      IF NOT local_status.normal THEN
        process_hung_pp_message (c$hpmt_bad_status, pp_entry, input_message, local_status);
        RETURN;
      IFEND;

     /equipment_loop/
      FOR index := LOWERVALUE (cmt$physical_equipment_number) TO UPPERVALUE (cmt$physical_equipment_number) DO
        IF NOT channel_element_p^.data_channel.connection.equipment [index].configured THEN
          CYCLE /equipment_loop/;
        IFEND;

        element_name := channel_element_p^.data_channel.connection.equipment [index].element_name;
        cmp$pc_get_element (element_name, iou_name, element_p, local_status);
        IF NOT local_status.normal THEN
          process_hung_pp_message (c$hpmt_bad_status, pp_entry, input_message, local_status);
          RETURN;
        IFEND;

        cmp$get_element_state (element_name, iou_name, state, local_status);
        IF NOT local_status.normal THEN
          process_hung_pp_message (c$hpmt_bad_status, pp_entry, input_message, local_status);
          RETURN;
        IFEND;
        IF state <> cmc$on THEN
          CYCLE /equipment_loop/;
        IFEND;

        nap$reload_network_pp (element_name, local_status);
        IF NOT local_status.normal THEN
          process_hung_pp_message (c$hpmt_bad_status, pp_entry, input_message, local_status);
          RETURN;
        IFEND;
      FOREND /equipment_loop/;
    IFEND;

  PROCEND process_hung_pp;
?? OLDTITLE ??
?? NEWTITLE := 'process_hung_pp_from_mtr', EJECT ??

{ PURPOSE:
{   This procedure processes the hung PPs that are not processed in monitor.  If the detected hung PP does
{   not support handshaking or reload then a message is sent to the operator action window.  Otherwise the
{   correct routine is called.

  PROCEDURE process_hung_pp_from_mtr
    (    signal_entry: dst$signal_contents_entry);

    VAR
      date: ost$date,
      index: iot$pp_number,
      local_status: ost$status,
      message: ost$string,
      number_string: ost$string,
      response: ost$string,
      time: ost$time;

    message.value := ' ';
    message.size := 0;
    pmp$format_compact_time (signal_entry.poa_data.date_time, osc$hms_time, time, local_status);
    IF local_status.normal THEN
      message.value ((message.size + 1), 8) := time.hms;
      message.size := message.size + 9;
    IFEND;
    pmp$format_compact_date (signal_entry.poa_data.date_time, osc$mdy_date, date, local_status);
    IF local_status.normal THEN
      message.value ((message.size + 1), 8) := date.mdy;
      message.size := message.size + 9;
    IFEND;

    IF signal_entry.hpp_data.sci_reload_failed THEN
      message.value ((message.size + 1), 35) := 'The Automatic Reload of the SCI PP ';
      message.size := message.size + 35;
      CASE dsv$automatic_pp_reload.iou_model_type [0] OF
      = dsc$imn_i4_44_model, dsc$imn_i4_46_model =
        message.value ((message.size + 1), 4) := '(CPP';
        message.size := message.size + 4;
      ELSE
        message.value ((message.size + 1), 3) := '(PP';
        message.size := message.size + 3;
      CASEND;
      clp$convert_integer_to_string (dsv$cpu_pp_communication_block.relocation.sci_pp_number, 8, TRUE,
            number_string, local_status);
      message.value ((message.size + 1), number_string.size) := number_string.value;
      message.size := message.size + number_string.size;
      message.value ((message.size + 1), 52) := ') failed.  The system console will not be available.';
      message.size := message.size + 52;
      pmp$log_ascii (message.value (1, message.size), $pmt$ascii_logset [pmc$system_log, pmc$job_log],
            pmc$msg_origin_system, local_status);
      ofp$send_operator_message_v1 (message.value (1, message.size), ofc$system_operator, TRUE, TRUE,
            local_status);
      RETURN;
    IFEND;

    IF signal_entry.hpp_data.check_entire_table THEN
      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.resources_acquired AND
              cmv$logical_pp_table_p^ [index].flags.pp_loaded AND
              cmv$logical_pp_table_p^ [index].flags.pp_hung AND
              NOT cmv$logical_pp_table_p^ [index].flags.pp_handshaking_supported THEN
          process_hung_pp (cmv$logical_pp_table_p^ [index], message);
        IFEND;
      FOREND;
    ELSE
      process_hung_pp (cmv$logical_pp_table_p^ [signal_entry.hpp_data.logical_pp_index], message);
    IFEND;

  PROCEND process_hung_pp_from_mtr;
?? OLDTITLE ??
?? NEWTITLE := 'process_hung_pp_message', EJECT ??

{ PURPOSE:
{   This procedure creates a message describing the hung PP for the operator action window.

  PROCEDURE process_hung_pp_message
    (    message_type: t$hung_pp_message_type;
         pp_entry: cmt$logical_pp_table_entry;
         input_message: ost$string;
         status: ost$status);

    VAR
      data_string: ost$string,
      local_status: ost$status,
      message: ost$string,
      response: ost$string;

    message := input_message;

    message.value ((message.size + 1), 3) := 'IOU';
    message.size := message.size + 3;
    clp$convert_integer_to_string (pp_entry.pp_info.physical_pp.iou_number, 10, FALSE, data_string,
          local_status);
    message.value ((message.size + 1), data_string.size) := data_string.value;
    message.size := message.size + data_string.size;

    IF pp_entry.pp_info.channel.channel_protocol = dsc$cpt_cio THEN
      message.value ((message.size + 1), 4) := ' CCH';
      message.size := message.size + 4;
    ELSE
      message.value ((message.size + 1), 3) := ' CH';
      message.size := message.size + 3;
    IFEND;
    clp$convert_integer_to_string (pp_entry.pp_info.channel.number, 8, TRUE, data_string, local_status);
    message.value ((message.size + 1), data_string.size) := data_string.value;
    message.size := message.size + data_string.size;

    IF pp_entry.pp_info.physical_pp.channel_protocol = dsc$cpt_cio THEN
      message.value ((message.size + 1), 4) := ' CPP';
      message.size := message.size + 4;
    ELSE
      message.value ((message.size + 1), 3) := ' PP';
      message.size := message.size + 3;
    IFEND;
    clp$convert_integer_to_string (pp_entry.pp_info.physical_pp.number, 8, TRUE, data_string, local_status);
    message.value ((message.size + 1), data_string.size) := data_string.value;
    message.size := message.size + data_string.size;

    message.value ((message.size + 1), 2) := ' (';
    message.size := message.size + 2;
    data_string.value := pp_entry.pp_info.driver_name;
    set_string_length (data_string);
    message.value ((message.size + 1), data_string.size) := data_string.value;
    message.size := message.size + data_string.size;
    message.value ((message.size + 1), 9) := ') hung.  ';
    message.size := message.size + 9;

    CASE message_type OF
    = c$hpmt_bad_status =
      message.value ((message.size + 1), 55) := 'Process detected bad status when attempting the reload.';
      message.size := message.size + 55;
    = c$hpmt_invalid_channel =
      message.value ((message.size + 1), 56) := 'Process detected invalid channel when attempting reload.';
      message.size := message.size + 56;
    = c$hpmt_no_handshaking =
      message.value ((message.size + 1), 32) := 'PP does not support handshaking.';
      message.size := message.size + 32;
    = c$hpmt_no_reload =
      message.value ((message.size + 1), 37) := 'PP does not support automatic reload.';
      message.size := message.size + 37;
    ELSE
    CASEND;

    pmp$log_ascii (message.value (1, message.size), $pmt$ascii_logset [pmc$system_log, pmc$job_log],
          pmc$msg_origin_system, local_status);
    IF message_type = c$hpmt_bad_status THEN
      osp$log_unformatted_status (^local_status, $pmt$ascii_logset [pmc$system_log, pmc$job_log],
            pmc$msg_origin_system, FALSE);
    IFEND;
    ofp$send_operator_message_v1 (message.value (1, message.size), ofc$system_operator, TRUE, true,
          local_status);

  PROCEND process_hung_pp_message;
?? OLDTITLE ??
?? NEWTITLE := 'retrieve_sys_msg_from_image', EJECT ??

{ PURPOSE:
{   This procedure retrieves the system message buffer that was stored in the RDF area during the recovering
{   of the mainframe.

  PROCEDURE retrieve_sys_msg_from_image;

    VAR
      data_size: integer,
      message_data_p: ^SEQ ( * ),
      message_header_p: ^dst$system_message_header,
      rdf_file_segment: mmt$segment_pointer,
      rdf_file_sfid: gft$system_file_identifier,
      rdf_pointers: dst$rdf_pointers,
      rdf_seq_p: ^SEQ ( * ),
      sys_msg_buffer_size: integer,
      valid_data_size_p: ^integer;

    { No messages are retrieved if this is NOT a recovery deadstart.

    IF (dsv$actual_deadstart_phase <> osc$recovery_deadstart) THEN
      RETURN;
    IFEND;

    { Retrieve the size of the RDF system message buffer.  If the size is zero then no buffer exists.

    dsp$get_integer_from_rdf (dsc$rdf_sys_msg_buffer_size, dsc$rdf_system_message_buffer,
          sys_msg_buffer_size);
    IF sys_msg_buffer_size = 0 THEN
      RETURN;
    IFEND;

    { Get the pointer to the RDF area.

    dsp$open_rdf (rdf_file_sfid, rdf_file_segment, rdf_pointers);
    dsp$get_rdf_entry_seq_pointer (dsc$rdf_system_messages_buffer, dsc$rdf_system_message_buffer,
          rdf_pointers, rdf_seq_p);
    RESET rdf_seq_p;
    NEXT valid_data_size_p IN rdf_seq_p;
    data_size := valid_data_size_p^;
    WHILE data_size > #SIZE (dst$system_message_header) DO
      NEXT message_header_p IN rdf_seq_p;
      data_size := data_size - #SIZE (message_header_p^);
      IF data_size >= message_header_p^.message_size THEN
        NEXT message_data_p: [[REP message_header_p^.message_size OF cell]] IN rdf_seq_p;
        data_size := data_size - #SIZE (message_data_p^);
        access_logging_routines (message_header_p^, message_data_p);
      IFEND;
    WHILEND;
    dsp$close_rdf (rdf_file_sfid, rdf_file_segment);

    { Set the buffer size to zero in the RDF to state that there is no longer any valid buffer data.

    dsp$clear_sys_msg_buffer_in_rdf;
    dsp$store_integer_in_rdf (dsc$rdf_sys_msg_buffer_size, dsc$rdf_system_message_buffer, 0);

  PROCEND retrieve_sys_msg_from_image;
?? OLDTITLE ??
?? NEWTITLE := 'set_string_length', EJECT ??

{ PURPOSE:
{   This procedure finds the length of a string that is passed in as a parameter.  It also removes
{   any spaces that are at the beginning and at the end of the string.

  PROCEDURE set_string_length
    (VAR string_data: ost$string);

    VAR
      begin_index: ost$string_size,
      end_index: ost$string_size,
      temp_string: string (osc$max_string_size);

    { If the string is all blank set the string length to one and return.

    IF string_data.value = ' ' THEN
      string_data.size := 1;
      RETURN;
    IFEND;

    { Find the first non-blank character in the string.

    begin_index := 1;
    WHILE (begin_index <= osc$max_string_size) AND (string_data.value (begin_index) = ' ') DO
      begin_index := begin_index + 1;
    WHILEND;

    { Find the last non-blank character in the string.

    end_index := osc$max_string_size;
    WHILE (end_index > begin_index) AND (string_data.value (end_index) = ' ') DO
      end_index := end_index - 1;
    WHILEND;

    { Move the data in the string so the first non-blank character is the first character in the string and
    { determine the size of the string from the first non-blank character to the last non-blank character.

    temp_string := string_data.value;
    string_data.value := temp_string (begin_index, (end_index - begin_index) + 1);
    string_data.size := (end_index - begin_index) + 1;

  PROCEND set_string_length;
?? OLDTITLE ??
?? NEWTITLE := 'sys_log_informative_message', EJECT ??

{ PURPOSE:
{   This procedure is called to log an informative message to the engineering log.  The format
{   of the log message is described in the deck cml$system_informative_message.

  PROCEDURE sys_log_informative_message
    (VAR log_data_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      message_data_p: ^string ( * ),
      message_size: 0 .. osc$max_string_size,
      message_value: string (osc$max_string_size);

    status.normal := TRUE;

    { Retrieve the message to be logged.

    RESET log_data_p;
    NEXT message_data_p: [#SIZE (log_data_p^)] IN log_data_p;

    message_value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message_size := v$mainframe_name.size;
    message_value ((message_size + 1), 1) := '*';
    message_size := message_size + 1;
    message_value ((message_size + 1), *) := message_data_p^;

    { Log the message to the engineering log.

    sfp$emit_statistic (cml$system_informative_message, message_value, NIL, status);

  PROCEND sys_log_informative_message;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$allow_sys_msg_logging', EJECT ??

{ PURPOSE:
{   This procedure allows system messages to be logged into the engineering log.  The system initialization
{   messages must be logged before any other messages can be logged.  Then any messages from the image file
{   are retrieved and logged.  The logging flag is then turned on and the messages on the system message
{   buffer can be logged.

  PROCEDURE [XDCL] dsp$allow_sys_msg_logging;

    VAR
      ignore_status: ost$status,
      iou_index: dst$number_of_ious,
      iou_information_table: dst$iou_information_table,
      number_of_ious: dst$number_of_ious;

    { Establish the statistic for the system messages.

    establish_sys_msgs_stats;

    { Retrieve the mainframe name for the statistic message.

    IF v$mainframe_name.size = 0 THEN
      get_mainframe_name;
    IFEND;

    { Set the flag that will allow system messages to be logged into the engineering log.

    dsp$set_record_errors_flag;

    { Retrieve and log any system messages that may have been saved on the image file.

    retrieve_sys_msg_from_image;

    { Log any messages that are on the circular buffer.

    dsp$retrieve_system_message (dsc$retrieve_system_message);

    { Log any DFT messages.

    IF NOT dsv$turn_dft_logging_off THEN
      dsp$log_dft_data (dsc$log_dft_flag_id);
    IFEND;

    { Log the system initialization messages.

    cm_cp_identification (ignore_status);
    cm_cm_identification (ignore_status);
    cm_iou_identification (ignore_status);
    cm_channel_identification (ignore_status);
    cm_peripheral_identification (ignore_status);

    { The identification of the page map is only logged on S0 mainframes.

    dsp$retrieve_iou_information (number_of_ious, iou_information_table);

   /search_for_s0_iou/
    FOR iou_index := 1 TO number_of_ious DO
      IF iou_information_table [iou_index].model_type = dsc$imn_i0_5x_model THEN
        cm_pm_identification (ignore_status);
        EXIT /search_for_s0_iou/;
      IFEND;
    FOREND /search_for_s0_iou/;
    cm_system_deadstart_status (ignore_status);

  PROCEND dsp$allow_sys_msg_logging;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$log_dft_data', EJECT ??

{ PURPOSE:
{   This procedure logs any errors that exist in the DFT buffer.  This routine makes calls to monitor
{   to retrieve the data from the DFT buffer.

  PROCEDURE [XDCL] dsp$log_dft_data
    (    flag_id: ost$system_flag);

    VAR
      ignore_status: ost$status,
      message: ost$string,
      rb: dst$rb_logging_request,
      request_completed: boolean,
      top_of_hour_logged: boolean;

    IF v$mainframe_name.size = 0 THEN
      get_mainframe_name;
    IFEND;

    { The following boolean notices if the top of hour statistics (element counters and SECDED ID table) are
    { logged.  If these statistics are logged then a statistic that just states 'TOP OF HOUR' must be logged.

    top_of_hour_logged := FALSE;

    { Allocate space to hold the DFT buffer data.  This space must be created in system core code.

    dsp$manage_dftb_space_in_mfw (dsc$dftb_allocate_space, rb.dftb_seq_p, request_completed);
    IF NOT request_completed THEN
      RETURN;
    IFEND;

    { Retrieve the buffer information for an error from DFT and call the correct logging routine.  Continue
    { calling monitor mode for more DFT information until there is no more information to log.

    rb.reqcode := syc$rc_logging_request;
    rb.action := dsc$rla_dft_access_buffer_entry;
    rb.dftb_data_structures := $dst$rb_dft_data_structures [ ];
    rb.dftb_clear_entries_checked := 0;
    rb.dftb_log_entries_checked := 0;

    REPEAT
      i#call_monitor (#LOC (rb), #SIZE (rb));
      CASE rb.response OF
      = dsc$rlr_dft_entry_to_log =
        top_of_hour_logged := top_of_hour_logged OR
              (rb.dftb_control_word.dft_analysis_code = dsc$dftb_dac_non_707);
        dft_log_failure_data (dsv$dftb_data.mrb_length, rb);
      = dsc$rlr_dft_entry_interlocked =
        pmp$cycle (ignore_status);
      ELSE
      CASEND;
    UNTIL (rb.response = dsc$rlr_dft_no_entry_to_log);

    { Free the space that was allocated earlier in mainframe wired.

    dsp$manage_dftb_space_in_mfw (dsc$dftb_free_space, rb.dftb_seq_p, request_completed);

    { If the top of hour stats were logged, log the 'TOP OF HOUR' statistic.

    IF top_of_hour_logged THEN
      message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
      message.size := v$mainframe_name.size;
      message.value ((message.size + 1), 12) := '*TOP OF HOUR';
      message.size := message.size + 12;

      sfp$emit_statistic (cml$dft_top_of_hour, message.value (1, message.size), NIL, ignore_status);
    IFEND;

  PROCEND dsp$log_dft_data;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$log_dft_top_of_hour', EJECT ??

{ PURPOSE:
{   This procedure makes a monitor call to the monitor routine to inform DFT that the top of hour
{   has occurred.  The monitor routine sets a bit in the DFT control word in the DFT block.  The
{   setting of this bit informs DFT to log the mainframe element counters and the SECDED ID table information.

  PROCEDURE [XDCL] dsp$log_dft_top_of_hour;

    VAR
      any_side_door_port_defined: boolean,
      ignore_status: ost$status,
      rb: dst$rb_logging_request;

    rb.reqcode := syc$rc_logging_request;
    rb.action := dsc$rla_dft_log_top_of_hour;
    i#call_monitor (#LOC (rb), #SIZE (rb));

    dfp$any_sdp_defined (any_side_door_port_defined);

    IF any_side_door_port_defined THEN
      dfp$log_side_door_port_status (dfc$sdp_top_of_hour, ignore_status);
    IFEND;

  PROCEND dsp$log_dft_top_of_hour;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$log_job_recovery_statistics', EJECT ??

{ PURPOSE:
{   This procedure logs the job recovery statistics.

  PROCEDURE [XDCL] dsp$log_job_recovery_statistics
    (    recovered_job_count: integer;
         jobs_recovering_count: integer;
     VAR status: ost$status);

    CONST
      c$cm1112_job_recovery_totals = 1,
      c$cm1113_failed_job_p_addresses = 1;

    TYPE
      t$cm1112_counters = RECORD
        total_jobs_found: integer,
        total_jobs_recovered: integer,
        total_jobs_failed: integer,
        total_jobs_terminated: integer,
      RECEND,

      t$cm1113_count_word = integer,

      t$header_word = RECORD
        id: 0 .. 0ff(16),
        rfu: 0 .. 0ffffffffff(16),
        words_per_block: 0 .. 0ffff(16),
      RECEND;

    VAR
      cm1112_counters_p: ^t$cm1112_counters,
      cm1112_data_seq_p: ^SEQ ( * ),
      cm1113_condition_code_p: ^integer,
      cm1113_count_word_p: ^t$cm1113_count_word,
      cm1113_data_seq_p: ^SEQ ( * ),
      condition_code_index: integer,
      counters_p: sft$counters,
      data_size: integer,
      error_index: integer,
      header_word_p: ^t$header_word,
      local_status: ost$status,
      message: ost$string,
      message_size: integer,
      temp_string: ost$string;

    status.normal := TRUE;

    IF v$mainframe_name.size = 0 THEN
      get_mainframe_name;
    IFEND;

    { Log the Job Recovery Totals (CM1112) Statistic.

    message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
    message.size := v$mainframe_name.size;
    message.value ((message.size + 1), 1) := '*';
    message.size := message.size + 1;
    temp_string.value := 'JOB RECOVERY COMPLETED';
    set_string_length (temp_string);
    message.value ((message.size + 1), temp_string.size) := temp_string.value;
    message.size := message.size + temp_string.size;

    data_size := #SIZE (t$cm1112_counters) + #SIZE (t$header_word);
    PUSH cm1112_data_seq_p: [[REP data_size OF cell]];
    RESET cm1112_data_seq_p;

    NEXT header_word_p IN cm1112_data_seq_p;
    header_word_p^.id := c$cm1112_job_recovery_totals;
    header_word_p^.rfu := 0;
    header_word_p^.words_per_block := (data_size - #SIZE (t$header_word)) DIV 8;

    NEXT cm1112_counters_p IN cm1112_data_seq_p;
    cm1112_counters_p^.total_jobs_found := recovered_job_count;
    cm1112_counters_p^.total_jobs_recovered := jobs_recovering_count;
    cm1112_counters_p^.total_jobs_failed := syv$recovery_failure_count;
    cm1112_counters_p^.total_jobs_terminated := syv$file_rcv_failure_count;

    RESET cm1112_data_seq_p;
    NEXT counters_p: [1 .. (data_size DIV 8)] IN cm1112_data_seq_p;
    sfp$emit_statistic (cml$job_recovery_totals, message.value (1, message.size), counters_p, status);

    STRINGREP (message.value, message_size, ' JOB RECOVERY COMPLETED', ' Jobs found:', recovered_job_count,
          '   Recovered:', jobs_recovering_count, '   Failed:', syv$recovery_failure_count,
          '   Terminated:', syv$file_rcv_failure_count);
    pmp$log_ascii (message.value (1, message_size), $pmt$ascii_logset [pmc$system_log, pmc$job_log],
          pmc$msg_origin_system, local_status);
    IF syv$debug_job_recovery THEN
      clp$put_job_command_response (message.value (1, message_size), local_status);
    IFEND;

    { Log the Job Recovery Failure (CM1113) Statistic(s).

    IF syv$failure_reason_p = NIL THEN
      RETURN;
    IFEND;

   /log_cm1113_statistic/
    FOR error_index := LOWERBOUND (syv$failure_reason_p^) TO UPPERBOUND (syv$failure_reason_p^) DO
      IF syv$failure_reason_p^ [error_index].msg_count <= 0 THEN
        EXIT /log_cm1113_statistic/;
      IFEND;
      message.value := ' ';
      message.size := 0;
      message.value (1, v$mainframe_name.size) := v$mainframe_name.value;
      message.size := v$mainframe_name.size;
      message.value ((message.size + 1), 1) := '*';
      message.size := message.size + 1;
      temp_string.value := syv$failure_reason_p^ [error_index].message;
      set_string_length (temp_string);
      message.value ((message.size + 1), temp_string.size) := temp_string.value;
      message.size := message.size + temp_string.size;

      data_size := #SIZE (t$header_word) + #SIZE (t$cm1113_count_word) +
            (syv$failure_reason_p^ [error_index].conditions_count * 8);
      ALLOCATE cm1113_data_seq_p: [[REP data_size OF cell]] IN osv$task_private_heap^;
      RESET cm1113_data_seq_p;

      NEXT header_word_p IN cm1113_data_seq_p;
      header_word_p^.id := c$cm1113_failed_job_p_addresses;
      header_word_p^.rfu := 0;
      header_word_p^.words_per_block := (data_size - #SIZE (t$header_word)) DIV 8;

      NEXT cm1113_count_word_p IN cm1113_data_seq_p;
      cm1113_count_word_p^ := syv$failure_reason_p^ [error_index].count_word;

      FOR condition_code_index := 1 TO syv$failure_reason_p^ [error_index].conditions_count DO
        NEXT cm1113_condition_code_p IN cm1113_data_seq_p;
        cm1113_condition_code_p^ :=
              syv$failure_reason_p^ [error_index].conditions [condition_code_index].code_word;
      FOREND;

      RESET cm1113_data_seq_p;
      NEXT counters_p: [1 .. (data_size DIV 8)] IN cm1113_data_seq_p;
      sfp$emit_statistic (cml$job_recovery_failure, message.value (1, message.size), counters_p, status);

      FREE cm1113_data_seq_p IN osv$task_private_heap^;
    FOREND /log_cm1113_statistic/;

  PROCEND dsp$log_job_recovery_statistics;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$log_system_message', EJECT ??

{ PURPOSE:
{   This procedure is called by any procedure that wants to log a system message into the engineering
{   log.  The reason this procedure is called first is to save the data in the circular buffer if it
{   is too early in deadstart to call the statistic routines.

  PROCEDURE [XDCL] dsp$log_system_message
    (    message_type: integer;
     VAR log_data_p: ^SEQ ( * );
     VAR status: ost$status);

    status.normal := TRUE;

    IF v$mainframe_name.size = 0 THEN
      get_mainframe_name;
    IFEND;

    { Check to see if it is too early to log any messages.  If it is too early place the messages on
    { the System Message Buffer until logging can occur.

    IF NOT dsv$record_errors THEN
      dsp$log_sys_msg_help (message_type, log_data_p);
    ELSE

      CASE message_type OF
      = cml$channel_identification =
        cm_channel_identification (status);
      = cml$cm_identification =
        cm_cm_identification (status);
      = cml$cp_identification =
        cm_cp_identification (status);
      = cml$element_state_change =
        cm_element_state_change (log_data_p, status);
      = cml$iou_identification =
        cm_iou_identification (status);
      = cml$ms_volume_initialization =
        cm_ms_volume_initialization (log_data_p, status);
      = cml$ms_media_flaw_change =
        cm_ms_media_flaw_change (log_data_p, status);
      = cml$peripheral_identification =
        cm_peripheral_identification (status);
      = cml$pm_identification =
        cm_pm_identification (status);
      = cml$pp_hung =
        os_pp_hung (log_data_p);
      = cml$pp_timed_out =
        os_pp_timed_out (log_data_p);
      = cml$system_continuation, cml$system_termination =
        os_log_system_control_data (log_data_p, status);
      = cml$system_informative_message =
        sys_log_informative_message (log_data_p, status);
      = cml$system_deadstart_status =
        cm_system_deadstart_status (status);
      = cml$system_error =
        os_log_system_error (log_data_p, status);
      ELSE
      CASEND;
    IFEND;

  PROCEND dsp$log_system_message;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$retrieve_system_message', EJECT ??

{ PURPOSE:
{   This procedure is called from a system flag that was set from the monitor routine that
{   controls the circular buffer.  It retrieves the messages from the circular buffer and
{   calls the appropriate logging routine.

  PROCEDURE [XDCL] dsp$retrieve_system_message
    (    flag_id: ost$system_flag);

    VAR
      add_data_ptr_offset: integer,
      message_to_log_p: ^SEQ ( * ),
      rb: dst$rb_logging_request,
      remove_data_seq_p: ^SEQ ( * ),
      sys_msg_header_p: ^dst$system_message_header;

    IF NOT jmv$executing_within_system_job THEN
      RETURN;
    IFEND;

    { Retrieve the information to be logged from the System Message buffer.

    rb.reqcode := syc$rc_logging_request;
    rb.action := dsc$rla_sys_msg_get_message;
    rb.sys_msg_clear_buffer := FALSE;
    i#call_monitor (#LOC (rb), #SIZE (rb));

    { Remove data from the System Message buffer until the 'remove' pointer equals the 'add' pointer.  All
    { the data after the 'remove' pointer and before the 'add' pointer is valid data.

    WHILE i#current_sequence_position (rb.sys_msg_add_data_seq_p) <>
          i#current_sequence_position (rb.sys_msg_remove_data_seq_p) DO

      remove_data_seq_p := rb.sys_msg_remove_data_seq_p;
      add_data_ptr_offset := i#current_sequence_position (rb.sys_msg_add_data_seq_p);

     /log_sys_msgs_buffer/
      WHILE TRUE DO

        { Check if all of the data has been removed from the buffer.

        IF add_data_ptr_offset = i#current_sequence_position (remove_data_seq_p) THEN
          EXIT /log_sys_msgs_buffer/;
        IFEND;

        { If the end of the buffer has been encountered then the buffer must be searched from the beginning.

        NEXT sys_msg_header_p IN remove_data_seq_p;
        IF sys_msg_header_p^.message_size = 0 THEN
          RESET remove_data_seq_p;
          CYCLE /log_sys_msgs_buffer/;
        IFEND;

        NEXT message_to_log_p: [[REP sys_msg_header_p^.message_size OF cell]] IN remove_data_seq_p;
        access_logging_routines (sys_msg_header_p^, message_to_log_p);
      WHILEND /log_sys_msgs_buffer/;

      { Clear the System Message buffer of the data that was just logged, check if there is any more data.

      rb.sys_msg_clear_buffer := TRUE;
      i#call_monitor (#LOC (rb), #SIZE (rb));
    WHILEND;

  PROCEND dsp$retrieve_system_message;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$signal_handler', EJECT ??

{ PURPOSE:
{   This procedure receives the deadstart signal from monitor and calls the appropriate routine.

  PROCEDURE [XDCL, #GATE] dsp$signal_handler
    (    originator: ost$global_task_id;
         signal: pmt$signal);

    VAR
      signal_data: dst$signal_contents;

     signal_data.signal := signal;
     CASE signal_data.identifier OF
     = dsc$deadstart_signal =
       CASE signal_data.contents.kind OF
       = dsc$signal_lock_unlock_window =
         dsp$lock_unlock_window_from_mtr (signal_data.contents);
       = dsc$signal_post_operator_action =
         post_operator_action (signal_data.contents);
       = dsc$signal_hung_pp_process =
         process_hung_pp_from_mtr (signal_data.contents);
       ELSE
       CASEND;
     ELSE
     CASEND;

  PROCEND dsp$signal_handler;
?? OLDTITLE ??
MODEND dsm$log_system_messages;
