?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Deadstart : Process DFT Requests' ??
MODULE dsm$process_dft_requests;

{ PURPOSE:
{   This module contains all of the procedures which make requests to DFT.
{ DESIGN:
{   The majority of the procedures in this module are called to create the request block that is used to make
{   the DFT request.  All of these procedures then call the one procedure that actually makes the DFT request.
{   This procedure issues a monitor request to make the DFT request.
{ NOTES:
{   This module contains many type declarations that can not be easily changed.  These type declarations
{   define a block of data that the DFT PP program expects to find in a particular order.  Caution must be
{   taken when dealing with these type declarations.  If any changes are made to the type declarations, a
{   corresponding change must be made to the DFT PP program.  All changes must be made in a way to preserve
{   backward compatibility.
{
{   *** ALL DFT REQUESTS THAT ACCESS THE CIP DISK MUST:
{          * INTERLOCK THE CHANNEL BEFORE CALLING DFT
{          * SEND THE REQUEST TO THE 170 SIDE WHEN RUNNING DUALSTATE
?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cmt$device_information
*copyc cmt$element_name
*copyc dmt$ms_logical_device_address
*copyc dse$error_codes
*copyc dst$change_date_time_set
*copyc dst$date_time_information
*copyc dst$deadstart_sector
*copyc dst$device_path
*copyc dst$dft_alert_source
*copyc dst$dft_cpu_selections
*copyc dst$dft_requests
*copyc dst$ds_sector_device_path
*copyc dst$mrt_entry
*copyc dst$rb_issue_dft_request
*copyc dst$resource_name
*copyc dst$vcu_cda_data
*copyc iot$completion_status
*copyc iot$io_function
*copyc osc$multiprocessor_constants
*copyc ost$date_time
*copyc ost$free_running_clock
*copyc ost$hardware_subranges
*copyc ost$pp_size
*copyc ost$processor_id
*copyc ost$status
?? POP ??
*copyc clp$convert_integer_to_string
*copyc cmp$dft_acquire_maintenance
*copyc cmp$dft_release_maintenance
*copyc dpp$put_critical_message
*copyc dsp$allocate_continuous_memory
*copyc dsp$call_dft_through_sda
*copyc dsp$convert_seq_p_to_r_pointer
*copyc dsp$get_ssr_data_r_pointer
*copyc dsp$request_resources
*copyc dsp$retrieve_iou_information
*copyc i#call_monitor
*copyc iop$mass_storage_io
*copyc osp$append_status_parameter
*copyc osp$clear_mainframe_sig_lock
*copyc osp$fatal_system_error
*copyc osp$initialize_signature_lock
*copyc osp$set_mainframe_sig_lock
*copyc osp$set_status_abnormal
*copyc osp$system_error
*copyc pmp$cycle
*copyc pmp$zero_out_table
*copyc syp$process_deadstart_status
?? EJECT ??
*copyc dsv$cip_path
*copyc dsv$mainframe_type
*copyc mtv$cst0
*copyc osv$mainframe_wired_cb_heap
*copyc osv$170_os_type
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
  CONST
    c$cda_cel_name = 'CEL ',
    c$cda_cft_name = 'CFT ',
    c$cda_mrt_name = 'MRT ',
    c$cda_rif_name = 'RIF ',
    c$cda_vcu_name = 'VCU ',

    c$cda_sector_size = (360(8) * 16) DIV 8,
    c$sector_size_for_12_bits_in_16 = 500(8) * 4;

  TYPE
    t$request_destination = (c$os_170_request, c$os_180_request),
    t$sector_for_16_bits_in_16 = RECORD
      sector: ALIGNED [0 MOD 480] PACKED ARRAY [1 .. c$cda_sector_size] OF cell,
    RECEND,
    t$sector_for_12_bits_in_16 = RECORD
      sector: ALIGNED [0 MOD 640]
            PACKED ARRAY [1 .. c$sector_size_for_12_bits_in_16] OF 0 .. 0f(16),
    RECEND;

?? EJECT ??

  VAR

    { The DFT request area sequence pointer is XDCL for debugging purposes.  It is nice to see when a system
    { crashes because of a DFT request.

    dsv$dft_request_area_p: [XDCL] ^SEQ ( * ) := NIL,

    v$dft_request_lock: ost$signature_lock,
    v$dft_request_lock_set: boolean := FALSE;
?? OLDTITLE ??
?? NEWTITLE := 'convert_name_to_cda_name', EJECT ??

{ PURPOSE:
{   This procedure converts a four character name into a CDA name which is in display code.

  PROCEDURE convert_name_to_cda_name
    (    name: dst$resource_name;
     VAR cda_name: dst$dft_cda_name);

    VAR
      display_code_characters: ARRAY [1 .. 4] OF 0 .. 077(8),
      index: 1 .. 4;

    FOR index := 1 TO 4 DO
      IF (name(index) >= '0') AND (name(index) <= '9') THEN
        display_code_characters [index] := $INTEGER (name(index)) - $INTEGER ('0') + 33(8);
      ELSEIF (name(index) >= 'A') AND (name(index) <= 'Z') THEN
        display_code_characters [index] := $INTEGER (name(index)) - $INTEGER ('A') + 01(8);
      ELSEIF (name(index) >= 'a') AND (name(index) <= 'z') THEN
        display_code_characters [index] := $INTEGER (name(index)) - $INTEGER ('a') + 01(8);
      ELSE
        display_code_characters [index] := 0;
      IFEND;
    FOREND;

    cda_name.character_1 := display_code_characters [1];
    cda_name.character_2 := display_code_characters [2];
    cda_name.character_3 := display_code_characters [3];
    cda_name.character_4 := display_code_characters [4];

  PROCEND convert_name_to_cda_name;
?? OLDTITLE ??
?? NEWTITLE := 'interpret_2ap_status', EJECT ??

{ PURPOSE:
{   This procedure converts the 2AP error status returned by DFT to a string and places the result into the
{   result status variable.

  PROCEDURE interpret_2ap_status
    (    request_code: dst$dft_request_codes;
     VAR dft_request_p: ^SEQ( * );
     VAR status: ost$status);

    VAR
      access_cda_sector_p: ^dst$dft_access_cda_sector,
      access_deadstart_sector_p: ^dst$dft_access_deadstart_sector,
      access_mrt_p: ^dst$dft_access_mrt,
      error_text: string (osc$max_string_size),
      integer_string: ost$string,
      request_recognized: boolean,
      retrieve_cda_size_p: ^dst$dft_retrieve_cda_size,
      size: ost$string_size,
      status_from_2ap: dst$dft_2ap_status;

    request_recognized := TRUE;
    RESET dft_request_p;
    CASE request_code OF
    = dsc$dft_access_deadstart_sector =
      NEXT access_deadstart_sector_p IN dft_request_p;
      status_from_2ap := access_deadstart_sector_p^.status_from_2ap;
    = dsc$dft_access_cda_sector =
      NEXT access_cda_sector_p IN dft_request_p;
      status_from_2ap := access_cda_sector_p^.status_from_2ap;
    = dsc$dft_access_mrt =
      NEXT access_mrt_p IN dft_request_p;
      status_from_2ap := access_mrt_p^.status_from_2ap;
    = dsc$dft_retrieve_program_size, dsc$dft_retrieve_cda_data_size =
      NEXT retrieve_cda_size_p IN dft_request_p;
      status_from_2ap := retrieve_cda_size_p^.status_from_2ap;
    ELSE
      request_recognized := FALSE;
    CASEND;

    IF request_recognized THEN
      error_text := 'DFT request for 2ap function ';
      size := 30;
      clp$convert_integer_to_string (status_from_2ap.function_number, 8, TRUE, integer_string, status);
      error_text (size, integer_string.size) := integer_string.value (1, integer_string.size);
      size := size + integer_string.size;
      error_text (size, 25) := ' failed:  error status = ';
      size := size + 25;
      clp$convert_integer_to_string (status_from_2ap.error_status, 8, TRUE, integer_string, status);
      error_text (size, integer_string.size) := integer_string.value (1, integer_string.size);
      size := size + integer_string.size;
      error_text (size, 1) := '.';
    ELSE
      error_text := 'DFT returned an unexpected 2AP status error for request code = ';
      size := 64;
      clp$convert_integer_to_string (request_code, 8, TRUE, integer_string, status);
      error_text (size, integer_string.size) := integer_string.value (1, integer_string.size);
      size := size + integer_string.size;
      error_text (size, 1) := '.';
    IFEND;

    osp$set_status_abnormal (dsc$display_processor_id, dse$dft_error_from_2ap, error_text, status);

  PROCEND interpret_2ap_status;
?? OLDTITLE ??
?? NEWTITLE := 'make_dft_request', EJECT ??

{ PURPOSE:
{   This procedure makes a call to monitor to issue a request to DFT.

  PROCEDURE [XDCL] make_dft_request
    (    destination: t$request_destination;
     VAR dft_request_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      access_deadstart_sector_info_p: ^dst$dft_access_deadstart_sector,
      change_element_state_req_p: ^dst$dft_change_element_state,
      controller_name: cmt$element_name,
      device_information: cmt$device_information,
      dft_request_header_p: ^dst$dft_request_header,
      disk_access_requested: boolean,
      device_path: dst$device_path,
      element_name: cmt$element_name,
      integer_string: ost$string,
      maintenance_acquired: boolean,
      mrt_entry: dst$mrt_entry,
      rb: dst$rb_issue_dft_request,
      size: ost$string_size,
      sp_error_seq_p: ^SEQ ( * ),
      text: string (osc$max_string_size),
      text_length: integer,
      unit_shared_interlock_set: boolean;

    status.normal := TRUE;

    IF NOT v$dft_request_lock_set THEN
      osp$initialize_signature_lock (v$dft_request_lock, status);
      IF NOT status.normal THEN
        osp$system_error (' Error in setting the DFT request interlock.', ^status);
      IFEND;
      v$dft_request_lock_set := TRUE;
    IFEND;

    { Determine whether the request requires disk access.

    RESET dft_request_p;
    NEXT dft_request_header_p IN dft_request_p;
    CASE dsv$mainframe_type OF
    = dsc$mt_962_972_mainframe, dsc$mt_992_mainframe, dsc$mt_2000_mainframe =
      disk_access_requested := FALSE;
    ELSE
      CASE dft_request_header_p^.request_code OF
      = dsc$dft_read_cda_program, dsc$dft_access_cda_sector, dsc$dft_access_deadstart_sector,
            dsc$dft_retrieve_program_size, dsc$dft_retrieve_cda_data_size =
        disk_access_requested := TRUE;
      = dsc$dft_update_hardware_clock, dsc$dft_access_mrt =
        disk_access_requested := (dsv$mainframe_type <> dsc$mt_93x_mainframe);
      ELSE
        disk_access_requested := FALSE;
      CASEND;
    CASEND;

    { Find the path to the CIP device.

    IF NOT dsv$cip_path.cip_path THEN

      { The following boolean must be set before the call to read the MRT because the call to read
      { the MRT subsequently calls this procedure.  A loop will result unless this boolean is set
      { before the call.

      CASE dsv$mainframe_type OF
      = dsc$mt_962_972_mainframe, dsc$mt_992_mainframe, dsc$mt_2000_mainframe =
        dsv$cip_path.cip_path := TRUE;

      ELSE
        dsv$cip_path.cip_path := TRUE;
        dsp$read_mrt_entry (dsc$mrt_id_global_processor, 0, mrt_entry, status);
        IF NOT status.normal THEN
          dsv$cip_path.cip_path := FALSE;
          RETURN;
        IFEND;

        { The CIP device is defined the same on both IOUs.  The IOU number is not used when
        { accessing the CIP device.  It is therefore just set to zero.

        dsv$cip_path.iou_number := 0;
        dsv$cip_path.channel_number := mrt_entry.global_processor.cip_channel;
        dsv$cip_path.unit_number := mrt_entry.global_processor.cip_disk_unit;
        dsv$cip_path.device_type := mrt_entry.global_processor.cip_disk_type;
      CASEND;
    IFEND;

    { Accessing the deadstart sector is performed only on a VE device.  No request should be sent to NOS to
    { access the deadstart sector.  The lock on the call to cmp$set_unit_shared should not be set when
    { accessing the deadstart sector because the lock will be set by device management when an attempt is
    { made to initialize the volume.

    IF disk_access_requested THEN
      IF dft_request_header_p^.request_code <> dsc$dft_access_deadstart_sector THEN
        device_path.iou_number := dsv$cip_path.iou_number;
        device_path.channel_number := dsv$cip_path.channel_number;
        device_path.unit_number := dsv$cip_path.unit_number;
        device_path.device_type := dsv$cip_path.device_type;
        device_path.cip_path := TRUE;
        unit_shared_interlock_set := TRUE;
      ELSE
        RESET dft_request_p;
        NEXT access_deadstart_sector_info_p IN dft_request_p;
        device_path.iou_number := access_deadstart_sector_info_p^.iou_number;
        device_path.channel_number := access_deadstart_sector_info_p^.channel_number;
        device_path.unit_number := access_deadstart_sector_info_p^.unit_number;
        device_path.device_type := access_deadstart_sector_info_p^.device_type;
        device_path.cip_path := ((device_path.iou_number = dsv$cip_path.iou_number) AND
              (device_path.channel_number = dsv$cip_path.channel_number) AND
              (device_path.unit_number = dsv$cip_path.unit_number) AND
              (device_path.device_type = dsv$cip_path.device_type));
        unit_shared_interlock_set := FALSE;
      IFEND;
    IFEND;
    maintenance_acquired := FALSE;

    osp$set_mainframe_sig_lock (v$dft_request_lock);

   /lock_set/
    BEGIN

      { Setup a buffer area in memory for the request to DFT.  This area must be continuous because
      { a PP (DFT) will be reading from or writing into this area.

      RESET dft_request_p;
      IF dsv$dft_request_area_p <> NIL THEN
        FREE dsv$dft_request_area_p IN osv$mainframe_wired_cb_heap^;
      IFEND;
      dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap, #SIZE (dft_request_p^),
            dsv$dft_request_area_p);
      rb.status.normal := TRUE;
      rb.dft_request_p := dsv$dft_request_area_p;
      RESET rb.dft_request_p;
      rb.dft_request_p^ := dft_request_p^;
      NEXT dft_request_header_p IN rb.dft_request_p;
      dft_request_header_p^.request_status := dsc$dft_rs_no_response;

      { Issue the DFT request.

      IF destination = c$os_170_request THEN
        dsp$call_dft_through_sda (rb.dft_request_p);
      ELSE

        { If the request accesses the disk then maintenance can not be using the disk at the same time.
        { If the disk is not being used then the disk must be reserved.  This does not have to happen
        { when the execution is in the boot.

        IF disk_access_requested THEN
          cmp$dft_acquire_maintenance (device_path, device_information, controller_name,
                element_name, unit_shared_interlock_set, maintenance_acquired, status);
          IF NOT status.normal THEN
            EXIT /lock_set/;
          IFEND;
        IFEND;

        { Call monitor to issue the request to DFT.

        rb.reqcode := syc$rc_issue_dft_request;
        i#call_monitor (#LOC (rb), #SIZE (rb));

        { Clear the shared unit if it was set.

        IF maintenance_acquired THEN
          cmp$dft_release_maintenance (device_information, controller_name, element_name,
                unit_shared_interlock_set, status);
          IF NOT status.normal THEN
            EXIT /lock_set/;
          IFEND;
        IFEND;
      IFEND;

      dft_request_p^ := rb.dft_request_p^;

      { Process the abnormal status and DFT timeout condition.

      IF NOT rb.status.normal THEN
        osp$set_status_abnormal (dsc$display_processor_id, rb.status.condition, '', status);
        EXIT /lock_set/;
      IFEND;

      CASE dft_request_header_p^.request_status OF
      = dsc$dft_rs_no_response =
        text := 'DFT is not responding ';
        size := 23;
        IF disk_access_requested THEN
          IF dft_request_header_p^.request_code <> dsc$dft_access_deadstart_sector THEN
            text (size, 13) := 'on channel = ';
            size := size + 13;
            clp$convert_integer_to_string (dsv$cip_path.channel_number, 10, TRUE, integer_string, status);
            text (size, integer_string.size) := integer_string.value (1, integer_string.size);
          ELSE
            NEXT access_deadstart_sector_info_p IN dft_request_p;
            text (size, 13) := 'on channel = ';
            size := size + 13;
            clp$convert_integer_to_string (access_deadstart_sector_info_p^.channel_number, 10, TRUE,
                  integer_string, status);
            text (size, integer_string.size) := integer_string.value (1, integer_string.size);
            size := size + integer_string.size;
            text (size, 9) := ', unit = ';
            size := size + 9;
            clp$convert_integer_to_string (access_deadstart_sector_info_p^.unit_number, 10, TRUE,
                  integer_string, status);
            text (size, integer_string.size) := integer_string.value (1, integer_string.size);
            size := size + integer_string.size;
            text (size, 1) := '.';
            RESET dft_request_p;
          IFEND;
        IFEND;
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_not_responding, text, status);
      = dsc$dft_rs_request_complete =
        { No abnormal status, request completed.
      = dsc$dft_rs_request_failed =
        STRINGREP (text, text_length, 'The DFT request, ', dft_request_header_p^.request_code: #(8),
              ', failed.');
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_request_failed, text (1, text_length),
              status);
      = dsc$dft_rs_invalid_cda_read =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_invalid_cda_read,
              'The CDA sector requested to be read contains invalid data.', status);
      = dsc$dft_rs_retry_request =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_retry_request,
              'The DFT request failed, but maybe retried.', status);
      = dsc$dft_rs_2ap_error =
        interpret_2ap_status (dft_request_header_p^.request_code, rb.dft_request_p, status);
      = dsc$dft_rs_incorrect_version =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_dual_i4_not_supported,
              'DFT buffer structure at incorrect version for dual IOU support.', status);
      = dsc$dft_rs_hw_element_not_found =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_hw_element_not_found,
              'DFT request failed, hardware element not found.', status);
      = dsc$dft_rs_hw_element_reserved =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_hw_element_reserved,
              'DFT request failed, hardware element reserved.', status);
      = dsc$dft_rs_hw_ele_not_power_up =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_hw_element_not_power_up,
              'DFT request failed, hardware element not powered up.', status);
      = dsc$dft_rs_insuff_req_length =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_insuff_request_length,
              'DFT request failed, request length insufficient for response.', status);
      = dsc$dft_rs_state_already_exists =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_state_already_exists, '', status);
      = dsc$dft_rs_state_not_changed =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_state_not_changed, '', status);
      = dsc$dft_rs_state_part_changed =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_state_part_changed, '', status);
      = dsc$dft_rs_undefined_mrt_state =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_undefined_mrt_state, '', status);
      = dsc$dft_rs_undefined_req_state =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_undefined_req_state, '', status);
      = dsc$dft_rs_sp_error =
        IF dft_request_header_p^.request_code = dsc$dft_change_element_state THEN
          sp_error_seq_p := rb.dft_request_p;
          RESET sp_error_seq_p;
          NEXT change_element_state_req_p IN sp_error_seq_p;
          clp$convert_integer_to_string (change_element_state_req_p^.sp_status, 16, TRUE, integer_string,
                status);
        ELSE
          integer_string.value := ' UNKNOWN';
          integer_string.size := 8;
        IFEND;
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_sp_error,
              integer_string.value (1, integer_string.size), status);
      = dsc$dft_rs_reissue_request =
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_reissue_request, '', status);
      ELSE
        clp$convert_integer_to_string (dft_request_header_p^.request_status, 16, TRUE, integer_string,
              status);
        osp$set_status_abnormal (dsc$display_processor_id, dse$dft_returned_unknown_status,
              integer_string.value (1, integer_string.size), status);
      CASEND;

    END /lock_set/;

    osp$clear_mainframe_sig_lock (v$dft_request_lock);

  PROCEND make_dft_request;
?? OLDTITLE ??
?? NEWTITLE := 'pack_sector', EJECT ??

{ PURPOSE:
{   This procedure takes data that is in the format of twelve bits of data in a sixteen bit unit and removes
{   the four bits of unused data.  The result is a continuous stream of data.  A PP passes data to the OS
{   from CTI in the unpacked format and this procedure removes the unused bits for the OS.

  PROCEDURE pack_sector
    (    unpacked_sector_p: ^t$sector_for_12_bits_in_16;
     VAR packed_sector_p: ^t$sector_for_12_bits_in_16);

    VAR
      index_1: 1 .. 500(8),
      index_2: 1 .. 3,
      packed_index: 1 .. (c$sector_size_for_12_bits_in_16 + 1),
      unpacked_index: 1 .. (c$sector_size_for_12_bits_in_16 + 1);

    { The unpacked_sector array is an array of half bytes.  For every sixteen bit units the first four bits
    { are zero and the last twelve bits are valid data.  The first four bits are ignored and the last twelve
    { bits of data are placed in the packed_sector array.  The unpacked_index is the index to the
    { unpacked_sector array and the packed_index is the index to the packed_sector array.  The first FOR LOOP
    { divides the arrays into sixteen bit units and the second FOR LOOP is for removing the last twelve bits
    { (three half bytes) of the sixteen bit units.

    unpacked_index := 1;
    packed_index := 1;
    FOR index_1 := 1 TO 500(8) DO
      unpacked_index := unpacked_index + 1;
      FOR index_2 := 1 TO 3 DO
        packed_sector_p^.sector [packed_index] := unpacked_sector_p^.sector [unpacked_index];
        packed_index := packed_index + 1;
        unpacked_index := unpacked_index + 1;
      FOREND;
    FOREND;

  PROCEND pack_sector;
?? OLDTITLE ??
?? NEWTITLE := 'unpack_sector', EJECT ??

{ PURPOSE:
{   This procedure takes a continuous stream of data and places it in the format of twelve bits of data in a
{   sixteen bit unit.  This is the format in which CTI expects data when it is received by a PP.

  PROCEDURE unpack_sector
    (    packed_sector_p: ^t$sector_for_12_bits_in_16;
     VAR unpacked_sector_p: ^t$sector_for_12_bits_in_16);

    VAR
      index_1: 1 .. 500(8),
      index_2: 1 .. 3,
      packed_index: 1 .. (c$sector_size_for_12_bits_in_16 + 1),
      unpacked_index: 1 .. (c$sector_size_for_12_bits_in_16 + 1);

    { The unpacked_sector array is an array of half bytes.  For every sixteen bit unit the first four bits
    { are zero and the last twelve bits are valid data from the packed_sector array.  The first FOR LOOP
    { divides the arrays into sixteen bit units and the second FOR LOOP fills the last twelve bits (three
    { half bytes) of the sixteen bit units.

    unpacked_index := 1;
    packed_index := 1;
    FOR index_1 := 1 TO 500(8) DO
      unpacked_sector_p^.sector [unpacked_index] := 0;
      unpacked_index := unpacked_index + 1;
      FOR index_2 := 1 TO 3 DO
        unpacked_sector_p^.sector [unpacked_index] := packed_sector_p^.sector [packed_index];
        packed_index := packed_index + 1;
        unpacked_index := unpacked_index + 1;
      FOREND;
    FOREND;

  PROCEND unpack_sector;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$access_deadstart_sector', EJECT ??

{ PURPOSE:
{   This procedure reads or writes the deadstart sector from the CIP device using the device path given
{   as a parameter.

  PROCEDURE [XDCL] dsp$access_deadstart_sector
    (    ds_sector_device_path: dst$ds_sector_device_path;
     VAR deadstart_sector_data_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      cda_sector_12_bit_p: ^t$sector_for_12_bits_in_16,
      completion_status_p: ^iot$completion_status,
      deadstart_sector_data_seq_p: ^SEQ ( * ),
      device_address: dmt$ms_logical_device_address,
      dft_request: dst$dft_access_deadstart_sector,
      dft_request_seq_p: ^SEQ ( * ),
      io_function: iot$io_function,
      temp_sector_data_p: ^t$sector_for_12_bits_in_16,
      temp_sector_data_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_not_allowed_on_cy2000,
            'DFT request not allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    { An area is allocated in mainframe wired to store the deadstart sector.  This area must not cross a page
    { boundary because a PP will be writing data into this area and reading data from this area.  The type
    { declaration of the pointer that is allocated is aligned such that it does not cross a page boundary.

    ALLOCATE temp_sector_data_p IN osv$mainframe_wired_cb_heap^;
    ALLOCATE cda_sector_12_bit_p IN osv$mainframe_wired_cb_heap^;
    pmp$zero_out_table (^temp_sector_data_p^.sector, #SIZE (temp_sector_data_p^.sector));
    pmp$zero_out_table (^cda_sector_12_bit_p^.sector, #SIZE (cda_sector_12_bit_p^.sector));
    temp_sector_data_seq_p := #SEQ (temp_sector_data_p^.sector);
    RESET temp_sector_data_seq_p;

    IF ds_sector_device_path.access_type = dsc$write_ds_sector THEN
      NEXT deadstart_sector_data_seq_p:
            [[REP #SIZE (deadstart_sector_data_p^) OF cell]] IN temp_sector_data_seq_p;
      deadstart_sector_data_seq_p^ := deadstart_sector_data_p^;
      RESET temp_sector_data_seq_p;
      unpack_sector (temp_sector_data_p, cda_sector_12_bit_p);
    IFEND;

    IF ds_sector_device_path.disk_type = dsc$large_sector_disk THEN

      { The disk type is a large sector disk (S0).  These types of disks are read with iop$mass_storage_io
      { instead of by DFT.

      device_address.maus_per_position := ds_sector_device_path.maus_per_cylinder;
      device_address.logical_unit_number := ds_sector_device_path.logical_unit_number;
      device_address.transfer_length := 1;
      device_address.transfer_mau_offset := 0;
      device_address.write_translation := FALSE;

      { CM3/FSD2 deadstart sector location Cylinder 702(10), Track 0, Sector 0.

      device_address.allocation_unit_mau_address := ds_sector_device_path.deadstart_sector_mau;
      IF ds_sector_device_path.access_type = dsc$write_ds_sector THEN
        io_function := ioc$explicit_write;
      ELSE
        io_function := ioc$explicit_read;
      IFEND;
      iop$mass_storage_io (cda_sector_12_bit_p, #SIZE (cda_sector_12_bit_p^.sector),
            io_function, device_address, TRUE, completion_status_p, status);
    ELSE

      { DFT reads all other types of disks.

      dft_request.header.request_code := dsc$dft_access_deadstart_sector;
      dft_request.iou_number := ds_sector_device_path.iou_number;
      dft_request.channel_number := ds_sector_device_path.channel_number;
      dft_request.unit_number := ds_sector_device_path.unit_number;
      dft_request.device_type := ds_sector_device_path.device_type;
      dft_request.write_sector := (ds_sector_device_path.access_type = dsc$write_ds_sector);
      dsp$convert_seq_p_to_r_pointer (#SEQ (cda_sector_12_bit_p^.sector),
            dft_request.deadstart_sector_data_rp);
      dft_request_seq_p := #SEQ (dft_request);
      make_dft_request (c$os_180_request, dft_request_seq_p, status);
    IFEND;
    IF NOT status.normal THEN
      syp$process_deadstart_status ('Error attempting to access deadstart sector', FALSE, status);
      FREE temp_sector_data_p IN osv$mainframe_wired_cb_heap^;
      FREE cda_sector_12_bit_p IN osv$mainframe_wired_cb_heap^;
      RETURN;
    IFEND;

    IF ds_sector_device_path.access_type = dsc$read_ds_sector THEN
      pack_sector (cda_sector_12_bit_p, temp_sector_data_p);
      RESET temp_sector_data_seq_p;
      NEXT deadstart_sector_data_seq_p:
            [[REP #SIZE (deadstart_sector_data_p^) OF cell]] IN temp_sector_data_seq_p;
      deadstart_sector_data_p^ := deadstart_sector_data_seq_p^;
    IFEND;

    FREE temp_sector_data_p IN osv$mainframe_wired_cb_heap^;
    FREE cda_sector_12_bit_p IN osv$mainframe_wired_cb_heap^;

  PROCEND dsp$access_deadstart_sector;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$access_secure_mode', EJECT ??

{ PURPOSE:
{   This procedure activates, deactivates or returns the secure mode.  This request is only valid on a
{   Cyber 2000 Mainframe.

  PROCEDURE [XDCL] dsp$access_secure_mode
    (    access_function: 0 .. 0ff(16);
     VAR mode: 0 .. 0ffff(16);
     VAR status: ost$status);

    VAR
      dft_request: dst$dft_access_secured_mode,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;
    IF dsv$mainframe_type <> dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_only_allowed_on_cy2000,
            'DFT request is only allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_access_secured_mode;
    dft_request.access_function := access_function;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (c$os_180_request, dft_request_seq_p, status);
    IF status.normal THEN
      mode := dft_request.mode;
    IFEND;

  PROCEND dsp$access_secure_mode;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$access_vcu_cda_data', EJECT ??

{ PURPOSE:
{   This procedure accesses the VCU area of the Common Disk Area (CDA) sector.  This sector contains several
{   pieces of data and this procedure accesses the correct piece.

  PROCEDURE [XDCL] dsp$access_vcu_cda_data
    (    type_of_access: dst$vcu_access_type;
         data_accessed: dst$vcu_data_accessed;
     VAR data_p: ^SEQ ( * );
     VAR status: ost$status);

    TYPE
      t$time_zone_variant = RECORD
        initialized: 0 .. 0ff(16),
        hours_from_gmt: integer,
        minutes_offset: integer,
        daylight_saving: 0 .. 0ff(16),
      RECEND;

    VAR
      bucket_data_p: ^dst$vcu_bucket_data,
      bucket_used_p: ^dst$vcu_bucket_types,
      password_data_p: ^dst$vcu_password_data,
      time_zone_data_p: ^dst$vcu_time_zone_data,
      time_zone_for_variant_p: ^dst$vcu_time_zone_data,
      time_zone_variant: t$time_zone_variant,
      time_zone_variant_seq_p: ^SEQ ( * ),
      vcu_cda_data: dst$vcu_cda_data,
      vcu_cda_data_seq_p: ^SEQ ( * ),
      version_p: ^dst$vcu_cda_version;

    status.normal := TRUE;

    RESET data_p;
    IF type_of_access = dsc$vcu_read_access THEN
      vcu_cda_data_seq_p := #SEQ (vcu_cda_data);
      pmp$zero_out_table (^vcu_cda_data_seq_p^, #SIZE (vcu_cda_data_seq_p^));
      dsp$read_cda_sector (c$cda_vcu_name, vcu_cda_data_seq_p, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      CASE data_accessed OF
      = dsc$vcu_bucket_data =
        NEXT bucket_data_p IN data_p;
        bucket_data_p^ := vcu_cda_data.bucket_data;
      = dsc$vcu_time_zone_data =
        time_zone_variant_seq_p := #SEQ (time_zone_variant);
        RESET time_zone_variant_seq_p;
        NEXT time_zone_for_variant_p IN time_zone_variant_seq_p;
        time_zone_for_variant_p^ := vcu_cda_data.time_zone_data;
        IF ((time_zone_variant.initialized < 0) OR (time_zone_variant.initialized > 1)) OR
              ((time_zone_variant.hours_from_gmt < -12) OR (time_zone_variant.hours_from_gmt > 12)) OR
              ((time_zone_variant.minutes_offset < -30) OR (time_zone_variant.minutes_offset > 30)) OR
              ((time_zone_variant.daylight_saving < 0) OR (time_zone_variant.daylight_saving > 1)) THEN
          osp$set_status_abnormal (dsc$display_processor_id, dse$read_invalid_time_zone,
                'Unable to obtain valid time zone data from VCU in the common disk area.', status);
          RETURN;
        IFEND;
        NEXT time_zone_data_p IN data_p;
        time_zone_data_p^ := vcu_cda_data.time_zone_data;
      = dsc$vcu_bucket_used =
        NEXT bucket_used_p IN data_p;
        bucket_used_p^ := vcu_cda_data.bucket_used;
      = dsc$vcu_password_data =
        NEXT password_data_p IN data_p;
        password_data_p^ := vcu_cda_data.password_data;
      = dsc$vcu_version =
        NEXT version_p IN data_p;
        version_p^ := vcu_cda_data.version;
      ELSE
      CASEND;

    ELSE { type_of_access = dsc$vcu_write_access }
      vcu_cda_data_seq_p := #SEQ (vcu_cda_data);
      pmp$zero_out_table (^vcu_cda_data_seq_p^, #SIZE (vcu_cda_data_seq_p^));
      dsp$read_cda_sector (c$cda_vcu_name, vcu_cda_data_seq_p, status);

      {  The status of the previous request is not checked here because if the VCU does not exist
      {  the read will fail but it is fine to try and write it.  The assumption is that this only
      {  happens once.  This should be fixed!

      CASE data_accessed OF
      = dsc$vcu_bucket_data =
        NEXT bucket_data_p IN data_p;
        vcu_cda_data.bucket_data := bucket_data_p^;
      = dsc$vcu_time_zone_data =
        time_zone_variant_seq_p := #SEQ (time_zone_variant);
        RESET time_zone_variant_seq_p;
        NEXT time_zone_for_variant_p IN time_zone_variant_seq_p;
        NEXT time_zone_data_p IN data_p;
        time_zone_for_variant_p^ := time_zone_data_p^;
        IF ((time_zone_variant.initialized < 0) OR (time_zone_variant.initialized > 1)) OR
              ((time_zone_variant.hours_from_gmt < -12) OR (time_zone_variant.hours_from_gmt > 12)) OR
              ((time_zone_variant.minutes_offset < -30) OR (time_zone_variant.minutes_offset > 30)) OR
              ((time_zone_variant.daylight_saving < 0) OR (time_zone_variant.daylight_saving > 1)) THEN
          osp$set_status_abnormal (dsc$display_processor_id, dse$write_invalid_time_zone,
                'Unable to store invalid time zone data in VCU in the common disk area.', status);
          RETURN;
        IFEND;
        vcu_cda_data.time_zone_data := time_zone_data_p^;
      = dsc$vcu_bucket_used =
        NEXT bucket_used_p IN data_p;
        vcu_cda_data.bucket_used := bucket_used_p^;
      = dsc$vcu_password_data =
        NEXT password_data_p IN data_p;
        vcu_cda_data.password_data := password_data_p^;
      = dsc$vcu_version =
        NEXT version_p IN data_p;
        vcu_cda_data.version := version_p^;
      ELSE
      CASEND;
      dsp$write_cda_sector (c$cda_vcu_name, vcu_cda_data_seq_p, status);
    IFEND;

  PROCEND dsp$access_vcu_cda_data;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$change_date_time_info', EJECT ??

{ PURPOSE
{   This procedure changes the date time information in the MRT on a Cyber 2000 mainframe.

  PROCEDURE [XDCL] dsp$change_date_time_info
    (    options_set: dst$change_date_time_set;
         date_time_information: dst$date_time_information;
     VAR status: ost$status);

    VAR
      dft_request: dst$dft_change_date_time_info,
      dft_request_seq_p: ^SEQ ( * );

    IF dsv$mainframe_type <> dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_only_allowed_on_cy2000,
            'DFT request is only allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.flags.update_bst := (dsc$cdt_base_system_time IN options_set);
    dft_request.flags.update_time_zone := (dsc$cdt_time_zone IN options_set);
    dft_request.flags.update_default_date_format := (dsc$cdt_default_date_format IN options_set);
    dft_request.flags.update_default_time_format := (dsc$cdt_default_time_format IN options_set);
    dft_request.flags.update_daylight_status := (dsc$cdt_daylight_saving_time IN options_set);

    IF dft_request.flags.update_bst THEN
      dft_request.bst_wcc.years.tens := date_time_information.bst_wcc.year DIV 10;
      dft_request.bst_wcc.years.units := date_time_information.bst_wcc.year MOD 10;
      dft_request.bst_wcc.months.tens := date_time_information.bst_wcc.month DIV 10;
      dft_request.bst_wcc.months.units := date_time_information.bst_wcc.month MOD 10;
      dft_request.bst_wcc.days.tens := date_time_information.bst_wcc.day DIV 10;
      dft_request.bst_wcc.days.units := date_time_information.bst_wcc.day MOD 10;
      dft_request.bst_wcc.hours.tens := date_time_information.bst_wcc.hour DIV 10;
      dft_request.bst_wcc.hours.units := date_time_information.bst_wcc.hour MOD 10;
      dft_request.bst_wcc.minutes.tens := date_time_information.bst_wcc.minute DIV 10;
      dft_request.bst_wcc.minutes.units := date_time_information.bst_wcc.minute MOD 10;
      dft_request.bst_wcc.seconds.tens := date_time_information.bst_wcc.second DIV 10;
      dft_request.bst_wcc.seconds.units := date_time_information.bst_wcc.second MOD 10;
      dft_request.bst_frc := date_time_information.bst_frc;
    IFEND;

    IF dft_request.flags.update_default_date_format THEN
      CASE date_time_information.default_date.date_format OF
      = osc$month_date =
        dft_request.default_date := dsc$dft_df_month;
      = osc$mdy_date =
        dft_request.default_date := dsc$dft_df_mdy;
      = osc$iso_date =
        dft_request.default_date := dsc$dft_df_isod;
      = osc$ordinal_date =
        dft_request.default_date := dsc$dft_df_ordinal;
      ELSE  {= osc$dmy_date =
        dft_request.default_date := dsc$dft_df_dmy;
      CASEND;
    IFEND;

    IF dft_request.flags.update_default_time_format THEN
      CASE date_time_information.default_time.time_format OF
      = osc$ampm_time =
        dft_request.default_time := dsc$dft_tf_ampm;
      = osc$hms_time =
        dft_request.default_time := dsc$dft_tf_hms;
      ELSE  {= osc$millisecond_time =
        IF date_time_information.default_time.format_string = 'ISOT' THEN
          dft_request.default_time := dsc$dft_tf_isot;
        ELSE
          dft_request.default_time := dsc$dft_tf_millisecond;
        IFEND;
      CASEND;
    IFEND;

    IF dft_request.flags.update_time_zone THEN
      IF date_time_information.time_zone.hours_from_gmt < 0 THEN
        dft_request.time_zone_flags.negative_time_zone_hours := TRUE;
        dft_request.time_zone_hours := date_time_information.time_zone.hours_from_gmt * (-1);
      ELSE
        dft_request.time_zone_flags.negative_time_zone_hours := FALSE;
        dft_request.time_zone_hours := date_time_information.time_zone.hours_from_gmt;
      IFEND;

      IF date_time_information.time_zone.minutes_offset < 0 THEN
        dft_request.time_zone_flags.negative_time_zone_minutes := TRUE;
        dft_request.time_zone_minutes := date_time_information.time_zone.minutes_offset * (-1);
      ELSE
        dft_request.time_zone_flags.negative_time_zone_minutes := FALSE;
        dft_request.time_zone_minutes := date_time_information.time_zone.minutes_offset;
      IFEND;
    IFEND;

    IF dft_request.flags.update_daylight_status THEN
      dft_request.time_zone_flags.daylight_saving_time :=
            date_time_information.time_zone.daylight_saving_time;
    IFEND;

    dft_request.header.request_code := dsc$dft_change_date_time_info;
    dft_request_seq_p := #SEQ (dft_request);
    make_dft_request (c$os_180_request, dft_request_seq_p, status);

  PROCEND dsp$change_date_time_info;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$change_monitor_xp', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to change the monitor exchange package pointer.

  PROCEDURE [XDCL] dsp$change_monitor_xp
    (    number: dst$dft_cpu_selections;
         mps: ost$real_memory_address;
     VAR status: ost$status );

    VAR
      dft_request: dst$dft_change_monitor_xp,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_change_monitor_xp;
    dft_request.number := number;
    dft_request.mps := mps;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (c$os_180_request, dft_request_seq_p, status);

  PROCEND dsp$change_monitor_xp;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$change_cy2000_element', EJECT ??

{ PURPOSE:
{   This procedure makes a request to the service processor to change an element in the MRT.

  PROCEDURE [XDCL] dsp$change_cy2000_element
    (    element_id: 0 .. 0ff(16);
         sub_element_id: 0 .. 0ffff(16);
         state: 0 .. 0ff(16);
     VAR status: ost$status);

    TYPE
      t$states = RECORD
        ordinal: 0 .. 0ff(16),
        data: string (40),
        data_size: 0 .. 40,
      RECEND;

    VAR
      dft_request: dst$dft_change_element_state,
      dft_request_seq_p: ^SEQ ( * ),
      index: 1 .. 3,
      states: ARRAY [1 .. 3] OF t$states;

    status.normal := TRUE;
    IF dsv$mainframe_type <> dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_only_allowed_on_cy2000,
            'DFT request is only allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_change_element_state;
    dft_request.element := element_id;
    dft_request.sub_element := sub_element_id;
    dft_request.state := state;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (c$os_180_request, dft_request_seq_p, status);
    IF NOT status.normal THEN
      states [1].ordinal := dft_request.state;
      states [2].ordinal := dft_request.before_state;
      states [3].ordinal := dft_request.after_state;

      FOR index := 1 TO 3 DO
        CASE states [index].ordinal OF
        = dsc$dft_state_on =
          states [index].data := 'ON';
          states [index].data_size := 2;
        = dsc$dft_state_off =
          states [index].data := 'OFF';
          states [index].data_size := 3;
        = dsc$dft_state_down_by_system =
          states [index].data := 'DOWN_BY_SYSTEM';
          states [index].data_size := 14;
        = dsc$dft_state_down_by_operator =
          states [index].data := 'DOWN_BY_OPERATOR';
          states [index].data_size := 16;
        = dsc$dft_state_powered_off =
          states [index].data := 'POWERED_OFF';
          states [index].data_size := 11;
        = dsc$dft_state_pow_off_and_off =
          states [index].data := 'POWERED_OFF_AND_OFF';
          states [index].data_size := 19;
        = dsc$dft_state_pow_off_and_down =
          states [index].data := 'POWERED_OFF_AND_DOWN_BY_OPERATOR';
          states [index].data_size := 32;
        = dsc$dft_state_not_installed =
          states [index].data := 'NOT_INSTALLED';
          states [index].data_size := 13;
        ELSE
          states [index].data := 'UNKNOWN';
          states [index].data_size := 7;
        CASEND;
      FOREND;

      IF status.condition = dse$dft_state_not_changed THEN
        osp$append_status_parameter (osc$status_parameter_delimiter,
              states [2].data (1, states [2].data_size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter,
              states [1].data (1, states [1].data_size), status);
      ELSEIF status.condition = dse$dft_state_part_changed THEN
        osp$append_status_parameter (osc$status_parameter_delimiter,
              states [3].data (1, states [3].data_size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter,
              states [1].data (1, states [1].data_size), status);
      IFEND;
    IFEND;

  PROCEND dsp$change_cy2000_element;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$dft_issue_system_alert', EJECT ??

{ PURPOSE:
{   This procedure issues a system alert to the service processor DFT.

  PROCEDURE [XDCL, #GATE] dsp$dft_issue_system_alert
    (    alert_source: dst$dft_alert_source;
         supportive_information_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      dft_request_entry_p: ^SEQ ( * ),
      dft_request_p: ^dst$dft_system_state_alert,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;
    IF dsv$mainframe_type <> dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_only_allowed_on_cy2000,
            'DFT request is only allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap,
          (#SIZE (dst$dft_system_state_alert) + #SIZE (supportive_information_p^)), dft_request_seq_p);
    RESET dft_request_seq_p;
    pmp$zero_out_table (^dft_request_seq_p^, #SIZE (dft_request_seq_p^));
    NEXT dft_request_p IN dft_request_seq_p;
    dft_request_p^.header.request_code := dsc$dft_system_state_alert;
    dft_request_p^.flags.hpa_ve_alert := (alert_source = dsc$dft_as_hpa_ve);
    dft_request_p^.supportive_information_length := #SIZE (supportive_information_p^) DIV 8;
    NEXT dft_request_entry_p: [[REP #SIZE (supportive_information_p^) OF cell]] IN dft_request_seq_p;
    RESET dft_request_entry_p;
    dft_request_entry_p^ := supportive_information_p^;
    RESET dft_request_seq_p;

    make_dft_request (c$os_180_request, dft_request_seq_p, status);
    FREE dft_request_seq_p IN osv$mainframe_wired_cb_heap^;

  PROCEND dsp$dft_issue_system_alert;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$get_cy2000_element', EJECT ??

{ PURPOSE:
{   This procedure makes a request to the service processor to read an element from the MRT.

  PROCEDURE [XDCL] dsp$get_cy2000_element
    (    element_id: 0 .. 0ff(16);
         sub_element_id: 0 .. 0ffff(16);
     VAR entry_p: ^SEQ ( * );
     VAR status: ost$status);


    VAR
      dft_entry_p: ^SEQ ( * ),
      dft_request_p: ^dst$dft_get_element_header,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;
    IF dsv$mainframe_type <> dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_only_allowed_on_cy2000,
            'DFT request is only allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    { Build the DFT request.

    dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap,
          (#SIZE (dst$dft_get_element_header) + #SIZE (entry_p^)), dft_request_seq_p);
    RESET dft_request_seq_p;
    pmp$zero_out_table (^dft_request_seq_p^, #SIZE (dft_request_seq_p^));

    NEXT dft_request_p IN dft_request_seq_p;
    dft_request_p^.header.request_code := dsc$dft_get_element_description;
    dft_request_p^.element := element_id;
    dft_request_p^.sub_element := sub_element_id;
    dft_request_p^.length := #SIZE (entry_p^) DIV 8;
    RESET dft_request_seq_p;

    { Make the DFT request.

    make_dft_request (c$os_180_request, dft_request_seq_p, status);
    IF status.normal THEN
      RESET dft_request_seq_p;
      NEXT dft_request_p IN dft_request_seq_p;
      NEXT dft_entry_p: [[REP #SIZE (entry_p^) OF cell]] IN dft_request_seq_p;
      RESET dft_entry_p;
      entry_p^ := dft_entry_p^;
    IFEND;

    FREE dft_request_seq_p IN osv$mainframe_wired_cb_heap^;

  PROCEND dsp$get_cy2000_element;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$get_iou_status_register', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to get the IOU status register (register 40(16)).

  PROCEDURE [XDCL] dsp$get_iou_status_register
    (    iou_number: dst$iou_number;
     VAR iou_status_register: integer;
     VAR status: ost$status);

    VAR
      dft_request: dst$dft_get_iou_status_register,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_get_iou_status_register;
    dft_request.iou_number := iou_number;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (c$os_180_request, dft_request_seq_p, status);
    IF status.normal THEN
      iou_status_register := dft_request.iou_status_register;
    IFEND;

  PROCEND dsp$get_iou_status_register;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$load_additional_dft', EJECT ??

{ PURPOSE:
{   If running on a machine with two IOU's, the procedure sets up the secondary DFT buffer and
{   issues a request to DFT to start up DFT in the secondary IOU.

  PROCEDURE [XDCL] dsp$load_additional_dft
    (VAR status: ost$status);

    VAR
      dft_request: dst$dft_load_additional_dft,
      dft_request_seq_p: ^SEQ ( * ),
      iou_information_table: dst$iou_information_table,
      iou1_index: dst$number_of_ious,
      number_of_ious: dst$number_of_ious,
      request: dst$resource_request,
      retry_count: 1 .. 6;

    status.normal := TRUE;

    { Cyber 2000 mainframes do not use a secondary DFT.  Do not return an error.

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      RETURN;
    IFEND;

    { Check for number of IOU's on the system.  Subsequent code will be executed only for a Dual IOU system.

    dsp$retrieve_iou_information (number_of_ious, iou_information_table);
    IF number_of_ious = 1 THEN
      RETURN;
    IFEND;

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    { Find the iou_information_table index for iou1 information.

    iou1_index := LOWERVALUE (dst$number_of_ious);
    WHILE iou_information_table [iou1_index].physical_iou_number <> 1 DO
      IF iou1_index = dsc$max_number_of_ious THEN
        osp$system_error ('Secondary IOU not found in iou_information_table.', NIL);
      ELSE
        iou1_index := iou1_index + 1;
      IFEND;
    WHILEND;

    { Find a pp for the secondary DFT (DFTs).

    request.resource_request_type := dsc$rrt_get_pp;
    request.channel.number := 2;
    request.channel.iou_number := 1;
    CASE iou_information_table [iou1_index].model_type OF
    = dsc$imn_i4_44_model =
      request.channel.channel_protocol := dsc$cpt_cio;
    ELSE
      request.channel.channel_protocol := dsc$cpt_nio;
    CASEND;
    request.options := $dst$resource_request_options [ ];
    dsp$request_resources (request, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { Build the DFT request.

    dft_request.header.request_code := dsc$dft_load_additional_dft;
    dft_request.pp := request.primary_pp;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    retry_count := 1;
    REPEAT
      make_dft_request (c$os_180_request, dft_request_seq_p, status);
      retry_count := retry_count + 1;
    UNTIL status.normal OR (retry_count > 5) OR
          ((NOT status.normal) AND (status.condition <> dse$dft_retry_request));

  PROCEND dsp$load_additional_dft;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$manage_virtual_cpu', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to halt the cpu.

  PROCEDURE [XDCL] dsp$manage_virtual_cpu
    (    number: ost$processor_id);

    VAR
      dft_request: dst$dft_manage_virtual_cpu,
      dft_request_seq_p: ^SEQ ( * ),
      local_status: ost$status;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_manage_virtual_cpu;
    dft_request.number := number;
    dft_request.action := 1;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.  If DFT is not responding then halt the system since the state of the CPU
    { is unknown.  Otherwise, DFT has at least shut down the memory port and the CPU as far as we are
    { concerned is "down".  Problems may occur when an attempt is made to on the CPU but they will be
    { addressed when the attempt is made.

    make_dft_request (c$os_180_request, dft_request_seq_p, local_status);
    IF NOT local_status.normal AND (local_status.condition = dse$dft_not_responding) THEN
{     osp$fatal_system_error ('DFT not responding when attempting to halt a CPU.', ^local_status);
    dpp$put_critical_message ('DFT not responding when attempting to halt CPU', local_status);
    dpp$put_critical_message ('Continueing - assuming CPU is Down', local_status);
    IFEND;

  PROCEND dsp$manage_virtual_cpu;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$process_pp_function', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to process a PP function.

  PROCEDURE [XDCL] dsp$process_pp_function
    (    subfunction: dst$dft_puf_subfunctions;
         pp: dst$iou_resource;
         resume_address: dst$dft_resume_address;
         pp_length: ost$pp_byte_size;
     VAR pp_data_seq_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      dft_request: dst$dft_process_pp_function,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_process_pp_function;
    dft_request.subfunction := subfunction;
    dft_request.pp := pp;
    dft_request.resume_address := resume_address;
    IF pp_data_seq_p <> NIL THEN
      dsp$convert_seq_p_to_r_pointer (pp_data_seq_p, dft_request.pp_image_rp);
      dft_request.pp_image_rp.length := (pp_length + 7) DIV 8;
    IFEND;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (c$os_180_request, dft_request_seq_p, status);

  PROCEND dsp$process_pp_function;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$read_cda_program', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to read a CDA program into the area specified as a parameter.

  PROCEDURE [XDCL] dsp$read_cda_program
    (    name: dst$resource_name;
     VAR program_data_p: ^SEQ ( * );
     VAR length: integer;
     VAR status: ost$status);

    VAR
      destination: t$request_destination,
      dft_request: dst$dft_read_cda_program,
      dft_request_seq_p: ^SEQ ( * ),
      first_word_address: integer,
      last_word_address: integer,
      r_pointer: dst$r_pointer;

    status.normal := TRUE;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    IF osv$170_os_type = osc$ot7_none THEN
      destination := c$os_180_request;
    ELSE
      destination := c$os_170_request;
    IFEND;
    dft_request.header.request_code := dsc$dft_read_cda_program;
    dsp$convert_seq_p_to_r_pointer (program_data_p, r_pointer);
    dft_request.program_rp.offset := r_pointer.offset;
    dft_request.program_rp.rlower := r_pointer.rlower;
    dft_request.program_rp.rupper := r_pointer.rupper;
    convert_name_to_cda_name (name, dft_request.name);
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (destination, dft_request_seq_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { Find the length of the CIP program.

    i#real_memory_address (program_data_p, first_word_address);
    last_word_address := ((dft_request.last_word_rp.rupper * 10000(8)) +
          (dft_request.last_word_rp.rlower MOD 10000(8))) * 100(8);
    last_word_address := (last_word_address + dft_request.last_word_rp.offset) * 8;
    length := last_word_address - first_word_address;

  PROCEND dsp$read_cda_program;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$read_cda_sector', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to read a sector from the common disk area.

  PROCEDURE [XDCL] dsp$read_cda_sector
    (    name: dst$resource_name;
     VAR sector_data_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      cda_data_seq_p: ^SEQ ( * ),
      cda_data_size: integer,
      cda_sector_data_p: ^SEQ ( * ),
      cda_sector_12_bit_p: ^t$sector_for_12_bits_in_16,
      destination: t$request_destination,
      dft_request: dst$dft_access_cda_sector,
      dft_request_seq_p: ^SEQ ( * ),
      temp_sector_data_p: ^t$sector_for_12_bits_in_16,
      temp_sector_data_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    { An area is allocated in mainframe wired to store the cda sector.  This area
    { must not cross a page boundary because a PP is writing data to this area.

    dsp$retrieve_cda_data_size (name, cda_data_size, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap, cda_data_size, cda_data_seq_p);
    RESET cda_data_seq_p;
    pmp$zero_out_table (^cda_data_seq_p^, cda_data_size);

   /request_cda_size/
    BEGIN

      { Build the DFT request.

      pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

      IF osv$170_os_type = osc$ot7_none THEN
        destination := c$os_180_request;
      ELSE
        destination := c$os_170_request;
      IFEND;
      dft_request.header.request_code := dsc$dft_access_cda_sector;
      convert_name_to_cda_name (name, dft_request.name);
      dft_request.cda_information.valid_data := FALSE;
      dft_request.cda_information.sixteen_bits := (name <> c$cda_cel_name);
      dft_request.cda_information.partial_read := FALSE;
      dft_request.cda_information.write_data := FALSE;
      dft_request.cda_information.cel_sector := (name = c$cda_cel_name);
      dsp$convert_seq_p_to_r_pointer (cda_data_seq_p, dft_request.cda_sector_data_rp);
      dft_request_seq_p := #SEQ (dft_request);

      { Make the DFT request.

      make_dft_request (destination, dft_request_seq_p, status);
      IF NOT status.normal THEN
        EXIT /request_cda_size/;
      IFEND;

      { Move the data from where DFT wrote the data to the callers sequence.

     /move_data/
      BEGIN
        IF name = c$cda_cel_name THEN
          ALLOCATE temp_sector_data_p IN osv$mainframe_wired_cb_heap^;
          IF #SIZE (sector_data_p^) > #SIZE (temp_sector_data_p^.sector) THEN
            osp$set_status_abnormal (dsc$display_processor_id, dse$cda_too_large,
                  'The CDA data is too large for the callers sequence area.', status);
            EXIT /move_data/;
          IFEND;
          pmp$zero_out_table (^temp_sector_data_p^.sector, #SIZE (temp_sector_data_p^.sector));
          temp_sector_data_seq_p := #SEQ (temp_sector_data_p^.sector);
          RESET temp_sector_data_seq_p;
          RESET cda_data_seq_p;
          IF #SIZE (cda_sector_12_bit_p^) > #SIZE (cda_data_seq_p^) THEN
            osp$set_status_abnormal (dsc$display_processor_id, dse$cda_too_large,
                  'The CDA data is too large for the callers sequence area.', status);
            EXIT /move_data/;
          IFEND;
          NEXT cda_sector_12_bit_p IN cda_data_seq_p;
          pack_sector (cda_sector_12_bit_p, temp_sector_data_p);
          RESET temp_sector_data_seq_p;
          NEXT cda_sector_data_p: [[REP #SIZE (sector_data_p^) OF cell]] IN temp_sector_data_seq_p;
          sector_data_p^ := cda_sector_data_p^;
        ELSE
          RESET cda_data_seq_p;
          IF #SIZE (sector_data_p^) > #SIZE (cda_data_seq_p^) THEN
            osp$set_status_abnormal (dsc$display_processor_id, dse$cda_too_large,
                  'The CDA data is too large for the callers sequence area.', status);
            EXIT /move_data/;
          IFEND;
          NEXT cda_sector_data_p: [[REP #SIZE (sector_data_p^) OF cell]] IN cda_data_seq_p;
          sector_data_p^ := cda_sector_data_p^;
        IFEND;
      END /move_data/;

      IF name = c$cda_cel_name THEN
        FREE temp_sector_data_p IN osv$mainframe_wired_cb_heap^;
      IFEND;
    END /request_cda_size/;
    FREE cda_data_seq_p IN osv$mainframe_wired_cb_heap^;

  PROCEND dsp$read_cda_sector;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$read_date_time_information', EJECT ??

{ PURPOSE
{   This procedure reads the date time information from the MRT on a Cyber 2000 mainframe.

  PROCEDURE [XDCL] dsp$read_date_time_information
    (VAR date_time_information: dst$date_time_information;
     VAR status: ost$status);

    VAR
      dft_request: dst$dft_read_date_time_info,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;
    IF dsv$mainframe_type <> dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_only_allowed_on_cy2000,
            'DFT request is only allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_read_date_time_info;
    dft_request_seq_p := #SEQ (dft_request);
    make_dft_request (c$os_180_request, dft_request_seq_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    date_time_information.bst_wcc.millisecond := 0;
    date_time_information.bst_wcc.second := dft_request.bst_wcc.seconds.units +
          dft_request.bst_wcc.seconds.tens * 10;
    date_time_information.bst_wcc.minute := dft_request.bst_wcc.minutes.units +
          dft_request.bst_wcc.minutes.tens * 10;
    date_time_information.bst_wcc.hour := dft_request.bst_wcc.hours.units +
          dft_request.bst_wcc.hours.tens * 10;

    date_time_information.bst_wcc.day := dft_request.bst_wcc.days.units +
          dft_request.bst_wcc.days.tens * 10;
    date_time_information.bst_wcc.month := dft_request.bst_wcc.months.units +
          dft_request.bst_wcc.months.tens * 10;
    date_time_information.bst_wcc.year := dft_request.bst_wcc.years.units +
          dft_request.bst_wcc.years.tens * 10;
    date_time_information.bst_frc := dft_request.bst_frc;

    CASE dft_request.default_date OF
    = dsc$dft_df_month =
      date_time_information.default_date.date_format := osc$month_date;
      date_time_information.default_date.format_string := 'MN D2, Y4';
    = dsc$dft_df_mdy =
      date_time_information.default_date.date_format := osc$mdy_date;
      date_time_information.default_date.format_string := 'M2/D2/Y2';
    = dsc$dft_df_isod =
      date_time_information.default_date.date_format := osc$iso_date;
      date_time_information.default_date.format_string := 'Y4-M2-D2';
    = dsc$dft_df_ordinal =
      date_time_information.default_date.date_format := osc$ordinal_date;
      date_time_information.default_date.format_string := 'Y4J3';
    = dsc$dft_df_dmy =
      date_time_information.default_date.date_format := osc$dmy_date;
      date_time_information.default_date.format_string := 'D2.M2.Y2';
    ELSE  {= dsc$dft_df_default =
      date_time_information.default_date.date_format := osc$iso_date;
      date_time_information.default_date.format_string := 'Y4-M2-D2';
    CASEND;

    CASE dft_request.default_time OF
    = dsc$dft_tf_ampm =
      date_time_information.default_time.time_format := osc$ampm_time;
      date_time_information.default_time.format_string := 'H12:MM AMORPM';
    = dsc$dft_tf_hms =
      date_time_information.default_time.time_format := osc$hms_time;
      date_time_information.default_time.format_string := 'H24:MM:SS';
    = dsc$dft_tf_millisecond =
      date_time_information.default_time.time_format := osc$millisecond_time;
      date_time_information.default_time.format_string := 'H24:MM:SS.S1000';
    = dsc$dft_tf_isot =
      date_time_information.default_time.time_format := osc$millisecond_time;
      date_time_information.default_time.format_string := 'ISOT';
    ELSE  {= dsc$dft_tf_default =
      date_time_information.default_time.time_format := osc$hms_time;
      date_time_information.default_time.format_string := 'HMS';
    CASEND;

    IF dft_request.time_zone_flags.negative_time_zone_hours THEN
      date_time_information.time_zone.hours_from_gmt := dft_request.time_zone_hours * (-1);
    ELSE
      date_time_information.time_zone.hours_from_gmt := dft_request.time_zone_hours;
    IFEND;

    IF dft_request.time_zone_flags.negative_time_zone_minutes THEN
      date_time_information.time_zone.minutes_offset := dft_request.time_zone_minutes * (-1);
    ELSE
      date_time_information.time_zone.minutes_offset := dft_request.time_zone_minutes;
    IFEND;

    date_time_information.time_zone.daylight_saving_time := dft_request.time_zone_flags.daylight_saving_time;

  PROCEND dsp$read_date_time_information;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$read_mrt_entry', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to read an entry from the MRT.

  PROCEDURE [XDCL] dsp$read_mrt_entry
    (    mrt_entry_id: dst$mrt_entry_id;
         mrt_element_number: dst$mrt_element_number;
     VAR mrt_entry: dst$mrt_entry;
     VAR status: ost$status);

    VAR
      destination: t$request_destination,
      dft_request: dst$dft_access_mrt,
      dft_request_seq_p: ^SEQ ( * ),
      mrt_entry_p: ^dst$mrt_entry,
      mrt_entry_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_not_allowed_on_cy2000,
            'DFT request not allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_access_mrt;
    dft_request.read_mrt := 1;
    dft_request.number := mrt_element_number;
    dft_request.entry_id := $INTEGER(mrt_entry_id);
    dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap, #SIZE (dst$mrt_entry), mrt_entry_seq_p);
    RESET mrt_entry_seq_p;
    dsp$convert_seq_p_to_r_pointer (mrt_entry_seq_p, dft_request.mrt_entry_rp);
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    IF osv$170_os_type = osc$ot7_none THEN
      destination := c$os_180_request;
    ELSE
      destination := c$os_170_request;
    IFEND;

    make_dft_request (destination, dft_request_seq_p, status);
    IF status.normal THEN
      RESET mrt_entry_seq_p;
      NEXT mrt_entry_p IN mrt_entry_seq_p;
      mrt_entry := mrt_entry_p^;
    IFEND;
    FREE mrt_entry_seq_p IN osv$mainframe_wired_cb_heap^;

  PROCEND dsp$read_mrt_entry;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$retrieve_cda_data_size', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to obtain the size of a particular CDA data.

  PROCEDURE [XDCL] dsp$retrieve_cda_data_size
    (    name: dst$resource_name;
     VAR cda_data_size: integer;
     VAR status: ost$status);

    VAR
      destination: t$request_destination,
      dft_request: dst$dft_retrieve_cda_size,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    IF osv$170_os_type = osc$ot7_none THEN
      destination := c$os_180_request;
    ELSE
      destination := c$os_170_request;
    IFEND;
    IF (name = c$cda_vcu_name) OR (name = c$cda_cel_name) OR (name = c$cda_cft_name) OR
          (name = c$cda_mrt_name) OR (name = c$cda_rif_name) THEN
      dft_request.header.request_code := dsc$dft_retrieve_cda_data_size;
    ELSE
      dft_request.header.request_code := dsc$dft_retrieve_program_size;
    IFEND;
    convert_name_to_cda_name (name, dft_request.name);
    dft_request.cda_data_size := 0;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (destination, dft_request_seq_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF dft_request.cda_data_size <= 0 THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$no_cda_data,
            'The CDA data size is zero.', status);
    ELSE
      cda_data_size := (dft_request.cda_data_size * 8);
    IFEND;

  PROCEND dsp$retrieve_cda_data_size;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$start_additional_cpu', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to start a CPU.

  PROCEDURE [XDCL] dsp$start_additional_cpu
    (    number: 0 .. (osc$max_number_of_processors - 1));

    VAR
      dft_request: dst$dft_start_additional_cpu,
      dft_request_seq_p: ^SEQ ( * ),
      local_status: ost$status;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_start_additional_cpu;
    dft_request.number := number;
    dft_request.mps := mtv$cst0 [number].monitor_mps;
    dsp$get_ssr_data_r_pointer (dsc$ssr_initial_cpu_registers, dft_request.registers_rp);
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.  If DFT is not responding then halt the system since the state of the CPU
    { is unknown.  Otherwise, the other CPU will notice if the started CPU is not running and down the
    { CPU because handshaking did not occur.

    make_dft_request (c$os_180_request, dft_request_seq_p, local_status);
    IF NOT local_status.normal AND (local_status.condition = dse$dft_not_responding) THEN
{     osp$fatal_system_error ('DFT not responding when attempting to start a CPU.', ^local_status);
     dpp$put_critical_message('DFT not responding when attempting to start CPU', local_status);
     dpp$put_critical_message('Will retry after DFT activity is quiet', local_status);
    IFEND;

  PROCEND dsp$start_additional_cpu;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$update_hardware_date_time', EJECT ??

{ PURPOSE:
{   This procedure updates the hardware date and time in the Hardware Descriptor Table (HDT) and the Wall
{   Clock Chip in all IOUs except I2s where it updates the CIP disk.
{ DESIGN:
{   A request to DFT is used to do the update of the date and time.  This update is done only in
{   standalone mode.

  PROCEDURE [XDCL] dsp$update_hardware_date_time
    (    clock: ost$free_running_clock;
         date_time: ost$date_time;
     VAR status: ost$status );

    CONST
      halfword = 100000000(16),
      parcel = 10000(16);

    VAR
      dft_request: dst$dft_update_hardware_clock,
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_not_allowed_on_cy2000,
            'DFT request not allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    IF osv$170_os_type <> osc$ot7_none THEN
      RETURN;
    IFEND;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_update_hardware_clock;
    dft_request.year := (date_time.year DIV 10)*16 + date_time.year MOD 10;
    dft_request.month := (date_time.month DIV 10)*16 + date_time.month MOD 10;
    dft_request.day := (date_time.day DIV 10)*16 + date_time.day MOD 10;
    dft_request.hour := (date_time.hour DIV 10)*16 + date_time.hour MOD 10;
    dft_request.minute := (date_time.minute DIV 10)*16 + date_time.minute MOD 10;
    dft_request.free_running_clock_1 := 0;
    dft_request.free_running_clock_2 := clock DIV halfword;
    dft_request.free_running_clock_3 := (clock MOD halfword) DIV parcel;
    dft_request.free_running_clock_4 := clock MOD parcel;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (c$os_180_request, dft_request_seq_p, status);

  PROCEND dsp$update_hardware_date_time;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$write_cda_sector', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to write a sector to the common disk area.

  PROCEDURE [XDCL] dsp$write_cda_sector
    (    name: dst$resource_name;
     VAR sector_data_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      adjusted_size_of_sector_data: 0 .. c$cda_sector_size,
      cda_sector_data_p: ^SEQ ( * ),
      cda_sector_16_bit_p: ^t$sector_for_16_bits_in_16,
      cda_sector_16_bit_seq_p: ^SEQ ( * ),
      cda_sector_12_bit_p: ^t$sector_for_12_bits_in_16,
      destination: t$request_destination,
      dft_request: dst$dft_access_cda_sector,
      dft_request_seq_p: ^SEQ ( * ),
      extra_bit_count: 0 .. c$cda_sector_size,
      sector_data_bit_count: 0 .. c$cda_sector_size,
      temp_sector_data_p: ^t$sector_for_12_bits_in_16,
      temp_sector_data_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    { Check that the callers sequence is not larger then a cda sector.  The size of the sector data has been
    { adjusted to be a byte boundary so that it will divide evenly by two and no data will be lost when DFT
    { reads the data.

    RESET sector_data_p;
    adjusted_size_of_sector_data := ((#SIZE (sector_data_p^) + 7) DIV 8) * 8;
    IF adjusted_size_of_sector_data > c$cda_sector_size THEN
      osp$system_error (' Data too large to write into CDA sector', NIL);
    IFEND;

    { Allocate space in mainframe wired to store the CDA data.  This area must not cross a page boundary
    { because DFT is reading data from this area and does not understand the concept of paging.

    IF name = c$cda_cel_name THEN

      { This is a special sector.  The data is stored in a data structure that contains twelve bits of data
      { in a sixteen bit unit with the upper four bits zero.  This data structure will actually exceed a
      { sector size because only the twelve bit quantities actually make up the sector.

      ALLOCATE temp_sector_data_p IN osv$mainframe_wired_cb_heap^;
      ALLOCATE cda_sector_12_bit_p IN osv$mainframe_wired_cb_heap^;
      pmp$zero_out_table (^temp_sector_data_p^.sector, #SIZE (temp_sector_data_p^.sector));
      pmp$zero_out_table (^cda_sector_12_bit_p^.sector, #SIZE (cda_sector_12_bit_p^.sector));
      temp_sector_data_seq_p := #SEQ (temp_sector_data_p^.sector);
      RESET temp_sector_data_seq_p;
      NEXT cda_sector_data_p: [[REP #SIZE (sector_data_p^) OF cell]] IN temp_sector_data_seq_p;
      cda_sector_data_p^ := sector_data_p^;
      RESET temp_sector_data_seq_p;
      unpack_sector (temp_sector_data_p, cda_sector_12_bit_p);
      dsp$convert_seq_p_to_r_pointer (#SEQ (cda_sector_12_bit_p^.sector), dft_request.cda_sector_data_rp);
      sector_data_bit_count := adjusted_size_of_sector_data * 8;
      extra_bit_count := ((sector_data_bit_count + 11) DIV 12) * 4;
      dft_request.cda_sector_data_rp.length := ((extra_bit_count + sector_data_bit_count) + 63) DIV 64;
    ELSE

      ALLOCATE cda_sector_16_bit_p IN osv$mainframe_wired_cb_heap^;
      pmp$zero_out_table (^cda_sector_16_bit_p^.sector, #SIZE (cda_sector_16_bit_p^.sector));
      cda_sector_16_bit_seq_p := #SEQ (cda_sector_16_bit_p^.sector);
      RESET cda_sector_16_bit_seq_p;
      NEXT cda_sector_data_p: [[REP #SIZE (sector_data_p^) OF cell]] IN cda_sector_16_bit_seq_p;
      cda_sector_data_p^ := sector_data_p^;
      RESET cda_sector_16_bit_seq_p;
      dsp$convert_seq_p_to_r_pointer (cda_sector_16_bit_seq_p, dft_request.cda_sector_data_rp);
      dft_request.cda_sector_data_rp.length := (adjusted_size_of_sector_data + 7) DIV 8;
    IFEND;

    { Build the DFT request.

    IF osv$170_os_type = osc$ot7_none THEN
      destination := c$os_180_request;
    ELSE
      destination := c$os_170_request;
    IFEND;
    dft_request.header.request_code := dsc$dft_access_cda_sector;
    convert_name_to_cda_name (name, dft_request.name);
    dft_request.cda_information.valid_data := TRUE;
    dft_request.cda_information.sixteen_bits := TRUE;
    dft_request.cda_information.partial_read := FALSE;
    dft_request.cda_information.write_data := TRUE;
    dft_request.cda_information.cel_sector := (name = c$cda_cel_name);
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    make_dft_request (destination, dft_request_seq_p, status);

    { Free the space in mainframe wired that was used to store the CDA data.

    IF name = c$cda_cel_name THEN
      FREE temp_sector_data_p IN osv$mainframe_wired_cb_heap^;
      FREE cda_sector_12_bit_p IN osv$mainframe_wired_cb_heap^;
    ELSE
      FREE cda_sector_16_bit_p IN osv$mainframe_wired_cb_heap^;
    IFEND;

  PROCEND dsp$write_cda_sector;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$write_mrt_entry', EJECT ??

{ PURPOSE:
{   This procedure makes a request to DFT to write an entry to the MRT.

  PROCEDURE [XDCL] dsp$write_mrt_entry
    (    mrt_entry_id: dst$mrt_entry_id;
         mrt_element_number: dst$mrt_element_number;
         mrt_entry: dst$mrt_entry;
     VAR status: ost$status);

    VAR
      destination: t$request_destination,
      dft_request: dst$dft_access_mrt,
      dft_request_seq_p: ^SEQ ( * ),
      mrt_entry_p: ^dst$mrt_entry,
      mrt_entry_seq_p: ^SEQ ( * );

    status.normal := TRUE;

    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      osp$set_status_abnormal (dsc$display_processor_id, dse$dft_not_allowed_on_cy2000,
            'DFT request not allowed on a Cyber 2000 mainframe.', status);
      RETURN;
    IFEND;

    { Build the DFT request.

    pmp$zero_out_table (#LOC (dft_request), #SIZE (dft_request));

    dft_request.header.request_code := dsc$dft_access_mrt;
    dft_request.read_mrt := 0;
    dft_request.number := mrt_element_number;
    dft_request.entry_id := $INTEGER(mrt_entry_id);
    dsp$allocate_continuous_memory (osv$mainframe_wired_cb_heap, #SIZE (dst$mrt_entry), mrt_entry_seq_p);
    RESET mrt_entry_seq_p;
    dsp$convert_seq_p_to_r_pointer (mrt_entry_seq_p, dft_request.mrt_entry_rp);
    NEXT mrt_entry_p IN mrt_entry_seq_p;
    mrt_entry_p^ := mrt_entry;
    CASE mrt_entry_id OF
    = dsc$mrt_id_iou =
      dft_request.mrt_entry_rp.length := (mrt_entry.iou.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_central_memory =
      dft_request.mrt_entry_rp.length := (mrt_entry.memory.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_processor =
      dft_request.mrt_entry_rp.length := (mrt_entry.processor.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_mainframe =
      dft_request.mrt_entry_rp.length := (mrt_entry.mainframe.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_flpp =
      dft_request.mrt_entry_rp.length := (mrt_entry.flpp.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_display_console =
      dft_request.mrt_entry_rp.length := (mrt_entry.console.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_global_processor =
      dft_request.mrt_entry_rp.length := (mrt_entry.global_processor.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_clock_data =
      dft_request.mrt_entry_rp.length := (mrt_entry.clock_data.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_model_dependent =
      dft_request.mrt_entry_rp.length := (mrt_entry.model_dependent.descriptor_id.size + 3) DIV 4;
    = dsc$mrt_id_page_map =
      dft_request.mrt_entry_rp.length := (mrt_entry.page_map.descriptor_id.size + 3) DIV 4;
    ELSE
      osp$system_error ('Illegal MRT entry id', NIL);
    CASEND;
    dft_request_seq_p := #SEQ (dft_request);

    { Make the DFT request.

    IF osv$170_os_type = osc$ot7_none THEN
      destination := c$os_180_request;
    ELSE
      destination := c$os_170_request;
    IFEND;

    make_dft_request (destination, dft_request_seq_p, status);
    FREE mrt_entry_seq_p IN osv$mainframe_wired_cb_heap^;

  PROCEND dsp$write_mrt_entry;
?? OLDTITLE ??
MODEND dsm$process_dft_requests;
