Writing Device Drivers

buf(9S) Handling

These interfaces manipulate the buf(9S) data structure. It is used to encode block I/O transfer requests, but some character drivers also use buf(9S) to encode character I/O requests with physio(9F). Drivers that use buf(9S) as their primary means of encoding I/O requests have to implement a strategy(9E) routine. For more information, see Chapter 9, Drivers for Character Devices and Chapter 10, Drivers for Block Devices.

void biodone(struct buf *bp);

biodone(9F) marks the I/O described by the buf(9S) structure pointed to by bp as complete by setting the B_DONE flag in bp->b_flags. biodone(9F) then notifies any threads waiting in biowait(9F) for this buffer. Call biodone(9F) on bp when the I/O request it encodes is finished.

void bioerror(struct buf *bp, int error);

bioerror(9F) marks the error bits in the I/O described by the buf(9S) structure pointed to by bp with error.

void bioreset(struct buf *bp);

Use bioreset(9F) reset the buf(9S) structure pointed to by bp, allowing a device driver to reuse privately allocated buffers. bioreset(9F) resets the buffer header to its initially allocated state.

int biowait(struct buf *bp);

biowait(9F) suspends the calling thread until the I/O request described by bp is completed. A call to biodone(9F) unblocks the waiting thread. Usually, if a driver does synchronous I/O, it calls biowait(9F) in its strategy(9E) routine, and calls biodone(9F) in its interrupt handler when the request is complete.

biowait(9F) is usually not called by the driver; instead it is called by physio(9F), or by the file system after calling strategy(9E). The driver is responsible for calling biodone(9F) when the I/O request is completed.

void bp_mapin(struct buf *bp);

bp_mapin(9F) maps the data buffer associated with the buf(9S) structure pointed to by bp into the kernel virtual address space so that the driver can access it. Programmed I/O device drivers often use bp_mapin(9F) because they have to transfer data explicitly between the buf(9S) structure's buffer and a device buffer. See "bp_mapin(9F)" for more information.

void bp_mapout(struct buf *bp);

bp_mapout(9F) unmaps the data buffer associated with the buf(9S) structure pointed to by bp. The buffer must have been mapped previously by bp_mapin(9F). bp_mapout(9F) can only be called from user or kernel context.

void clrbuf(struct buf *bp);

clrbuf(9F) zeroes bp->b_bcount bytes starting at bp->b_un.b_addr.

void disksort(struct diskhd *dp, struct buf *bp);

disksort(9F) implements a queueing strategy for block I/O requests to block-oriented devices. dp is a pointer to a diskhd structure that represents the head of the request queue for the disk. disksort(9F) sorts bp into this queue in ascending order of cylinder number. The cylinder number is stored in the b_resid field of the buf(9S) structure. This strategy minimizes seek time for some disks.

void freerbuf(struct buf *bp);

freerbuf(9F) frees the buf(9S) structure pointed to by bp. The structure must have been allocated previously by getrbuf(9F).

int geterror(struct buf *bp);

geterror(9F) returns the error code stored in bp if the B_ERROR flag is set in bp->b_flags. It returns zero if no error occurred.

struct buf *getrbuf(int sleepflag);

getrbuf(9F) allocates a buf(9S) structure and returns a pointer to it. sleepflag should be either KM_SLEEP or KM_NOSLEEP, depending on whether getrbuf(9F) should wait for a buf(9S) structure to become available if one cannot be allocated immediately.

int physio(int (*strat)(struct buf *), struct buf *bp, 
			dev_t dev, int rw, void (*mincnt)(struct buf *), struct uio *uio);

physio(9F) translates a read or write I/O request encoded in a uio(9S) structure into a buf(9S) I/O request. strat is a pointer to a strategy(9E) routine that physio(9F) calls to handle the I/O request. If bp is NULL, physio(9F) allocates a private buf(9S) structure.

Before calling strategy(9E), physio(9F) locks down the memory referred to by the buf(9S) structure (initialized from the uio(9S) structure). For this reason, many drivers that do DMA must use physio(9F), as it is the only way to lock down memory.

In most block device drivers, read(9E) and write(9E) handle raw I/O requests, and consist of little more than a call to physio(9F).

void minphys(struct buf *bp);

minphys(9F) can be passed as the mincnt argument to physio(9F). This causes physio(9F) to make I/O requests to the strategy routine that are no larger than the system default maximum data transfer size. If the original uio(9S) I/O request is to transfer a greater amount of data than )minphys(9F) allows, physio(9F) calls strategy(9E) repeatedly.