?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Deadstart : MTR - Issue DFT Requests' ??
MODULE dsm$mtr_issue_dft_request;

{ PURPOSE:
{   This module contains all of the procedures needed to issue a request to DFT in monitor.
{ 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.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dsc$dft_request_wait_times
*copyc dse$dft_errors
*copyc dst$dft_requests
*copyc dst$device_path
*copyc dst$rb_issue_dft_request
*copyc dst$mtr_dft_requests
*copyc ost$pp_size
?? POP ??
*copyc cmp$idle_system_device_driver
*copyc cmp$manage_channel_lock
*copyc dsp$convert_seq_p_to_r_pointer
*copyc dsp$mtr_get_ssr_data_seq_ptr
*copyc mtp$error_stop
*copyc mtp$interrupt_processor
*copyc mtp$set_status_abnormal
*copyc tmp$new_clear_lock
*copyc tmp$new_set_lock
?? EJECT ??
*copyc cmv$logical_pp_table_p
*copyc cmv$system_device_pp
*copyc dsv$automatic_pp_reload
*copyc dsv$dftb_nve_req_buffer_p
*copyc dsv$mainframe_type
*copyc osv$multiprocessor_running
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  CONST
    c$iou0_port_mask = 2;

  TYPE
    t$mtr_dft_request_locks = RECORD
      main_routine: tmt$new_ptl_lock,
      puf: tmt$new_ptl_lock,
      reload_sci: tmt$new_ptl_lock,
      puf_data: tmt$new_ptl_lock,
    RECEND;
?? EJECT ??

  VAR
    dsv$cip_path: [XDCL, #GATE] dst$device_path := [FALSE, 0, 0, 0, 0],
    dsv$mtr_dft_requests: [XDCL, #GATE] dst$mtr_dft_requests := [NIL, NIL, NIL],

    v$mtr_dft_request_locks: t$mtr_dft_request_locks := [[FALSE, 0], [FALSE, 0], [FALSE, 0], [FALSE, 0]];
?? OLDTITLE ??
?? NEWTITLE := 'issue_request', EJECT ??

{ PURPOSE:
{   This procedure issues a request to DFT.
{ DESIGN:
{   The DFT Buffer contains an area referred to as the NOS/VE Request Buffer which consists of four
{   R pointers.  One of these R pointers is used to issue the request to DFT.

  PROCEDURE issue_request
    (VAR request_seq_p: ^SEQ ( * ));

    { Specifies the maximum amount of time monitor will wait for a DFT request to be completed.

    CONST
      c$cpu_wait_time = 10000000,       { 10 seconds in microseconds.
      c$dft_wait_time = 6*30000000;     { 6*30 seconds in microseconds.  = 3 minutes

    VAR
      current_time: ost$free_running_clock,
      dft_request_header_p: ^dst$dft_request_header,
      expired_time: ost$free_running_clock,
      request_r_pointer: dst$r_pointer;

    tmp$new_set_lock (v$mtr_dft_request_locks.main_routine);

    { Issue the request to DFT.  DFT monitors the R pointer and when the length is set to a nonzero value,
    { DFT will respond to the request.

    RESET request_seq_p;
    NEXT dft_request_header_p IN request_seq_p;
    RESET request_seq_p;

    dsp$convert_seq_p_to_r_pointer (request_seq_p, request_r_pointer);

    { Move the created request R pointer in to the correct slot in the NOS/VE Request Buffer in the DFT
    { Buffer.  This should be done using #SPOIL to assure that the R pointer is totally created before
    { it is moved into the buffer.

    #SPOIL (dsv$dftb_nve_req_buffer_p^.system_request_r_pointer);
    dsv$dftb_nve_req_buffer_p^.system_request_r_pointer := request_r_pointer;
    IF dsv$mainframe_type = dsc$mt_2000_mainframe THEN
      mtp$interrupt_processor (c$iou0_port_mask);
    IFEND;

    { Wait for the DFT request to complete.

    current_time := #FREE_RUNNING_CLOCK (0);
    expired_time := current_time + c$dft_wait_time;
    WHILE current_time < expired_time DO
      #SPOIL (dft_request_header_p^);
      IF dft_request_header_p^.request_status = dsc$dft_rs_no_response THEN
        current_time := #FREE_RUNNING_CLOCK (0);
      ELSE
        expired_time := current_time;
      IFEND;
    WHILEND;

    dsv$dftb_nve_req_buffer_p^.system_request_r_pointer.length := 0;

    { If starting a CPU, wait until the CPU has started before continuing.

    IF (dft_request_header_p^.request_code = dsc$dft_start_additional_cpu) AND
          (dft_request_header_p^.request_status = dsc$dft_rs_request_complete) THEN
      current_time := #FREE_RUNNING_CLOCK (0);
      expired_time := current_time + c$cpu_wait_time;
      WHILE current_time < expired_time DO
        IF osv$multiprocessor_running THEN
          expired_time := current_time;
        ELSE
          current_time := #FREE_RUNNING_CLOCK (0);
        IFEND;
      WHILEND;
    IFEND;

    tmp$new_clear_lock (v$mtr_dft_request_locks.main_routine);

  PROCEND issue_request;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$issue_dft_request', EJECT ??

{ PURPOSE:
{   This procedure issues a request to DFT.  Requests that pass through this routine are initiated from job
{   mode.

  PROCEDURE [XDCL] dsp$issue_dft_request
    (VAR rb: dst$rb_issue_dft_request);

    VAR
      access_deadstart_sector_p: ^dst$dft_access_deadstart_sector,
      channel_number: dst$physical_resource_number,
      dft_request_header_p: ^dst$dft_request_header,
      driver_pp_p: ^array [ost$pp_size] of ost$pp_byte_size,
      dual_system_device_driver: boolean,
      ignore_status: syt$monitor_status,
      iou_number: dst$iou_number,
      load_dual_pp: boolean,
      lock_channel: boolean,
      pp_interface_table_rma: ost$real_memory_address,
      process_pp_function_p: ^dst$dft_process_pp_function,
      request_issued: boolean,
      ssr_ppbf_seq_p: ^SEQ ( * ),
      system_device_partner_pp: dst$iou_resource;

    rb.status.normal := TRUE;

    RESET rb.dft_request_p;
    NEXT dft_request_header_p IN rb.dft_request_p;
    load_dual_pp := FALSE;

    CASE dsv$mainframe_type OF
    = dsc$mt_962_972_mainframe, dsc$mt_992_mainframe, dsc$mt_2000_mainframe =
      lock_channel := 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 =
        lock_channel := TRUE;
      = dsc$dft_update_hardware_clock, dsc$dft_access_mrt =
        lock_channel := (dsv$mainframe_type <> dsc$mt_93x_mainframe);
      ELSE
        lock_channel := FALSE;
      CASEND;
    CASEND;

   /channel_locked/
    BEGIN
      IF lock_channel THEN
        IF dft_request_header_p^.request_code = dsc$dft_access_deadstart_sector THEN
          RESET rb.dft_request_p;
          NEXT access_deadstart_sector_p IN rb.dft_request_p;
          iou_number := access_deadstart_sector_p^.iou_number;
          channel_number := access_deadstart_sector_p^.channel_number;
        ELSE
          iou_number := dsv$cip_path.iou_number;
          channel_number := dsv$cip_path.channel_number;
        IFEND;
        cmp$manage_channel_lock ({set_lock} TRUE, iou_number, channel_number,
               {concurrent channel} FALSE, rb.status);
        IF NOT rb.status.normal THEN
          EXIT /channel_locked/;
        IFEND;
      IFEND;

      IF cmv$system_device_pp.software_idle AND
            (dft_request_header_p^.request_code = dsc$dft_process_pp_function) THEN
        RESET rb.dft_request_p;
        NEXT process_pp_function_p IN rb.dft_request_p;
        IF process_pp_function_p^.subfunction = dsc$dpuf_load_pp THEN
          cmp$idle_system_device_driver (process_pp_function_p^.pp, dual_system_device_driver,
                pp_interface_table_rma, system_device_partner_pp);
          load_dual_pp := dual_system_device_driver;
        IFEND;
      IFEND;

      issue_request (rb.dft_request_p);
    END /channel_locked/;

    IF lock_channel THEN
      cmp$manage_channel_lock ({set_lock} FALSE, iou_number, channel_number,
            {concurrent channel} FALSE, ignore_status);
    IFEND;
    IF NOT rb.status.normal OR (dft_request_header_p^.request_status <> dsc$dft_rs_request_complete) THEN
      RETURN;
    IFEND;

    IF (dft_request_header_p^.request_code = dsc$dft_process_pp_function) AND load_dual_pp THEN
      dft_request_header_p^.request_status := dsc$dft_rs_no_response;

      { Update rma of the PP interface table in the PP image.  Words 72(8) and 73(8) contain the RMA to
      { the PP interface table.  Update the PP number in the DFT request.

      dsp$mtr_get_ssr_data_seq_ptr (dsc$ssr_pp_controlware_buf, ssr_ppbf_seq_p);
      RESET ssr_ppbf_seq_p;
      NEXT driver_pp_p IN ssr_ppbf_seq_p;
      driver_pp_p^ [72(8)] := pp_interface_table_rma DIV 10000(16);
      driver_pp_p^ [73(8)] := pp_interface_table_rma MOD 10000(16);
      process_pp_function_p^.pp.number := system_device_partner_pp.number;
      issue_request (rb.dft_request_p);
    IFEND;

  PROCEND dsp$issue_dft_request;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$mtr_dft_puf_request', EJECT ??

{ PURPOSE:
{   This procedure issues the 'process pp function' DFT request from monitor.

  PROCEDURE [XDCL] dsp$mtr_dft_puf_request
    (    subfunction: dst$dft_puf_subfunctions;
         logical_pp: iot$pp_number;
         resume_address: dst$dft_resume_address;
    VAR pp_data_seq_p: ^SEQ ( * );
    VAR status: syt$monitor_status);

    TYPE
      t$pp_parameter = RECORD
        fill: ARRAY [0 .. 71(8)] OF ost$pp_byte_size,
        table_rma: ost$real_memory_address,
      RECEND;

    VAR
      dft_request_seq_p: ^SEQ ( * ),
      iou_number: dst$iou_number,
      pp_parameter_p: ^t$pp_parameter;

    status.normal := TRUE;

    { Master clearing of the channel via DFT is only allowed on I4 type IOUs.

    IF subfunction = dsc$dpuf_master_clear_channel THEN
      iou_number := cmv$logical_pp_table_p^ [logical_pp].pp_info.channel.iou_number;
      CASE dsv$automatic_pp_reload.iou_model_type [iou_number] OF
      = dsc$imn_null_model, dsc$imn_i1_10_model, dsc$imn_i1_11_model, dsc$imn_i1_12_model,
            dsc$imn_i1_13_model, dsc$imn_i1_14_model, dsc$imn_i2_20_model, dsc$imn_i0_5x_model =
        RETURN;
      ELSE
      CASEND;
    IFEND;

    tmp$new_set_lock (v$mtr_dft_request_locks.puf);

    dsv$mtr_dft_requests.puf_p^.header.request_code := dsc$dft_process_pp_function;
    dsv$mtr_dft_requests.puf_p^.header.request_status := 0;

    IF subfunction = dsc$dpuf_master_clear_channel THEN
      dsv$mtr_dft_requests.puf_p^.pp := cmv$logical_pp_table_p^ [logical_pp].pp_info.channel;
    ELSE
      dsv$mtr_dft_requests.puf_p^.pp := cmv$logical_pp_table_p^ [logical_pp].pp_info.physical_pp;
    IFEND;

    dsv$mtr_dft_requests.puf_p^.subfunction := subfunction;
    dsv$mtr_dft_requests.puf_p^.resume_address := resume_address;

    IF subfunction = dsc$dpuf_load_pp THEN
      RESET cmv$logical_pp_table_p^ [logical_pp].pp_info.driver_code_p;
      NEXT pp_parameter_p IN cmv$logical_pp_table_p^ [logical_pp].pp_info.driver_code_p;
      pp_parameter_p^.table_rma := cmv$logical_pp_table_p^ [logical_pp].pp_info.pp_interface_table_rma;
      RESET cmv$logical_pp_table_p^ [logical_pp].pp_info.driver_code_p;
      dsp$convert_seq_p_to_r_pointer (cmv$logical_pp_table_p^ [logical_pp].pp_info.driver_code_p,
            dsv$mtr_dft_requests.puf_p^.pp_image_rp);
    ELSEIF pp_data_seq_p <> NIL THEN
      dsp$convert_seq_p_to_r_pointer (pp_data_seq_p, dsv$mtr_dft_requests.puf_p^.pp_image_rp);
    ELSE
      dsv$mtr_dft_requests.puf_p^.pp_image_rp.offset := 0;
      dsv$mtr_dft_requests.puf_p^.pp_image_rp.rupper := 0;
      dsv$mtr_dft_requests.puf_p^.pp_image_rp.rlower := 0;
      dsv$mtr_dft_requests.puf_p^.pp_image_rp.length := 0;
    IFEND;

    dft_request_seq_p := #SEQ (dsv$mtr_dft_requests.puf_p^);
    issue_request (dft_request_seq_p);

    IF dsv$mtr_dft_requests.puf_p^.header.request_status <> dsc$dft_rs_request_complete THEN
      IF dsv$mtr_dft_requests.puf_p^.header.request_status = dsc$dft_rs_no_response THEN
        mtp$set_status_abnormal (dsc$display_processor_id, dse$dft_not_responding, status);
      ELSE
        mtp$set_status_abnormal (dsc$display_processor_id, dse$dft_request_failed, status);
      IFEND;
    IFEND;

    tmp$new_clear_lock (v$mtr_dft_request_locks.puf);

  PROCEND dsp$mtr_dft_puf_request;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$mtr_dft_reload_sci', EJECT ??

{ PURPOSE:
{   This procedure issues the 'reload SCI' DFT request from monitor.

  PROCEDURE [XDCL] dsp$mtr_dft_reload_sci
    (    pp: dst$iou_resource;
    VAR status: syt$monitor_status);

    VAR
      dft_request_seq_p: ^SEQ ( * );

    status.normal := TRUE;
    tmp$new_set_lock (v$mtr_dft_request_locks.reload_sci);

    dsv$mtr_dft_requests.reload_sci_p^.header.request_code := dsc$dft_reload_sci;
    dsv$mtr_dft_requests.reload_sci_p^.header.request_status := 0;
    dsv$mtr_dft_requests.reload_sci_p^.pp := pp;
    dsv$mtr_dft_requests.reload_sci_p^.rfu := 0;

    dft_request_seq_p := #SEQ (dsv$mtr_dft_requests.reload_sci_p^);
    issue_request (dft_request_seq_p);

    IF dsv$mtr_dft_requests.reload_sci_p^.header.request_status <> dsc$dft_rs_request_complete THEN
      IF dsv$mtr_dft_requests.reload_sci_p^.header.request_status = dsc$dft_rs_no_response THEN
        mtp$set_status_abnormal (dsc$display_processor_id, dse$dft_not_responding, status);
      ELSE
        mtp$set_status_abnormal (dsc$display_processor_id, dse$dft_request_failed, status);
      IFEND;
    IFEND;

    tmp$new_clear_lock (v$mtr_dft_request_locks.reload_sci);

  PROCEND dsp$mtr_dft_reload_sci;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$mtr_reserve_puf_memory_area', EJECT ??

{ PURPOSE:
{   This procedure reserves the memory area for PUF monitor dft requests.

  PROCEDURE [XDCL] dsp$mtr_reserve_puf_memory_area
    (VAR data_p: ^dst$mtr_dft_puf_memory_area);

    tmp$new_set_lock (v$mtr_dft_request_locks.puf_data);

    data_p := dsv$mtr_dft_requests.puf_data_p;

  PROCEND dsp$mtr_reserve_puf_memory_area;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$mtr_return_puf_memory_area', EJECT ??

{ PURPOSE:
{   This procedure returns the memory area for PUF monitor dft requests.

  PROCEDURE [XDCL] dsp$mtr_return_puf_memory_area;

    tmp$new_clear_lock (v$mtr_dft_request_locks.puf_data);

  PROCEND dsp$mtr_return_puf_memory_area;
?? OLDTITLE ??
MODEND dsm$mtr_issue_dft_request;
