info-vax@ucbvax.ARPA (10/24/84)
From: engvax!KVC@cit-vax Well folks, it's done. The long-awaited DEUNA document is ready to be sent. I mailed a preliminary article out to INFO-VAX a few weeks ago. The new one contains a lot more detail. I am not sure how to go about distributing it... First of all, the article has already been sent to Larry Kilgallen (the Pageswapper editor). If you can wait, the best thing to do is read it when it comes out there. If you think you need to see it sooner (I do not know what the publication delay is on Pageswapper articles) I can send the article via mail. It is 104 blocks long, though, and I don't think I should send that much to the whole of INFO-VAX. On the other hand, it may be useful if it appeared in the INFO-VAX archives (this stuff does get archived, doesn't it????). Anyone have any ideas? What does the INFO-VAX maintainer think? Should I just see who is interested and send to them? I got a lot of responses to my preliminary article, though, and I expect at least as many to this one. Since my mailer isn't very smart (is anybody's?) I'd have to mail a separate copy to each person anyway, which would put a burden on the friendly people at CIT-VAX who gateway for us... How about this idea: I'll mail the article to someone on the ARPAnet who can put it where other ARPAnauts can FTP it (you cannot get to my system with FTP, only MAIL). If you really think you need the info and cannot FTP, then drop me a line and I'll mail you a special copy. Anyone think that's a problem? Am I making a lot of fuss for 104 blocks? Any volunteers who can put make it available to other FTP's? Oh well, I'll just sit back and see what people think I should do. Maybe Larry'll publish it before I have to decide... :-) By the way, is there anyway he can be reached by e-mail? It'd sure be nice to be able to submit articles electronically. What ever happened to the DECUS VAX? Weren't they gonna put the SIG newsletters on it? /Kevin Carosso engvax!kvc @ CIT-VAX.ARPA Hughes Aircraft Co.
info-vax@ucbvax.ARPA (10/24/84)
From: Richard Garland <OC.GARLAND%CU20B@COLUMBIA.ARPA> Mail-From: OC.GARLAND created at 24-Oct-84 09:26:03 Date: Wed 24 Oct 84 09:26:03-EDT From: Richard Garland <OC.GARLAND@CU20B.ARPA> Subject: Re: DEUNA details... To: engvax!KVC%cit-vax@COLUMBIA.ARPA cc: M_INFOVAX%cit-vax@COLUMBIA.ARPA, OC.GARLAND@CU20B.ARPA In-Reply-To: Message from "engvax!KVC%cit-vax@columbia.arpa" of Tue 23 Oct 84 23:40:52-EDT in re electronic input to DECUS: There is a VAX is Massachusetts on which DECUS folks have accounts for MAIL meeting announcements etc. Anybody from DEC listening? How about DEC creating a gateway from DEC-Marlboro through DEC enet to that machine? At least maybe a mailbox for suggestions. Anyone from DEC listening who knows how to ask about this please do. Rg ------- -------
info-vax@ucbvax.ARPA (10/28/84)
From: William "Chops" Westfield <BILLW@SRI-KL.ARPA>
Using the DEUNA/DEQNA Ethernet Interface Under VMS
Ned Freed, Kevin Carosso and Dan Newman
MATHLIB Project
Harvey Mudd College
Claremont, CA 91711
We recently completed adapting an implementation of TCP/IP originally
written for an Interlan NI1010 ethernet interface to a DEC DEUNA. This
provided us a lot of insight into the way the DEUNA works. (Most of the
insight came as a result of studying the VMS XEDRIVER source code and not
by reading the I/O User's Guide.)
___ ______ _____
This article attempts to summarize what we learned so others will start
with something more than what the I/O User's Guide provides. We also
___ ______ _____
present a program which captures and displays DEUNA performance
statistics.
We assume the reader is somewhat familiar with, but not necessarily an
expert on, the principles of Ethernet operation.
DISCLAIMER: Although the information contained herein is believed to be
correct, the DEUNA and XEDRIVER are very complex and it is quite possible
that our description is incorrect in some areas. We assume no
responsibility for the content of this article.
1.0 The DEQNA versus the DEUNA
The DEQNA is the equivalent of the DEUNA for a Q-bus system. It appears that
the device driver interface for the DEQNA is nearly identical to the DEUNA.
Differences appear to be minor -- we mention the ones we know of where
appropriate. When we refer to the DEUNA or to XEDRIVER, we are also talking
about the DEQNA and XQDRIVER unless a specific statement is made to the
contrary.
2.0 The basics of XEDRIVER
The VMS device driver for the DEUNA is called XEDRIVER. This driver is the
one used by DECnet if it is running over the Ethernet, but DECnet's use of the
device does not preclude additional utilization of the device by other
programs.
XEDRIVER is a very complex and sophisticated piece of software with an amazing
range of capabilities. A large portion of its complexity is devoted to making
it possible for multiple users to utilize the Ethernet simultaneously without
disturbing each other. We wish to take this opportunity to express our
appreciation to Rod Gamache, who wrote the beast.
Page 2
3.0 Using the DEUNA
In order to use the DEUNA via XEDRIVER, 6 basic steps must be performed:
(1) Assign a channel or channels.
(2) Establish device characteristics.
(3) Start up the device.
(4) Perform any desired I/O operations.
(5) Shut down the device.
(6) Deassign the channel(s).
XEDRIVER provides a conventional $QIO interface for user use. (DECnet and the
LAT-11 use their own special direct path into XEDRIVER at the IRP level, but
other users should not use this facility. We will describe only the $QIO
interface.) Regular high level languages whose I/O facilities employ RMS
cannot use the DEUNA directly. First of all, certain set mode $QIO functions
must be performed to establish required operational parameters. Second, $QIO
write functions must be accompanied by a special P5 parameter specifying the
destination address. These additional required parameters cannot be supplied
by RMS.
However, programs to control the DEUNA are not too difficult to write. In the
following sections, we will describe the various details involved in
performing each of the steps listed above. The excessive amount of detail
provided is an attempt to accomodate any conceivable use for the DEUNA and is
not an indication of how complex a simple program to use the device must be.
3.1 Assigning a channel
When a channel is $ASSIGN'ed to the DEUNA (usually the device named "XEA0")
the driver creates a new Unit Control Block (UCB), assigns a channel to it,
and returns this channel to the caller. This new unit is a device in its own
right and has a name of the form XEAn, where n is an ever-increasing integer
greater than 0. If a user needs to $ASSIGN more than one channel to a single
unit, the name of the unit associated with one channel can be determined via
$GETDVI and another channel can be $ASSIGN'ed to the device name $GETDVI
returns.
The unit will remain in existence as long as someone has a channel assigned to
it. When the last channel to a unit is $DASSGN'ed the unit is deleted
automatically.
3.2 Establishing device characteristics
The hardest part of using the DEUNA is setting its operating parameters
properly. This is especially difficult if DECnet is running on the same
device, because certain device characteristics will then be immutable.
A IO$_SETMODE function $QIO with the IO$M_CTRL modifier bit set is used to set
all operational parameters of the DEUNA. The parameter list used by the $QIO
always has the same form -- a sequential list of ordered pairs: (parameter
code, parameter value). Each parameter code is a 16 bit value and has a
Page 3
symbolic name beginning with the prefix "NMA$C_". The parameters can be
specified in any order in the list. Note that not all symbols of this form
defined by the $NMADEF macro are valid DEUNA parameter codes; these symbols
are used to establish characteristics for many different devices besides the
DEUNA.
A descriptor must be created that describes the parameter list and the address
of this descriptor is passed as the P2 parameter in the IO$_SETMODE + IO$_CTRL
$QIO call. P2 is the only parameter that this call uses.
The following sections describe the various DEUNA parameters that can appear
in the list.
3.2.1 The Ethernet physical address (NMA$C_PCLI_PHA)
Every DEUNA on the Ethernet must be assigned a 48 bit physical address. This
address serves to uniquely identify the device. Such addresses are
customarily written as a series of six 8 bit hexadecimal values separated by
dashes, e.g. AA-00-FA-23-3A-20.
Each network packet sent by the DEUNA has a header that specifies the sender's
and receiver's physical addresses. The DEUNA only bothers to receive packets
that are addressed to it; normally all other packets are ignored (see
promiscious mode and multicasting below).
It would not make sense for one user to change the physical address of the
device while someone else is using it. Consequently, when a request to change
the physical address is made XEDRIVER checks to see if there is only one unit
attached to the DEUNA. If so, the physical address can be changed. If not, a
SS$_BADPARM error will be returned. In other words, the physical address can
only be changed by an exclusive user of the device.
If no one specifies a physical address the DEUNA will use its default hardware
address. All DEUNA default addresses fall in the range AA-00-00-00-00-00
through AA-00-04-FF-FF-FF. Specific default addresses are uniquely assigned
to each DEUNA during manufacture.
The physical address parameter value appears in the parameter list as a
counted string of bytes. The count word precedes the string. The first
element in the string must be a modifier word, either NMA$C_LINMC_SET or
NMA$C_LINMC_CLR, which specifies whether the physical address is to be set or
cleared. (The symbols that begin with NMA$C_LINPR described in the I/O User's
___ ______
Guide do not seem to exist.) If NMA$C_LINMC_SET is used the physical address
_____
must appear as the next 6 bytes in the string. When NMA$C_LINMC_CLR is used
the rest of the string is ignored.
A physical address remains in effect until it is explicitly cleared or the
DEUNA goes idle (no one has channels assigned to it), at which point the
physical address will reset unconditionally to the default hardware address.
DECnet insists on setting the physical address to something of the form
AA-00-04-00-xx-04, where xx is the DECnet node number. If some user beats
DECnet to the DEUNA and sets up a different address (or even leaves the
default address active) DECnet will report a circuit error and refuse to use
the device. We recommend that DECnet be allowed to establish contact with the
Page 4
DEUNA prior to attempting any other use so it can establish all the parameter
settings it needs.
If another user has to use the DEUNA prior to DECnet the physical address must
be set to the value DECnet expects. In order to facilitate this, an
additional modifier word for the NMA$C_PCLI_PHA parameter value has been added
in version 4.0 of VMS. This modifier word, NMA$C_LINMC_SDF, sets the physical
address of the DEUNA to the DECnet default address. The address is
constructed by merging the value of the SYSGEN parameter SCSSYSTEMID to the
constant portions of the DECnet address.
3.2.2 Protocol type (NMA$C_PCLI_PTY)
Additional information is required to select who actually gets each received
packet since everyone sharing the same DEUNA uses the same physical address.
This information is provided by a 16 bit value called the protocol type. Each
unit must select its own protocol type, so this must be specified by each unit
prior to starting the DEUNA.
Some protocol types already in use are:
60-00 Loopback functions
60-01 Dump/load functions
60-02 Remote console functions
60-03 DECnet
60-04 LAT (Ethernet terminal server)
60-06 Reserved for customer use by Digital
00-08 TCP/IP (as implemented by 4.2BSD UNIX)
90-00 Cross-company loopback messages
The first three protocol types in the table above are handled specially by the
DEUNA hardware. We only describe the functionality available via this
mechanism briefly; for more information refer to the DEUNA User's Guide
_____ ______ _____
(pages 4-76 to 4-99 and Appendix B).
Packets with loopback function protocol types are received by the DEUNA and
immediately retransmitted somewhere without informing the VAX of their
presence. The first word of the data portion of the packet is used as an
offset (skip count) into the packet indicating where to find a function code.
The function code specifies exactly what loopback operation should be
performed. The possible function codes are:
1 - reply, return packet to sender
2 - forward, send packet on to specified forwarding address
In the returned packet the skip count is incremented by 8 while the protocol
type is still 60-00, so whoever receives the packet sees a possibly different
function code and forwarding address. Packets can be sent through multiple
relay points by choosing an appropriate list of function codes and forwarding
addresses.
The remote console protocol type is used to determine what other DEUNAs, if
any, are present on the network and their characteristics. The second word of
the data portion of the packet is a function code:
Page 5
5 - return this DEUNA's system ID table
6 - boot system request
9 - return this DEUNA's usage counters to sender
The read internal usage counters operation is actually implemented in XEDRIVER
-- it is not a hardware function like the first two.
The dump/load protocol type is used for the loading and starting of remote
hardware over the network for systems such as VAXELN and the LAT-11.
There are no special checks in XEDRIVER to prevent any user from transmitting
messages with these protocol types, so these capabilities can be used by
nonprivileged user programs.
3.2.3 Access to different protocol types (NMA$C_PCLI_ACC)
The first unit to use a given protocol type gets to pick how that protocol
type may be used via this parameter. The possible parameter values are:
Exclusive use = NMA$C_ACC_EXE
This protocol type is reserved for the current user. Anyone else who
tries to use it will get a SS$_BADPARM error. This access mode will be
the default unless this parameter is specified.
Default user = NMA$C_ACC_SHR
Anyone may use this protocol type to transmit packets, but only the
default user (the first one to use this protocol type) gets any received
packets that have this protocol type associated with them.
Shared use = NMA$C_ACC_LIM
Each unit using this protocol type is required to declare a single
physical address they are going to be communicating with (NMA$C_PCLI_DES
parameter). Then they are locked into sending each to that single
destination. When a packet of this protocol type is received, XEDRIVER
figures out who its from and hands it to whoever is communicating with
that particular place. If no one is sending there the packet is
discarded.
The NMA$C_PCLI_DES parameter (see below) is required if NMA$C_ACC_LIM is
used.
Whenever a protocol is shared among units all the parameter settings for each
unit are cross-checked by XEDRIVER to insure the settings are compatible.
Protocol sharing should be used whenever the special protocol types for
loopback, system loading, or remote console functions are used. In these
cases protocol sharing will prevent a single user from locking others out who
need these capabilities as well. DECnet uses its protocol type (60-03) in
exclusive use mode, so nonprivileged users cannot interfere with DECnet
operations via XEDRIVER.
Page 6
3.2.4 Shared protocol destination address (NMA$C_PCLI_DES)
This parameter is used when NMA$C_PCLI_ACC is set to NMA$C_ACC_LIM to specify
the address this unit is going to communicate with. See the NMA$C_PCLI_ACC
parameter above.
3.2.5 Promiscious mode (NMA$C_PCLI_PRM)
Promiscious mode is used to defeat the normal blocking of incoming packets
whose destination addresses do not match the DEUNA's physical address. All
packets regardless of physical address will be received if this mode is active
(NMA$_STATE_ON). The default is promiscious mode off (NMA$_STATE_OFF).
A promiscious mode user receives absolutely every packet that arrives on the
network, including any packets received by other users of the same DEUNA.
XEDRIVER contains special packet duplication code so who needs each packet
gets their own copy.
Promiscious mode also makes it possible to send packets with an arbitrary
protocol type code. The protocol type for each packet transmitted must be
specified in the P5 buffer of each write $QIO.
Only one unit can have promiscious mode activated, so whoever turns it on
first is the only one who can use it. Activating promiscious mode requires
PHY_IO privilege. DECnet does not use promiscious mode.
3.2.6 Echo mode (NMA$C_PCLI_EKO)
The DEUNA has the option of either receiving or ignoring the packets it
transmits itself. If echo (or "half duplex") mode is off the DEUNA ignores
its own transmissions (NMA$C_STATE_OFF). If echo mode is on (NMA$C_STATE_ON)
any packet that is sent will also be eligible for reception. Echo mode is on
by default.
Echo mode is not available on the DEQNA and this parameter cannot be turned
on.
Packets received via echoing are treated in the same manner as packets
obtained from the network -- the destination address and protocol type
determine who, if anyone, gets the echoed packet.
Echoed packet's checksums are not checked by the DEUNA hardware. However,
XEDRIVER recognizes this fact and computes checksums for echoed packets
automatically.
Echo reception is a hardware feature of the DEUNA and thus everyone using the
device must agree on the setting of this parameter. You have to be the
exclusive user of the DEUNA to change the setting of echo mode. DECnet
insists that echo mode be off.
If echo mode is turned on you can do wierd things like activating default user
mode and sending a packet to another user of the device. It is particularly
useful for debugging, when you have no idea of what you are sending to the
Page 7
network and want to receive and check it. DECnet must be shut down in order
to perform such debugging operations.
3.2.7 Internal loopback or controller mode (NMA$C_PCLI_CON)
If internal loopback mode is active the DEUNA's transmitter is looped back to
the receiver and the entire device is isolated from the network. This is very
similar to echo mode except for the enforced isolation from the network.
Loopback mode is a hardware feature of the DEUNA and setting it will prevent
the device from receiving any incoming packets. Consequently, you have to be
the exclusive user of the DEUNA to turn on loopback mode. Loopback mode is
off by default, and DECnet requires that it remain off, of course.
The DEUNA will not respond to any special protocol type function requests
while in internal loopback mode. (Don't confuse internal loopback mode with
the loopback protocol type -- they are NOT the same thing. The former is a
loopback to the local host CPU, while the latter is a loopback to someone else
on the network.)
The I/O User's Guide claims that the symbols NMA$C_LINCN_NOR and
___ ______ _____
NMA$C_LINCN_LOO are used to control loopback mode. These symbols do not
exist. Use NMA$C_STATE_ON for NMA$C_LINCN_NOR and NMA$C_STATE_OFF for
NMA$C_LINCN_LOO. These are the symbols used in XEDRIVER, at least.
Loopback mode should be used when debugging a DEUNA connected to an active
network to prevent any possible interference with that network from buggy
programs.
3.2.8 Multicasting (NMA$C_PCLI_MLT and NMA$C_PCLI_MCA)
Multicasting is a feature whereby the DEUNA can be instructed to receive
messages with addresses other than the current physical address. Any packets
sent to these "multicast" addresses will be received and processed by the
DEUNA.
Multicasting should not be confused with broadcast messages. The DEUNA, and
in fact every other standard Ethernet interface, will always receive messages
addressed to FF-FF-FF-FF-FF-FF (the standard broadcast address) regardless of
the setting of the current physical address.
Note: Physical addresses must have a 0 in the least significant bit of their
first byte, while multicast addresses must have a 1 in this position.
Each unit can enable or disable multicasting independently and set up its own
list of multicast addresses. The lists from all the various units are
combined by XEDRIVER and sent to the DEUNA hardware. Due to hardware
limitations, a total of 10 different addresses can be nominated as multicast
addresses by all the units combined.
There are two parameters that control multicasting. The first,
NMA$C_PCLI_MLT, is used to turn on and off the entire multicasting system.
Multicasting is activated by setting NMA$C_PCLI_MLT to NMA$C_STATE_ON.
Page 8
NMA$C_STATE_OFF is the default.
The NMA$C_PCLI_MCA parameter is used to specify the current list of multicast
addresses. This parameter's value is a counted string of bytes formed in the
same fashion as the NMA$C_PCLI_PHA parameter's value is. The modifier word
must be one of:
NMA$C_LINMC_SET - Add these addresses to the list
NMA$C_LINMC_CLR - Remove these addresses from the list
NMA$C_LINMC_CAL - Clear the entire list unconditionally
The multicasting address list is initially empty.
DECnet enables only a single multicasting address, so 9 slots are left for
users if DECnet is running (as of VMS version 3.5, at least).
3.2.9 Number of receive buffers (NMA$C_PCLI_BFN)
This parameter specifies the number of receive buffers to maintain in system
memory for this unit. Each unit must specify a (possibly different) value for
this parameter.
3.2.10 Size of receive buffers (NMA$C_PCLI_BUS)
The maximum size of user packet buffers on this unit is specified by this
parameter. Each unit may choose its own receive buffer size. The default if
this parameter is left unspecified is 512. The minimum value for this
parameter is 46, the maximum 1500.
Transmit buffers are allocated automatically by XEDRIVER as they are needed
and can be of any size up 1500 bytes. (See the sections on padding and
checksumming below for the true limits on the size of a transmitted packet.)
3.2.11 Data chaining (NMA$C_PCLI_DCH)
Messages may be received by the DEUNA that will not fit into a single receive
buffer. If data chaining is on (NMA$C_STATE_ON) the DEUNA has the option of
splitting a received packet and placing it in two or more receive buffers. If
data chaining is off (NMA$C_STATE_OFF) all packets will be truncated to fit
into a single receive buffer. Data chaining is on by default.
Data chaining is useful in avoiding having excessive buffers when large
numbers of irregularly sized packets are expected. On the other hand, data
chaining could have a tendency to fill too many of the available buffers when
anomalously large packets are received. Since normal buffer sizes are fairly
small (around 512 bytes), data chaining is recommended for almost all
applications.
Each unit can choose whether or not the packets it receives will be eligible
for data chaining.
Page 9
3.2.12 Checksum computation (NMA$C_PCLI_CRC)
Ethernet packets normally have a 32 bit check sequence appended to them to
insure detection of network errors. The check is a CRC code with this
generating polynomial:
G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 +
x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
The entire Ethernet packet, including the destination address, source address,
protocol type field and data is checksummed. The packet is treated as a
binary polynomial M(x) which is divided by G(x) to produce a remainder R(x).
The check sequence is the complement of R(x), with the most significant bit
corresponding to the highest term in R(x).
The receiver runs the entire packet including the checksum, through the same
algorithm, at which time if the packet is valid the checksum register should
contain the value C704DD7D. Receiver checksumming cannot be disabled.
Checksums are also returned at the end of the packet by the IO$_READVBLK $QIO
if there is room for it in the supplied buffer, although the reported length
of the packet does not include the checksum. The checksum is returned so the
user can check to make sure that packets are being properly transferred from
the DEUNA to the VAX. A VAX CRC instruction can be used to check the
checksum. The XEDRIVER source contains a list of the required coefficients
(see CRCTABLE and the routine ASSEM_PKTS).
Computation of checksums on transmitted packets will be disabled if
NMA$C_PCLI_CRC is set to NMA$C_STATE_OFF. In addition, the operation of all
special protocol types like loopback or remote console will be inhibited. The
default for checksumming is initially NMA$C_STATE_ON, or alternately the value
the first user of the DEUNA set it to.
The NMAC_PCLI_CRC parameter is permanently set to NMA$C_STATE_ON on the DEQNA
and cannot be turned off.
The CRC takes up space in outgoing packets so its presence or absence affects
the maximum allowable packet size -- see the description of padding below for
more information.
The CRC is computed in hardware, so the setting of this parameter affects all
users of the DEUNA. Exclusive usage rights are required to change the setting
of this parameter. DECnet requires that CRC checking be active.
3.2.13 Message padding (NMA$C_PCLI_PAD)
The Ethernet specification imposes a minimum length limit on all packets. The
DEUNA can optionally extend all packets to meet this requirement. This
hardware facility is always enabled by XEDRIVER. However, XEDRIVER contains
its own message padding facility that allows the lengths of short packets to
be preserved. It is this facility of XEDRIVER, and not the hardware
capability that is controlled by this parameter.
If NMA$C_PCLI_PAD is disabled (NMA$C_STATE_OFF) all transmitted packets must
be at least 46 bytes long including checksum. Shorter packets will be
Page 10
extended and transmitted, but their lengths will be arbitrarily extended to
the 46 byte minimum by the DEUNA.
Enabling NMA$C_PCLI_PAD (NMA$C_STATE_ON) causes XEDRIVER to take some special
actions. A length word is placed between the header and the data in each
outgoing packet. The packet is then extended, if need be, and transmitted.
Upon reception, the length word is removed and is used in lieu of length
returned by the DEUNA. XEDRIVER padding is on by default.
IMPORTANT: The presence of the length word in a padded packet makes padded
and unpadded packets INCOMPATIBLE. Transmitters and receivers MUST agree on
whether or not to pad their packets or errors will occur. For example, 4.2BSD
TCP/IP does not pad its packets so the default of packet padding must be
changed by VMS TCP/IP.
Since padding adds some overhead to each packet it changes the maximum
allowable size of a packet. The following table shows the maximum size of
packets for the each possible padding and checksumming setting:
padding on, checksumming on = 1494 bytes maximum size
padding off, checksumming on = 1496
padding on, checksumming off = 1498
padding off, checksumming off = 1500
3.2.14 Device buffer size (NMA$C_PCLI_BSZ)
This parameter controls the size of the hardware packet buffer used by the
DEUNA. It affects all users of the device and exclusive access rights are
required to change its value. Under normal conditions it should never be
changed from its default value of 1500. Obviously, DECnet will not approve of
changes to this parameter's value.
3.2.15 Protocol selection mode (NMA$C_PCLI_PRO)
This undocumented parameter is used to select between normal network
operations and point-to-point communications. Specifics on its use are
unavailable at this time.
3.2.16 Hardware buffer quota (NMA$C_PCLI_HBQ)
This undocumented parameter's function is unknown. It is, however, a
write-only parameter and cannot be read back with a IO$_SENSEMODE operation.
3.2.17 Parameter summary
Summing up, there are four basic categories of parameters:
Page 11
(1) Mandatory parameters every unit must specify:
NMA$C_PCLI_PTY, NMA$C_PCLI_BFN
(2) Optional parameters any user can specify:
NMA$C_PCLI_ACC, NMA$C_PCLI_DES, NMA$C_PCLI_BUS, NMA$C_PCLI_PAD,
NMA$C_PCLI_MLT, NMA$C_PCLI_MCA, NMA$C_PCLI_DCH
(3) Optional paramaters at most one user can use:
NMA$C_PCLI_PRM
(4) Optional parameters requiring exclusive usage rights:
NMA$C_PCLI_PHA, NMA$C_PCLI_EKO, NMA$C_PCLI_CON, NMA$C_PCLI_CRC,
NMA$C_PCLI_BSZ
3.3 Starting the DEUNA
A $QIO IO$_SETMODE function with a IO$M_STARTUP modifier is used to start up
the DEUNA. This runs the onboard diagnostics, which take about 6 seconds.
After the diagnostics complete the device is ready for I/O operations. Only
the first user of the device has to wait for the diagnostics to run.
The operations of setting DEUNA parameters and actually starting the device
may be combined in the same $QIO if both the IO$M_CTRL and IO$M_STARTUP
modifiers are used together. Thus, the steps configuring and starting the
device can be combined.
3.4 I/O operations
Normal $QIO read and write operations are used to transfer packets to and from
the DEUNA. The usual IO$_READVBLK and IO$_WRITEVBLK functions should be used.
3.4.1 Write $QIO parameters
The P5 parameter of the IO$_WRITEVBLK $QIO specifies to whom the packet is
being sent; the actual packet data (pointer in P1) contains only data. P2
specifies the length of the data block, all the other parameters are unused.
P5 must point to an 8 byte buffer. The first 6 bytes specify the destination
address for the packet, while the last 2 bytes specify the protocol type. The
protocol type is ignored unless in promiscious mode. If promiscious mode is
active this protocol specification overrides the one specified by the
NMA$C_PCLI_ACC IO$_SETMODE parameter.
The P5 parameter is ignored if a non-exclusive shared protocol type is being
used -- XEDRIVER already knows who to send the message to.
Page 12
3.4.2 Read $QIO parameters
Read $QIO requests require the address of a buffer for the packet in P1 and
the length of that buffer as P2. P5 can optionally point to a 14 byte buffer
that will receive the destination address, the source address and the protocol
type (in that order). The destination address may be either physical or
multicast, the source address is always physical. The protocol type may vary
from that set by NMA$C_PCLI_ACC if promiscious mode is enabled. The P5 buffer
is not needed when communicating with a single other DEUNA on the Ethernet --
you should already know all the information the buffer can provide.
The length of the packet received can only be determined by examining the
transfer size field (the second word) in the I/O status block, so the IOSB is
usually specified in read $QIO requests to the DEUNA.
by examining the
transfer size field (the second word) in the I/O status block, so the IOSB is
usually specified in read $QIO requests to the DEUNA.
3.5 Shutting down the DEUNA
After all I/O operations on the DEUNA are complete the device should be shut
down in order to flush all active buffers and return buffer space to the
system nonpaged memory pool. A IO$_SETMODE $QIO is used with the IO$M_CTRL
and IO$M_SHUTDOWN modifiers to perform this function. Once this is applied to
a unit, the unit cannot be used for additional I/O until another IO$M_STARTUP
function is executed.
3.6 Deassigning the DEUNA
Units attached to the DEUNA will not be dismantled until all channels to them
are released. When this is done (normally via the usual $DASSGN system
service) the unit will be deleted and all the parameter settings and
information associated with it will be destroyed.
4.0 Debugging hints
Debugging code for the DEUNA is usually pretty simple. If error returns from
$QIO requests are encountered the key is to pay close attention to all values
returned in the I/O status block. In particular, when performing IO$_SETMODE
operations (the most error-prone of them all) the code of any offending
parameter will be returned in the second longword of the IOSB. If the
erroneous parameter was in fact specified, the value it was given is illegal.
If the parameter is one that was left unspecified, it is required and must be
specified in order for the $QIO to work.
Any outstanding read requests will abort immediately if the DEUNA is unplugged
from its H4000 transceiver. Most software can avoid problems caused by this
by waiting a bit and then requeueing its read requests.
Page 13
5.0 Sense mode $QIO's
The IO$_SENSEMODE $QIO function can be used to retrieve various sorts of
information about the DEUNA. A function modifier must be included with
IO$_SENSEMODE to specify what information to return.
5.1 Characteristics retrieval
If IO$_SENSEMODE is paired with the IO$M_CTRL modifier the $QIO will return
device characteristics in a 2 longword buffer pointed to by P1 and extended
device characteristics in a block of memory whose descriptor is pointed to by
P2. Both parameters are optional. The returned block will be truncated to
fit within the available space in the P2 buffer. The actual length of the
returned information will be placed in the second word of the I/O status block
if one is specified in the $QIO.
The structure of the P1 buffer is shown in figure 6-4 in the I/O User's Guide.
___ ______ _____
The P2 buffer contains parameters that have the same format as those passed to
a IO$_SETMODE function. However, IO$_SENSEMODE tries to return the ENTIRE
list of all possible parameters in a user-supplied buffer; you don't get to
pick what you want. The parameters are always returned in a specific order
and all that must be done is to make the P2 buffer long enough to get what you
want. (Of course, the order of the parameters may change in future versions
of the driver, so it is best to search the returned list to find the desired
information. See the DEUNA monitor program below for one way of doing this in
Pascal.)
Currently, the order in which the parameters are returned is:
(1) NMA$C_PCLI_ACC - access mode for protocol (a)
(2) NMA$C_PCLI_PRO - protocol selection mode
(3) NMA$C_PCLI_BUS - receive buffer size
(4) NMA$C_PCLI_BFN - number of receive buffers
(5) NMA$C_PCLI_PHA - physical device address (b)
(6) NMA$C_PCLI_PRM - promiscious mode
(7) NMA$C_PCLI_MLT - multicast mode
(8) NMA$C_PCLI_PAD - transmit data padding
(9) NMA$C_PCLI_DCH - data chaining
(10) NMA$C_PCLI_CRC - CRC generated on transmitted packets
(11) NMA$C_PCLI_CON - loopback or controller mode
(12) NMA$C_PCLI_PTY - protocol type
(13) NMA$C_PCLI_MCA - multicast address list (c)
(14) NMA$C_PCLI_EKO - echo mode
(15) NMA$C_PCLI_BSZ - device buffer size
(16) NMA$C_PCLI_HWA - default hardware address (d)
(17) NMA$C_PCLI_DES - shared destination address (e)
Notes:
(a) Unless otherwise noted below, all parameter values are returned as
longwords.
Page 14
(b) The physical device address is returned as a counted string starting
with a length word (always 6) and followed by the 6 byte address. If
no one has explicitly set an address the address returned will be
FF-FF-FF-FF-FF-FF, NOT the default hardware address. The
NMA$C_PCLI_HWA parameter always returns the default hardware address.
(c) The multicast address list is returned as a counted string containing
all the addresses. There is no modifier word in the list.
(d) NMA$C_PLCI_HWA always returns the default hardware address regardless
of what the physical address is set to. It is returned as a counted
string with no modifier word.
(e) NMA$C_PLCI_DES is only returned to the shared-protocol users to whom
it applies (i.e. NMA$C_PCLI_ACC is set to NMA$C_ACC_LIM). It is
returned as a counted string with no modifier word.
See the XEDRIVER source (in particular, the table LINE_PARAM) for more
information on these parameters.
5.2 Usage counters
The IO$_SENSEMODE function also has an undocumented function modifier. The
DEUNA maintains a slew of statistics about what activities it has performed.
These counters may be read using the function modifier IO$M_RD_COUNT along
with IO$M_CTRL. If IO$M_CLR_COUNT is used as well the counters are read and
then zeroed. The counters returned are in the order defined by the hardware
starting with the seconds since the counters were last zeroed. Refer to
figure 4-16 (page 4-31) of the DEUNA User's Guide (NOT the I/O User's Guide)
_____ ______ _____ ___ ______ _____
for a complete list of all the counters. See the program at the end of this
article for a demonstration of how to read the returned parameter block. The
actual structure of the parameter block is similar in form to all the other
DEUNA parameter blocks.
The counters apply to the whole DEUNA and reflect the activities of everyone
using the device, but it seems that any user can read or clear them with
impunity.
6.0 SYSGEN parameter considerations
Due to the potentially large size of Ethernet packets you should watch system
nonpaged pool carefully when using a DEUNA (especially when TWO programs are
using it at the same time). The pool may be exhausted and cause the system to
hang.
A possible cause of SS$_EXQUOTA errors is that the SYSTEM parameter MAXBUF,
which controls the maximum size of an I/O buffer, is set to too small a value.
(The routine EXE$ALLOCBUF allocates such buffers for XEDRIVER and checks this
limit.) The default value for MAXBUF is around 1300 bytes, while the maximum
Ethernet packet size is 1500 bytes.
Page 15
7.0 A DEUNA monitoring program
The following program monitors DEUNA performance by periodically sampling the
internal hardware counters via a $QIO. Both transmission and reception
information is presented in the form of "current" (e.g. bytes
received/second), "average" (e.g. average bytes received/second), "minimum"
and "maximum" (e.g. minimum and maximum bytes received/second) and "counter"
(e.g. present value of the DEUNA's bytes received counter). The result is a
MONITOR-like display of DEUNA activity.
XEA0 is monitored by default. If you want to monitor a different device, just
define a symbol to run the program. The device name to monitor will then be
read off the command line with a LIB$GET_FOREIGN call.
The program begins operations by clearing the terminal screen and drawing its
display. To exit type either control-c or control-z. To repaint the screen,
type contrl-w. The counters will be reset if the "seconds since last reset"
counter exceeds 65530. The counters can be reset manually by typing
control-r.
The program uses the protocol type 61-02, which is not reserved for any
specific purpose. This protocol type can be changed if it conflicts with
anything. The program is written in VAX Pascal V2 and requires no special
privileges.
(* Monitor DEUNA performance statistics.
Written by Dan Newman and Ned Freed, 21-July-84,
MATHLIB Project, Harvey Mudd College *)
[inherit ('SYS$LIBRARY:STARLET.PEN')] Program DEUNA;
Const
NMA$C_PCLI_BFN = %x451; NMA$C_PCLI_PTY = %xB0E; NMA$C_CTLIN_ZER = %x000;
NMA$C_CTLIN_DBR = %x3F2; NMA$C_CTLIN_MBL = %x3F4; NMA$C_CTLIN_RFL = %x426;
NMA$C_CTLIN_BRC = %x3E8; NMA$C_CTLIN_MBY = %x3EA; NMA$C_CTLIN_OVR = %x428;
NMA$C_CTLIN_LBE = %x411; NMA$C_CTLIN_DBS = %x3F3; NMA$C_CTLIN_MBS = %xA8D;
NMA$C_CTLIN_BSM = %x3F7; NMA$C_CTLIN_BS1 = %x3F6; NMA$C_CTLIN_BID = %x3F5;
NMA$C_CTLIN_BSN = %x3E9; NMA$C_CTLIN_MSN = %xA8E; NMA$C_CTLIN_SFL = %x424;
NMA$C_CTLIN_CDC = %x425; NMA$C_CTLIN_UFD = %x427;
Type
UnsignedWord = [Word] 0..65535; $Word = [Word] -32768..32767;
CounterType = array [1..256] of unsigned;
Counters = (BRC, DBR, MBY, MBL, RFL, OVR, LBE, BSN, DBS, MSN, MBS,
BID, SFL, BSM, BS1, CDC, UFD);
StartupType = Record
PCLI_BFN : UnsignedWord; PCLI_BFN_VALUE : unsigned;
PCLI_PTY : UnsignedWord; PCLI_PTY_VALUE : unsigned;
end; (* StartupType *)
StatType = Record
Current, Previous : array [Counters] of unsigned;
Rate, Accumulated, Min, Max : array [Counters] of real;
end; (* StatType *)
Var
DEUNAChannel, TTYChannel : $Word; Count, Flag, Status : integer := 0;
CounterBuffer : CounterType; StartupBuffer : StartupType; Stats : StatType;
CounterDescriptor, IOStatus, StartupDescriptor : array [1..2] of integer;
CurrentTime, LastTime : unsigned; Exit : boolean := false;
DeviceName : varying [20] of char; DeviceNameLength : integer;
Page 16
First : boolean := true; Index : Counters;
Lines : array [Counters] of integer;
LongPointer : ^unsigned; WordPointer : ^UnsignedWord;
[Unbound, External (LIB$GET_FOREIGN)] Function $GetForeign (
var GetStr : varying [l1] of char;
Prompt : [Class_S] packed array [l2..u2 : integer] of char := %Immed 0;
%Ref OutLen, Force : integer := %Immed 0) : integer; extern;
[Unbound, External (LIB$STOP)] Function $STOP (
%Immed Error : integer) : integer; extern;
[Unbound, External (LIB$SET_BUFFER)] Function $SetBuffer (
Buffer : [Class_S] packed array [l1..u1 : integer] of char := %Immed 0;
%Ref OldBuffer : packed array [l2..u2 : integer] of char := %Immed 0)
: integer; extern;
[Unbound, External (LIB$PUT_BUFFER)] Function $PutBuffer (
%Ref OldBuffer : packed array [l1..u1 : integer] of char := %Immed 0)
: integer; extern;
[Unbound, External (LIB$PUT_SCREEN)] Function $PutScreen (
Text : [Class_S] packed array [l1..u1 : integer] of char;
%Ref LineNo, ColNo, Flags : integer) : integer; extern;
[Unbound, External (LIB$ERASE_PAGE)] Function $ErasePage (
%Ref LineNo, ColNo : integer := %Immed 0) : integer; extern;
Function Min (Real1, Real2 : real) : real;
Begin Min := Real1; if Real2 < Real1 then Min := Real2; End;
Function Max (Real1, Real2 : real) : real;
Begin Max := Real1; if Real2 > Real1 then Max := Real2; End; (* Max *)
Procedure IncrementPointers (Inc : integer);
Begin (* IncrementPointers *)
LongPointer::unsigned := LongPointer::unsigned + Inc;
WordPointer::unsigned := WordPointer::unsigned + Inc;
End; (* IncrementPointers *)
Procedure ReadCounterBuffer;
var CurrentCounter : UnsignedWord; i : integer;
Begin (* ReadCounterBuffer *)
WordPointer := nil; LongPointer := nil;
IncrementPointers (Iaddress (Counterbuffer));
while LongPointer::unsigned < Iaddress (Counterbuffer) +
size (Counterbuffer) do begin
CurrentCounter := WordPointer^;
IncrementPointers (2);
i := int (uand (%xFFF, CurrentCounter));
if CurrentCounter = 0 then IncrementPointers (256)
else if i = NMA$C_CTLIN_ZER then CurrentTime := WordPointer^
else if i = NMA$C_CTLIN_DBR then Stats.Current[DBR] := LongPointer^
else if i = NMA$C_CTLIN_MBL then Stats.Current[MBL] := LongPointer^
else if i = NMA$C_CTLIN_RFL then Stats.Current[RFL] := WordPointer^
else if i = NMA$C_CTLIN_BRC then Stats.Current[BRC] := LongPointer^
else if i = NMA$C_CTLIN_MBY then Stats.Current[MBY] := LongPointer^
Page 17
else if i = NMA$C_CTLIN_OVR then Stats.Current[OVR] := WordPointer^
else if i = NMA$C_CTLIN_LBE then Stats.Current[LBE] := WordPointer^
else if i = NMA$C_CTLIN_DBS then Stats.Current[DBS] := LongPointer^
else if i = NMA$C_CTLIN_MBS then Stats.Current[MBS] := LongPointer^
else if i = NMA$C_CTLIN_BSM then Stats.Current[BSM] := LongPointer^
else if i = NMA$C_CTLIN_BS1 then Stats.Current[BS1] := LongPointer^
else if i = NMA$C_CTLIN_BID then Stats.Current[BID] := LongPointer^
else if i = NMA$C_CTLIN_BSN then Stats.Current[BSN] := LongPointer^
else if i = NMA$C_CTLIN_MSN then Stats.Current[MSN] := LongPointer^
else if i = NMA$C_CTLIN_SFL then Stats.Current[SFL] := WordPointer^
else if i = NMA$C_CTLIN_CDC then Stats.Current[CDC] := WordPointer^
else if i = NMA$C_CTLIN_UFD then Stats.Current[UFD] := WordPointer^;
if CurrentCounter > %xCFFF then IncrementPointers (4)
else IncrementPointers (2);
end; (* while *)
End; (* ReadCounterBuffer *)
Procedure PutScreen (Text : packed array [l1..u1 : integer] of char;
LineNo, ColNo, Flags : integer);
var Status : integer;
Begin (* PutScreen *)
Status := $PutScreen (Text, LineNo, ColNo, Flags);
if not odd (Status) then $STOP (Status);
End; (* PutScreen *)
Procedure UpdateLine (Rate, Average, Min, Max : real; Current : unsigned;
LineNo : integer);
var String : varying [9] of char;
Begin (* UpdateLine *)
writev (String, Rate:7:1); PutScreen (String, LineNo, 37, 0);
writev (String, Average:7:1); PutScreen (String, LineNo, 46, 0);
writev (String, Min:7:1); PutScreen (String, LineNo, 55, 0);
writev (String, Max:7:1); PutScreen (String, LineNo, 64, 0);
writev (String, Current:9); PutScreen (String, LineNo, 72, 0);
End; (* UpdateLine *)
Procedure Update;
var
Buffer : packed array [1..1000] of char; String : varying [7] of char;
Date : packed array [1..23] of char; Index : Counters; Status : integer;
Begin (* Update *)
(* Set up the screen buffer *)
Status := $SetBuffer (Buffer); if not odd (Status) then $STOP (Status);
(* Get the date *)
$ASCTIM (,Date);
for Status := 23 downto 13 do Date[Status] := Date[Status-1];
(* Build the Buffer *)
PutScreen (Date, 2, 29, 0);
for Index := BRC to UFD do
UpdateLine (Stats.Rate[Index], Stats.Accumulated[Index]/Count,
Stats.Min[Index], Stats.Max[Index],
Stats.Current[Index], Lines[Index]);
writev (String, CurrentTime:6);
Status := 1; While String[Status] = ' ' do Status := succ (Status);
PutScreen (substr (String, Status, 1+length(String)-Status), 24, 35, 0);
(* Post the buffer to the screen via one $QIO *)
Status := $PutBuffer; if not odd (Status) then $STOP (Status);
Page 18
(* Stop blocking the AST's *)
Status := $SETAST (1); if not odd (Status) then $STOP (Status);
(* See if the "Resetting the Counters" flag needs to be removed *)
if Flag = 2 then begin
Flag := 0; PutScreen (' ', 1, 59, 0);
PutScreen (' ', 24, 35, 0);
end; (* if Flag *)
if Flag = 1 then Flag := succ (Flag);
End; (* Update *)
Procedure Paint;
var Buffer : packed array [1..900] of char; Status : integer;
Begin (* Paint *)
(* Set up the Screen buffer *)
Status := $SetBuffer (Buffer); if not odd (Status) then $STOP (Status);
(* Erase the page *)
$ErasePage (1,1);
(* Put up the headers *)
PutScreen ('DEUNA Performance Statistics', 1, 26, 1);
PutScreen ('Device', 4, 1, 0); PutScreen (DeviceName, 4, 8, 0);
PutScreen ('Current', 4, 37, 8); PutScreen ('Average', 4, 46, 8);
PutScreen ('Minimum', 4, 55, 8); PutScreen ('Maximum', 4, 64, 8);
PutScreen ('Counter', 4, 74, 8); PutScreen ('Received:', 5, 1, 0);
PutScreen ('Bytes', 6, 3, 0); PutScreen ('Packets', 7, 3, 0);
PutScreen ('Multicast Bytes', 8, 3, 0);
PutScreen ('Multicast Packets', 9, 3, 0);
PutScreen ('Packets in Error', 10, 3, 0);
PutScreen ('Lost - Internal Buffer Errors', 11, 3, 0);
PutScreen ('Lost - Local Buffer Errors', 12, 3, 0);
PutScreen ('Transmitted:', 13, 1, 0); PutScreen ('Bytes', 14, 3, 0);
PutScreen ('Packets', 15, 3, 0); PutScreen ('Multicast Bytes', 16, 3, 0);
PutScreen ('Multicast Packets', 17, 3, 0);
PutScreen ('Packets Deferred', 18, 3, 0);
PutScreen ('Packets Aborted', 19, 3, 0);
PutScreen ('Packets with Several Errors', 20, 3, 0);
PutScreen ('Packets with 1 Error', 21, 3, 0);
PutScreen ('Collision Check Failures', 22, 3, 0);
PutScreen ('Unrecognized Frame Destinations', 23, 1, 0);
PutScreen ('Seconds Since Last Counter Reset:', 24, 1, 0);
(* Now put the info to the screen in one $QIO *)
Status := $PutBuffer; if not odd (Status) then $STOP (Status);
End; (* Paint *)
Procedure ResetDEUNA;
var Status : integer;
Begin (* ResetDEUNA *)
Flag := 1; PutScreen ('Resetting the Counters' + chr (7), 1, 59, 3);
Status := $QIOW (Chan := DEUNAChannel, Iosb := IOStatus,
Func := IO$_SENSEMODE + IO$M_CTRL + IO$M_CLR_COUNT +
IO$M_RD_COUNT, P2 := IAddress (CounterDescriptor));
if not odd (Status) then $STOP (Status);
if not odd (IOStatus[1]) then $STOP (IOStatus[1]);
ReadCounterBuffer;
for Index := BRC to UFD do Stats.Previous[Index] := Stats.Current[Index];
LastTime := CurrentTime; PutScreen (' ', 24, 34, 0);
End; (* ResetDEUNA *)
Page 19
Procedure EnableAST; forward;
Procedure AST (var Character : char);
var Status : integer;
Begin (* AST *)
(* Kill any other I/O requests on this channel *)
Status := $CANCEL (TTYChannel); if not odd (Status) then $STOP (Status);
case IAddress (Character) of
(* ^C and ^Z -- Exit gracefully *)
03, 26 : begin
(* Shut the DEUNA down *)
RetStatus := $CANCEL (DEUNAChannel);
if not odd (RetStatus) then $STOP (RetStatus);
RetStatus := $QIOW (Chan := DEUNAChannel, Iosb := IOStatus,
Func := IO$_SETMODE + IO$M_CTRL + IO$M_SHUTDOWN);
if not odd (RetStatus) then $STOP (RetStatus);
RetStatus := $DASSGN (DEUNAChannel);
if not odd (RetStatus) then $STOP (RetStatus);
Exit := true; end;
(* ^R -- Reset the DEUNA *)
18 : ResetDEUNA;
(* ^W -- Repaint the screen *)
23 : begin Paint; Update; end;
end; (* case *)
(* Reset the AST *)
EnableAST;
End; (* AST *)
Procedure EnableAST;
var Mask : array [1..2] of integer; Status : integer;
Begin (* EnableAST *)
(* Out-of-band AST Mask -- Trap ^C, ^R, ^W and ^Z*)
Mask[1] := 0; Mask[2] := (2**3) + (2**18) + (2**23) + (2**26);
(* Queue the out-of-band AST *)
Status := $QIOW (Chan := TTYChannel, Func := IO$_SETMODE + IO$M_OUTBAND,
P1 := %Immed AST, P2 := IAddress (Mask));
if not odd (Status) then $STOP (Status);
End; (* EnableAST *)
Begin (* DEUNA *)
(* These numbers represent which lines on the screen to place the data on *)
Lines[BRC] := 6; Lines[DBR] := 7; Lines[MBY] := 8; Lines[MBL] := 9;
Lines[RFL] := 10; Lines[OVR] := 11; Lines[LBE] := 12; Lines[BSN] := 14;
Lines[DBS] := 15; Lines[MSN] := 16; Lines[MBS] := 17; Lines[BID] := 18;
Lines[SFL] := 19; Lines[BSM] := 20; Lines[BS1] := 21; Lines[CDC] := 22;
Lines[UFD] := 23;
(* Setup the information to initialize the DEUNA *)
with StartupBuffer do begin
PCLI_BFN := NMA$C_PCLI_BFN; PCLI_BFN_VALUE := 1;
PCLI_PTY := NMA$C_PCLI_PTY;
PCLI_PTY_VALUE := %x0261; (* some unused protocol here *)
end; (* with *)
(* Build the descriptors for the $QIO calls *)
CounterDescriptor[1] := size (CounterBuffer);
CounterDescriptor[2] := IAddress (CounterBuffer);
StartupDescriptor[1] := size (StartupBuffer);
StartupDescriptor[2] := IAddress (StartupBuffer);
Page 20
(* Get a Channel to the terminal *)
Status := $ASSIGN ('TT:', TTYChannel);
if not odd (Status) then $STOP (Status);
(* Get a Channel to the DEUNA *)
Status := $GetForeign (DeviceName, , DeviceNameLength);
if not odd (Status) then $STOP (Status);
if DeviceNameLength = 0 then DeviceName := 'XEA0';
Status := $ASSIGN (DeviceName, DEUNAChannel);
if not odd (Status) then $STOP (Status);
(* Set up the ^C, ^R, ^W and ^Z traps *)
EnableAST;
(* Initialize the DEUNA *)
Status := $QIOW (Chan := DEUNAChannel, Iosb := IOStatus,
Func := IO$_SETMODE + IO$M_STARTUP + IO$M_CTRL,
P2 := IAddress (StartupDescriptor));
if not odd (Status) then $STOP (Status);
if not odd (IOStatus[1]) then $STOP (IOStatus[1]);
(* Start our loop *)
Repeat
(* Read the DEUNA counters *)
Status := $QIOW (Chan := DEUNAChannel, Iosb := IOStatus,
Func := IO$_SENSEMODE + IO$M_RD_COUNT + IO$M_CTRL,
P2 := IAddress (CounterDescriptor));
if not odd (Status) then $STOP (Status);
if not odd (IOStatus[1]) then $STOP (IOStatus[1]);
(* Dissect the returned information *)
ReadCounterBuffer;
(* Now generate the statisitics *)
if CurrentTime > 65530 then ResetDEUNA else begin
if LastTime <> CurrentTime then begin
if First then begin
for Index := BRC to UFD do begin
Stats.Previous[Index] := Stats.Current[Index];
Stats.Accumulated[Index] := 0;
Stats.Min[Index] := maxint; Stats.Max[Index] := -1;
end; (* for *)
end else begin
Count := succ (Count);
for Index := BRC to UFD do begin
Stats.Rate[Index] := (Stats.Current[Index] -
Stats.Previous[Index]) / (CurrentTime - LastTime);
Stats.Accumulated[Index] := Stats.Accumulated[Index] +
Stats.Rate[Index];
Stats.Min[Index] := Min (Stats.Min[Index], Stats.Rate[Index]);
Stats.Max[Index] := Max (Stats.Max[Index], Stats.Rate[Index]);
Stats.Previous[Index] := Stats.Current[Index];
end; (* for *)
end; (* if First *)
(* Display the information on the terminal *)
if First then begin
First := false; Paint;
end else Update;
if Exit then begin
$ErasePage (1,1); $EXIT (1);
end; (* if Exit *)
end; (* if LastTime <> CurrentTime *)
LastTime := CurrentTime;
Page 21
end; (* if CurrentTime > 65530 *)
until 1 = 2;
End. (* DEUNA *)
-------