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