DRDRV.TXT

DRDRV is a DR11-K software driver.  It is in use at our location with a
single DR11 jumpered for input direct from the control lines and interrupts
on negative transitions on input bit 15.  Our implementation uses it as
a loadable driver.  Although it seems to work on our system and configuration,
it has not been tested with any other configuration.  It probably would
handle a DR11-C with minor modifications.  This driver runs under RSX11M V3.1.
Future releases, 11-D, IAS....???

DRDRV is a read-only driver at this time.  It only supports the following
functions (with sub-functions defined below):
	1) IO.KIL  --  cancel I/O
	2) IO.ATT  --  attach device
	3) IO.DET  --  detach device
	4) IO.RLB  --  read logical block (reads one word at a time)

Normally, these four functions operate exactly as expected (IO.RLB requires
the Exec module $PTWRD which is a sysgen option).

The primary feature of DRDRV is that it was designed to handle high-speed
interrupts without losing data during executive and task level queueing and
dequeueing of I/O requests.  In order to do this, the driver will, under
QIO control, dynamically allocate a ring buffer from the system dynamic
storage area (pool), and use this space for stacking unsolicited input.
The buffer is allocated when the device is attached with the function code
IO.ATT or'ed with the subfunction DR.ATB (this buffer has, consequently,
been nicknamed the ATB buffer).  The first parameter in the DPB parameter
block of such a QIO request must contain the buffer size to allocate, in
multiples of 4 bytes.  In reality, an extra 4 bytes are tacked on to hold
the queue/dequeue ptrs.  The detach function (IO.DET), which is implicitly
called on task exit (I/O rundown), deallocates the pool buffer and releases
it to the Executive.  Two mechanisms exist for preventing depletion of pool
by accident:  1) there is an arbitrary maximum ATB size limit defined at
assembly-time  (see ATBLIM and SIZMSK in DRPRE.MAC)  and  2) there is a
dynamic ATB size limit which can be modified by the command  SET /BUF=DR:###.
This dynamic limit is stored in UCB offset U.CW4, which is the DEC standard
"buffer size" storage word.  The initial value is defined by  DEFMAX in
DRPRE.MAC. When a request to attach an ATB buffer is received, the driver
performs the following checks:  (atbsize refers to requested allocation)
	0) Is device already attached?              ... yes--error IE.DAA
	1) Is atbsize =< 0 ?                        ... yes--error IE.SPC
	2) Is atbsize a multiple of 4 ?             ...  no--error IE.SPC
	3) Is atbsize > SET /BUF=DR: size (U.CW4) ? ... yes--error IE.SPC
	4) Is atbsize > maximum size (ATBLIM) ?     ... yes--error IE.SPC
	5) Can Exec allocate atbsize+4 bytes?       ...  no--error IE.NDR

Once the ATB buffer is attached, input interrupts are enabled and the data
from each interrupt is queued onto the ring buffer.  If there are no
current I/O requests, or if a FORK is currently executing, or waiting to
execute, a new FORK routine is NOT queued....this eliminates pool depletion
from too many FORK blocks.  If there is a current read request, each pass
through the FORK routine empties the ring buffer completely.

There are three flavors of read requests (IO.RLB):
	1) IO.RLB -- with no ATB buffer attached.
		     This functions like a normal read logical block request.
		     Interrupts are enabled only for the duration of the
		     input request and inter-request data is lost.
	2) IO.RLB -- with ATB buffer attached.
		     Since interrupts have been enabled ever since the ATB
		     buffer was attached, the buffer is presumably full or
		     overflowing.  This function causes the buffer to be
		     emptied first, then the request is satisfied.  If the
		     ATB buffer overflows again during the course of the
		     request, the interrupt rate is too high and/or the ATB
		     buffer is too small.
	3) IO.RLB!DR.RIB -- Read Input Buffer
		     This is the same as IO.RLB with an ATB buffer attached,
		     except that the buffer is not cleared before the request
		     is satisfied.  If the ATB buffer overflowed before the
		     request  was dequeued, or during the course of satisfying
		     the request, the error  IE.DAO  is returned, and the 2nd
		     I/O status word contains the number of words transferred
		     before the overflow.

A typical sequence of events for an input sweep would then be:
	1) IO.ATT!DR.ATB -- attach ATB buffer
	2) IO.RLB        -- flush the buffer and start the read request
	3) IO.RLB!DR.RIB -- continue the read request without losing data
	4) if IE.DAO (DAta Overrun), try increasing the ATB
	5) go to 3 until done

An even more elegant routine might keep two I/O requests queued and use
ASTs to handle completion.  This would shorten the time between active
I/O requests and allow a smaller ATB buffer to do the same job.

NOTES:
	1) All error returns are in the low order byte of the first I/O
	   status word.  This is just like DEC drivers.  Thus, the line:
		MOV   IOSTAT,R0
		BMI   ERROR
	   would not work, but:
		MOVB  IOSTAT,R0
		BMI   ERROR
	   would, and the sign bit will have propagated through R0.
	2) I don't know about the DR11-C, but the DR11-K has some crummy
	   design "features" which you might not know about:
		a) The input buffer bits (0-11) are set only on a negative
		   transition and cleared only when a 1 is written to them.
		   However, if your data line goes low and stays low thru
		   many interrupts, the bit will not be set for more than
		   the first interrupt!!
		b) Since the input bits are gated, interrupting on input
		   lines seems to work ok.  That is, an interrupt comes,
		   the Interrupt Enable is cleared, you service it and
		   enable interrupts, and then you wait for the next one.
		   However, the External Data Ready interrupt control
		   line is not gated.  In fact, it is directly ANDed with
		   Interrupt Enable and the result clocks the interrupt
		   request logic.  Therefore, the interrupt line goes low,
		   Interrupt Enable is cleared, you service it, you set
		   Interrupt Enable, and (bango!) if you're quick enough
		   and External Data Ready is still low, you get another
		   interrupt a few microseconds later! (cute, huh?)


If you have any trouble, or if you implement WRITE functions, feel free to
call me.  I would actually appreciate hearing from anyone who uses this
driver because, if anyone's interested, i will continue to submit updates
and support suubroutines to the DECUS tapes.  I am currently working on
a set of FORTRAN callable routines which look similar to the K-Series
Peripheral garbage that DEC gives out. (This driver was the result of
that stuff, in a sense, because the K-Series routines require that the
user be privileged, and a Common Region is mapped over the I/O Page, which
is clearly unacceptable in a multi-user environment).

Daniel Steinberg     April 5, 1979
@SRI International
loc K1023
333 Ravenswood
Menlo Park, CA
94025
(415) 326-6200  ext.5539