149 lines
5.4 KiB
Plaintext
149 lines
5.4 KiB
Plaintext
# $NetBSD: ncr5380.doc,v 1.3 2001/08/20 12:20:07 wiz Exp $
|
|
|
|
MI 5380 driver
|
|
==============
|
|
|
|
(What? Documentation? Is this guy nuts? :-)
|
|
|
|
Reselection
|
|
-----------
|
|
|
|
This driver will permit reselection on non-polled commands if
|
|
sc->sc_flags & NCR5380_PERMIT_RESELECT is 1. This permits enabling of
|
|
reselection on a per-device basis.
|
|
|
|
Disconnect/reselect is never permitted for polled commands.
|
|
|
|
|
|
|
|
Interfacing the driver to MD code
|
|
---------------------------------
|
|
|
|
/sys/dev/ic/ncr5380.c is now stand-alone. DON'T include it after your
|
|
MD stuff!
|
|
|
|
This allows for more than one 5380-based SCSI board in your system. This is
|
|
a real possibility for Amiga generic kernels.
|
|
|
|
Your driver's softc structure must have an instance of struct ncr5380_softc
|
|
as the first thing in the structure. The MD code must initialize the
|
|
following:
|
|
|
|
sci_*: pointers to the 5380 registers. All accesses are done through
|
|
these pointers. This indirection allows the driver to work with
|
|
boards that map the 5380 on even addresses only or do other
|
|
weirdnesses.
|
|
|
|
int (*sc_pio_out)(sc, phase, datalen, data)
|
|
int (*sc_pio_in)(sc, phase, datalen, data)
|
|
These point to functions that do programmed I/O transfers to the bus and
|
|
from the bus, respectively. Arguments:
|
|
|
|
sc points to the softc
|
|
phase the current SCSI bus phase
|
|
datalen length of data to transfer
|
|
data pointer to the buffer
|
|
|
|
Both functions must return the number of bytes successfully transferred.
|
|
A transfer operation must be aborted if the target requests a different
|
|
phase before the transfer completes.
|
|
|
|
If you have no special requirements, you can point these to
|
|
ncr5380_pio_out() and ncr5380_pio_in() respectively. If your board
|
|
can do pseudo-DMA, then you might want to point these to functions
|
|
that use this feature.
|
|
|
|
void (*sc_dma_alloc)(sc)
|
|
This function is called to set up a DMA transfer. You must create and
|
|
return a "DMA handle" in sc->sc_dma_hand which identifies the DMA transfer.
|
|
The driver will pass you your DMA handle in sc->sc_dma_hand for future
|
|
operations. The contents of the DMA handle are immaterial to the MI
|
|
code - the DMA handle is for your bookkeeping only. Usually, you
|
|
create a structure and point to it here.
|
|
|
|
For example, you can record the mapped and unmapped addresses of the
|
|
buffer. The Sun driver places an Am9516 UDC control block in the DMA
|
|
handle.
|
|
|
|
If for some reason you decide not to do DMA for the transfer, make
|
|
sc->sc_dma_hand NULL. This might happen if the proposed transfer is
|
|
misaligned, or in the wrong type of memory, or...
|
|
|
|
void (*sc_dma_start)(sc)
|
|
This function starts the transfer.
|
|
|
|
void (*sc_dma_stop)(sc)
|
|
This function stops a transfer. sc->sc_datalen and sc->sc_dataptr must
|
|
be updated to reflect the portion of the DMA already done.
|
|
|
|
void (*sc_dma_eop)(sc)
|
|
This function is called when the 5380 signals EOP. Either continue
|
|
the DMA or stop the DMA.
|
|
|
|
void (*sc_dma_free)(sc)
|
|
This function frees the current DMA handle.
|
|
|
|
u_char *sc_dataptr;
|
|
int sc_datalen;
|
|
These variables form the active SCSI data pointer. DMA code must start
|
|
DMA at the location given, and update the pointer/length in response to
|
|
DMA operations.
|
|
|
|
u_short sc_dma_flags;
|
|
See ncr5380var.h
|
|
|
|
|
|
|
|
Writing your DMA code
|
|
---------------------
|
|
|
|
DMA on a system with protected or virtual memory is always a problem. Even
|
|
though a disk transfer may be logically contiguous, the physical pages backing
|
|
the transfer may not be. There are two common solutions to this problem:
|
|
|
|
DMA chains: the DMA is broken up into a list of contiguous segments. The first
|
|
segment is submitted to the DMA controller, and when it completes, the second
|
|
segment is submitted, without stopping the 5380. This is what the sc_dma_eop()
|
|
function can do efficiently - if you have a DMA chain, it can quickly load up
|
|
the next link in the chain. The sc_dma_alloc() function builds the chain and
|
|
sc_dma_free() releases any resources you used to build it.
|
|
|
|
DVMA: Direct Virtual Memory Access. In this scheme, DMA requests go through
|
|
the MMU. Although you can't page fault, you can program the MMU to remap
|
|
things so the DMA controller sees contiguous data. In this mode, sc_dma_alloc()
|
|
is used to map the transfer into the address space reserved for DVMA and
|
|
sc_dma_free() is used to unmap it.
|
|
|
|
|
|
Interrupts
|
|
----------
|
|
|
|
ncr5380_sbc_intr() must be called when the 5380 interrupts the host.
|
|
|
|
You must write an interrupt routine pretty much from scratch to check for
|
|
things generated by MD hardware.
|
|
|
|
|
|
Known problems
|
|
--------------
|
|
|
|
I'm getting this out now so that other ports can hack on it and integrate it.
|
|
|
|
The sun3, DMA/Interrupt appears to be working now, but needs testing.
|
|
|
|
Polled commands submitted while non-polled commands are in progress are not
|
|
handled correctly. This can happen if reselection is enabled and a new disk
|
|
is mounted while an I/O is in progress on another disk.
|
|
|
|
The problem is: what to do if you get reselected while doing the selection
|
|
for the polled command? Currently, the driver busy waits for the non-polled
|
|
command to complete, but this is bogus. I need to complete the non-polled
|
|
command in polled mode, then do the polled command.
|
|
|
|
|
|
Timeouts in the driver are EXTREMELY sensitive to the characteristics of the
|
|
local implementation of delay(). The Sun3 version delays for a minimum of 5us.
|
|
However, the driver must assume that delay(1) will delay only 1us. For this
|
|
reason, performance on the Sun3 sucks in some places.
|
|
|