?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Network Access : Intranet Layer Mgmt R1' ??
MODULE nam$intranet_layer_mgmt_r1;
{
{ PURPOSE:
{         The purpose of this module is to provide support in ring 1 for the
{         INTRANET LAYER MGMT FUNCTIONS.
{
{ DESIGN:
{         This module is designed to reside in OSF$SYSTEM_CORE_113 library.
{         It contains procedures to queue dump requests on the unit i/f table,
{         flush unit queues and to free request blocks in the mainframe wired
{         segment. These procedures can run only in ring 1 as they reference
{         mainframe wired segment and need to call procedures that execute in
{         ring 1. These procedures execute in the intranet layer mgmt task only.
{         This module also contains procedures which support the Change_Nam_Attrbutes
{         and Display_Nam_Attributes commands. These procedures need to access
{         global variables that reside in mainframe wired.
{
?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc ioc$unsolicited_response_codes
*copyc iot$command
*copyc iot$io_request
*copyc iot$logical_unit
*copyc iot$unit_interface_table
*copyc nat$monitor_request_block
*copyc nat$nam_attributes
*copyc nat$request_block_list
*copyc nlc$nam_configuration_constants
*copyc nlt$master_control_table
*copyc nlt$network_device
*copyc osc$purge_map_and_cache
*copyc ost$hardware_subranges
*copyc ost$signature_lock
*copyc syc$monitor_request_codes
?? POP ??
*copyc i#call_monitor
*copyc nap$free_request_block
*copyc nap$get_request_block
*copyc osp$fetch_locked_variable
*copyc syp$cycle
*copyc cmv$logical_unit_table
*copyc nav$network_paged_heap
*copyc nav$network_response_processor
*copyc nlv$cl_connections
*copyc nlv$maximum_system_connections
*copyc nlv$pp_buffer
*copyc nlv$pp_send_queue_tails
*copyc oss$mainframe_paged_literal
*copyc osv$mainframe_wired_cb_heap
*copyc osv$page_size
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
    VAR
      clear_lockword: [READ, OSS$MAINFRAME_PAGED_LITERAL] iot$lockword := [FALSE, 0, [FALSE, 0, 0]],
      set_lockword: [READ, OSS$MAINFRAME_PAGED_LITERAL] iot$lockword := [TRUE, 0, [TRUE, FALSE,
        0, 0]];


?? OLDTITLE ??
?? NEWTITLE := 'nap$flush_unit_queue', EJECT ??
*copy nah$flush_unit_queue
  PROCEDURE [XDCL, #GATE] nap$flush_unit_queue
    (    network_device: ^nlt$network_device;
     VAR message_id_array: ^array [1 .. * ] of nlt$bm_message_id);

    VAR
      actual: nlt$pp_send_queue_tail,
      cs_status: osc$cs_successful .. osc$cs_variable_locked,
      current: nlt$pp_send_queue_tail,
      end_of_queue: boolean,
      first_request: ost$real_memory_address,
      index: integer,
      local_status: ost$status,
      master_control_table: ^nlt$master_control_table,
      message_id_count: integer,
      new: nlt$pp_send_queue_tail,
      next_request_block: ^nat$request_block,
      queue: nlt$cc_connection_class,
      request_block: ^nat$request_block;


    master_control_table := #LOC(cmv$logical_unit_table^ [network_device^.logical_unit].
           unit_communication_buffer_pva^);

    message_id_count := 0;
    message_id_array := NIL;
    FOR queue := nlc$cc_normal_class TO nlc$cc_priority_class DO
      current.send_queue_tail := NIL;
      new := current;
      REPEAT
        #compare_swap (nlv$pp_send_queue_tails^ [network_device^.device_id] [queue],
              current, new, actual, cs_status);
      UNTIL cs_status <> osc$cs_variable_locked;

      request_block := actual.send_queue_tail;

{ Calculate the number of message_ids in the queue. The CPU scans the
{ queue from the tail backward. The requests are chained via a backward
{ link that is not terminated by a NIL. Rather, the end of the chain is
{ discovered by comparing the pointer of the current request to that of
{ the first request in the queue.

      IF request_block <> NIL THEN
        end_of_queue := FALSE;
        first_request := master_control_table^.request_queues [queue].request_rma;
        WHILE (NOT end_of_queue) DO
          IF request_block^.network_request.message_id.descriptor <> NIL THEN
            message_id_count := message_id_count + 1;
          IFEND;
          IF request_block^.peripheral_request_rma = first_request THEN
            end_of_queue := TRUE;
          ELSE
            request_block := request_block^.network_request.request_block_link;
          IFEND;
        WHILEND;
      IFEND;
    FOREND;

    IF message_id_count > 0 THEN

{  Note: The message_id_array will be released by the PROC flush_unit_queue
{  in nam$intranet_layer_mgmt_r3.

      REPEAT
        ALLOCATE message_id_array: [1 .. message_id_count] IN nav$network_paged_heap^;
        IF message_id_array = NIL THEN
          syp$cycle;
        IFEND;
      UNTIL message_id_array <> NIL;
    IFEND;

    index := 1;
    FOR queue := nlc$cc_normal_class TO nlc$cc_priority_class DO
      request_block := NIL;
      current.send_queue_tail := NIL;
      current.fill := 0;
      new := current;
      REPEAT
        #compare_swap (nlv$pp_send_queue_tails^ [network_device^.device_id] [queue],
              current, new, actual, cs_status);
        IF cs_status = osc$cs_failed THEN
          current := actual;
        IFEND;
      UNTIL cs_status = osc$cs_successful;
      request_block := actual.send_queue_tail;

      first_request := master_control_table^.request_queues [queue].request_rma;
      master_control_table^.request_queues [queue].request_rma := 0;
      master_control_table^.request_queues [queue].request_length := 0;

{ Place the message ids associated with the requests in the message_id_array.
{ The CPU scans the queue exactly as before.

      IF request_block <> NIL THEN
        end_of_queue := FALSE;
        WHILE (NOT end_of_queue) DO
          IF request_block^.network_request.message_id.descriptor <> NIL THEN
            message_id_array^ [index] := request_block^.network_request.message_id;
            index := index + 1;
          IFEND;
          IF request_block^.peripheral_request_rma = first_request THEN
            end_of_queue := TRUE;
          ELSE
            next_request_block := request_block^.network_request.request_block_link;
          IFEND;
          nap$free_request_block (request_block);
          IF NOT end_of_queue THEN
            request_block := next_request_block;
          IFEND;
        WHILEND;
      IFEND;
    FOREND;

  PROCEND nap$flush_unit_queue;
?? OLDTITLE ??
?? NEWTITLE := 'nap$change_nam_attributes_r1', EJECT ??
*copy nah$change_nam_attributes_r1
  PROCEDURE [XDCL, #GATE] nap$change_nam_attributes_r1 (
        attribute_kind: nat$nam_attribute_kind;
        attribute: nat$nam_attribute);

    CASE attribute_kind OF
    = nac$max_connections_attr =
      nlv$maximum_system_connections := attribute.maximum_connections;
    ELSE
    CASEND;

  PROCEND nap$change_nam_attributes_r1;
?? OLDTITLE ??
?? NEWTITLE := 'nap$get_nam_attributes_r1', EJECT ??
*copy nah$get_nam_attributes_r1
  PROCEDURE [XDCL, #GATE] nap$get_nam_attributes_r1 (
        attribute_kind: nat$nam_attribute_kind;
    VAR attribute: nat$nam_attribute);


    VAR
      current_connections: integer;

    CASE attribute_kind OF
    = nac$max_connections_attr =
      attribute.maximum_connections := nlv$maximum_system_connections;

    = nac$current_connections_status =
      osp$fetch_locked_variable (nlv$cl_connections.active, current_connections);
      attribute.current_connections := current_connections;
    ELSE
    CASEND;

  PROCEND nap$get_nam_attributes_r1;
?? OLDTITLE ??
?? NEWTITLE := 'nap$build_master_control_table', EJECT ??
*copy nah$build_master_control_table
  PROCEDURE [XDCL, #GATE] nap$build_master_control_table
    (    logical_unit: iot$logical_unit;
         device_id: nlt$device_identifier);

    VAR
      last_request_rma: integer,
      master_control_table: ^nlt$master_control_table,
      pool: 0 .. 0ff(16),
      pp_pool_headers: integer,
      queue: nlt$cc_connection_class,
      unit_communication_buffer_seq: ^iot$unit_communication_buffer;

{ It is assumed that the unit communication buffer has been zeroed out
{ by configuration management.

    unit_communication_buffer_seq := cmv$logical_unit_table^ [logical_unit].
           unit_communication_buffer_pva;
    RESET unit_communication_buffer_seq;
    NEXT master_control_table IN unit_communication_buffer_seq;
    master_control_table^.device_id := device_id;
    FOR queue := nlc$cc_normal_class TO nlc$cc_priority_class DO
{     master_control_table^.request_queues [queue].request_rma := 0;
{     master_control_table^.request_queues [queue].request_length := 0;
      i#real_memory_address (#LOC (nlv$pp_send_queue_tails^ [device_id] [queue]),
            last_request_rma);
      master_control_table^.request_queues [queue].last_request := last_request_rma;
    FOREND;

    i#real_memory_address (#LOC (nlv$pp_buffer^.pool_header), pp_pool_headers);
    master_control_table^.buffer_pool_headers := pp_pool_headers;

    master_control_table^.initialized := TRUE;

  PROCEND nap$build_master_control_table;
?? OLDTITLE ??
MODEND nam$intranet_layer_mgmt_r1;

