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

Reply via email to