[dpdk-dev] [PATCH v2 2/2] vhost: add vhost-scsi support to vhost library

Changpeng Liu changpeng.liu at intel.com
Thu Sep 15 02:28:18 CEST 2016


Since we changed the vhost library as a common framework to add other
VIRTIO device type, here we add VIRTIO_ID_SCSI device type to vhost
library to support vhost-scsi target.

Signed-off-by: Changpeng Liu <changpeng.liu at intel.com>
---
 lib/librte_vhost/Makefile          |   4 +-
 lib/librte_vhost/rte_virtio_dev.h  |   1 +
 lib/librte_vhost/rte_virtio_scsi.h |  68 +++++++
 lib/librte_vhost/socket.c          |   2 +
 lib/librte_vhost/vhost_device.h    |   3 +
 lib/librte_vhost/vhost_net.c       |   2 +-
 lib/librte_vhost/vhost_scsi.c      | 354 +++++++++++++++++++++++++++++++++++++
 lib/librte_vhost/vhost_scsi.h      |  68 +++++++
 lib/librte_vhost/vhost_user.c      |  31 +++-
 lib/librte_vhost/vhost_user.h      |   5 +
 lib/librte_vhost/virtio_scsi.c     | 145 +++++++++++++++
 11 files changed, 675 insertions(+), 8 deletions(-)
 create mode 100644 lib/librte_vhost/rte_virtio_scsi.h
 create mode 100644 lib/librte_vhost/vhost_scsi.c
 create mode 100644 lib/librte_vhost/vhost_scsi.h
 create mode 100644 lib/librte_vhost/virtio_scsi.c

diff --git a/lib/librte_vhost/Makefile b/lib/librte_vhost/Makefile
index af30491..e8fca35 100644
--- a/lib/librte_vhost/Makefile
+++ b/lib/librte_vhost/Makefile
@@ -48,10 +48,10 @@ endif
 
 # all source are stored in SRCS-y
 SRCS-$(CONFIG_RTE_LIBRTE_VHOST) := fd_man.c socket.c vhost_net.c vhost_user.c \
-				   virtio_net.c
+				   virtio_net.c vhost_scsi.c virtio_scsi.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_VHOST)-include += rte_virtio_net.h rte_virtio_dev.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_VHOST)-include += rte_virtio_net.h rte_virtio_scsi.h rte_virtio_dev.h
 
 # dependencies
 DEPDIRS-$(CONFIG_RTE_LIBRTE_VHOST) += lib/librte_eal
diff --git a/lib/librte_vhost/rte_virtio_dev.h b/lib/librte_vhost/rte_virtio_dev.h
index e3c857a..325a208 100644
--- a/lib/librte_vhost/rte_virtio_dev.h
+++ b/lib/librte_vhost/rte_virtio_dev.h
@@ -40,6 +40,7 @@
 #define RTE_VHOST_USER_TX_ZERO_COPY	(1ULL << 2)
 
 #define RTE_VHOST_USER_DEV_NET		(1ULL << 32)
+#define RTE_VHOST_USER_DEV_SCSI		(1ULL << 33)
 
 /**
  * Device and vring operations.
diff --git a/lib/librte_vhost/rte_virtio_scsi.h b/lib/librte_vhost/rte_virtio_scsi.h
new file mode 100644
index 0000000..4e4cec5
--- /dev/null
+++ b/lib/librte_vhost/rte_virtio_scsi.h
@@ -0,0 +1,68 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VIRTIO_SCSI_H_
+#define _VIRTIO_SCSI_H_
+
+/**
+ * @file
+ * Interface to vhost net
+ */
+
+#include <stdint.h>
+#include <linux/vhost.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_scsi.h>
+#include <sys/eventfd.h>
+#include <sys/socket.h>
+
+#include <rte_memory.h>
+#include <rte_mempool.h>
+#include <rte_virtio_dev.h>
+
+enum {DIR_DMA_NONE, DIR_DMA_FROM_DEV, DIR_DMA_TO_DEV};
+
+/* Register callbacks. */
+int rte_vhost_scsi_driver_callback_register(struct virtio_net_device_ops const * const);
+
+int rte_vhost_scsi_pop_request(int vid, uint16_t queue_id,
+	struct virtio_scsi_cmd_req **request,
+	struct virtio_scsi_cmd_resp **response,
+	struct iovec *iovs, int *iov_cnt, uint32_t *desc_idx,
+	uint32_t *xfer_direction);
+
+int rte_vhost_scsi_push_response(int vid, uint16_t queue_id,
+				 uint32_t req_idx, uint32_t len);
+
+
+#endif /* _VIRTIO_SCSI_H_ */
\ No newline at end of file
diff --git a/lib/librte_vhost/socket.c b/lib/librte_vhost/socket.c
index 1474c98..2b3f854 100644
--- a/lib/librte_vhost/socket.c
+++ b/lib/librte_vhost/socket.c
@@ -527,6 +527,8 @@ rte_vhost_driver_register(const char *path, uint64_t flags)
 	}
 
 	vsocket->type = VIRTIO_ID_NET;
+	if (flags & RTE_VHOST_USER_DEV_SCSI)
+		vsocket->type = VIRTIO_ID_SCSI;
 	vhost_user.vsockets[vhost_user.vsocket_cnt++] = vsocket;
 
 out:
diff --git a/lib/librte_vhost/vhost_device.h b/lib/librte_vhost/vhost_device.h
index 7101bb0..f1125e1 100644
--- a/lib/librte_vhost/vhost_device.h
+++ b/lib/librte_vhost/vhost_device.h
@@ -37,6 +37,7 @@
 #include <linux/virtio_ids.h>
 
 #include "vhost_net.h"
+#include "vhost_scsi.h"
 #include "vhost_user.h"
 
 /* Used to indicate that the device is running on a data core */
@@ -109,6 +110,7 @@ struct virtio_dev {
 	uint32_t		dev_type;
 	union {
 		struct virtio_net	net_dev;
+		struct virtio_scsi	scsi_dev;
 	} dev;
 
 	uint32_t		nr_guest_pages;
@@ -120,6 +122,7 @@ struct virtio_dev {
 } __rte_cache_aligned;
 
 extern struct virtio_net_device_ops const *notify_ops;
+extern struct virtio_net_device_ops const *scsi_notify_ops;
 
 /*
  * Define virtio 1.0 for older kernels
diff --git a/lib/librte_vhost/vhost_net.c b/lib/librte_vhost/vhost_net.c
index f141b32..e38e3ac 100644
--- a/lib/librte_vhost/vhost_net.c
+++ b/lib/librte_vhost/vhost_net.c
@@ -518,7 +518,7 @@ vhost_net_device_init(struct virtio_dev *device)
 
 	device->fn_table.vhost_dev_ready  = vhost_dev_is_ready;
 	device->fn_table.vhost_dev_get_queues  = vhost_dev_get_queues;
-	device->fn_table.vhost_dev_cleanup = cleanup_device;
+	device->fn_table.vhost_dev_cleanup  = cleanup_device;
 	device->fn_table.vhost_dev_free  = free_device;
 	device->fn_table.vhost_dev_reset  = reset_device;
 	device->fn_table.vhost_dev_get_features  = vhost_dev_get_features;
diff --git a/lib/librte_vhost/vhost_scsi.c b/lib/librte_vhost/vhost_scsi.c
new file mode 100644
index 0000000..0f14f77
--- /dev/null
+++ b/lib/librte_vhost/vhost_scsi.c
@@ -0,0 +1,354 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/vhost.h>
+#include <linux/virtio_scsi.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <rte_log.h>
+#include <rte_string_fns.h>
+#include <rte_memory.h>
+#include <rte_malloc.h>
+
+#include "vhost_scsi.h"
+#include "vhost_device.h"
+
+/* device ops to add/remove device to/from data core. */
+struct virtio_net_device_ops const *scsi_notify_ops;
+
+/* Features supported by this lib. */
+#define VHOST_SCSI_SUPPORTED_FEATURES ((1ULL << VIRTIO_SCSI_F_INOUT) | \
+				(1ULL << VIRTIO_SCSI_F_HOTPLUG) | \
+				(1ULL << VIRTIO_SCSI_F_CHANGE))
+
+static uint64_t VHOST_SCSI_FEATURES = VHOST_SCSI_SUPPORTED_FEATURES;
+
+struct virtio_scsi *
+get_scsi_device(struct virtio_dev *dev)
+{
+	if (!dev)
+		return NULL;
+ 
+	return &dev->dev.scsi_dev;
+}
+
+static void
+cleanup_vq(struct vhost_virtqueue *vq, int destroy)
+{
+	if ((vq->callfd >= 0) && (destroy != 0))
+		close(vq->callfd);
+	if (vq->kickfd >= 0)
+		close(vq->kickfd);
+}
+
+/*
+ * Unmap any memory, close any file descriptors and
+ * free any memory owned by a device.
+ */
+static void
+cleanup_device(struct virtio_dev *device, int destroy)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+	uint32_t i;
+
+	dev->features = 0;
+	dev->protocol_features = 0;
+
+	for (i = 0; i < dev->virt_q_nb; i++) {
+		cleanup_vq(dev->virtqueue[i], destroy);
+	}
+}
+
+static void
+init_vring_queue(struct vhost_virtqueue *vq)
+{
+	memset(vq, 0, sizeof(struct vhost_virtqueue));
+
+	vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;
+	vq->callfd = VIRTIO_UNINITIALIZED_EVENTFD;
+
+	/* Backends are set to -1 indicating an inactive device. */
+	vq->backend = -1;
+	vq->enabled = 1;
+}
+
+static void
+reset_vring_queue(struct vhost_virtqueue *vq)
+{
+	int callfd;
+
+	callfd = vq->callfd;
+	init_vring_queue(vq);
+	vq->callfd = callfd;
+}
+
+static int
+alloc_vring_queue(struct virtio_scsi *dev, uint32_t q_idx)
+{
+	struct vhost_virtqueue *virtqueue = NULL;
+
+	virtqueue = rte_malloc(NULL,
+			       sizeof(struct vhost_virtqueue), 0);
+	if (virtqueue == NULL) {
+		RTE_LOG(ERR, VHOST_CONFIG,
+			"Failed to allocate memory for virt qp:%d.\n", q_idx);
+		return -1;
+	}
+
+	dev->virtqueue[q_idx] = virtqueue;
+
+	init_vring_queue(virtqueue);
+
+	dev->virt_q_nb += 1;
+
+	return 0;
+}
+
+/*
+ * Reset some variables in device structure, while keeping few
+ * others untouched, such as vid, ifname, virt_qp_nb: they
+ * should be same unless the device is removed.
+ */
+static void
+reset_device(struct virtio_dev *device)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+	uint32_t i;
+
+	for (i = 0; i < dev->virt_q_nb; i++)
+		reset_vring_queue(dev->virtqueue[i]);
+}
+
+/*
+ * Release virtqueues and device memory.
+ */
+static void
+free_device(struct virtio_dev *device)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+	uint32_t i;
+
+	for (i = 0; i < dev->virt_q_nb; i++)
+		rte_free(dev->virtqueue[i]);
+
+	rte_free(dev);
+}
+
+static uint64_t
+vhost_dev_get_features(struct virtio_dev *dev)
+{
+	if (dev == NULL)
+		return 0;
+
+	return VHOST_SCSI_FEATURES;	
+}
+
+static int
+vhost_dev_set_features(struct virtio_dev *device, uint64_t features)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+
+	if (features & ~VHOST_SCSI_FEATURES)
+		return -1;
+
+	dev->features = features;
+	LOG_DEBUG(VHOST_CONFIG,
+		"(%d) RW %s, Hotplug %s, Status Change %s\n",
+		device->vid,
+		(dev->features & (1ULL << VIRTIO_SCSI_F_INOUT)) ? "on" : "off",
+		(dev->features & (1ULL << VIRTIO_SCSI_F_HOTPLUG)) ? "on" : "off",
+		(dev->features & (1ULL << VIRTIO_SCSI_F_CHANGE)) ? "on" : "off");
+
+	return 0;
+}
+
+static int
+vq_is_ready(struct vhost_virtqueue *vq)
+{
+	return vq && vq->desc   &&
+	       vq->kickfd != VIRTIO_UNINITIALIZED_EVENTFD &&
+	       vq->callfd != VIRTIO_UNINITIALIZED_EVENTFD;
+}
+
+static int
+vhost_dev_is_ready(struct virtio_dev *device)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+	struct vhost_virtqueue *vq;
+	uint32_t i;
+
+	for (i = 0; i < dev->virt_q_nb; i++) {
+		vq = dev->virtqueue[i];
+
+		if (!vq_is_ready(vq)) {
+			RTE_LOG(INFO, VHOST_CONFIG,
+				"virtio is not ready for processing.\n");
+			return 0;
+		}
+	}
+
+	RTE_LOG(INFO, VHOST_CONFIG,
+		"virtio is now ready for processing.\n");
+	return 1;
+}
+
+static int
+vhost_dev_set_vring_call(struct virtio_dev *device, struct vhost_vring_file *file)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+	struct vhost_virtqueue *vq;
+	uint32_t cur_q_idx;
+
+	/*
+	 * FIXME: VHOST_SET_VRING_CALL is the first per-vring message
+	 * we get, so we do vring queue pair allocation here.
+	 */
+	cur_q_idx = file->index;
+	if (cur_q_idx + 1 > dev->virt_q_nb) {
+		if (alloc_vring_queue(dev, cur_q_idx) < 0)
+			return -1;
+	}
+
+	vq = dev->virtqueue[file->index];
+	assert(vq != NULL);
+
+	if (vq->callfd >= 0)
+		close(vq->callfd);
+
+	vq->callfd = file->fd;
+	return 0;
+}
+
+static uint32_t
+vhost_dev_get_default_queue_num(struct virtio_dev *dev)
+{
+	if (dev == NULL)
+		return 0;
+
+	return VHOST_MAX_SCSI_QUEUES;
+}
+
+static uint32_t
+vhost_dev_get_queue_num(struct virtio_dev *device)
+{
+	struct virtio_scsi *dev;
+	if (device == NULL)
+		return 0;
+
+	dev = get_scsi_device(device);
+	return dev->virt_q_nb;
+}
+
+static int
+vhost_dev_get_vring_base(struct virtio_dev *device, struct vhost_virtqueue *vq)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+
+	if (dev == NULL)
+		return 0;
+	/*
+	 * Based on current qemu vhost-user implementation, this message is
+	 * sent and only sent in vhost_vring_stop.
+	 * TODO: cleanup the vring, it isn't usable since here.
+	 */
+	if (vq->kickfd >= 0)
+		close(vq->kickfd);
+	vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;
+
+	if (vq->callfd >= 0)
+		close(vq->callfd);
+	vq->callfd = VIRTIO_UNINITIALIZED_EVENTFD;
+
+	return 0;
+}
+
+static struct vhost_virtqueue *
+vhost_dev_get_queues(struct virtio_dev *device, uint16_t queue_id)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+	struct vhost_virtqueue *vq;
+
+	vq = dev->virtqueue[queue_id];
+
+	return vq;
+}
+
+int
+vhost_user_scsi_set_endpoint(struct virtio_dev *device, struct VhostUserMsg *pmsg)
+{
+       struct virtio_scsi *dev = get_scsi_device(device);
+
+       if (!dev || pmsg->size != sizeof(dev->scsi_target))
+               return -1;
+
+       memcpy(&dev->scsi_target, &pmsg->payload.scsi_target, sizeof(dev->scsi_target));
+
+       return 0;
+}
+
+void
+vhost_scsi_device_init(struct virtio_dev *device)
+{
+	struct virtio_scsi *dev = get_scsi_device(device);
+
+	device->fn_table.vhost_dev_ready  = vhost_dev_is_ready;
+	device->fn_table.vhost_dev_get_queues  = vhost_dev_get_queues;
+	device->fn_table.vhost_dev_cleanup  = cleanup_device;
+	device->fn_table.vhost_dev_free  = free_device;
+	device->fn_table.vhost_dev_reset  = reset_device;
+	device->fn_table.vhost_dev_get_features  = vhost_dev_get_features;
+	device->fn_table.vhost_dev_set_features  = vhost_dev_set_features;
+	device->fn_table.vhost_dev_get_default_queue_num  = vhost_dev_get_default_queue_num;
+	device->fn_table.vhost_dev_get_queue_num  = vhost_dev_get_queue_num;
+	device->fn_table.vhost_dev_get_vring_base  = vhost_dev_get_vring_base;
+	device->fn_table.vhost_dev_set_vring_call  = vhost_dev_set_vring_call;
+
+	dev->device = device;
+}
+
+
+/*
+ * Register ops so that we can add/remove device to data core.
+ */
+int
+rte_vhost_scsi_driver_callback_register(struct virtio_net_device_ops const * const ops)
+{
+	scsi_notify_ops = ops;
+
+	return 0;
+}
\ No newline at end of file
diff --git a/lib/librte_vhost/vhost_scsi.h b/lib/librte_vhost/vhost_scsi.h
new file mode 100644
index 0000000..4aba9b4
--- /dev/null
+++ b/lib/librte_vhost/vhost_scsi.h
@@ -0,0 +1,68 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VHOST_SCSI_H_
+#define _VHOST_SCSI_H_
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <linux/vhost.h>
+
+#include <rte_log.h>
+
+#include "rte_virtio_scsi.h"
+#include "vhost_user.h"
+
+#define VHOST_MAX_SCSI_QUEUES		0x1
+
+#define VHOST_USER_SCSI_ABI_VERSION	0x1
+
+/**
+ * Device structure contains all configuration information relating
+ * to the device.
+ */
+struct virtio_scsi {
+	uint64_t		features;
+	uint64_t		protocol_features;
+	uint32_t		virt_q_nb;
+	struct vhost_scsi_target scsi_target;
+	struct vhost_virtqueue	*virtqueue[VHOST_MAX_SCSI_QUEUES + 2];
+	struct virtio_dev	*device;
+} __rte_cache_aligned;
+
+struct virtio_scsi *get_scsi_device(struct virtio_dev *dev);
+void vhost_scsi_device_init(struct virtio_dev *device);
+int vhost_user_scsi_set_endpoint(struct virtio_dev *device, struct VhostUserMsg *pmsg);
+
+#endif
\ No newline at end of file
diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
index 90c4b03..320f86b 100644
--- a/lib/librte_vhost/vhost_user.c
+++ b/lib/librte_vhost/vhost_user.c
@@ -50,6 +50,7 @@
 
 #include "vhost_device.h"
 #include "vhost_net.h"
+#include "vhost_scsi.h"
 #include "vhost_user.h"
 
 #define MAX_VHOST_DEVICE        1024
@@ -76,6 +77,9 @@ static const char *vhost_message_str[VHOST_USER_MAX] = {
 	[VHOST_USER_GET_QUEUE_NUM]  = "VHOST_USER_GET_QUEUE_NUM",
 	[VHOST_USER_SET_VRING_ENABLE]  = "VHOST_USER_SET_VRING_ENABLE",
 	[VHOST_USER_SEND_RARP]  = "VHOST_USER_SEND_RARP",
+	[VHOST_USER_SCSI_SET_ENDPOINT] = "VHOST_USER_SCSI_SET_ENDPOINT",
+	[VHOST_USER_SCSI_CLEAR_ENDPOINT] = "VHOST_USER_SCSI_CLEAR_ENDPOINT",
+	[VHOST_USER_SCSI_GET_ABI_VERSION] = "VHOST_USER_SCSI_GET_ABI_VERSION",
 };
 
 static uint64_t
@@ -163,6 +167,12 @@ vhost_new_device(int type)
 			vhost_net_device_init(dev);
 			assert(notify_ops != NULL);
 			break;
+
+		case VIRTIO_ID_SCSI:
+			dev->notify_ops = scsi_notify_ops;
+			vhost_scsi_device_init(dev);
+			assert(scsi_notify_ops != NULL);
+			break;
 		default:
 			return -1;
 	}
@@ -713,6 +723,11 @@ vhost_user_set_vring_call(struct virtio_dev *dev, struct VhostUserMsg *pmsg)
 
 	if (dev->fn_table.vhost_dev_set_vring_call)
 		dev->fn_table.vhost_dev_set_vring_call(dev, &file);
+
+	if (virtio_is_ready(dev) && !(dev->flags & VIRTIO_DEV_RUNNING)) {
+		if (dev->notify_ops->new_device(dev->vid) == 0)
+			dev->flags |= VIRTIO_DEV_RUNNING;
+	}
 }
 
 /*
@@ -740,11 +755,6 @@ vhost_user_set_vring_kick(struct virtio_dev *dev, struct VhostUserMsg *pmsg)
 		close(vq->kickfd);
 
 	vq->kickfd = file.fd;
-
-	if (virtio_is_ready(dev) && !(dev->flags & VIRTIO_DEV_RUNNING)) {
-		if (dev->notify_ops->new_device(dev->vid) == 0)
-			dev->flags |= VIRTIO_DEV_RUNNING;
-	}
 }
 
 /*
@@ -1027,6 +1037,17 @@ vhost_user_msg_handler(int vid, int fd)
 		vhost_user_send_rarp(dev, &msg);
 		break;
 
+	case VHOST_USER_SCSI_SET_ENDPOINT:
+		vhost_user_scsi_set_endpoint(dev, &msg);
+		break;
+	case VHOST_USER_SCSI_CLEAR_ENDPOINT:
+		break;
+	case VHOST_USER_SCSI_GET_ABI_VERSION:
+		msg.payload.s32 = VHOST_USER_SCSI_ABI_VERSION;
+		msg.size = sizeof(msg.payload.s32);
+		send_vhost_message(fd, &msg);
+		break;
+
 	default:
 		break;
 
diff --git a/lib/librte_vhost/vhost_user.h b/lib/librte_vhost/vhost_user.h
index 59f80f2..dfeb27f 100644
--- a/lib/librte_vhost/vhost_user.h
+++ b/lib/librte_vhost/vhost_user.h
@@ -65,6 +65,9 @@ typedef enum VhostUserRequest {
 	VHOST_USER_GET_QUEUE_NUM = 17,
 	VHOST_USER_SET_VRING_ENABLE = 18,
 	VHOST_USER_SEND_RARP = 19,
+	VHOST_USER_SCSI_SET_ENDPOINT = 20,
+	VHOST_USER_SCSI_CLEAR_ENDPOINT = 21,
+	VHOST_USER_SCSI_GET_ABI_VERSION = 22,
 	VHOST_USER_MAX
 } VhostUserRequest;
 
@@ -97,10 +100,12 @@ typedef struct VhostUserMsg {
 #define VHOST_USER_VRING_IDX_MASK   0xff
 #define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
 		uint64_t u64;
+		int32_t s32;
 		struct vhost_vring_state state;
 		struct vhost_vring_addr addr;
 		VhostUserMemory memory;
 		VhostUserLog    log;
+		struct vhost_scsi_target scsi_target;
 	} payload;
 	int fds[VHOST_MEMORY_MAX_NREGIONS];
 } __attribute((packed)) VhostUserMsg;
diff --git a/lib/librte_vhost/virtio_scsi.c b/lib/librte_vhost/virtio_scsi.c
new file mode 100644
index 0000000..a49f9ce
--- /dev/null
+++ b/lib/librte_vhost/virtio_scsi.c
@@ -0,0 +1,145 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_scsi.h>
+#include <sys/uio.h>
+
+#include <rte_mbuf.h>
+#include <rte_memcpy.h>
+#include <rte_virtio_scsi.h>
+
+#include "vhost_scsi.h"
+#include "vhost_device.h"
+
+int
+rte_vhost_scsi_pop_request(int vid, uint16_t queue_id,
+	struct virtio_scsi_cmd_req **request, struct virtio_scsi_cmd_resp **response, struct iovec *iovs, int *iov_cnt, uint32_t *desc_idx, uint32_t *xfer_direction)
+{
+	struct virtio_dev *device;
+	struct virtio_scsi *dev;
+	struct vhost_virtqueue *vq;
+	struct vring_desc *desc;
+	uint16_t avail_idx;
+	uint32_t resp_idx, data_idx;
+	uint32_t free_entries;
+
+	device = get_device(vid);
+	if (!device)
+		return 0;
+
+	dev = get_scsi_device(device);
+
+	if (queue_id >= dev->virt_q_nb) {
+		return -1;
+	}
+
+	vq = dev->virtqueue[queue_id];
+	if (unlikely(vq->enabled == 0))
+		return 0;
+
+	free_entries = *((volatile uint16_t *)&vq->avail->idx) -
+			vq->last_avail_idx;
+	if (free_entries == 0)
+		return 0;
+
+	LOG_DEBUG(VHOST_DATA, "(%d) %s\n", dev->device->vid, __func__);
+
+#define FLAGS_NEXT 0x1
+#define FLAGS_WRITE 0x2
+
+	/* Prefetch available and used ring */
+	avail_idx = vq->last_avail_idx & (vq->size - 1);
+	rte_prefetch0(&vq->avail->ring[avail_idx]);
+
+	*desc_idx = vq->avail->ring[avail_idx];
+
+	/* 1st descriptor */
+	desc = &vq->desc[*desc_idx];
+	*request = (void *)gpa_to_vva(device, desc->addr);
+	/* 2st descriptor */
+	resp_idx = desc->next;
+	desc = &vq->desc[resp_idx];
+	*response = (void *)gpa_to_vva(device, desc->addr);
+
+	if (desc->flags & FLAGS_NEXT) {
+		data_idx = desc->next;
+		desc = &vq->desc[data_idx];
+		iovs[0].iov_base = (void *)gpa_to_vva(device, desc->addr);
+		iovs[0].iov_len = desc->len;
+		if (desc->flags & FLAGS_WRITE)
+			*xfer_direction = DIR_DMA_FROM_DEV;
+		*iov_cnt = 1;
+	}
+
+	rte_smp_wmb();
+	rte_smp_rmb();
+	vq->last_avail_idx += 1;
+
+	return 1;
+}
+
+int
+rte_vhost_scsi_push_response(int vid, uint16_t queue_id, uint32_t req_idx, uint32_t len)
+{
+	struct virtio_dev *device;
+	struct virtio_scsi *dev;
+	struct vhost_virtqueue *vq;
+
+	device = get_device(vid);
+	if (!device)
+		return 0;
+
+	dev = get_scsi_device(device);
+
+	if (queue_id >= dev->virt_q_nb) {
+		return -1;
+	}
+
+	vq = dev->virtqueue[queue_id];
+	if (unlikely(vq->enabled == 0))
+		return 0;
+
+	vq->used->ring[vq->used->idx & (vq->size - 1)].id = req_idx;
+	vq->used->ring[vq->used->idx & (vq->size - 1)].len = len;
+
+	rte_smp_wmb();
+	rte_smp_rmb();
+	vq->used->idx++;
+
+	eventfd_write(vq->callfd, (eventfd_t)1);
+
+	return 0;
+}
-- 
1.9.3



More information about the dev mailing list