|
|
#include <sys/buf.h>void dma_breakup(int *xxstrategy ( struct buf *bp), struct buf *bp);
buf
structure.
b_flags
b_flags
is ORed with B_ERROR and B_DONE, and
b_error
is set to EAGAIN
b_error
b_flags
b_error
is
set to 0 (zero) if end of media occurs
in transfer of second and subsequent blocks
b_un.b_addr
b_blkno
b_bcount
u.u_segflg
u.u_base
u.u_count
u.u_offset
dma_breakup first determines the correct block number of the data being passed.
If a read is being requested, the strategy(D2oddi) entry point is called to get a buffer header. If a buffer header is not available, dma_breakup( ) blocks sleep until one is free. While blocked, the request for a buffer is protected from signals and from interrupts occurring at or below spl6(D3oddi). When a buffer is free, data is read from user space.
A write request is similar, except that the data is copied to a kernel page from user space before the strategy( ) routine is called. Again, the driver blocks while waiting for a free buffer header.
After ensuring that a buffer header is free,
DMA transfer starts.
If an error is caused by reaching the end of the media during
the first block transfer,
ENXIO is set in bp->b_error
when
dma_breakup returns.
An end of media fault, on second and subsequent blocks,
causes ENXIO to be cleared from b_error
,
the number of blocks remaining to be transferred
to be put in b_resid
,
and B_ERROR to be set in bp->b_flags
.
During DMA transfer,
strategy( )
is called to put the current buffer on the buffering mechanism.
Each time
xxstrategy( )
is called, sleep is also
called to wait until buffering occurs.
dma_breakup depends on the following fields of the user structure that are set up by the kernel when the I/O request is passed to the driver:
u.u_base
u.u_count
u.u_offset
b_flags
to indicate the type of transfer.
Possible values are B_READ or B_WRITE.
Use splx(D3oddi) to save your spl setting before calling dma_breakup because dma_breakup calls spl0(D3oddi) and cancels all previously set spl levels.