DKSUBR(9) | Kernel Developer's Manual | DKSUBR(9)

# NAME

`dk_softc`, `dk_init`, `dk_attach`, `dk_detach`, `dk_open`, `dk_close`, `dk_size`, `dk_dump`, `dk_ioctl`, `dk_strategy`, `dk_strategy_defer`, `dk_strategy_pending`, `dk_start`, `dk_done`, `dk_drain`, `dk_discard`, `dk_getdefaultlabel`, `dk_getdisklabel` —
disk driver subroutines

# SYNOPSIS

`#include <sys/bufq.h>`
`#include <sys/disk.h>`
`#include <dev/dkvar.h>`

void
`dk_init`(struct dk_softc *, device_t, int dtype);

void
`dk_attach`(struct dk_softc *);

void
`dk_detach`(struct dk_softc *);

int
`dk_open`(struct dk_softc *, dev_t, int flags, int fmt, struct lwp *);

int
`dk_close`(struct dk_softc *, dev_t, int flags, int fmt, struct lwp *);

int
`dk_discard`(struct dk_softc *, dev_t, off_t pos, off_t len);

int
`dk_size`(struct dk_softc *, dev_t);

int
`dk_dump`(struct dk_softc *, dev_t, daddr_t blkno, void *vav, size_t size);

int
`dk_ioctl`(struct dk_softc *, dev_t, u_long cmd, void *data, int flag, struct lwp *);

void
`dk_strategy`(struct dk_softc *, struct buf *);

int
`dk_strategy_defer`(struct dk_softc *, struct buf *);

int
`dk_strategy_pending`(struct dk_softc *);

void
`dk_start`(struct dk_softc *, struct buf *);

void
`dk_done`(struct dk_softc *, struct buf *);

int
`dk_drain`(struct dk_softc *);

void
`dk_getdefaultlabel`(struct dk_softc *, struct disklabel *);

void
`dk_getdisklabel`(struct dk_softc *, dev_t);

# DESCRIPTION

The disk driver subroutines provide common functionality for all disk drivers to reduce the amount of replicated code. For many disk drivers, their corresponding entry points can be made mostly stubs.

The subroutines encapsulate data structures found in a driver's softc into

    struct dk_softc {
    	device_t		sc_dev;
    	struct disk		sc_dkdev;
    	struct bufq_state	sc_bufq;
    	krndsource_t		sc_rnd_source;
    ...
    }

The `dk_softc` structure therefore replaces the `device_t` member of the driver's softc struct.

The following is a brief description of each function in the framework:

`dk_init`()
  Initialize the dk_softc structure.
`dk_attach`()
  Attach framework after driver has attached the disk(9) subsystem, created a bufq(9) and is ready to handle I/O.
`dk_detach`()
  Undo dk_attach.
`dk_open`()
  Handles open steps for the disk(9) framework, acquires the disklabel and validates open parameters. The driver may provide the `d_firstopen` callback to handle initialization steps.
`dk_close`()
  Handles close steps for the disk(9) framework. The driver may provide the `d_lastclose` callback to handle finalization steps. `dk_open` and `dk_close` are serialized by the openlock mutex.
`dk_discard`()
  Validates parameters, computes raw block numbers and passes these to the `d_discard` callback.
`dk_size`()
  Returns dump size information from the disklabel(9) and opens and closes the driver when necessary.
`dk_dump`()
  Validates parameters, computes raw block numbers and iterates over the `d_dumpblocks` callback in appropriate chunks determined by the `d_iosize` callback.
`dk_ioctl`()
  Handles the ioctls `DIOCKLABEL`, `DIOCWLABEL`, `DIOCGDEFLABEL`, `DIOCGSTRATEGY`, and `DIOCSSTRATEGY` and passes other disk ioctls through the disk(9) framework. Returns `ENOTTY` when an ioctl isn't implemented. This routine is run as a fallback to handle commands that are not specific to the driver.
`dk_strategy`()
  Validates parameters, computes raw block numbers, queues a buffer for I/O and triggers queue processing by calling `dk_start`.
`dk_strategy_defer`()
  Alternative to `dk_strategy` that only queues the buffer. Drivers that implement a separate I/O thread can use `dk_strategy_defer` within their own strategy routine and signal the thread through a private interface.
`dk_strategy_pending`()
  This function is called by an I/O thread to determine if work has been queued by `dk_strategy_defer`. The driver must then call `dk_start` to trigger queue processing.
`dk_start`()
  If bp != `NULL` put it into the queue. Run the `d_diskstart` callback for every buffer until the queue is empty or the callback returns `EAGAIN`. In the latter case, the buffer is saved and issued on the next queue run. This also calls `disk_busy` accordingly to handle I/O metrics.
`dk_done`()
  Called by the driver when an I/O operation completed. `dk_done` logs errors, calls `disk_unbusy` to handle I/O metrics and collects entropy for the cprng(9).
`dk_drain`()
  Aborts all queued I/O. This function must be called instead of `bufq_drain`() to cooperate with `dk_start`.
`dk_getdefaultlabel`()
  Compute a common default disklabel for all disk drivers. Some drivers provide device specific information or assign specific disk formats to partitions. Such drivers may implement the `d_label` callback that is called by `dk_getdefaultlabel` after initializing the label with common values.
`dk_getdisklabel`()
  Read disklabel with machine dependent low-level function `readdisklabel` and do sanity checks.

# DRIVER INTERFACE

The driver needs to provide a common set of entry points that are used by the disk driver subroutines and the disk(9) framework.

    struct dkdriver {
            void    (*d_strategy)(struct buf *);
            void    (*d_minphys)(struct buf *);
            int     (*d_open)(dev_t, int, int, struct lwp *);
            int     (*d_close)(dev_t, int, int, struct lwp *);
            int     (*d_diskstart)(device_t, struct buf *);
            void    (*d_iosize)(device_t, int *);
            int     (*d_dumpblocks)(device_t, void *, daddr_t, int);
            int     (*d_lastclose)(device_t);
            int     (*d_discard)(device_t, off_t, off_t);
            int     (*d_firstopen)(device_t, dev_t, int, int);
            void    (*d_label)(device_t, struct disklabel *);
    };

`d_strategy`()
  The driver strategy routine queues a single buffer for I/O and starts queue processing as appropriate.
`d_minphys`()
  The driver minphys routine limits the buffer `b_bcount` to the maximum size for an I/O transfer supported by the driver and hardware. It also calls `minphys` to apply the platform limit.
`d_open`()
  The driver open routine.
`d_close`()
  The driver close routine.
`d_diskstart`()
  Issues a single I/O request, called by `dk_start`.
`d_iosize`()
  Truncate I/O size to the driver limit. This is similar to `minphys` but operates on an integer value instead of a buffer.
`d_dumpblocks`()
  Issue a single I/O requests, called by `dk_dump`.
`d_lastclose`()
  Private cleanup after last user is finished. Often used to flush write caches.
`d_discard`()
  Issue a single I/O request to invalidate a disk region.
`d_firstopen`()
  Private initialization when first user opens the driver.

# SEE ALSO

cgd(4), ld(4), cprng(9), disk(9), driver(9)

# HISTORY

The NetBSD common disk driver subroutines appeared in NetBSD 2.0 as a base for the cryptographic disk driver and was extended to handle disk wedges in NetBSD 4.0. Most functionality provided by ld(4) was included and extended in NetBSD 8.0 to support other disk drivers. The callback interface used by the disk(9) framework has been merged as well.

# BUGS

The framework includes a `dk_lookup` helper function, that is used by the cgd(4) driver to open a vnode for a block device. This looks too generic and should be put somewhere better (and be renamed).

November 28, 2016 | NetBSD 9.3