EPICURE Design Note 3.9
VMS System Services for QVI Support
David M. Kline
This document shows the calling sequences for the QVI routines on the
80386 DAE processors with C as well as for use on the VAX under VMS.
In addition, several VME Common Memory
structures are outlined. See Epicure Design Note 6 for more information
on Common Memory data structures and formats.
Introduction
The data sources for the EPICURE system are the MicroVAX Front End
and the VME-based Data Acquisition Engines (DAE). The MicroVAX is
interfaced to the VME crate by the QBus/VME Interface (QVI) which allows
VME address space to appear as if it were QBus memory. The MicroVAX and
DAE processors communicate via the Common Memory (CM) area in a VME memory
module. All communication between the MicroVAX and the DAE and between DAE
modules is done by passing messages using queues in the CM.
A set of user-written VMS system services supports access to the CM
from the MicroVAX. A smaller set of routines provides support for the
DAE processors to manipulate information in the Common Memory.
These various services are required due to:
-
Data transfers through the QVI are 32-bit longwords
aligned on longword boundaries. This requirement permits
the QVI to correct for the byte ordering differences
between the 68020 Motorola and the VAX architectures. With the change
of the DAE processors to Intel 80386s, this becomes less important since
the MicroVAX and the 80386 use the same byte-order memory address model.
However, the QVI still does not correctly handle longword or word accesses
on byte addresses (the data is scrambled) so a set of VAX services is
still required to isolate the QVI users from this deficiency. Since
the Common Memory is directly accessible (as VMEbus memory) to the
DAE processors, special data transfer routines are not needed there.
-
Bus interlocks must be generated for Test and Set
instructions to interlock access to the queues. Since the MicroVAX
test and set instructions do not generate interlocked QBus cycles,
hardware on the QVI is preset to turn a back-to-back pair of read/write
QBus cycles into a single VMEBus cycle. To insure correct timing, these
actions must be taken as an atomic operation and done at IPL 31 in the
MicroVAX to prevent any intervening interrupts from stealing CPU cycles.
The assembly routines needed for the interlocking instructions on the
DAE processors are embedded in the CM services and invisible to the
DAE programmers.
-
The QVI control registers in QBus I/O space and interrupt
control registers in VME address space must be manipulated.
-
The details of the manipulating the queues in Common Memory used
for interprocessor communications are hidden from the users of the
services. In addition, the queue manipulations are done with a
software lock on the queue and with the CPU interrupts disabled
to insure timely completion of the queue operation. On the MicroVAX
this requires kernel mode services.
The QVI services provide a means of encapsulating these needs and
presenting a simpler interface to the Data Acquisition Server (DAS), the
primary user of the QVI services. Similarly, the CM routines for the
DAE processors provide a simple interface to the programmers and
implement the same queue handling protocol as the QVI services.
A special device driver on the MicroVAX, the UICDRIVER, is needed to
handling the fielding of interrupts from the QVI. This driver was
derived from the Digital Connect-to-Interrupt driver and is designed
to handle the Advanced Micro Devices 9519A Universal Interrupt
Controller.
Descriptions of the QVI and CM Services
The QVI services are similar to the VMS system services. All the
routines are functions returning a 32-bit VMS condition code as a status
(with one exception). Scalar input arguments are passed by value; output
or modified (read-write) arguments and input arrays are passed by reference
(except as noted). The QVI services are divided into two classes, the
QVI_US routines for most users and the QVI_CS core routines for special
programs and diagnostics.
Service routines for the DAE processors are based on a simple subset of
the QVI_US routines called the CM (for Common
Memory) routines. The CM routines return VMS status codes to indicate
success or failure; input arguments are passed by value and output arguments
have a pointer passed by value (standard C calling sequences).
Common Memory queues and blocks are referenced by ``handles'' which are
either offsets relative to the start of the Common Memory or addresses
within the Common Memory as mapped into the local process's virtual address
space (VAS). In particular, the actual interpretation of the ``handles''
returned by the QVI_US routines is unimportant to the users of the QVI_US
routines. This does not hold true for the QVI_CS routines where the
documentation spells out whether a particular ``handle'' is an actual address
or just an offset. The CM routines use 32-bit VMEBus addresses for Common
Memory structures (normal startup of the 80386 DAE processors must setup for
a 4 Gigabyte linear address space).
Common Memory Block Format
The Common Memory block which is entered or removed from a CM queue is
called a CMB (for Common Memory Block). The CMB consists
of two concatenated structures: the UMB contains the fields of importance
to users, the CMH is the Common Memory Header containing information used
only by the QVI services and the DAE modules. The fields of the UMB and
The format of a CM block which is entered or removed from a CM queue
is:
This structure is called a CMB for Common Memory Block. The CMB consists
of two concatenated structures: the UMB contains the fields of importance
to users, the CMH is the Common Memory Header containing information used
only by the QVI services and the DAE modules. The fields of the UMB and
CMH which are common to all types of CMBs are:
list
[cmb_r_cmh]
This structure contains the header fields of the CMB:
list
[cmh_l_link]
This longword is the queue link. It
contains a pointer to the next entry in the
queue or a 0 if this is the tail entry. Normally this field
is only of concern to the QVI and CM routines.
[cmh_l_rtnqid]
This longword is set to the queue handle
(qhdl) for the
VAX return queue associated
with the user process. The return qhdl is
used to return the CMB to the originator upon
completion of the actions requested by the CMB
contents.
[cmh_l_orgid]
This longword contains the same value as the rtnqid
longword for normal return queues. Such queues are normally
associated with an interrupt attached to the destination process
on the VAX or are polled by that process.
If the return queue used is the multiplexed return queue, then
the value in this longword is used by the process
to locate the true destination process and its return queue
(see the information on the Queue Demultiplexing Block below).
[cmh_l_diqhdl]
This longword contains the handle of the DAE input queue. The
QVI_US_GET routine uses this field to route the CM block to
its destination queue if it is to be recycled. The queue handle
is taken from the QIB which specifies the default DAE input queue.
Applications can override the default queue by specifying the
altdiq parameter of the QVI_US_PUT routine.
[cmb_r_umb]
This structure is the portion of the CMB manipulated
by the user of the QVI or CM
services. The fields of the UMB are:
list
[umb_l_flags]
This is a bit-vector of flags in a longword.
The lowest bit (bit 0) is used
as the CYCLE bit. If this
bit is 1, when the CMB is removed from
the VAX return queue it is placed back on the
default processing queue rather than released
to the free queue (cycled for another processing pass).
Bit 1 is used by the DAE processors as the first time
flag ( 1ST_TIME). This flag is used by the DAE Timer
processor on cyclic requests
to flag the first cycle
(or the first time that the Timer has seen this request).
Bits 2-4 are used by the DAE Timer processor to support
fast time plot control and data buffer processing and
expunges.
[umb_w_type]
This word contains an identification code
describing the data contents of this UMB and is
of direct concern to the users of the QVI and CM routines.
[umb_w_reqsiz]
This word contains the requested UMB size in
bytes. This may not be the actual size of the
UMB (or enclosing CMB); there may be unused bytes (internal
fragmentation) between the end of the data and
the actual end of the UMB.
[umb_r_data]
This is the start of the data field of the
UMB. The format and contents of this portion of the UMB are
specific to the block type defined by the Common Memory user.
The cmh_l_rtnqid field is sometimes of concern to the
DAE programmer. This field identifies the return queue of the
``originator'' of the message and is sometimes used if the
request is fatally flawed and cannot be processed. In this case,
the return queue identifier is used to route the request immediately
back to the originator, usually with the CYCLE bit cleared and a
error status someplace in the data fields.
CMB Structure Definitions
There C structure definitions reflect those in (see below).
The definition of the UMB0 structure is given here as a prototype
definition for the user block. Common Memory
users should supply their own definitions,
replacing the umb_r_data field with definitions specific to their
applications.
struct CMH {
unsigned long cmh_l_link;
unsigned long cmh_l_rtnqid;
unsigned long cmh_l_orgid;
unsigned long cmh_l_diqhdl;
};
struct UMB0 { /* Prototypical definition */
unsigned long umb_l_flags;
unsigned short umb_w_type;
unsigned short umb_w_reqsiz;
unsigned long umb_r_data[2];
};
#define UMB_M_CYCLE 0X00000001
#define UMB_M_1ST_TIME 0X00000002
#define UMB_M_SUSPEND 0X00000004
#define UMB_M_AVAILABLE 0X00000008
#define UMB_M_EXPNDG 0X00000010
struct CMB {
struct CMH cmb_r_cmh;
struct UMB0 cmb_r_umb;
};
Multicast Block Format
Provision is made for a special form of a UMB for ``multicast''
messages which are routed to all the DAE processors for which entries
appear in the Queues Table. This special UMB is constructed by the
DAP$MULTICAST routines (see below); the QVI user provides a block type and up
to 4 longwords of multicast parameters. The DAE programmer basically
receives this like any other request but does have QVI-equivalent CM services
for forwarding the multicast request to the next destination.
The multicast message is sent to the first DAE processor with a non-zero
Queue Table entry. The Queue Table Index (QTI) for this entry is stored in
the multicast message. Each destination picks up the current QTI from the
multicast message and begins searching the Queue Table from that point
forward (towards the end of the Queue Table) for the next non-zero entry
which will be the next destination of the multicast message. When the end
of the Queue Table is reached, the multicast message is returned via the
return queue handle in the CMB header.
Locating the QVI Files and Linking With the QVI Services
The QVI code is stored under the
project of the .
The procedure in
area of defines the
logical names and
which specify the current locations of
the QVI include files (except for those which are stored under the logical
name ) and the
shareable image. The files include:
list
[CMDEF.H] Contains definitions for the Common Memory structures for VAX
and 80386 C programs.
Stored in .
[CMDEF.S]
Public Common Memory definitions for 68020
assembly code modules ( semi-Obsolete).
[QVIDEF.H]
Definitions of QVI and AMD 9519 Interrupt
Controller hardware (used internally in the QVI
routines).
[QVIMSG.A86]
Definitions of the QVI status code constants (as
symbols QVI__xxxx) for 80386 assembly language modules.
[QVIMSG.H]
Definitions of the QVI status code constants (as
symbols QVI__xxxx) for C programs.
Stored in .
[QVIMSG.S]
Definitions of the QVI status code constants for
68020 assembly code.
[QVIVAXC.OPT]
Options file for VAX Linker to link with the
QVIUSS shareable image.
The QVI routines in the shareable image can be linked to by
adding to the command line:
$ link ...,qvi_inc:qvivaxc/options,...
This options
file specifies that both the
and the (VAX C Run Time
Library shareable image in ) be linked to the image.
The QVI procedure also defines the
logical name
which specifies the current location of the object code
files for the 80386 (file types ). The available
files are:
list
[CMQLOCK] Contains the queue lock routines with the Test and Set
instructions. Must be linked with all DAE system software.
[CMQ] Contains the basic CM routines for manipulating
the Common Memory queues. Must be linked with all DAE system software.
[CMQGET] Contains the optional CM routines used if the DAE system
will be generating unsolicited requests and so needs access to the free
list queues.
[CMQPOOL] Contains the optional CM data pool services for locating
a Common Memory DataPool and locking or unlocking a DataPool.
VAX QVI User Services
Several ``combined'' service routines are defined to provide a simple
interface to the DAE for the Data Acquisition Server (DAS) and other
similar processes. The details of the Core Services are hidden within the
US calls. In addition, the initialization routine provides for connecting
to a interrupt-driven queue and receiving the interrupt notifications
via event flags or ASTs.
QVI_US_DAP$LOCATE
status = QVI_US_DAP$LOCATE( qti, qhdl )
Locate a queue by its DAP queue index and return the queue handle.
This routine is usually called once and the queue handle saved for
later use in QVI_US_DAP$MULTICAST.
qti DAP Queue Table index (unsigned byte, 0..255).
Passed by value.
qhdl queue handle returned in a longword. Passed by
reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOQUE fatal, queue not found
QVI__NOTINIT fatal, QVI_US services not initialized
QVI_US_DAP$MULTICAST
status = QVI_US_DAP$MULTICAST( blktyp, mcpars, [cmbhdl] )
Allocate a free CM block and build a multicast UMB into this block.
The first longword of the multicast UMB (after the standard UMB header)
contains the Queue Table Index of the current queue; this is followed
by 4 longwords of multicast parameters specified by the caller. This
routine initializes the QTI longword to the first non-zero QTI entry.
The CM block is then placed on the CM queue specified by
that QTI entry. As each destination processes the multicast message,
it advances the QTI longword to the next non-zero entry in the QTI table
and passes the block on to that destination until all the QTI entries
have been visited; after which the block is returned to the VAX by
the return queue identifier found in the CM block header.
blktyp Block type for the multicast UMB. Passed by value.
mcpars Parameters for the multicast message. A block of
4 longwords (16 bytes) passed by reference.
cmbhdl optional longword in which to return a pointer to
the CMB allocated from the free list and filled with
the multicast UMB contents. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__QTIEMPTY success, no multicast as QTI empty
QVI__NOFREE error, no free CM blocks of the needed
size are available
QVI__QLCKFAI error, failed to acquire queue lock
QVI__IVQLINK fatal, invalid queue link, possible CM corruption
QVI__NOTINIT fatal, QVI_US services not initialized
QVI_US_GET
status = QVI_US_GET( maxsize, umbbuf, [,blkhdl] )
Remove the CM block from the head of the VAX return queue specified
in the QVI_US_INIT call and return the UMB contents from the CM
block in the provided buffer. The CM block is either released to the
free list or recycled depending on the value of the CYCLE flag.
maxsize maximum expected UMB size. Passed by value.
umbbuf address of a buffer in VAX memory to be filled with the
contents of the UMB in the dequeued CM block.
Passed by reference.
blkhdl optional longword in which the block handle used to
identify the dequeued CM block is returned. Passed
by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__EMPTY warning, return queue was empty
QVI__TRU warning, return block truncated as UMB too small
QVI__QLCKFAI error, failed to acquire queue lock
QVI__IVQLINK fatal, invalid queue link, possible CM corruption
QVI__NOTINIT fatal, QVI_US services not initialized
others as returned by QVI_CS and VMS services
QVI_US_INIT
status = QVI_US_INIT( qname [,efn] [,ast] [,astprm] [,astcnt] )
Initialize the QVI_US services, including mapping all needed global
sections which were created during the Common Memory initialization.
The logical name RDCS$QVI_DAE_QUEUE
is translated to provide the name of the CM queue to which messages
are queued by QVI_US_PUT if no explicit target queue is given. This
default queue is also used by QVI_US_GET for messages with the CYCLE
flag set. The RDCS$QVI_WASTE_QUEUE logical name provides the name of
the CM queue used as the "toxic waste" queue when inserts of "defunct"
blocks onto the free lists fail.
Also, the name of the CM return queue
specified in the call is used to form the RDCS$QVI_VAXQ_name logical
name which should translate to the VMS device to assign an I/O channel
for the interrupt handling if either an event flag or an AST routine
is specified in the call to this service. The RDCS$QVI_DEMUX_QUEUE
logical name gives the name of the multiplexed CM queue to allow
QVI user processes using that queue to specify it as the return queue.
This is done automatically by QVI_US_INIT if the queue name specified
in the call is marked as a multiplexed queue (MUX bit in the queue
header).
qname queue name to be used by this process as its VAX return
queue. The queue name is a 1-8 character string passed
by descriptor.
efn Optional event flag number to be set when a block
appears on the VAX return queue for processing. Passed
by value.
ast Optional address of an AST routine to be invoked when a
block appears on the VAX return queue for processing.
Passed by reference (address of the procedure's entry
mask).
astprm Optional parameter to be passed to the AST routine.
Passed by value.
astcnt Optional parameter specifying a count of AST blocks to be
preallocated for handling rapid interrupts. Default
value of 10 is used. Passed by value.
status returns a VMS condition code:
SS$_NORMAL success
QVI__CMINIT fatal, CM not initialized
QVI__MAPERR fatal, failed to map CM properly
QVI__NOQUE fatal, queue named not found
others as returned by QVI_CS and VMS services
QVI_US_LOCATE
status = QVI_US_LOCATE( qname, qhdl )
Locate a named queue and return its queue handle. This service is
typically used once per queue and the resulting queue handle saved
for later use with QVI_US_PUT.
qname queue name to be located. The queue name is a 1-8
character string passed by descriptor.
qhdl Queue handle returned in a longword. Passed by
reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOQUE fatal, queue named not found
QVI__NOTINIT fatal, QVI_US services not initialized
others as returned by QVI_CS and VMS services
QVI_US_MODFLG
status = QVI_US_MODFLG( blkhdl [,rmask] [,smask] )
Modify the flag bits of the specified CM block. This is normally
used to clear the CYCLE flag before queuing a multicast EXPUNGE request
for that CM block. The CM block handle must have been saved from a
previous QVI_US_PUT call.
blkhdl block handle used to identify the CM block whose flag
bits are to be modified. Passed by value.
rmask mask of those UMB_L_FLAGS bits to be reset (cleared
to zero). Passed by value.
smask mask of those UMB_L_FLAGS bits to be set (to one).
Passed by value.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOTORG error, not originator of CM block
QVI__BADBHDL fatal, bad block handle
QVI__NOTINIT fatal, QVI_US services not initialized
others as returned by QVI_CS and VMS services
QVI_US_PUT
status = QVI_US_PUT( umbbuf [,toqhdl] [,blkhdl] [,altdiq] )
Allocate a block of CM and copy the UMB (User Memory Block) contents
into the CM block from the VAX buffer. The CM block is then placed
on the specified target CM queue.
umbbuf address of a buffer in VAX memory to be copied into the
UMB portion of the CM block. Passed by reference. The
UMB size will be taken from the umb_w_reqsiz word in the
VAX buffer.
toqhdl optional queue handle of the target CM queue. Passed by
value. If not specified (or specified as 0), then the
block will be placed on the default DAE queue. This
argument is the queue handle returned from a previous
call to QVI_US_LOCATE.
blkhdl optional longword in which the block handle used to
identify the allocated CM block is returned. Passed
by reference.
altdiq optional queue handle of the CM queue which will receive
the CM block if the CYCLE bit is set. Passed by value.
If the parameter is not supplied or contains a value of
zero, the CM block is directed towards the default DAE
input queue as specified by the RDCS$QVI_DAE_QUEUE logical.
This argument is the queue handle return from a previous call
to QVI_US_LOCATE.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOFREE error, no free CM blocks of the required size
QVI__QLCKFAI error, failed to acquire queue lock
QVI__BADQHDL fatal, bad queue handle
QVI__IVQLINK fatal, invalid queue link, possible CM corruption
QVI__NOTINIT fatal, QVI_US services not initialized
QVI__TOOBIG fatal, requested size exceeds that of the
largest CM block
others as returned by QVI_CS and VMS services
QVI_US_RESINM
status = QVI_US_RESINM( [efn] [,ast, astprm] )
This routine is called to reestablish the mechanism used to notify
processes that an interrupt from the Qbus adapter has been received.
efn integer value of the event flag
number set when an interrupt is
received. Passed by value.
ast address of the function to execute
when an interrupt occurs. Passed
by reference.
astprm integer value passed to the AST routine
if the ``ast'' parameter is specified.
Passed by value.
status returns a VMS condition code:
SS$_NORMAL success
SS$_BADPARAM fatal, bad parameter value
FALSE error, services not initialized
others as returned by VMS and $QIO services
QVI_US_TEST
status = QVI_US_TEST( [size] )
Test the VAX return queue (specified in the QVI_US_INIT call) to see
if any entries are currently queued.
size optional longword in which the size of the UMB in the
CM block at the head of the queue is returned. Passed
by reference. If the queue is empty, then zero is
returned.
status returns a VMS condition code:
SS$_NORMAL success
QVI__EMPTY warning, return queue was empty
QVI__QLCKFAI error, failed to acquire queue lock
QVI__IVQLINK fatal, invalid queue link, possible CM corruption
QVI__NOTINIT fatal, QVI_US services not initialized
others as returned by QVI_CS and VMS services
QVI Core Services
The QVI Core Services (CS) are meant for direct use by the
Common Memory initialization program and by diagnostics
programs. In addition, several of the Core Services are used by the
User-level Services (US routines) described above.
In the US routines, queue headers and CM blocks are identified using
``handles'' which are meant to be transparent to the US users. In the CS
routines, the handles are explicitly referred to as either offsets relative
to the CM base or as addresses in the CM (in the local process's VAS). The
CS routines locate the CM global section in the local VAS by the
Common Memory
Descriptor (cmdescr arguments in the routine descriptions). The
CM Descriptor is a structure of 16 longwords (64 bytes) containing the base
addresses (in the process's VAS) of the CM global section and other
QVI-associated global sections along with other information needed by the QVI
services. The US routines maintain a Common Memory
descriptor in hidden static storage.
QVI_CS_CM2VAX
status = QVI_CS_CM2VAX( cmdescr, cmbptr, size, block )
Copy an array of longwords from a CM block into VAX memory.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. Passed by reference.
cmbptr pointer to the CM block to be copied. Consider the
pointer as passed by value or that the CM block itself
is passed by reference (address of the CM block
appears in the argument list).
size Size of the longword array in bytes. Passed by
value.
block address of target VAX buffer to receive the longwords
from the CM block.
Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__IVCMDS fatal, invalid CM descriptor
QVI__BADBHDL fatal, bad block handle
QVI_CS_CREAA
status = QVI_CS_CREAA( cmdescr, blksiz, blkcnt, qptr, curcmo, aadptr )
Create a Common Memory allocation area. This routine is meant for
use by the CM initialization program or by stand-alone diagnostics.
cmdescr address of a CM descriptor returned by the QVI_CS_MAKECM
routine. Passed by reference.
blksiz size, in bytes, of the blocks in the allocation area
being defined. The size must be less than 65,535.
Passed by value.
blkcnt number of blocks requested for the area (less may be defined
if the end of the CM is reached first). Passed by value.
qptr pointer to header of free list queue for the new allocation
area. The free list queue is populated with all the blocks
in the new area. Passed by value.
curcmo current Common Memory offset on input, modified to reflect
new value after the new allocation area has been setup.
Passed by reference.
aadptr returns the address of the Allocation Area Descriptor for
the new allocation area. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
SS$_NOPRIV fatal, no privilege for the requested operation
QVI__BADQHDL fatal, bad CM queue handle
QVI__CMALRINI fatal, CM already completed initialization
QVI__IVCMDS fatal, invalid CM descriptor
QVI__IVQLINK fatal, invalid queue link, possible CM corruption
QVI__IVSIZE fatal, invalid CM block size
QVI__OUTOFCM fatal, no free Allocation Area Descriptors remain
This routine requires DIAGNOSE privilege to use.
QVI_CS_CREQH
status = QVI_CS_CREQH( cmdescr, qname, qptr )
Create and initialize a Common Memory queue header. This routine is
meant for use by the Common Memory initialization program or
by standalone diagnostics.
cmdescr address of a CM descriptor returned by the QVI_CS_MAKECM
routine. Passed by reference.
qname queue name given as (up to 8) ASCII characters. Passed
by fixed-length string descriptor.
qptr pointer to the new queue header returned in a longword.
Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
SS$_NOPRIV fatal, no privilege for the requested operation
QVI__CMALRINI fatal, CM already completed initialization
QVI__IVCMDS fatal, invalid CM descriptor
QVI__NOQUE fatal, no free queue headers left in CM
This routine requires DIAGNOSE privilege to use.
QVI_CS_DAP$MULTICAST
status = QVI_CS_DAP$MULTICAST( cmdescr, qib, blktyp, mcpars, [cmbptr] )
Allocate a free CM block and build a multicast UMB into this block.
The first longword of the multicast UMB (after the standard UMB header)
contains the Queue Table Index of the current queue; this is followed
by 4 longwords of multicast parameters specified by the caller. This
routine initializes the QTI longword to the first non-zero QTI entry.
The CM block is then placed on the CM queue specified by that QTI entry.
As each destination processes the multicast message,
it advances the QTI longword to the next non-zero entry in the QTI table
and passes the block on to that destination until all the QTI entries
have been visited; after which the block is returned to the VAX by
the return queue identifier found in the CM block header.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. Passed by reference.
qib Queues Information Block containing default
DAE queue header pointer, free queue table and
the DAP Queues Table.
Passed by reference.
blktyp Block type for the multicast UMB. Passed by value.
mcpars Parameters for the multicast message. A block of
4 longwords (16 bytes) passed by reference.
cmbptr optional longword in which to return a pointer to
the CMB allocated from the free list and filled with
the multicast UMB contents. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__QTIEMPTY success, no multicast as the DAP Queue
Table is empty
QVI__IVCMDS fatal, invalid CM descriptor
QVI__IVQLINK fatal, invalid queue link, possible
CM corruption
QVI__NOFREE error, no free CM blocks of the needed
size are available
QVI__QLCKFAI error, failed to acquire queue lock
QVI_CS_GET
status = QVI_CS_GET( cmdescr, qib, maxs, umbbuf, [qptr], [cmbptr] )
Remove the CM block from the head of the specified CM queue. If no explicit
queue is specified, the VAX return queue specified in the Queues Information
Block (QIB) is used.
The contents of the UMB portion of the dequeued CM block (if any) are
returned in the provided VAX UMB buffer. The CM block dequeued is either
released to the CM free lists or recycled depending upon the UMB_M_CYCLE
flag in the UMB header. A recycled CM block is placed on the DAE input
queue as given in the CMH.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. Passed by reference.
qib Queues Information Block containing the default
return queue header pointer and free queue table.
Passed by reference.
maxs size of user data return buffer (in bytes). Passed
by value.
umbbuf buffer for user data returned from the CMB removed from
the head of the queue. Passed by reference.
qptr optional pointer to queue header from which to remove
the head entry, default is the return queue pointed to
in the QIB. Passed by value.
cmbptr optional longword in which to return a pointer to
the CMB dequeued. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__EMPTY warning, return queue was empty
QVI__TRU warning, return block truncated
QVI__BADQHDL fatal, bad queue handle
QVI__IVCMDS fatal, invalid CM descriptor
QVI__IVQLINK fatal, invalid queue link, possible
CM corruption
QVI__IVSIZE fatal, invalid block size
QVI__NOQUE fatal, no target or default queue given
QVI__QLCKFAI error, failed to acquire queue lock
QVI_CS_INIT
status = QVI_CS_INIT( cmdescr )
Initializes the QVI control registers and creates the
permanent global section which maps the QVI control registers. The
pages of this global section are locked into the page tables to permit
access at elevated IPLs. This service is meant for use by the
Common Memory initialization program and by standalone diagnostics.
cmdescr address of a 16 longword CM descriptor returned by this
routine and used in other QVI_CS routines. Passed by
reference.
status returns a VMS condition code:
SS$_NORMAL success
SS$_NOPRIV fatal, no privilege for the requested operation
QVI__MAPERR fatal, error mapping the QVI registers
QVI__NOVMEPWR fatal, VME Bus is not powered
others as returned by VMS services
This routine requires SYSGBL, PRMGBL, PFNMAP and DIAGNOSE privileges to use.
QVI_CS_INSQT
status = QVI_CS_INSQT( cmdescr, cmbptr, qptr, genint )
Insert a Common Memory block onto the tail of a queue in the Common Memory.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. Passed by reference.
cmbptr pointer to the CM block within the mapped CM section.
Passed by value.
qptr pointer to CM queue header on which to insert the
CM block. Passed by value.
genint interrupt generation control flag. If 1 then the
interrupt associated with the queue is triggered.
If 0, then the interrupt (if any) is not triggered.
status returns a VMS condition code:
SS$_NORMAL success
QVI__IVCMDS fatal, invalid CM descriptor
QVI__IVQLINK fatal, invalid queue link, possible
CM corruption
QVI__BADBHDL fatal, bad block handle
QVI__BADQHDL fatal, bad queue handle
QVI__QLCKFAI fatal, failed to acquire queue lock
QVI_CS_INTERRUPT
status = QVI_CS_INTERRUPT( cmdescr, intno )
Generate an external mapped interrupt to a VME module using the QVI.
The external mapped interrupts are generated by writing a mask of bits
into a 16-bit control register on the QBus.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. The variant form of the CM
descriptor returned by the QVI_CS_VMEWINDOW routine
is also acceptable.
Passed by reference.
intno external interrupt number (0-7). Passed by value.
status returns a VMS condition code:
SS$_NORMAL success
SS$_BADPARAM fatal, bad interrupt number
QVI__IVCMDS fatal, invalid CM descriptor
QVI_CS_LOCATE
status = QVI_CS_LOCATE( cmdescr, qname, qptr )
Locate a Common Memory queue header.
cmdescr address of a CM descriptor returned by the QVI_CS_MAKECM
or QVI_CS_MAP routine. Passed by reference.
qname queue name given as (up to 8) ASCII characters. Passed
by fixed-length string descriptor.
qptr pointer to the new queue header returned in a longword.
This is the address of the queue header in the CM as
mapped into the process's virtual address space.
Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__IVCMDS fatal, invalid CM descriptor
QVI__NOQUE fatal, no queue found
QVI_CS_LOCKCM
status = QVI_CS_LOCKCM( cmdescr )
Lock the Common Memory global section into
the paging tables to permit access at elevated IPLs.
This service is meant for use by the CM initialization
program and by stand-alone diagnostics.
Requires that QVI_CS_MAKECM have already been called.
cmdescr address of a 16 longword CM descriptor which was returned
by QVI_CS_MAKECM. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__IVCMDS fatal, invalid CM descriptor
QVI__MAPERR fatal, not all of CM locked
others as returned by VMS services
This routine requires PSWAPM privilege to use.
QVI_CS_MAKECM
status = QVI_CS_MAKECM( cmavme, size, cmdescr )
Create and map the permanent global sections for the Common Memory
and the transient VME window global section into the process's
virtual address space.
This service is meant for use by the CM initialization program.
Requires that QVI_CS_INIT have been called previously.
cmavme VME address of the base of the Common Memory module.
Must be aligned on a QVI boundary (multiple of 128 KBytes).
Passed by value.
size number of bytes of the Common Memory module to be used.
Must be an integral number of Kbytes (an even number of
VAX pages).
Passed by value.
cmdescr address of a 16 longword CM descriptor which was returned
by QVI_CS_INIT and will be modified here. Passed by
reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__CMBASE fatal, CM base address not on QVI mapping boundary
QVI__CMSIZEXC fatal, CM size exceeds QBus address space
QVI__CMSIZODD fatal, CM size not even number of VAX pages
QVI__IVCMDS fatal, invalid CM descriptor
QVI__MAPERR fatal, not all of CM mapped
others as returned by VMS services
This routine requires SYSGBL, PRMGBL and PFNMAP privileges to use.
QVI_CS_MAKEFQT
status = QVI_CS_MAKEFQT( cmdescr, maxfq, fqtable )
Build a free queue location table to provide fast access to the free lists.
cmdescr address of a CM descriptor returned by the QVI_CS_MAKECM
or QVI_CS_MAP routine. Passed by reference.
maxfq maximum number of free list queues provided for in
the table. Passed by value.
fqtable free list queue table giving block sizes and pointers to
the associated free queue headers. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__IVCMDS fatal, invalid CM descriptor
QVI__TOOMNYFQ fatal, too many free queues for table
QVI_CS_MAPCM
status = QVI_CS_MAPCM( cmdescr )
Map the Common Memory, transient VME window and QVI control registers global
sections into the current process's virtual address space. These global
sections must have already been setup by a previous program (such as the
CM initialization program). This service is used instead of QVI_US_INIT
by those programs which depend upon the CM being initialized by a special
program (usually at system startup).
cmdescr address of a 16 longword block in which a CM descriptor
is returned. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__MAPERR fatal, not all of a global section mapped or
locked into the page tables
QVI__NOVMEPWR fatal, VME Bus is not powered
others as returned by VMS services
QVI_CS_MODIFLAGS
status = QVI_CS_MODIFLAGS( bp, [rstmsk], [setmsk] )
Modify the flag bits of the specified CM block. This is normally used
the clear the CYCLE bit before queuing a CANCEL or EXPUNGE multicast
request for a particular CM block. This is an internal routine for
the QVI_US_MODFLG routine to do the flag modifications at elevated IPL.
bp pointer to Common Memory block. Passed by
value.
rstmsk mask of flag bits to be cleared. Passed by value.
setmsk mask of flag bits to be set. Passed by value.
status returns a VMS condition code:
SS$_NORMAL success
SS$_ACCVIO fatal, no access to CMB flags
QVI_CS_POOLPOINTER
status = QVI_CS_POOLPOINTER( cmdescr, poolno, poolptr, poolsize )
Return pointer to selected Common Memory DataPool.
cmdescr address of a 16 longword block returned by the QVI_CS_MAPCM
service. Passed by reference.
poolno selector number of Common Memory DataPool. Passed by value.
poolptr address of a longword to receive a pointer to the base
of the DataPool as mapped in current process virtual
address space. Pointer to pool is passed by reference.
poolsize address of a longword to receive size of the DataPool.
Size is passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOPOOL error, no space allocated for selected data pool
QVI__IVCMDS fatal, invalid CM descriptor
QVI__BADPOOLNO fatal, bad CM data pool number
others as returned by VMS services
QVI_CS_PUNCHVME
status = QVI_CS_PUNCHVME( cmdescr, vmeadr, [word], [noaswap] )
Generate an interrupt or a reset by touching a VME location.
Normally VME bus accesses are done in Extended Supervisory Data access
mode (32 bit address). However, if the VME address passed to this
routine is a 16 bit address (the upper 16 bits are zero), then the VME
location is touched in Short Supervisory access mode. The access
modes refer to the VME address modifier codes generated on the VME
bus along with the VME address. This routine extends the capabilities
provided by the TOUCHVME routine (see below).
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. A variant CM descriptor
returned by QVI_CS_VMEWINDOW is also acceptable.
Passed by reference.
vmeadr VME address to touch (with Clear Byte or Clear Word)
to generate
the interrupt or desired signal. Passed by value.
word Select word operation if value is TRUE (1). Passed
by value. Default (0) selects byte operation.
noaswap This parameter is obsolete, a value must be specified
but its value is ignored and not used.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOTRNSWIN warning, no transient window
SS$_BADPARAM fatal, bad interrupt number
QVI__IVCMDS fatal, invalid CM descriptor
QVI_CS_PUT
status = QVI_CS_PUT( cmdescr, umbbuf, qib, [tqptr], [cmbptr], [altdiq] )
Allocate a free CM block and copy the UMB contents into this free block
from the VAX UMB buffer. The CM block size is retrieved from the UMB
UMB buffer size field. The CM block is then placed on the specified CM
queue or the default DAE queue (given in the QIB) if no target queue
handle is provided. The CM block is recycled to the queue handle as
specified by the altdiq parameter if the CYCLE bit is set.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. Passed by reference.
umbbuf buffer of user data to be inserted into a CMB and
placed on a queue for processing. Passed by
reference. This data must have the structure of
a UMB with the length of the UMB in the umb_w_reqsiz
word.
qib Queues Information Block containing default
DAE queue header pointer and free queue table.
Passed by reference.
tqptr optional pointer to target queue header. If not given
then the target is the default DAE queue from the QIB.
Passed by value.
cmbptr optional longword in which to return a pointer to
the CMB allocated from the free list and queued to the
target queue. Passed by reference.
altdiq optional longword directing the CM block to be recycled
on an alternate DAE input queue (DIQ). Passed by value.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOFREE error, no free CM blocks of the needed
size are available
QVI__QLCKFAI error, failed to acquire queue lock
QVI__BADQHDL fatal, bad queue handle
QVI__IVCMDS fatal, invalid CM descriptor
QVI__IVQLINK fatal, invalid queue link, possible
CM corruption
QVI__IVSIZE fatal, invalid block size
QVI__NOQUE fatal, no target or default queue given
QVI__TOOBIG fatal, requested UMB size exceeds that
of the largest CM block
QVI_CS_REMQH
status = QVI_CS_REMQH( cmdescr, qptr, cmbptr )
Remove the entry from the head of a queue in the Common Memory.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. Passed by reference.
qptr pointer to queue header from which to
remove the entry at the head of the queue.
Passed by value.
cmbptr returns a pointer to the CM block removed in a
longword. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__EMPTY warning, queue is empty
QVI__BADQHDL fatal, bad queue handle
QVI__IVQLINK fatal, invalid queue link, possible
CM corruption
QVI__IVCMDS fatal, invalid CM descriptor
QVI__QLCKFAI fatal, failed to acquire queue lock
QVI_CS_RESETVME
status = QVI_CS_RESETVME( cmdescr )
Use the QVI to generate a RESET on the VME bus.
cmdescr address of a 16 longword block returned by the QVI_CS_INIT
service. The variant form returned by the QVI_CS_VMEWINDOW
routine is also acceptable. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
SS$_NOPRIV fatal, no privilege for requested operation
QVI__IVCMDS fatal, invalid CM descriptor
others as returned by VMS services
The process must have DIAGNOSE privilege.
QVI_CS_SHUTDOWN
status = QVI_CS_SHUTDOWN( )
Shutdown the QVI services by deleting the permanent global sections used
by these services. This service is meant for use by the CMShutdown
program or stand-alone diagnostics.
status returns a VMS condition code:
SS$_NORMAL success
SS$_NOPRIV fatal, no privilege for the requested operation
others as returned by VMS services
This routine requires SYSGBL, PRMGBL, PFNMAP and DIAGNOSE privileges to use.
QVI_CS_STATUS
status = QVI_CS_STATUS( cmdescr )
Return status from the QVI.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. The variant form CM descriptor
returned by QVI_CS_VMEWINDOW is also acceptable.
Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__VMEBUSBSY warning, a QVI operation is in
progress on the VME bus
QVI__IVCMDS fatal, invalid CM descriptor
QVI__VMEBUSERR fatal, a VME bus error has occurred
QVI_CS_TEST
status = QVI_CS_TEST( cmdescr, qptr, [size] )
Test the specified queue to see if any entries are on it.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. Passed by reference.
qptr pointer to CM queue header. Passed by value.
size returns the size of the UMB of the entry at the
head of the queue (or 0 if the queue is empty).
Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__EMPTY warning, queue was empty
QVI__QLCKFAI error, failed to acquire queue lock
QVI__BADQHDL fatal, bad queue handle
QVI__IVQLINK fatal, invalid queue link possible
CM corruption
QVI__IVCMDS fatal, invalid CM descriptor
QVI_CS_TOUCHVME
status = QVI_CS_TOUCHVME( cmdescr, vmeadr )
Generate an interrupt or a reset by ``touching'' a VME location.
Normally all VME bus accesses via the QVI are done in Extended
Supervisory Data access mode with 32-bit addresses. However, if
the VME address passed to this routine is a 16-bit address (upper 16-bits
are zero), then the VME location is ``touched'' in Short Supervisory
access mode. The access modes refer to the VME address modifier codes
generated on the VME bus along with the VME address. This capability
was added to permit the correct access to be made to the mailbox
locations on the Heurikon 68020 processor boards.
The generation of queue-associated interrupts by ``touching'' VME locations
(internal to the INSQT, GET and PUT routines) is done in the same
manner as for the TOUCHVME routine. If the VME interrupt address
associated with a queue is a 16-bit address, a Short Supervisory
VME address modifier is used.
This routine has been superceded by the PUNCHVME routine (see above).
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. The variant form CM descriptor
returned by the QVI_CS_VMEWINDOW routine is also
acceptable.
Passed by reference.
vmeadr VME address to touch (with Clear Byte) to generate
the interrupt or desired signal. Passed by value.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOTRNSWIN warning, no transient window
SS$_BADPARAM fatal, bad interrupt number
QVI__IVCMDS fatal, invalid CM descriptor
QVI_CS_VAX2CM
status = QVI_CS_VAX2CM( cmdescr, block, size, cmbptr )
Copy an array of longwords from VAX memory into a CM block.
cmdescr CM descriptor returned by the QVI_CS_MAKECM or
QVI_CS_MAPCM service. Passed by reference.
block address of a buffer of one or more longwords in VAX
memory.
Passed by reference.
size Size of the longword buffer in bytes. Passed by
value.
cmbptr pointer to the CM block to be filled (pointer refers
to the CM block as mapped by the CM global section into
the process' virtual address space). Consider the
pointer as passed by value or that the CM block itself
is passed by reference (address of the CM block
appears in the argument list).
status returns a VMS condition code:
SS$_NORMAL success
QVI__IVCMDS fatal, invalid CM descriptor
QVI__BADBHDL fatal, bad block handle
QVI__IVSIZE fatal, not integral number of longwords
QVI_CS_VMEADRMOD
status = QVI_CS_VMEADRMOD( cmdescr, amod )
Set the VME address modifier of the roving VME window defined by the call
to QVI_CS_VMEWINDOW to the selected value (or revert to the default).
cmdescr address of a 16 longword block returned by from the
QVI_CS_VMEWINDOW routine. Passed by reference.
amod unsigned longword giving the VME address modifier code
(see definitions in QVIDEF.H file) for the roving VME
window. If 0 is passed, the VME address modifier is reset
to the initialization value of QVI_C_ESDA for Extended
Supervisory Data Access.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOVME fatal, VME window not initialized
QVI__NOTQVIPLUS fatal, not supported except for QVI-Plus
QVI_CS_VMEMAP
status = QVI_CS_VMEMAP( cmdescr, vmeadr )
Set the VME base address of the roving VME window defined by the call
to QVI_CS_VMEWINDOW.
cmdescr address of a 16 longword block returned by from the
QVI_CS_VMEWINDOW routine. Passed by reference.
vmeadr unsigned longword giving the base VME address of the window
into the VME address space. The low-order 17 bits of the
VME address are ignored. Passed by value.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOVME fatal, VME window not initialized
QVI_CS_VMEPOINTER
address = QVI_CS_VMEPOINTER( cmdescr, vmeadr )
Return the VAX virtual address (in the process' virtual address space)
which corresponds to the VME address
as mapped by the roving VME window. The VME window has to have been
setup by a call to QVI_CS_VMEMAP to map a range of VME addresses
(including the VME address specified to this routine).
cmdescr address of a 16 longword block returned by from the
QVI_CS_VMEWINDOW routine. Passed by reference.
vmeadr unsigned longword giving the VME address to be located.
Passed by value.
address VAX virtual address in the process' virtual address
space which corresponds to the VME address as mapped
by a QVI window. If the CM descriptor was not
initialized, if the VMEMAP routine was not called or
if the VME address given by vmeadr is not accessible
within the QVI window, then an address of 0 is returned.
QVI_CS_VMEWINDOW
status = QVI_CS_VMEWINDOW( cmdescr )
Setup a ``roving'' VME window by allocating the ``rover'' QVI map register.
This VME window is then under the control of the process and can be
moved in VME address space by using the QVI_CS_VMEMAP routine. The
``rover'' QVI map register is allocated by taking out a
system-wide lock on the
resource named QVI_VME_WINDOW. A PFN (page frame number) section near
the top of Qbus address space will be created; the size of this section
is that of 1 QVI map register (128 Kbytes).
The lock on the QVI_VME_WINDOW
resource is only released when the program is exited, for this reason,
the common memory descriptor used by the QVI_VME_WINDOW
must be allocated in static memory, not on the stack.
cmdescr address of a 16 longword block returned by this routine
with the QVI addresses. This variant form of the CM
descriptor must be used with the QVI_CS_VMEMAP routine
and is acceptable to the QVI_CS_INTERRUPT, QVI_CS_STATUS,
and QVI_CS_RESETVME routines. This block must be
allocated in static storage due to existence of an exit
handler block within the common memory descriptor.
Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
SS$_NOPRIV fatal, no privilege for the requested operation
QVI__VMEINUSE fatal, VME window in use by another process
others as returned by QVI_CS and VMS services
This routine requires PFNMAP and DIAGNOSE privileges to use.
Basic Services for 80386 Code
The CM routines are linked with the DAE code itself and provide
services at the level of the VAX QVI_US routines. The CM routines
locate Common Memory blocks and queues by their VMEBus address in
the memory module used to support the Common Memory.
cm_dapmcast
status = cm_dapmcast( cmbptr )
Insert a Common Memory block with a DAP Multicast message
the next destination queue of the message.
The next destination queue is given by either
the next non-empty entry in the DAP Queue Table (as specified by the
QTI within the Multicast message) or is the originator's return queue.
By convention, DAP Multicast messages originate in the host MicroVAX.
cmbptr pointer to CM block with the Multicast message.
Passed by value (or consider the CM block as passed
by reference).
status returns a VMS condition code:
SS$_NORMAL success
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__QLCKFAI fatal, failed to acquire queue lock
cm_dapqloc
status = cm_dapqloc( qti, qhdl )
Locate a Common Memory queue by its Queue Table Index (QTI) as used in the
Data Access Protocol (DAP) packets.
qti queue table index given as a byte. Passed by value.
qhdl returns a pointer to the queue header. Passed by
reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__NOQUE fatal, could not find named queue
cm_insqt
status = cm_insqt( cmbptr, qptr, genint )
Insert a Common Memory block onto the tail of a queue in Common Memory.
cmbptr pointer to the CM block. Passed by value (or consider
the CM block as passed by reference).
Note that the pointer is to the CMB, not the UMB
which is contained within the CMB.
qptr pointer to CM queue header on which to insert the
CM block or the offset of the queue header relative
to the base of the CM. Passed by value (or consider
the CM queue header as passed by reference).
genint interrupt generation control flag.
If 1 then the interrupt
associated with the queue is triggered. If 0, then
the interrupt (if any) is not triggered. Passed by
value.
status returns a VMS condition code:
SS$_NORMAL success
QVI__BADBHDL fatal, bad pointer to CM block
QVI__BADQHDL fatal, bad pointer to CM queue header
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__QLCKFAI fatal, failed to acquire queue lock
cm_locate
status = cm_locate( qname, qhdl )
Locate a Common Memory queue header.
qname queue name given as (up to 8) ASCII characters. Passed
by reference (a C string terminated by a NUL character).
qhdl pointer to the new queue header returned in a longword.
This is the address of the queue header in the CM.
Passed by reference.
status returns as VMS condition code:
SS$_NORMAL success
QVI__NOQUE fatal, no queue found
cm_remqh
status = cm_remqh( qptr, cmbptr )
Remove entry from the head of a Common Memory queue.
qptr pointer to CM queue header from which to remove the
CM block. Passed by value (consider the CM queue
header as passed by reference).
cmbptr address of longword to return pointer to the block
removed from the head of the queue. Passed by
reference.
Note that the pointer is to the CMB, not to the UMB
which is contained within the CMB.
status returns a VMS condition code:
SS$_NORMAL success
QVI__EMPTY warning, queue is empty
QVI__BADQHDL fatal, bad pointer to CM queue header
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__QLCKFAI fatal, failed to acquire queue lock
cm_tstq
status = cm_tstq( qptr )
Test the status of a Common Memory queue.
qptr pointer to CM queue header. Passed by value (consider
the CM queue header as passed by reference).
status returns a VMS condition code:
SS$_NORMAL success
QVI__EMPTY warning, queue is empty
QVI__BADQHDL fatal, bad pointer to CM queue header
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__QLCKFAI fatal, failed to acquire queue lock
Additional 80386 Services
These CM services are an optional addition to those listed above. Normally,
the DAE processors receive requests from the VAX and pass responses back to
the VAX in the same CMB as the request arrived in. In order to allow the
DAE processors to generate unsolicited messages, these additional routines
interface the DAE processors to the free block lists in the Common Memory.
These routines assume that the VAX will be the sink for these messages and
depend on the MicroVAX to restore the exhausted block to its free list.
cm_get_block
status = cm_get_block( size, qhdl, cmbptr )
Allocate a block from the Common Memory free lists.
size requested size of the UMB to be allocated from the
CM free lists. Passed by value. The size will be
stored in the standard field in the UMB header of the
allocated block. The caller must fill in the UMB block
type.
qhdl queue pointer, returned by cm_locate(), of a queue
owned by a VAX process which is the ultimate destination of
the message in the block being requested.
cmbptr address of longword to return pointer to the block
removed from a free list queue. Passed by
reference.
Note that the pointer returned is to the CMB, not
the UMB which is contained within the CMB.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOFREE error, no free CM blocks
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__IVSIZE fatal, invalid UMB size request
QVI__QLCKFAI fatal, failed to acquire queue lock
QVI__TOOBIG fatal, size exceeds largest CM block size
cm_get_init
status = cm_get_init()
Perform necessary one-time-only initializations for the cm_get_block() routine.
This includes building a list of the free lists in static storage which is
sorted by the size of the blocks on the free lists.
status returns a VMS condition code:
SS$_NORMAL success
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__TOOMNYFQ fatal, too many free queues for table
Other optional CM services deal with Common Memory DataPools. A DataPool
is a section of Common Memory set aside for the use of a group of
cooperating processes (usually on multiple processors) as a data storage
area. The usual setup is for one process to collect data, reformat it
and deposit in the DataPool. Another process will then pick data out
of the DataPool in response to user data acquisition requests.
cm_lockpool
status = cm_lockpool( pn )
Lock the selected data pool against updates by other processors.
pn number of Common Memory DataPool. Passed by value.
status returns a VMS condition code:
SS$_NORMAL success, pool locked by this processor
QVI__LOCKED warning, pool is already locked
QVI__BADPOOLNO fatal, bad CM data pool number
cm_poolpointer
status = cm_poolpointer( pn, pp )
Return address of selected Common Memory DataPool area.
pn number of Common Memory DataPool. Passed by value.
pp address of a longword to return the pointer to the Common
Memory DataPool. Passed by reference.
status returns a VMS condition code:
SS$_NORMAL success
QVI__NOPOOL error, no space allocated for selected data pool
QVI__CMNOTINI fatal, Common Memory not initialized
QVI__BADPOOLNO fatal, bad CM data pool number
cm_unlockpool
status = cm_unlockpool( pn )
Release the lock on the selected data pool to allow updates by other
processors.
pn number of Common Memory DataPool. Passed by value.
status returns a VMS condition code:
SS$_NORMAL success, pool locked by this processor
QVI__NOTLOCKED warning, pool was already unlocked
QVI__BADPOOLNO fatal, bad CM data pool number
CM Initialization
The Common Memory is setup from the VAX program called CMInitializer.
This program is run whenever the VAX is booted or the DAE is reset and
restarted (without booting the VAX). The CMInitializer program must run in
a process with the necessary privileges to run the various QVI_CS services
(CMKRNL, PFNMAP and DIAGNOSE) along with others as deemed necessary.
The CMInitializer performs the following actions in roughly the
listed order:
-
Read a text file of parameters using the logical name
. The format of this file is described below.
-
Create a permanent global section named if not
already present. The global section is created using PFN (Page
Frame Number) mapping of the QBus addresses used for the main CM
window. In either case, map the global section into current
process VAS P0 region.
-
Initialize the QVI control registers to map the QBus addresses
of the CM to the actual VME addresses of the CM memory board.
Also create a permanent global section named
to map the QVI control registers (access limited to kernel mode).
-
Zero all of the VME memory module locations (including the
entire Common Memory region).
-
Initialize the CM global area locations and build the CM queue
headers, allocation area descriptors and other fixed structures.
-
Initialize CM free queues and place all the CM blocks on their
respective free queues.
Format of Parameter Descriptions
The parameters file is located by the logical name.
The defaults for the file specification of the parameters file are:
SYS_STARTUP:CM_PARAMETERS.INI
Each line of this file contains the description of a single parameter using
DCL-like syntax:
parameter-name[/qualifier(s)] value[,value...]
Optional arguments are indicated by square brackets ([...]) in the syntax
descriptions.
Depending upon the parameter, values can be decimal numbers, hexadecimal
numbers (%X...), non-delimited symbol names of alphanumeric characters
(including ``$'' and ``_''), text strings
enclosed in double quotes ("...") or
keywords.
Comments may be included with the parameters. All characters after an
exclamation mark (``!'') to the end of the line are ignored and treated as
comments. Multiple spaces and tabs outside of quoted text are treated as a
single space. Lowercase characters are converted to uppercase, except
within quoted text.
CMInitializer Parameters
list
[ADDRESS address]
Specifies an address:
list
[/CM]
the base address of the memory board on the VME bus to be
used for the Common Memory.
[/EXTERNAL_INTERRUPT]
Specifies the VME address of the QVI's external interrupt register.
[BLOCKS queue-name]
Specifications for a free block area.
The argument is the name of the queue
header for the free list of these
blocks.
list
[/SIZE=n]
Size, in bytes, of each of this class of blocks.
[/COUNT=n]
Number of blocks to be created in this class.
[/AVAILABLE]
Use remainder of available Common Memory
for blocks of this free
list.
Note, and are mutually exclusive
and only one can be used on a given BLOCKS command. Similarly, only
a single BLOCKS command in a parameters file can use the
qualifier.
[CLEARMEMORY size]
Specifies the amount of memory in the VME memory module to be
cleared to zeroes. Size is given in Kbytes.
[DATAPOOL n size]
Specifies that DataPool number n is to be initialized with a
size of size bytes.
[EXIT]
Terminates parameters command file.
[LDD name]
Specifies the node name whose Listener Data Descriptor (LDD) is to be
setup. The ``DEFS'' string is passed as the name parameter to specify
defaults values. The defaults are used if a particular qualifier isn't
specified for a given name, or if the current node doesn't match any
of the names defined by the LDD command. Furthermore, ``DEFS''
be specified before any other LDD command definitions.
list
[/ID=number] Specifies the Listener ARCnet node number (0-255).
[/DAE=number] Specifies the number (0-255) of seconds that must
elapse before the DAE data is considered stale.
[/FTP=number] Specifies the number (0-255) of seconds that must
elapse before the FTP data is considered stale.
[MUXQUEUE name]
Specifies the name of the multiplexed return queue (if any).
[QUEUE name]
Defines a named queue whose header is
to be setup. Queue names are
alphanumeric symbol names (``$'' and
``_'' permitted). The case of the queue name is unimportant as
all the queue names are kept in uppercase.
list
[/VME=address]
Specifies the address of a VME location used to generate the
interrupt associated with this queue. The interrupt is triggered
when an entry is made on the queue to signal the destination that
a request is available on its input queue.
[/EXTERNAL=number]
Specifies the number (0-7) of a
QVI mapped external interrupt associated with
this queue. This interrupt is generated by writing a 1 to the
selected bit number in a register.
[/DEMUX]
Specifies that this is a VAX return queue fed via the multiplexed
return queue and the process.
[/NONE]
No interrupt is associated with the
queue (normally used only for free
list queues or input queues watched by a polling algorithm).
[/DEVICE=device]
Specifies the name of a VAX device
with the UIC driver
for handling interrupts for this
queue. Used for input queues for VAX processes only.
[/DAP_INDEX=number]
Specifies that this queue is to be
entered in the DAP queue table at the
specified index number.
[/NOBYTE_OPERATION]
Specifies that the hardware generating the interrupt will only respond to
word operations (otherwise a byte access will be used).
Only one of the qualifiers , ,
or may be present ( is
taken by default if no qualifier is present). The
, and qualifiers are
not allowed with (either an explicit or
one implied by default) or .
Similarly, can only be used
with the qualifier (if is used, the default
is ).
[RESET]
Generate a VME bus reset.
[SET keyword]
Select an option:
list
[CHECK_ONLY]
Read and validate the parameters, but
do not actually initialize the CM.
[VERIFY]
List the commands as they are read.
[TEST_MODE]
Used for testing CMI.
[SHOW keyword]
Select an output option:
list
[BUILD]
Show details during the
initialization of the Common Memory.
[PARAMETERS]
Show a table of the initialization
parameters after the commands are read
and before the CM is initialized.
[SUMMARY]
Show a summary of the initialization operations.
[SIZE Kbytes]
Specifies the size of the CM in
Kbytes.
The following is an example of a command procedure used to initialize the
Common Memory. The first part of the procedure defines the logical names
which CMInitializer will cross-check against its input parameters.
$ DEFINE := DEFINE /NOLOG
$ SET PROCESS /PRIVILEGE=SYSNAM
$!
$! Define logical names to identify default queue to send packets to
$! Data Acquisition Engine and to hold packets incase of INSQ failures.
$!
$ DEFINE /SYSTEM RDCS$QVI_DAE_QUEUE TIMER
$ DEFINE /SYSTEM RDCS$QVI_WASTE_QUEUE $TOXIC$
$!
$! Define logical names for VAX devices associated with CM queues used
$! as "input" to VAX processes; devices are used with Connect-to-Interrupt.
$!
$ DEFINE /SYSTEM RDCS$QVI_VAXQ_DASRET VAXQA0:
$ DEFINE /SYSTEM RDCS$QVI_VAXQ_TSRET VAXQB0:
$ DEFINE /SYSTEM RDCS$QVI_VAXQ_HERMES VAXQC0:
$ DEFINE /SYSTEM RDCS$QVI_VAXQ_FEEDER VAXQF0:
$ DEFINE /SYSTEM RDCS$QVI_VAXQ_ECHOBACK VAXQG0:
$!
$! Initialize the common memory with parameters in the specified file.
$!
$ SET PROCESS /PRIVILEGE=(CMKRNL,DIAGNOSE,PSWAPM,PRMGBL,SYSGBL,PFNMAP,SYSLCK)
$ DEFINE /USER_MODE CM_PARAMETERS SYS$INPUT:
$ RUN CMI
address %XE0000000 /cm !CM VME card address
address %XFF00E010 /external_interrupt !Mapped External Interrupts
size 3072 !Use 3 MB of memory
clear 4096 !Clear all 4 MB of memory
!
! Queues for free lists:
!
queue $256 /none
queue $1K /none
queue $4k /none
queue $tiny /none
blocks $4k /size=4096 /count=150
blocks $1k /size=1048 /count=300
blocks $256 /size=280 /count=500
blocks $tiny /size=128 /available
!
! Listener parameters:
! The defaults MUST be defined first!
!
ldd defs /id=1 /dae=120 /ftp=120 !Setup listener defaults
ldd huey /id=1 !For HUEY
ldd dewey /id=2 !For DEWEY
ldd louie /id=3 !For LOUIE
ldd webby /id=4 !For WEBBY
!
! Action queues:
!
queue $toxic$ /none
queue dasret /vme=%XFF00E000 /device=vaxqa0: /nobyte !DAS return queue
queue tsret /vme=%XFF00E002 /device=vaxqb0: /nobyte !TS return queue
queue camac /external=1 /dap_index=2 !CAMAC module's queue
queue timer /external=0 /dap_index=1 !Timer module's queue
queue Hermes /vme=%XFF00E004 /device=vaxqc0: /nobyte !Message handler queue
exit
$ EXIT
Internals
Logical Names
A set of logical names of the form are used to
specify special-purpose CM queues and to associate VAX return (or input)
queues with a set of VMS device names (see the section on the
UICDRIVER below). CMInitializer cross-checks its input
parameters against these logical names. The Common Memory initialization
procedure example in section
illustrates some of
these logical name definitions. The special logical names used by the
QVI services are:
list
[RDCS$QVI_DAE_QUEUE] gives the name of the default DAE queue in
Common Memory. This is the queue that blocks with the CYCLE bit
set are placed on after being removed from a VAX return queue.
[RDCS$QVI_WASTE_QUEUE] gives the name of
the ``toxic waste'' Common Memory queue.
The ``toxic waste'' queue provides a
place for the QVI services on the VAX (and possibly their equivalents in
the DAE processing elements) to place CM blocks which would otherwise be
``lost''. Some of the QVI services use this queue when problems arise in
queuing blocks to other queues; the ``toxic waste'' queue is used rather than
dropping the CM block on the floor which would result in the lose of the CM
resources. The ``toxic waste'' queue is not associated with an interrupt,
but a periodic VAX process will attempt to empty the ``toxic waste'' queue
and recover the blocks (restore them to the free lists).
[RDCS$QVI_DEMUX_QUEUE] gives the name of the multiplexed VAX return
queue. This is the input queue for the process.
[RDCS$QVI_VAXQ_qname] where ``qname'' is the name of a Common
Memory queue. The equivalence string of the logical name is the name
of the VAX device used to process the interrupts associated with the
specified VAX return queue.
UICDRIVER and VAX Interrupt Devices
Interrupts associated with the VAX input queues are handled using
VMS devices supported by the driver for the AMD 9519A
Universal Interrupt Controller chip.
The is a modified and simplified Connect-to-Interrupt
driver. The association between the VAX device name and the
interrupt vector is setup at system startup by
(see the example below). The QVI
interrupt services associate a VAX device name with an interrupt level
number in the AMD9519 Interrupt Controller Chip by the controller letter in
the device name. Thus controller letters ``A'' through ``H'' map into the 9519
interrupt levels 0 through 7. The interrupt vector to be loaded into the
9519's response memory is located in the Interrupt Dispatch Block (IDB) of
the system's I/O database as setup by . A startup file for
to define 8 devices for the 8 interrupt levels on the QVI is:
$ RUN SYS$SYSTEM:SYSGEN
!
! NOTE: The CSR addresses here are of the Command Register of the
! AMD9519 Interrupt Controller, NOT of the 1st QVI register.
!
CONNECT VAXQA0 /ADAPTER=UB0 /DRIVERNAME=UICDRIVER /CSR=%O777102 /VECTOR=%O700
CONNECT VAXQB0 /ADAPTER=UB0 /DRIVERNAME=UICDRIVER /CSR=%O777102 /VECTOR=%O704
CONNECT VAXQC0 /ADAPTER=UB0 /DRIVERNAME=UICDRIVER /CSR=%O777102 /VECTOR=%O710
CONNECT VAXQD0 /ADAPTER=UB0 /DRIVERNAME=UICDRIVER /CSR=%O777102 /VECTOR=%O714
CONNECT VAXQE0 /ADAPTER=UB0 /DRIVERNAME=UICDRIVER /CSR=%O777102 /VECTOR=%O720
CONNECT VAXQF0 /ADAPTER=UB0 /DRIVERNAME=UICDRIVER /CSR=%O777102 /VECTOR=%O724
CONNECT VAXQG0 /ADAPTER=UB0 /DRIVERNAME=UICDRIVER /CSR=%O777102 /VECTOR=%O730
CONNECT VAXQH0 /ADAPTER=UB0 /DRIVERNAME=UICDRIVER /CSR=%O777102 /VECTOR=%O734
EXIT
$ EXIT
At system startup, the arms the chip but does not enable
any of the interrupt levels. A level is enabled and its vector is loaded
into the chip once an I/O operation is started with the
I/O function code (same function code as used by
the VMS Connect-to-Interrupt Driver supplied by Digital). Similarly
once the I/O operation is completed or cancelled, the interrupt level
is disabled on the chip.
The following is a short description of calling the .
Serious users are directed to the description of the VMS Connect-to-Interrupt
driver in the VAX/VMS Device Driver manual.
status = SYS$QIO( [efn], chan, func, [iosb], [astadr], [astprm],
[p1], [p2], [p3], [p4], [p5], [p6])
The standard VMS $QIO system service when used with the
takes the following arguments. Note that there is
a distinction between the completion of the I/O operation and
device interrupts. The $QIO call can be setup to receive
a single interrupt and then have the I/O request complete. A more
normal mode of operation, as used by the QVI_US routines,
is to have multiple device interrupts reported without the I/O
request completing.
efn number of event flag set on completion of the I/O request.
Passed by value.
chan channel number assigned to one of the
devices using the $ASSIGN system service.
Passed by value.
func I/O function code of IO$_CONINTREAD.
Passed by value.
iosb I/O status block set on completion of the I/O request.
Passed by reference.
astadr AST routine called upon completion of the I/O request.
Passed by reference.
astprm parameter for the I/O completion AST.
Passed by value.
p1 this parameter is ignored by the .
Passed by value.
p2 optionally specifies the interrupt level number if the
flag in the p3 argument.
Passed by value.
p3 longword containing flags and an optional event flag
number. This event flag is set on each device interrupt (as distinct
from the efn parameter above).
Passed by value.
p4 AST routine called on each device interrupt (address of
routine's entry mask).
Passed by reference.
p5 AST parameter to be passed to the device interrupt
AST specified in p4.
Passed by value.
p6 number of AST control blocks to preallocate in
anticipation of fast, recurrent interrupts from the device.
Passed by value.
status returns a VMS condition code:
SS$_NORMAL success.
SS$_BADPARAM number of preallocated AST control blocks
in the p6 argument exceeds 65535.
SS$_DISCONNECT a connection is already outstanding for
the device or the driver cannot reallocate AST control blocks quickly
enough.
SS$_EXQUOTA process has exceeded its direct I/O limit
quota or its AST limit quota.
SS$_ILLEFC an illegal event flag number was specified.
SS$_INSFMEM insufficient system dynamic memory is available
to complete the system service.
SS$_UNASEFC the process is not associated with the cluster
containing the specified event flag.
list
[CIN$M_EFN] set event flag on interrupt.
[CIN$M_USECAL] p2 parameter contains the interrupt
level number.
[CIN$M_REPEAT] leave process connected to the interrupt
vector until the connection is canceled and repeatedly report interrupts
for this single I/O operation.
[CIN$M_AST] queue p4 AST routine on interrupt.
[CIN$M_EFNUM] high-order word specifies the number of the
event flag to be set when an interrupt occurs.
KerrMcGee Process
This detached VMS process is planned to monitor the integrity of the
Common Memory and the ``toxic waste'' queue in particular. Currently,
only updates the time-of-year clink value in the
Common Memory global area approximately every 21 minutes to keep
the value in synchrony with the VAX system time.
DeMuxer Process
This detached VMS process has the multiplexed queue as its input queue.
When an entry is made on this queue, is awakened by an
interrupt and proceeds to empty the queue. As each entry is removed,
the originator identifier in the CM block is used to locate the
Queue Demultiplexing Block (QDB, see below) which contains a pointer to the
true destination queue for the CM block. The QDB also identifies the
VMS process associated with this return queue; simulates
an interrupt to this process by using the Declare External Process AST
routine in the Epicure System Services (ESS).
Queue Organization, Queue Headers and Queue Operations
A CM queue is a singly-linked FIFO list. The head pointer is the CM
offset (from the base of Common Memory)
to the first entry on the queue (or 0 if the queue is empty). The
first longword of each queue entry contains the CM offset of the next
entry; the last entry contains a 0 in the link longword (see Section 2.1,
Format of a Common Memory Block). The tail pointer is the CM offset to
the last (tail) entry on the queue (of 0 if the queue is empty).
A CM queue header occupies 8 longwords (32 bytes). The format of a
CM queue header (as seen on the VAX) is:
The fields of the CM queue header are:
list
[cqh_b_lock]
Lock byte. The LCK bit is used to lock the queue
during manipulations (by a on the VAX, a
the 68020 and a on the 80386).
list
[CQH_V_LOCK] Offset to the lock bit in the lock byte.
[cqh_b_flags] Byte of bit flags:
list
[CQH_V_INT]
Offset to the INT bit. This bit is set if an
interrupt is associated with the queue (thus the
cqh_l_intid field contains valid information).
[CQH_V_EXT]
Offset to the EXT bit. This bit indicates whether
the interrupt is an external interrupt (EXT=1) or
an interrupt triggered by touching a VME address
(EXT=0). The EXT bit thus describes the contents
of the cqh_l_intid field.
[CQH_V_WRD] If set, a word instruction to
the specified VME address is used to
generate the associated interrupt.
[CQH_V_DAS] Obsolete.
[cqh_l_headp]
Offset to entry at head of queue.
[cqh_l_tailp]
Offset to entry at tail of queue.
[cqh_w_curcnt]
Count of current queue entries.
[cqh_w_maxcnt]
Count of maximum number of entries on queue since
initialization (or last reset).
[cqh_l_intid]
Interrupt address on VME bus or a bit number for
the external interrupt register (on the QVI board).
This interrupt is associated with this queue to
inform the destination processor of an entry on the
queue.
[cqh_q_name]
Queue name given as 1-8 uppercase ASCII characters, padded
with blanks.
[cqh_l_putcnt]
Unsigned count of the insert operations performed to the queue since
the counter was zeroed (initially zeroed at CM initialization).
/*
As seen by the VAX and the 80386:
*/
struct CQH {
unsigned char cqh_b_lock;
unsigned char cqh_b_flags;
unsigned : 16;
unsigned long cqh_l_headp;
unsigned long cqh_l_tailp;
unsigned short cqh_w_curcnt;
unsigned short cqh_w_maxcnt;
unsigned long cqh_l_intid;
unsigned long cqh_q_name[2];
unsigned long cqh_l_putcnt;
};
/*
As seen by the 68020:
*/
struct CQH {
unsigned : 16;
unsigned char cqh_b_flags;
unsigned char cqh_b_lock;
unsigned long cqh_l_headp;
unsigned long cqh_l_tailp;
unsigned short cqh_w_maxcnt;
unsigned short cqh_w_curcnt;
unsigned long cqh_l_intid;
unsigned long cqh_q_name[2];
unsigned long cqh_l_putcnt;
};
/*
Common to all processors:
*/
#define CQH_V_LOCK 7
#define CQH_M_LOCK 0X80
#define CQH_V_INT 0
#define CQH_M_INT 0X01
#define CQH_V_EXT 1
#define CQH_M_EXT 0X02
#define CQH_V_WRD 6
#define CQH_M_WRD 0X40
The CM queues are manipulated with the following sequence of
operations:
-
The queue reserve lock is set. This is done with a
instruction on the 68020 against the lock byte of the queue
header at offset CQH_B_LOCK. The 80386 uses a
byte instruction with the prefix on that same byte with
the register loaded with (this may
change in the future to a instruction).
The VAX sets the reserve lock
with the instruction (Interlocked Branch on Bit Set
and Set bit) on the bit at offset in the lock
byte at offset . The offsets will be defined so
that the , and
instructions are manipulating the
same bit in the Common Memory.
Before the VAX issues the instruction, the QVI is preset
to stretch the VMEBus cycle since the results in separate
read and write QBus cycles. The QVI preset will keep the VMEBus busy
until the next write operation (the write cycle from the in
this case).
-
The requested queue operation (insert entry at tail or
remove entry from head) is performed by updating all the
affected pointers.
-
The counters (current and maximum number of entries, count of queue
inserts) are updated.
-
The queue reserve lock is cleared by clearing the lock byte
with a Clear Byte instruction.
VAX Structures
This section describes some of the VAX-based data structures
associated with the QVI services. These are internal to the QVI_US
routines (maintained in local own storage) and are explicit arguments to
the QVI_CS routines.
Common Memory Descriptor
A CM descriptor occupies 16 longwords (64 bytes). The CM descriptor
basically describes the QVI and CM global sections as mapped into a process
(each process has its own CM descriptor). The format of a CM descriptor
is:
The fields of the CM descriptor are:
list
[cmd_l_check]
Longword with validation check value. Used to
validate CM descriptor as initialized.
[cmd_a_base]
Pointer to base of the CM global section as mapped
into the process's virtual address space (VAS).
This pointer, like all non-system space virtual
addresses, is valid only for a the current process.
This field also holds the pointer to the base of
the ``roving'' VME window section created by the
QVI_CS_VMEWINDOW service (see below).
[cmd_a_qvi]
Pointer to QVI registers global section as mapped
by this process.
[cmd_a_top]
Address of the top of the CM global section.
[cmd_a_cqhbot]
Pointer to the CM queue header array in the CM
global section. Used to validate queue handles.
[cmd_a_cqhtop]
Pointer to end of the CM queue header array in the
CM global section. Used to validate queue handles.
[cmd_a_baabot]
Pointer to the base of the CM block allocation
areas in the CM global section. Used to validate
block handles.
[cmd_a_baatop]
Pointer to the top of the CM block allocation areas
in the CM global section. Used to validate block
handles.
[cmd_a_itwmr]
Pointer to the QVI map register used for the
``transient'' window by the QVI services. A primary
use of this window will be to trigger interrupts
which require the touching of specific VME
addresses. This window will be moved (at elevated
IPL) to map the VME address to be touched.
[cmd_a_itw]
Pointer to the ``transient'' window address range as
mapped into the virtual address space of the VAX
process. See the above explanation for
cmd_a_itwmr.
[cmd_a_mapreg]
This field overlays cmd_a_cqhbot in the variant
Common Memory descriptor produced by the QVI_CS_VMEWINDOW
routine; a more detailed explanation is given
below. This field stores the pointer to the QVI
map register used by the ``roving'' VME window and is
used by the QVI_CS_VMEMAP routine.
[cmd_l_vwba]
This field overlays cmd_a_cqhbot in the variant
Common Memory descriptor produced by the QVI_CS_VMEWINDOW
routine. This field stores the VME base address of
the QVI window. It is setup by the QVI_CS_VMEMAP
routine and used in the QVI_CS_VMEPOINTER routine.
[cmd_l_exitsts]
This field overlays cmd_a_top in the variant
Common Memory descriptor procedure by the QVI_CS_VMEWINDOW
routine. This field stores the exit status for the
internally-declared exit handler used to release
the lock on the ``roving'' VME window.
[cmd_r_ehblk]
This is the exit handler block passed to the
$DCLEXH system service by the VME_CS_VMEWINDOW
routine to setup the internal exit handler.
struct CMDescriptor { /* Normal format */
unsigned long cmd_l_check;
address cmd_a_base;
struct qvi_r_csrs *cmd_a_qvi;
address cmd_a_top;
struct CQH *cmd_a_cqhbot;
struct CQH *cmd_a_cqhtop;
address cmd_a_baabot;
address cmd_a_baatop;
unsigned short *cmd_a_itwmr;
address cmd_a_itw;
};
struct CMDescriptor { /* VMEWINDOW variant */
unsigned long cmd_l_check;
address cmd_a_base;
struct qvi_r_csrs *cmd_a_qvi;
unsigned long cmd_l_exitsts;
unsigned short *cmd_a_mapreg;
unsigned long cmd_l_vwba;
address cmd_a_baabot;
address cmd_a_baatop;
unsigned short *cmd_a_itwmr;
address cmd_a_itw;
struct {
address ehb_a_link;
unsigned long (*exit_handler)();
unsigned long ehb_l_argcnt;
unsigned long *ehb_a_exitsts;
unsigned long ehb_l_lockid;
} cmd_r_ehblk;
};
The validation check field holds a 32-bit coded integer to describe
the ``state'' of the Common Memory descriptor. The check value permits the Common Memory descriptor
to have two states of partial and complete initialization. The partial
initialization state is setup by the QVI_CS_INIT routine and reflects that
the only valid field of the Common Memory descriptor is the pointer to the QVI
registers. In the complete initialization state, all the Common Memory descriptor
fields are valid. In addition, the validation check can hold a third value
indicating that the Common Memory descriptor is the variant produced by the
QVI_CS_VMEWINDOW routine. In this variant, the only valid fields are the
pointers to the QVI registers and the QVI mapping register used for the
``roving'' VME window, the pointer to the base of (now) the VME window
section in the process's VAS and (after a call to QVI_CS_VMEMAP) the VME
base address field. Some routines (including
QVI_CS_INTERRUPT, QVI_CS_RESETVME and
QVI_CS_STATUS) will accept any valid form of the Common Memory descriptor (either state
or the variant). The QVI_CS_VMEMAP routine will only accept the variant
form and QVI_CS_MAPCM only accepts the partially initialized state. All
other routines require a fully initialized Common Memory descriptor.
Queues Information Block
The Queues Information Block (QIB) contains process-specific
information on Common Memory queues. An internal copy is maintained by the
QVI_US routines and passed in the calling sequences of the QVI_CS_GET and
QVI_CS_PUT routines.
The fields of the Queues Information Block are:
list
[myqh]
Pointer to the CM queue header for the VAX return queue
for this process. Used as the default return queue
by QVI_CS_GET. Used by QVI_CS_PUT to set the
return queue handle in CMBs put onto DAE queues. If the
multiplexed queue is used, then this points to the real return
queue for this specific process (queue without interrupts).
[retqh]
Pointer to actual CM return queue. If the multiplexed return queue is
not used, then this has the same value as myqh, otherwise it
points to the input queue of the process.
[myid]
Longword containing this process's originator
identifier to be placed in CMBs put on DAE queues. If
the multiplexed return queue is being used, then this is a pointer
to the Queue Demux Block (QDB) in the CM for this process.
If a normal return queue is used, then this has the same value
as myqh.
[daeqh]
Pointer to the CM queue header defined as the
default DAE queue. Used by QVI_CS_GET for reCYCLEd
CMBs.
[twqh]
Pointer to the CM queue header defined as the
``toxic waste'' queue. Used by QVI_CS_GET and
QVI_CS_PUT to avoid dropping CM blocks on the floor
and losing them as available resources. This
queue is periodically examined and emptied by a
separate VAX process ().
[fqtable]
Free list queue table of quadword descriptors of
the free queues. Each quadword contains the free
block size and a pointer to the free list queue for
blocks of that size (see the structure, below).
Sorted by block size for
efficient searching.
[dapqtbl]
DAP queue table copied from CM with queue header
offsets converted to handles. Used by the
QVI_US_DAP$LOCATE routine.
struct QIB {
struct CQH *myqh;
unsigned long myid;
struct CQH *daeqh;
struct CQH *twqh;
struct FQL fqtable[QIB_C_MAXFQS];
struct CQH *dapqtbl[QIB_C_MAXDQS];
};
struct FQL {
unsigned long fql_l_size;
struct CQH *fql_a_qhdr;
};
Queue Demultiplexing Block
The Queue Demux Block (QDB) is stored in the Common Memory, but only
used by the MicroVAX. It is used by the process to
redirect CMBs from the input queue
(the multiplexed return queue) to the return queues of the real
destination processes. The format of the QDB is:
list
[qdb_l_pid] Owning process identification.
[qdb_l_astadr] Notification AST address in the destination process.
[qdb_l_rtnqoff] Offset to header of the destination process
return queue in Common Memory.
[qdb_b_flags] Flag bits. Currently only the
bit is defined. If the flag is set, the DeMuxer process
will empty the destination process return queue (to the free lists)
if the destination process does not exist.
struct QDB {
unsigned long qdb_l_pid;
unsigned long qdb_l_astadr;
unsigned long qdb_l_rtnqoff;
unsigned char qdb_b_flags;
};
#define QDB_V_EINXP 0
#define QDB_M_EINXP 1
Keywords: EPICURE, VME, QVI, Common_Memory.
Distribution:
Normal
Security, Privacy, Legal
rwest@fsus04.fnal.gov