File:  [NetBSD Developer Wiki] / wikisrc / users / mlelstv / disk-driver-template.mdwn
Revision 1.3: download - view: text, annotated - select for diffs
Mon Dec 21 10:08:45 2015 UTC (5 years, 3 months ago) by mlelstv
Branches: MAIN
CVS tags: HEAD
typo

**Contents**

[[!toc levels=2]]

# Disk driver template when using dksubr library

## Declaration

<pre><code>
const struct bdevsw xxx_bdevsww= {
	.d_open = xxxopen,
	.d_close = xxxclose,
	.d_strategy = xxxstrategy,
	.d_ioctl = xxxioctl,
	.d_dump = xxxdump,
	.d_psize = xxxsize,
	.d_discard = xxxdiscard,
	.d_flag = D_DISK
};

const struct cdevsw xxx_cdevsw = {
	.d_open = xxxopen,
	.d_close = xxxclose,
	.d_read = xxxread,
	.d_write = xxxwrite,
	.d_ioctl = xxxioctl,
	.d_stop = nostop,
	.d_tty = notty,
	.d_poll = nopoll,
	.d_mmap = nommap,
	.d_kqfilter = nokqfilter,
	.d_discard = xxxdiscard,
	.d_flag = D_DISK
};

static const struct dkdriver xxxdkdriver = {
	.d_open = xxxopen,
	.d_close = xxxclose,
	.d_strategy = xxxstrategy,
	.d_iosize = xxx_iosize,
	.d_minphys  = xxxminphys,
	.d_diskstart = xxx_diskstart,
	.d_dumpblocks = xxx_dumpblocks,
	.d_lastclose = xxx_lastclose,
	.d_discard = xxx_discard
};

extern struct   cfdriver xxx_cd;

static dev_type_open(xxxopen);
static dev_type_close(xxxclose);
static dev_type_read(xxxread);
static dev_type_write(xxxwrite);
static dev_type_ioctl(xxxioctl);
static dev_type_strategy(xxxstrategy);
static dev_type_dump(xxxdump);
static dev_type_size(xxxsize);
static dev_type_discard(xxxdiscard);

static void     xxxminphys(struct buf *bp);
static int      xxxdiskstart(device_t, struct buf *bp);
static void     xxx_iosize(device_t, int *);
static int      xxx_dumpblocks(device_t, void *, daddr_t, int);
static int      xxx_lastclose(device_t);
static int      xxx_discard(device_t, off_t, off_t);


#define DEVPROLOG \
	struct xxx_softc *sc; \
	struct dk_softc *dksc; \
	int unit; \
\
	unit = DISKUNIT(dev); \
	if ((sc = device_lookup_private(&xxx_cd, unit)) == NULL) \
		return ENXIO; \
	dksc = &sc->sc_dksc
</code></pre>

----

## Attachment and Standard driver interface

<pre><code>
void
xxxattach(struct xxx_softc *sc)
{
	device_t self = sc->sc_dv;
	struct dk_softc *dksc = &sc->sc_dk;

	dk_init(dksc, self, DKTYPE_xxx);
	disk_init(&dksc->sc_dkdev, dksc->sc_xname, &xxdkdriver);

	dk_attach(dksc);
	disk_attach(&dksc->sc_dkdev);
	// initialize dksc->sc_dkdev.dk_geom

	bufq_alloc(&dksc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);

	// possibly deferred with config_interrupts()
	dkwedge_discover(&dksc->sc_dkdev);
}

static int
xxxopen(dev_t dev, int flags, int fmt, struct lwp *l)
{
	DEVPROLOG;

	return dk_open(dksc, dev, flags, fmt, l);
}

static int
xxxclose(dev_t dev, int flags, int fmt, struct lwp *l)
{
	DEVPROLOG;

	return dk_close(dksc, dev, flags, fmt, l);
}

static int
xxxread(dev_t dev, struct uio *uio, int ioflag)
{

	return physio(xxxstrategy, NULL, dev, B_READ, xxxminphys, uio);
}

static int
xxxwrite(dev_t dev, struct uio *uio, int ioflag)
{

	return physio(xxxstrategy, NULL, dev, B_WRITE, xxxminphys, uio);
}

static int
xxxioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l)
{
	int error;
	DEVPROLOG;

	error = dk_ioctl(dksc, dev, cmd, addr, flag, l);
	if (error != EPASSTHROUGH)
		return error;

	error = 0;

	switch (cmd) {
	// private IOCTLs
	default:
		error = ENOTTY;
	}

	return error;
}

static void
xxxstrategy(struct buf *bp)
{
	DEVPROLOG;

	dk_strategy(dksc, bp);
}

static int
xxxdiscard(dev_t dev, off_t pos, off_t len)
{
	DEVPROLOG;

	return dk_discard(dksc, dev, pos, len);
}

static int
xxxsize(dev_t dev)
{
	DEVPROLOG;

	return dk_size(dksc, dev);
}

static int
xxxdump(dev_t dev, daddr_t blkno, void *va, size_t size)
{
	DEVPROLOG;

	return dk_dump(dksc, dev, blkno, va, size);
}

static void
xxxminphys(struct buf *bp)
{
	struct xxx_softc *sc;
	int unit;

	unit = DISKUNIT(bp->b_dev);
	if ((sc = device_lookup_private(&xxx_cd, unit)) == NULL)
		return;

	xxx_iosize(sc->sc_dv, &bp->b_count);
	minphys(bp);
}
</code></pre>

----

## I/O callback

<pre><code>
static void
xxxdone(struct xxx_softc *sc, struct buf *bp)
{
	struct dk_softc *dksc = &sc->sc_dksc;

	dk_done(dksc, bp);
	dk_start(dksc, NULL);
}
</code></pre>

----

##  DK driver interface

<pre><code>
static int
xxx_lastclose(device_t dv)
{
	// private cleanup

	return 0;
}

static int
xxx_diskstart(device_t dv, struct buf *bp)
{
	// issue I/O for bp
	// return EAGAIN if controller busy
}

static int
xxx_dumpblocks(device_t dv, void *va, daddr_t blkno, int nblk)
{
	// issue polling I/O to dump a page
}

static void
xxx_iosize(device_t dv, int *countp)
{
	// limit *countp as necessary
}

static int
xxx_discard(device_t dv, off_t pos, off_t len)
{
	// issue request to discard bytes
}
</code></pre>

----

## Alternative when using a separate I/O thread

<pre><code>
static void
xxxstrategy(struct buf *bp)
{
	DEVPROLOG;

	if (dk_strategy_defer(dksc, bp))
		return;

	// wake up I/O thread
}

static int
xxx_diskstart(device_t dv, struct buf *bp)
{
	// issue I/O for bp
}

static void
xxxdone(struct xxx_softc *sc, struct buf *bp)
{
	struct dk_softc *dksc = &sc->sc_dksc;

	dk_done(dksc, bp);
	// wake up I/O thread
}

static void
xxx_IOTHREAD(struct dk_softc *dksc)
{
	while (!shutting_down) {
		if (dk_strategy_pending(dksc))
			dk_start(dksc, NULL);
		// sleep
	}
}
</code></pre>

----

CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb