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

{ PURPOSE:
{   This module contains all of the procedures which make requests to the 170 operating system.
{ DESIGN:
{   The majority of the procedures in this module are called to create the request block that is used to make
{   the 170 request.  All of these procedures then call the one procedure that actually makes the 170 request.
{ NOTES:
{   This module contains many type declarations that can not be easily changed.  These type declarations
{   define a block of data that the 170 operating system code 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 170 operating system code.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dse$error_codes
*copyc dst$dft_free_run_clock_value
*copyc dst$170_request_block
*copyc dst$resource_request
*copyc ost$string
*copyc ost$wait
?? POP ??
*copyc clp$convert_integer_to_string
*copyc dpp$put_critical_message
*copyc dsp$get_data_from_ssr
*copyc dsp$store_data_in_ssr
*copyc i#real_memory_address
*copyc osp$clear_mainframe_sig_lock
*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$delay
?? EJECT ??
*copyc osv$mainframe_wired_heap
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
  VAR
    v$ssr_170_request_lock: ost$signature_lock;
?? OLDTITLE ??
?? NEWTITLE := 'create_170_status', EJECT ??

{ PURPOSE:
{   This procedure analyzes the status that was returned from the 170 resource request and produces a status
{   message for the system.

  PROCEDURE create_170_status
    (    resource_request_170: dst$170_resource_request;
     VAR status: ost$status);

    VAR
      condition_code: ost$status_condition_code,
      insert_size: 0 .. 80,
      insert_text: string (80),
      integer_string: ost$string,
      size: ost$string_size,
      text: string (osc$max_string_size);

    status.normal := TRUE;
    insert_text (1, *) := ' ';
    insert_size := 1;

    CASE resource_request_170.resource_request_type OF
    = dsc$170_rrt_get_pp =
      IF resource_request_170.channel_used.channel_protocol = dsc$cpt_cio THEN
        insert_text (insert_size, 4) := 'CIO ';
        insert_size := insert_size + 4;
      IFEND;
      IF resource_request_170.partner_pp THEN
        insert_text (insert_size, 8) := 'PARTNER ';
        insert_size := insert_size + 8;
      IFEND;
      IF resource_request_170.driver_pp THEN
        insert_text (insert_size, 7) := 'DRIVER ';
        insert_size := insert_size + 7;
      IFEND;
      insert_text (insert_size, 3) := 'PP ';
      insert_size := insert_size + 3;
    = dsc$170_rrt_return_pp =
      IF resource_request_170.channel_used.channel_protocol = dsc$cpt_cio THEN
        insert_text (insert_size, 4) := 'CIO ';
        insert_size := insert_size + 4;
      IFEND;
      insert_text (insert_size, 3) := 'PP ';
      insert_size := insert_size + 3;
      clp$convert_integer_to_string (resource_request_170.primary_pp.number, 10, TRUE,
            integer_string, status);
      insert_text (insert_size, integer_string.size) := integer_string.value (1, integer_string.size);
      insert_size := insert_size + integer_string.size;
    = dsc$170_rrt_get_channel, dsc$170_rrt_return_channel =
      IF resource_request_170.channel.channel_protocol = dsc$cpt_cio THEN
        insert_text (insert_size, 4) := 'CIO ';
        insert_size := insert_size + 4;
      IFEND;
      insert_text (insert_size, 8) := 'CHANNEL ';
      insert_size := insert_size + 8;
      clp$convert_integer_to_string (resource_request_170.channel.number, 10, TRUE, integer_string, status);
      insert_text (insert_size, integer_string.size) := integer_string.value (1, integer_string.size);
      insert_size := insert_size + integer_string.size;
    = dsc$170_rrt_get_equipment, dsc$170_rrt_return_equipment =
      insert_text (insert_size, 9) := 'CHANNEL: ';
      insert_size := insert_size + 9;
      clp$convert_integer_to_string (resource_request_170.equipment_path.channel_number, 10, TRUE,
            integer_string, status);
      insert_text (insert_size, integer_string.size) := integer_string.value (1, integer_string.size);
      insert_size := insert_size + integer_string.size;
      insert_text (insert_size, 12) := ' EQUIPMENT: ';
      insert_size := insert_size + 12;
      clp$convert_integer_to_string (resource_request_170.equipment_path.equipment_number, 10, TRUE,
            integer_string, status);
      insert_text (insert_size, integer_string.size) := integer_string.value (1, integer_string.size);
      insert_size := insert_size + integer_string.size;
      insert_text (insert_size, 7) := ' UNIT: ';
      insert_size := insert_size + 7;
      clp$convert_integer_to_string (resource_request_170.equipment_path.unit_number, 10, TRUE,
            integer_string, status);
      insert_text (insert_size, integer_string.size) := integer_string.value (1, integer_string.size);
      insert_size := insert_size + integer_string.size;
    = dsc$170_rrt_update_free_clock =
      insert_text (insert_size, 25) := 'Update free running clock';
      insert_size := insert_size + 25;
    ELSE
      insert_text (insert_size, 12) := 'NULL REQUEST';
      insert_size := 12;
    CASEND;

    CASE resource_request_170.status OF
    = dsc$170_rre_ch_not_available, dsc$170_rre_eq_not_available, dsc$170_rre_pp_not_available =
      condition_code := dse$resource_not_available;
    = dsc$170_rre_unit_not_available =
      insert_text (1, 4) := 'UNIT';
      insert_size := 4;
      condition_code := dse$resource_not_available;
    = dsc$170_rre_cm_not_available =
      insert_text (1, 2) := 'CM';
      insert_size := 2;
      condition_code := dse$resource_not_available;
    = dsc$170_rre_no_such_resource =
      condition_code := dse$resource_does_not_exist;
    = dsc$170_rre_already_assigned =
      condition_code := dse$resource_already_assigned;
    = dsc$170_rre_no_load_controlware =
      condition_code := dse$dont_load_controlware;
    = dsc$170_rre_cio_ch_not_present =
      clp$convert_integer_to_string (resource_request_170.channel.number, 10, TRUE, integer_string, status);
      insert_text (1, integer_string.size) := integer_string.value (1, integer_string.size);
      insert_size := integer_string.size;
      condition_code := dse$cio_channel_not_present;
    = dsc$170_rre_cio_pp_not_present =
      clp$convert_integer_to_string (resource_request_170.primary_pp.number, 10, TRUE,
            integer_string, status);
      insert_text (1, integer_string.size) := integer_string.value (1, integer_string.size);
      insert_size := integer_string.size;
      IF resource_request_170.partner_pp THEN
        insert_text (insert_size, 7) := ' OR PP ';
        insert_size := insert_size + 7;
        clp$convert_integer_to_string (resource_request_170.secondary_pp.number, 10, TRUE,
              integer_string, status);
        insert_text (insert_size, integer_string.size) := integer_string.value (1, integer_string.size);
        insert_size := insert_size + integer_string.size;
      IFEND;
      condition_code := dse$cio_pp_not_present;
    ELSE
      CASE resource_request_170.resource_request_type OF
      = dsc$170_rrt_get_pp =
        insert_text (1, 6) := 'get_pp';
        insert_size := 6;
      = dsc$170_rrt_return_pp =
        insert_text (1, 9) := 'return_pp';
        insert_size := 9;
      = dsc$170_rrt_get_channel =
        insert_text (1, 11) := 'get_channel';
        insert_size := 11;
      = dsc$170_rrt_return_channel =
        insert_text (1, 14) := 'return_channel';
        insert_size := 14;
      = dsc$170_rrt_get_equipment =
        insert_text (1, 13) := 'get_equipment';
        insert_size := 13;
      = dsc$170_rrt_return_equipment =
        insert_text (1, 16) := 'return_equipment';
        insert_size := 16;
      ELSE
      CASEND;
      condition_code := dse$illegal_request;
    CASEND;

    CASE condition_code OF
    = dse$resource_not_available =
      text := 'The desired resource, ';
      size := 22;
      text (size, insert_size) := insert_text (1, insert_size);
      size := size + insert_size;
      text (size, 44) := ' is not available or not assigned to NOS/VE.';
      size := size + 44;
    = dse$resource_does_not_exist =
      text := 'The desired resource, ';
      size := 22;
      text (size, insert_size) := insert_text (1, insert_size);
      size := size + insert_size;
      text (size, 16) := ' does not exist.';
      size := size + 16;
    = dse$resource_already_assigned =
      text := 'The desired resource, ';
      size := 22;
      text (size, insert_size) := insert_text (1, insert_size);
      size := size + insert_size;
      text (size, 31) := ' is already assigned to NOS/VE.';
      size := size + 31;
    = dse$dont_load_controlware =
      text := 'Do not load controlware.';
      size := 24;
    = dse$cio_channel_not_present =
      text := 'The concurrent channel ';
      size := 23;
      text (size, insert_size) := insert_text (1, insert_size);
      size := size + insert_size;
      text (size, 16) := ' is not present.';
      size := size + 16;
    = dse$cio_pp_not_present =
      text := 'The concurrent PP ';
      size := 18;
      text (size, insert_size) := insert_text (1, insert_size);
      size := size + insert_size;
      text (size, 16) := ' is not present.';
      size := size + 16;
    = dse$illegal_request =
      text := 'The request, ';
      size := 13;
      text (size, insert_size) := insert_text (1, insert_size);
      size := size + insert_size;
      text (size, 12) := ' is illegal.';
      size := size + 12;
    ELSE
    CASEND;

    osp$set_status_abnormal (dsc$display_processor_id, condition_code, text (1, size), status);

  PROCEND create_170_status;
?? OLDTITLE ??
?? NEWTITLE := 'send_170_request', EJECT ??

{ PURPOSE:
{   This procedure is used to send requests for resources to the 170 operating system.
{ DESIGN:
{   The request is sent to the 170 operating system through the SSR.  To send a request to the 170 operating
{   system, a pointer to the request is placed in the 180 buffer in the SSR.  A program on the 170 side
{   observes the 180 buffer for the request and acts upon it when one appears.  Any response from the 170
{   operating system is sent via the 170 buffer in the SSR.

  PROCEDURE send_170_request
    (    wait: ost$wait;
     VAR request_170: dst$170_request_block);

    VAR
      c180_length: integer,
      c180_transfer_entry_seq_p: ^SEQ ( * ),
      c180_transfer_entry: dst$ssr_170_transfer_entry,
      c170_length: integer,
      c170_transfer_entry_seq_p: ^SEQ ( * ),
      c170_transfer_entry: dst$ssr_170_transfer_entry,
      local_status: ost$status,
      receive_buffer_p: ^SEQ ( * ),
      request_170_p: ^dst$170_request_block,
      request_170_seq_p: ^SEQ ( * ),
      send_buffer_p: [STATIC] ^SEQ ( * ) := NIL;

    { The SSR buffers must be interlocked so only one user is using them at a time.

    osp$set_mainframe_sig_lock (v$ssr_170_request_lock);
    c180_transfer_entry_seq_p := #SEQ (c180_transfer_entry);

    { Wait until any previous request is finished with the request area.

    IF send_buffer_p <> NIL THEN
      REPEAT
        pmp$cycle (local_status);
        dsp$get_data_from_ssr (dsc$ssr_c180_transfer_buffer, c180_transfer_entry_seq_p);
      UNTIL c180_transfer_entry.length = 0;
      FREE send_buffer_p IN osv$mainframe_wired_heap^;
    IFEND;

    { Send the request to the 170 operating system via the 180 buffer.

    request_170_seq_p := #SEQ (request_170);
    c180_length := #SIZE (request_170_seq_p^);
    ALLOCATE send_buffer_p: [[REP c180_length OF cell]] IN osv$mainframe_wired_heap^;
    send_buffer_p^ := request_170_seq_p^;
    c180_transfer_entry.length := ((c180_length + 14) DIV 15) * 15;
    c180_transfer_entry.offset := #OFFSET (send_buffer_p);
    dsp$store_data_in_ssr (dsc$ssr_c180_transfer_buffer, #SEQ (c180_transfer_entry));

    IF wait = osc$wait THEN
      c170_transfer_entry_seq_p := #SEQ (c170_transfer_entry);
      dsp$get_data_from_ssr (dsc$ssr_c170_transfer_buffer, c170_transfer_entry_seq_p);

      { Wait until any previous request has been received.

      WHILE c170_transfer_entry.length = 0 DO
        pmp$cycle (local_status);
        dsp$get_data_from_ssr (dsc$ssr_c170_transfer_buffer, c170_transfer_entry_seq_p);
      WHILEND;

      c170_length := c170_transfer_entry.length;
      ALLOCATE receive_buffer_p: [[REP c170_length OF cell]] IN osv$mainframe_wired_heap^;
      c170_transfer_entry.offset := #OFFSET (receive_buffer_p);
      dsp$store_data_in_ssr (dsc$ssr_c170_transfer_buffer, #SEQ (c170_transfer_entry));

      { Wait for a response from the 170 operating system.

      REPEAT
        pmp$cycle (local_status);
        dsp$get_data_from_ssr (dsc$ssr_c170_transfer_buffer, c170_transfer_entry_seq_p);
      UNTIL c170_transfer_entry.offset = 0;
      c170_transfer_entry.length := 0;
      dsp$store_data_in_ssr (dsc$ssr_c170_transfer_buffer, #SEQ (c170_transfer_entry));

      RESET receive_buffer_p;
      NEXT request_170_p IN receive_buffer_p;
      request_170 := request_170_p^;
      FREE receive_buffer_p IN osv$mainframe_wired_heap^;
    IFEND;

    osp$clear_mainframe_sig_lock (v$ssr_170_request_lock);

  PROCEND send_170_request;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$call_dft_through_sda', EJECT ??

{ PURPOSE:
{   This procedure sends a request to the 170 operating system to issue a request to DFT through SDA.

  PROCEDURE [XDCL] dsp$call_dft_through_sda
    (    dft_request_p: ^SEQ ( * ));

    VAR
      request_170: dst$170_request_block,
      request_rma: integer;

    i#real_memory_address (dft_request_p, request_rma);
    request_170.request := dsc$170_rb_call_dft_through_sda;
    request_170.dft_request_rma := request_rma;
    send_170_request (osc$wait, request_170);

  PROCEND dsp$call_dft_through_sda;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$exit_deadstart', EJECT ??

{ PURPOSE:
{   This procedure sends a request to the 170 operating system to exit deadstart and begin the code to either
{   RUN VE or TERMINATE VE.

  PROCEDURE [XDCL, #GATE] dsp$exit_deadstart
    (    next_program: (dsc$terminate_ve, dsc$run_ve));

    VAR
      request_170: dst$170_request_block;

    request_170.request := dsc$170_rb_complete_deadstart;
    request_170.terminating := next_program = dsc$terminate_ve;
    send_170_request (osc$nowait, request_170);

  PROCEND dsp$exit_deadstart;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$send_170_resource_request', EJECT ??

{ PURPOSE:
{   This procedure sends the resource request to the 170 operating system.

  PROCEDURE [XDCL] dsp$send_170_resource_request
    (VAR request: dst$resource_request;
     VAR status: ost$status);

    CONST
      four_minute_wait = 4 * 60 * 1000000;

    VAR
      end_wait_time: integer,
      msg_displayed: boolean,
      request_170: dst$170_request_block;

    status.normal := TRUE;
    msg_displayed := FALSE;
    end_wait_time := #free_running_clock (0) + four_minute_wait;

  /wait_for_resource/
    WHILE TRUE DO
      request_170.request := dsc$170_rb_request_resources;
      request_170.resource_request.status := dsc$170_rre_null_response;

      CASE request.resource_request_type OF
      = dsc$rrt_get_pp =
        request_170.resource_request.resource_request_type := dsc$170_rrt_get_pp;
      = dsc$rrt_return_pp =
        request_170.resource_request.resource_request_type := dsc$170_rrt_return_pp;
      = dsc$rrt_get_channel =
        request_170.resource_request.resource_request_type := dsc$170_rrt_get_channel;
      = dsc$rrt_return_channel =
        request_170.resource_request.resource_request_type := dsc$170_rrt_return_channel;
      = dsc$rrt_get_equipment =
        request_170.resource_request.resource_request_type := dsc$170_rrt_get_equipment;
      = dsc$rrt_return_equipment =
        request_170.resource_request.resource_request_type := dsc$170_rrt_return_equipment;
      ELSE
        osp$system_error ('Invalid 170 resource request.', NIL);
      CASEND;

      CASE request.resource_request_type OF
      = dsc$rrt_get_pp, dsc$rrt_return_pp =
        request_170.resource_request.driver_pp := (dsc$rro_driver_pp IN request.options);
        request_170.resource_request.partner_pp := (dsc$rro_partner_pp IN request.options);
        request_170.resource_request.channel_used.channel_protocol := request.channel.channel_protocol;
        request_170.resource_request.channel_used.number := request.channel.number;
        request_170.resource_request.primary_pp.channel_protocol := request.primary_pp.channel_protocol;
        request_170.resource_request.primary_pp.number := request.primary_pp.number;
        request_170.resource_request.secondary_pp.channel_protocol := request.secondary_pp.channel_protocol;
        request_170.resource_request.secondary_pp.number := request.secondary_pp.number;
      = dsc$rrt_get_channel, dsc$rrt_return_channel =
        request_170.resource_request.channel.channel_protocol := request.channel.channel_protocol;
        request_170.resource_request.channel.number := request.channel.number;
      = dsc$rrt_get_equipment, dsc$rrt_return_equipment =
        request_170.resource_request.equipment_path.channel_number := request.channel.number;
        request_170.resource_request.equipment_path.equipment_number := request.equipment_number;
        request_170.resource_request.equipment_path.unit_number := request.unit_number;
      ELSE
        osp$system_error ('Invalid 170 resource request.', NIL);
      CASEND;

      send_170_request (osc$wait, request_170);

      IF request_170.resource_request.status = dsc$170_rre_request_ok THEN
        IF msg_displayed THEN
          dpp$put_critical_message ('PP obtained', status);
        IFEND;
        EXIT /wait_for_resource/;
      IFEND;

      IF (request_170.resource_request.status = dsc$170_rre_pp_not_available) AND
            (#free_running_clock (0) <= end_wait_time) THEN
        IF NOT msg_displayed THEN
          dpp$put_critical_message
                ('A PP is not yet available, will keep trying for about four minutes.', status);
          msg_displayed := TRUE;
        IFEND;
        pmp$delay (100, status);
      ELSE
        create_170_status (request_170.resource_request, status);
        EXIT /wait_for_resource/;
      IFEND;

    WHILEND /wait_for_resource/;

    CASE request.resource_request_type OF
    = dsc$rrt_get_pp =
      request.primary_pp.number := request_170.resource_request.primary_pp.number;
      request.secondary_pp.number := request_170.resource_request.secondary_pp.number;
    = dsc$rrt_get_channel =
      request.channel.number := request_170.resource_request.channel.number;
    ELSE
    CASEND;

  PROCEND dsp$send_170_resource_request;
?? OLDTITLE ??
?? NEWTITLE := 'dsp$setup_170_request_interlock', EJECT ??

{ PURPOSE:
{   This procedure is called to initialize an interlock that this module uses.

  PROCEDURE [XDCL] dsp$setup_170_request_interlock;

    VAR
      local_status: ost$status;

    osp$initialize_signature_lock (v$ssr_170_request_lock, local_status);
    IF NOT local_status.normal THEN
      osp$system_error (' Error in setting the 170 request interlock.', ^local_status);
    IFEND;

  PROCEND dsp$setup_170_request_interlock;
?? OLDTITLE ??
MODEND dsm$process_170_requests;
