[comp.unix.wizards] VAX uba{alloc,relese,setup,go,done} routines

ehrlich@psuvax1.UUCP (Dan Ehrlich) (07/22/87)

Could someone please explain to me the proper sequence in which these
routines should be used?  

I am trying to write a device driver for a DR11-W running in "link"
mode.  All I have to do is send and recieve blocks of bytes to the
device at the other end.

Unfourtunately the UNIBUS magic is much to black for me to be able
to figure out what is supposed to happen.  Any help or hints would
be appreciated.  Thanks in advance.

--Dan Ehrlich
-- 
--Dan Ehrlich <ehrlich@psuvax1.{psu.edu,bitnet,uucp}>
The Pennsylvania State University, Computer Science Department
333 Whitmore Laboratory, University Park, PA   16802
+1 814 863 1142

chris@mimsy.UUCP (Chris Torek) (07/24/87)

In article <2617@psuvax1.UUCP> ehrlich@psuvax1.UUCP (Dan Ehrlich) writes:
>Could someone please explain to me the proper sequence in which these
>routines should be used?  

Here is a short summary of these routines.  Note that I speak only
for 4.[23]BSD, and for that matter, that I have never even read a
Unibus manual.  I have been forced to learn how the hardware works
by reading software.  (E.g., I still do not know exactly what a
buffered data path *does* and when one must be used.)


	int
	uballoc(ubanum, addr, bytecount, flags)
		int ubanum;
		caddr_t addr;
		int bytecount, flags;

This is the same as ubasetup(), except that it takes a kernel space
address and a bytecount instead of a `struct buf *'.


	int
	ubasetup(ubanum, bp, flags)
		int ubanum;
		struct buf *bp;
		int flags;

This allocates some Unibus memory space and makes it equivalent to
the address and byte count specified by the `struct buf *' parameter.
In other words, Unibus devices can now get at the Vax memory region
associated with this buffer.  (The region can be in user space,
unlike uballoc.  This detail is usually uninteresting within the
driver itself.)

The return value from ubasetup is either zero (temporary failure
because there were insufficient Unibus resources) or a packed
representation in which the lower 18 bits represent a Unibus address
(hence the `& 0x3ffff' or `& 0777777' in the drivers).  The 4.3BSD
header file ubavar.h has macros to break this up:

	UBAI_BDP(i)	buffered data path register (zero means none)
	UBAI_NMR(i)	number of map registers
	UBAI_MR(i)	map register index
	UBAI_BOFF(i)	byte offset
	UBAI_ADDR(i)	Unibus address (i & 0x3ffff)

The flags parameter is made up from the following:

    UBA_NEEDBDP
	The transfer needs a buffered data path.

    UBA_CANTWAIT
	The caller must not be blocked, i.e., is running at interrupt
	level, or for some other reason is not running in the context of
	the process that made the I/O request.

    UBA_NEED16
	The device needs a 16 bit Unibus address (that is, the upper
	two bits of the 18 bit Unibus address must be zero).

    UBA_HAVEBDP
	The caller already has a BDP.  This flag is mutually exclusive
	with UBA_NEEDBDP.  The BDP number must be given in the upper
	four bits of the flags parameter (flags |= bdp << 28).  (Return
	values from uballoc or ubasetup are suitable after masking:
	ubasetup(uban, bp, (bdpstuff & 0xf0000000) | UBA_HAVEBDP).)

Note that the return value from ubasetup() or uballoc() will never
be zero unless the caller says not to wait.  (There is an exception:
At present, UBA_NEED16 implies UBA_CANTWAIT, since to do otherwise
would take extra code, and the routines that NEED16 already CANTWAIT
anyway.)


	ubarelse(ubanum, info)
		int ubanum;
		int *info;

This releases the resources that were allocated with uballoc() or
ubasetup().  The caller must pass the address of the place it stored
the return value from uballoc() or ubasetup() because of Unibus
resets (below).


	ubago(ui)
		struct uba_device *ui;

This routine is for devices that sit on controllers, e.g., disk
drives.  In some cases it may be more convenient in a driver to
pretend the existence of some controller, so as to be able to use
this routine.  For instance, TS11 tapes (and lookalikes) come one
to a package: no one sells a single controller that runs multiple
tape drives.  (You can buy two-drive TS11 controllers, but they
look like two controllers to the hardware, and hence to the O/S.)

Ubago() allocates resources for the transfer given by
ui->ui_mi->um_tab.b_actf->b_actf, which must be the first transfer
for the current drive on this controller.  If there are no resources
available, ubago() returns 0 after placing the `ui' pointer on
queue for this Unibus, arranging for the work to be done later.
If the work can be done immediately, ubago() returns 1 after doing
it.  The work itself is done by the device driver's `dgo' routine,
called (either now or later) as (*ui->ui_driver->ud_dgo)(ui->ui_mi).
(This particular interface works for most controllers, which can
only execute one read or write transfer at a time.  For UDA50
controllers it is insufficient, and I have changed it, but in a
backwards compatible way.)


	ubadone(um)
		struct uba_ctlr *um;

This routine works with ubago() to release the resources allocated
by ubago(), and to release the Unibus itself in case the controller
is marked as a `bus hog' (RK07s).  Ubadone() should be called from
the controller transfer-done interrupt handler.


	Unibus resets.

Every driver must be prepared to handle a Unibus reset.  Whenever
a particular Unibus adapter is reset, that automatically cancels
any transfers that are in progress and throws away any allocated
resources.  A typical device-only reset handler will set some
variable to zero:

		xxx->xxx_info = 0;

where `xxx_info' is used to store the return value from uballoc or
ubasetup.  A controller-plus-devices driver will use

		um->um_ubinfo = 0;

Some drivers own multiple bits of Unibus memory space; these need
to zap more variables, or otherwise remember that they have lost
those spaces:

		sc->sc_flags &= ~SC_MAPPED;

The device registers themselves, though, sit in Unibus I/O space,
which always stays mapped.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris