Module Name:    src
Committed By:   martin
Date:           Fri Jun 22 10:15:18 UTC 2018

Modified Files:
        src/sys/dev/pci [netbsd-8]: ld_virtio.c

Log Message:
Pull up following revision(s) (requested by jakllsch in ticket #888):

        sys/dev/pci/ld_virtio.c: revision 1.19-1.21,1.23

remove trailing whitespace

add feature/register definitions from virtio-v1.0-cs04

unload payload dma map upon command completion

Make ld_virtio aware of a possible device-side write cache.

The virtio block device capacity config item is expressed always in
request protocol sector units of 512 bytes.

Also, add and use a symbolic constant to refer to request protocol
sector units.

destroy 'sc_sync_wait' condvar and mutex upon detach


To generate a diff of this commit:
cvs rdiff -u -r1.15.6.1 -r1.15.6.2 src/sys/dev/pci/ld_virtio.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/ld_virtio.c
diff -u src/sys/dev/pci/ld_virtio.c:1.15.6.1 src/sys/dev/pci/ld_virtio.c:1.15.6.2
--- src/sys/dev/pci/ld_virtio.c:1.15.6.1	Fri Sep  1 09:59:11 2017
+++ src/sys/dev/pci/ld_virtio.c	Fri Jun 22 10:15:18 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_virtio.c,v 1.15.6.1 2017/09/01 09:59:11 martin Exp $	*/
+/*	$NetBSD: ld_virtio.c,v 1.15.6.2 2018/06/22 10:15:18 martin Exp $	*/
 
 /*
  * Copyright (c) 2010 Minoura Makoto.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.15.6.1 2017/09/01 09:59:11 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.15.6.2 2018/06/22 10:15:18 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -60,6 +60,7 @@ __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,
 #define VIRTIO_BLK_CONFIG_GEOMETRY_H	18 /* 8bit */
 #define VIRTIO_BLK_CONFIG_GEOMETRY_S	19 /* 8bit */
 #define VIRTIO_BLK_CONFIG_BLK_SIZE	20 /* 32bit */
+#define VIRTIO_BLK_CONFIG_WRITEBACK	32 /* 8bit */
 
 /* Feature bits */
 #define VIRTIO_BLK_F_BARRIER	(1<<0)
@@ -70,15 +71,19 @@ __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,
 #define VIRTIO_BLK_F_BLK_SIZE	(1<<6)
 #define VIRTIO_BLK_F_SCSI	(1<<7)
 #define VIRTIO_BLK_F_FLUSH	(1<<9)
+#define VIRTIO_BLK_F_TOPOLOGY	(1<<10)
+#define VIRTIO_BLK_F_CONFIG_WCE	(1<<11)
 
-/*      
+/*
  * Each block request uses at least two segments - one for the header
  * and one for the status.
-*/     
+*/
 #define	VIRTIO_BLK_MIN_SEGMENTS	2
 
 #define VIRTIO_BLK_FLAG_BITS \
 	VIRTIO_COMMON_FLAG_BITS \
+	"\x0c""CONFIG_WCE" \
+	"\x0b""TOPOLOGY" \
 	"\x0a""FLUSH" \
 	"\x08""SCSI" \
 	"\x07""BLK_SIZE" \
@@ -91,11 +96,16 @@ __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,
 /* Command */
 #define VIRTIO_BLK_T_IN		0
 #define VIRTIO_BLK_T_OUT	1
+#define VIRTIO_BLK_T_FLUSH	4
 #define VIRTIO_BLK_T_BARRIER	0x80000000
 
+/* Sector */
+#define VIRTIO_BLK_BSIZE	512
+
 /* Status */
 #define VIRTIO_BLK_S_OK		0
 #define VIRTIO_BLK_S_IOERR	1
+#define VIRTIO_BLK_S_UNSUPP	2
 
 /* Request header structure */
 struct virtio_blk_req_hdr {
@@ -103,7 +113,7 @@ struct virtio_blk_req_hdr {
 	uint32_t	ioprio;
 	uint64_t	sector;
 } __packed;
-/* 512*virtio_blk_req_hdr.sector byte payload and 1 byte status follows */
+/* payload and 1 byte status follows */
 
 
 /*
@@ -113,6 +123,7 @@ struct virtio_blk_req {
 	struct virtio_blk_req_hdr	vr_hdr;
 	uint8_t				vr_status;
 	struct buf			*vr_bp;
+#define DUMMY_VR_BP				((void *)1)
 	bus_dmamap_t			vr_cmdsts;
 	bus_dmamap_t			vr_payload;
 };
@@ -128,6 +139,13 @@ struct ld_virtio_softc {
 	bus_dma_segment_t	sc_reqs_seg;
 
 	int			sc_readonly;
+
+	enum {
+		SYNC_FREE, SYNC_BUSY, SYNC_DONE
+	}			sc_sync_use;
+	kcondvar_t		sc_sync_wait;
+	kmutex_t		sc_sync_wait_lock;
+	uint8_t			sc_sync_status;
 };
 
 static int	ld_virtio_match(device_t, cfdata_t, void *);
@@ -151,6 +169,7 @@ ld_virtio_match(device_t parent, cfdata_
 static int ld_virtio_vq_done(struct virtqueue *);
 static int ld_virtio_dump(struct ld_softc *, void *, int, int);
 static int ld_virtio_start(struct ld_softc *, struct buf *);
+static int ld_virtio_ioctl(struct ld_softc *, u_long, void *, int32_t, bool);
 
 static int
 ld_virtio_alloc_reqs(struct ld_virtio_softc *sc, int qsize)
@@ -263,7 +282,8 @@ ld_virtio_attach(device_t parent, device
 	virtio_child_attach_start(vsc, self, IPL_BIO, &sc->sc_vq,
 	    NULL, virtio_vq_intr, 0,
 	    (VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX |
-	     VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE),
+	     VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE |
+	     VIRTIO_BLK_F_FLUSH | VIRTIO_BLK_F_CONFIG_WCE),
 	    VIRTIO_BLK_FLAG_BITS);
 
 	features = virtio_features(vsc);
@@ -277,7 +297,7 @@ ld_virtio_attach(device_t parent, device
 		ld->sc_secsize = virtio_read_device_config_4(vsc,
 					VIRTIO_BLK_CONFIG_BLK_SIZE);
 	} else
-		ld->sc_secsize = 512;
+		ld->sc_secsize = VIRTIO_BLK_BSIZE;
 
 	/* At least genfs_io assumes maxxfer == MAXPHYS. */
 	if (features & VIRTIO_BLK_F_SIZE_MAX) {
@@ -327,7 +347,7 @@ ld_virtio_attach(device_t parent, device
 
 	ld->sc_dv = self;
 	ld->sc_secperunit = virtio_read_device_config_8(vsc,
-				VIRTIO_BLK_CONFIG_CAPACITY);
+	    VIRTIO_BLK_CONFIG_CAPACITY) / (ld->sc_secsize / VIRTIO_BLK_BSIZE);
 	ld->sc_maxxfer = maxxfersize;
 	if (features & VIRTIO_BLK_F_GEOMETRY) {
 		ld->sc_ncylinders = virtio_read_device_config_2(vsc,
@@ -337,13 +357,18 @@ ld_virtio_attach(device_t parent, device
 		ld->sc_nsectors   = virtio_read_device_config_1(vsc,
 					VIRTIO_BLK_CONFIG_GEOMETRY_S);
 	}
-	ld->sc_maxqueuecnt = qsize;
+	ld->sc_maxqueuecnt = qsize - 1; /* reserve slot for dumps, flushes */
 
 	if (ld_virtio_alloc_reqs(sc, qsize) < 0)
 		goto err;
 
+	cv_init(&sc->sc_sync_wait, "vblksync");
+	mutex_init(&sc->sc_sync_wait_lock, MUTEX_DEFAULT, IPL_BIO);
+	sc->sc_sync_use = SYNC_FREE;
+
 	ld->sc_dump = ld_virtio_dump;
 	ld->sc_start = ld_virtio_start;
+	ld->sc_ioctl = ld_virtio_ioctl;
 
 	ld->sc_flags = LDF_ENABLED | LDF_MPSAFE;
 	ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
@@ -398,7 +423,8 @@ ld_virtio_start(struct ld_softc *ld, str
 	vr->vr_bp = bp;
 	vr->vr_hdr.type = isread?VIRTIO_BLK_T_IN:VIRTIO_BLK_T_OUT;
 	vr->vr_hdr.ioprio = 0;
-	vr->vr_hdr.sector = bp->b_rawblkno * sc->sc_ld.sc_secsize / 512;
+	vr->vr_hdr.sector = bp->b_rawblkno * sc->sc_ld.sc_secsize /
+	    VIRTIO_BLK_BSIZE;
 
 	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
 			0, sizeof(struct virtio_blk_req_hdr),
@@ -436,13 +462,23 @@ ld_virtio_vq_done1(struct ld_virtio_soft
 	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
 			0, sizeof(struct virtio_blk_req_hdr),
 			BUS_DMASYNC_POSTWRITE);
+	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
+			sizeof(struct virtio_blk_req_hdr), sizeof(uint8_t),
+			BUS_DMASYNC_POSTREAD);
+	if (bp == DUMMY_VR_BP) {
+		mutex_enter(&sc->sc_sync_wait_lock);
+		sc->sc_sync_status = vr->vr_status;
+		sc->sc_sync_use = SYNC_DONE;
+		cv_signal(&sc->sc_sync_wait);
+		mutex_exit(&sc->sc_sync_wait_lock);
+		virtio_dequeue_commit(vsc, vq, slot);
+		return;
+	}
 	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload,
 			0, bp->b_bcount,
 			(bp->b_flags & B_READ)?BUS_DMASYNC_POSTREAD
 					      :BUS_DMASYNC_POSTWRITE);
-	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
-			sizeof(struct virtio_blk_req_hdr), sizeof(uint8_t),
-			BUS_DMASYNC_POSTREAD);
+	bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload);
 
 	if (vr->vr_status != VIRTIO_BLK_S_OK) {
 		bp->b_error = EIO;
@@ -504,7 +540,7 @@ ld_virtio_dump(struct ld_softc *ld, void
 	if (r != 0)
 		return r;
 
-	r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + 
+	r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs +
 	    VIRTIO_BLK_MIN_SEGMENTS);
 	if (r != 0) {
 		bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload);
@@ -514,7 +550,8 @@ ld_virtio_dump(struct ld_softc *ld, void
 	vr->vr_bp = (void*)0xdeadbeef;
 	vr->vr_hdr.type = VIRTIO_BLK_T_OUT;
 	vr->vr_hdr.ioprio = 0;
-	vr->vr_hdr.sector = (daddr_t) blkno * ld->sc_secsize / 512;
+	vr->vr_hdr.sector = (daddr_t) blkno * ld->sc_secsize /
+	    VIRTIO_BLK_BSIZE;
 
 	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
 			0, sizeof(struct virtio_blk_req_hdr),
@@ -549,7 +586,7 @@ ld_virtio_dump(struct ld_softc *ld, void
 		} else
 			break;
 	}
-		
+
 	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
 			0, sizeof(struct virtio_blk_req_hdr),
 			BUS_DMASYNC_POSTWRITE);
@@ -596,11 +633,158 @@ ld_virtio_detach(device_t self, int flag
 
 	ldenddetach(ld);
 
+	cv_destroy(&sc->sc_sync_wait);
+	mutex_destroy(&sc->sc_sync_wait_lock);
+
 	virtio_child_detach(sc->sc_virtio);
 
 	return 0;
 }
 
+static int
+ld_virtio_flush(struct ld_softc *ld, bool poll)
+{
+	struct ld_virtio_softc * const sc = device_private(ld->sc_dv);
+	struct virtio_softc * const vsc = sc->sc_virtio;
+	const uint32_t features = virtio_features(vsc);
+	struct virtqueue *vq = &sc->sc_vq;
+	struct virtio_blk_req *vr;
+	int slot;
+	int r;
+
+	if ((features & VIRTIO_BLK_F_FLUSH) == 0)
+		return 0;
+
+	mutex_enter(&sc->sc_sync_wait_lock);
+	while (sc->sc_sync_use != SYNC_FREE) {
+		if (poll) {
+			mutex_exit(&sc->sc_sync_wait_lock);
+			ld_virtio_vq_done(vq);
+			mutex_enter(&sc->sc_sync_wait_lock);
+			continue;
+		}
+		cv_wait(&sc->sc_sync_wait, &sc->sc_sync_wait_lock);
+	}
+	sc->sc_sync_use = SYNC_BUSY;
+	mutex_exit(&sc->sc_sync_wait_lock);
+
+	r = virtio_enqueue_prep(vsc, vq, &slot);
+	if (r != 0) {
+		return r;
+	}
+
+	vr = &sc->sc_reqs[slot];
+	KASSERT(vr->vr_bp == NULL);
+
+	r = virtio_enqueue_reserve(vsc, vq, slot, VIRTIO_BLK_MIN_SEGMENTS);
+	if (r != 0) {
+		return r;
+	}
+
+	vr->vr_bp = DUMMY_VR_BP;
+	vr->vr_hdr.type = VIRTIO_BLK_T_FLUSH;
+	vr->vr_hdr.ioprio = 0;
+	vr->vr_hdr.sector = 0;
+
+	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
+			0, sizeof(struct virtio_blk_req_hdr),
+			BUS_DMASYNC_PREWRITE);
+	bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts,
+			offsetof(struct virtio_blk_req, vr_status),
+			sizeof(uint8_t),
+			BUS_DMASYNC_PREREAD);
+
+	virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts,
+			 0, sizeof(struct virtio_blk_req_hdr),
+			 true);
+	virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts,
+			 offsetof(struct virtio_blk_req, vr_status),
+			 sizeof(uint8_t),
+			 false);
+	virtio_enqueue_commit(vsc, vq, slot, true);
+
+	mutex_enter(&sc->sc_sync_wait_lock);
+	while (sc->sc_sync_use != SYNC_DONE) {
+		if (poll) {
+			mutex_exit(&sc->sc_sync_wait_lock);
+			ld_virtio_vq_done(vq);
+			mutex_enter(&sc->sc_sync_wait_lock);
+			continue;
+		}
+		cv_wait(&sc->sc_sync_wait, &sc->sc_sync_wait_lock);
+	}
+
+	if (sc->sc_sync_status == VIRTIO_BLK_S_OK)
+		r = 0;
+	else
+		r = EIO;
+
+	sc->sc_sync_use = SYNC_FREE;
+	cv_signal(&sc->sc_sync_wait);
+	mutex_exit(&sc->sc_sync_wait_lock);
+
+	return r;
+}
+
+static int
+ld_virtio_getcache(struct ld_softc *ld, int *bitsp)
+{
+	struct ld_virtio_softc * const sc = device_private(ld->sc_dv);
+	struct virtio_softc * const vsc = sc->sc_virtio;
+	const uint32_t features = virtio_features(vsc);
+
+	*bitsp = DKCACHE_READ;
+	if ((features & VIRTIO_BLK_F_CONFIG_WCE) != 0)
+		*bitsp |= DKCACHE_WCHANGE;
+	if (virtio_read_device_config_1(vsc,
+	    VIRTIO_BLK_CONFIG_WRITEBACK) != 0x00)
+		*bitsp |= DKCACHE_WRITE;
+
+	return 0;
+}
+
+static int
+ld_virtio_setcache(struct ld_softc *ld, int bits)
+{
+	struct ld_virtio_softc * const sc = device_private(ld->sc_dv);
+	struct virtio_softc * const vsc = sc->sc_virtio;
+	const uint8_t wce = (bits & DKCACHE_WRITE) ? 0x01 : 0x00;
+
+	virtio_write_device_config_1(vsc,
+	    VIRTIO_BLK_CONFIG_WRITEBACK, wce);
+	if (virtio_read_device_config_1(vsc,
+	    VIRTIO_BLK_CONFIG_WRITEBACK) != wce)
+		return EIO;
+
+	return 0;
+}
+
+static int
+ld_virtio_ioctl(struct ld_softc *ld, u_long cmd, void *addr, int32_t flag, bool poll)
+{
+	int error;
+
+	switch (cmd) {
+	case DIOCCACHESYNC:
+		error = ld_virtio_flush(ld, poll);
+		break;
+
+	case DIOCGCACHE:
+		error = ld_virtio_getcache(ld, (int *)addr);
+		break;
+
+	case DIOCSCACHE:
+		error = ld_virtio_setcache(ld, *(int *)addr);
+		break;
+
+	default:
+		error = EPASSTHROUGH;
+		break;
+	}
+
+	return error;
+}
+
 MODULE(MODULE_CLASS_DRIVER, ld_virtio, "ld,virtio");
 
 #ifdef _MODULE
@@ -612,7 +796,7 @@ MODULE(MODULE_CLASS_DRIVER, ld_virtio, "
 #define CFDRIVER_DECL(name, class, attr)
 #include "ioconf.c"
 #endif
- 
+
 static int
 ld_virtio_modcmd(modcmd_t cmd, void *opaque)
 {
@@ -624,7 +808,7 @@ ld_virtio_modcmd(modcmd_t cmd, void *opa
 	static struct cfdriver * const no_cfdriver_vec[] = { NULL };
 #endif
 	int error = 0;
- 
+
 #ifdef _MODULE
 	switch (cmd) {
 	case MODULE_CMD_INIT:

Reply via email to