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

Message ID 1473899298-4580-2-git-send-email-changpeng.liu@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Yuanhan Liu
Headers

Commit Message

Liu, Changpeng Sept. 15, 2016, 12:28 a.m. UTC
  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@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
  

Comments

Yuanhan Liu Sept. 14, 2016, 3:28 a.m. UTC | #1
On Thu, Sep 15, 2016 at 08:28:18AM +0800, Changpeng Liu wrote:
> Since we changed the vhost library as a common framework to add other

As I said in my earlier email, I don't see how common it becomes after
your refactoring. __Another__ for example, I just saw a bunch of
duplicated code below that should not even be there (vhost-scsi.c).

Assuming we may add vhost-crypto in future, don't we have to duplicate
again in vhost-crypto.c in your way? The answer is obviously NO.

> +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;
> +}
> +

[... snipped a bunch of duplicated code ...]

> +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)

We definitely don't want to introduce a new such API for each vhost device.
The proposal I gave is something like rte_vhost_vring_dequeue_burst(),
which, as the name explains, just dequeues some vring entries and let the
application to consume it. The application then could be a virtio-scsi
device, virtio-crypto device, and even, a virtio-net device.

Few more generic comments:

- you touched way more code than necessary.

- you should split your patches into some small patches: one patch just
  does one tiny logic. Doing one bunch of stuff in one patch is really
  hard for review. For example, in patch 1, you did:

  * move bunch of code from here and there
  * besides that, you even modified the code you moved.
  * introduce virtio_dev_table
  * split virtio_net_dev and introduce virtio_dev
  * change some vhost user message handler, say VHOST_USER_GET_QUEUE_NUM.
  * ...

  That's way too much for a single patch!

  If you think some functions are not well placed, that you want to move
  them to somewhere else, fine, just move it. And if you want to modify
  few of them, that's fine, too. But you should make the changes in another
  patch. 

  This helps review, and what's more importantly, it helps us to locate
  buggy code if any. Just assume you introduced a bug in patch 1, it's
  so big a patch that it's hard for human to spot it. Later, someone
  reported that something is broken and he make a bisect and show this
  patch is the culprit. However, it's so big a patch, that even we know
  there is a bug there, it may take a lot of time to figure out which
  change breaks it.

  If you're splitting patches properly, the bug code could even be spotted
  in review time.

  That are some generic comments about making patches to introduce something
  big.


Besides, I'd like to state again, it seems you are heading the wrong
direction: again, you touched way too much code than necessary to add
vhost-scsi support. In a rough thinking, it could be simple as:

- handle vring queues correctly for vhost-scsi; currently, it sticks to
  virtio-net queue pairs.

- add vring operation functions, such as dequeue/enqueue vrings, update
  used rings, ...

- add vhost-scsi messages

- may need change they way to trigger new_device() callback for
  vhost-scsi device.

Above should be enough (I guess). And again, please make one patch for each
item.  Besides the 2nd item may introduce some code, others should be small
changes.

And, let us forget about the names so far, just reuse what we have. Say,
don't bother to introduce virtio_dev, just use virtio_net (well, I don't
object to make the change now, only if you can do it elegantly). Also, let's
stick to the rte_virtio_net.h as well: let's make it right later.

So far, just let us focus on what's need be done to make vhost-scsi work.
Okay to you guys?

	--yliu
  
Liu, Changpeng Sept. 14, 2016, 4:46 a.m. UTC | #2
> -----Original Message-----
> From: Yuanhan Liu [mailto:yuanhan.liu@linux.intel.com]
> Sent: Wednesday, September 14, 2016 11:29 AM
> To: Liu, Changpeng <changpeng.liu@intel.com>
> Cc: dev@dpdk.org; Harris, James R <james.r.harris@intel.com>
> Subject: Re: [PATCH v2 2/2] vhost: add vhost-scsi support to vhost library
> 
> On Thu, Sep 15, 2016 at 08:28:18AM +0800, Changpeng Liu wrote:
> > Since we changed the vhost library as a common framework to add other
> 
> As I said in my earlier email, I don't see how common it becomes after
> your refactoring. __Another__ for example, I just saw a bunch of
> duplicated code below that should not even be there (vhost-scsi.c).
> 
> Assuming we may add vhost-crypto in future, don't we have to duplicate
> again in vhost-crypto.c in your way? The answer is obviously NO.
> 
> > +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;
> > +}
> > +

Agreed, cleanup_vq and init_vring_queue can be eliminated as duplicated code here.

> 
> [... snipped a bunch of duplicated code ...]
> 
> > +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)
> 
> We definitely don't want to introduce a new such API for each vhost device.
> The proposal I gave is something like rte_vhost_vring_dequeue_burst(),
> which, as the name explains, just dequeues some vring entries and let the
> application to consume it. The application then could be a virtio-scsi
> device, virtio-crypto device, and even, a virtio-net device.
> 
> Few more generic comments:
> 
> - you touched way more code than necessary.
> 
> - you should split your patches into some small patches: one patch just
>   does one tiny logic. Doing one bunch of stuff in one patch is really
>   hard for review. For example, in patch 1, you did:
> 
>   * move bunch of code from here and there
>   * besides that, you even modified the code you moved.
>   * introduce virtio_dev_table
>   * split virtio_net_dev and introduce virtio_dev
>   * change some vhost user message handler, say
> VHOST_USER_GET_QUEUE_NUM.
>   * ...
> 
>   That's way too much for a single patch!

Agreed, the 2 patch set I sent as RFC purpose, I will break it into small patches at last. 

> 
>   If you think some functions are not well placed, that you want to move
>   them to somewhere else, fine, just move it. And if you want to modify
>   few of them, that's fine, too. But you should make the changes in another
>   patch.
> 
>   This helps review, and what's more importantly, it helps us to locate
>   buggy code if any. Just assume you introduced a bug in patch 1, it's
>   so big a patch that it's hard for human to spot it. Later, someone
>   reported that something is broken and he make a bisect and show this
>   patch is the culprit. However, it's so big a patch, that even we know
>   there is a bug there, it may take a lot of time to figure out which
>   change breaks it.
> 
>   If you're splitting patches properly, the bug code could even be spotted
>   in review time.
> 
>   That are some generic comments about making patches to introduce something
>   big.
> 
> 
> Besides, I'd like to state again, it seems you are heading the wrong
> direction: again, you touched way too much code than necessary to add
> vhost-scsi support. In a rough thinking, it could be simple as:
> 
> - handle vring queues correctly for vhost-scsi; currently, it sticks to
>   virtio-net queue pairs.
> 
> - add vring operation functions, such as dequeue/enqueue vrings, update
>   used rings, ...
> 
> - add vhost-scsi messages
> 
> - may need change they way to trigger new_device() callback for
>   vhost-scsi device.
> 
> Above should be enough (I guess). And again, please make one patch for each
> item.  Besides the 2nd item may introduce some code, others should be small
> changes.
> 
> And, let us forget about the names so far, just reuse what we have. Say,
> don't bother to introduce virtio_dev, just use virtio_net (well, I don't
> object to make the change now, only if you can do it elegantly). Also, let's
> stick to the rte_virtio_net.h as well: let's make it right later.
> 
> So far, just let us focus on what's need be done to make vhost-scsi work.
> Okay to you guys?

Cannot agree with this comments, as you already know that virtio_net and virtio_scsi
are different devices, why should add SCSI related logic into virtio_net file, just because
it's easy for code review?

> 
> 	--yliu
  
Yuanhan Liu Sept. 14, 2016, 5:48 a.m. UTC | #3
On Wed, Sep 14, 2016 at 04:46:21AM +0000, Liu, Changpeng wrote:
> > Few more generic comments:
> > 
> > - you touched way more code than necessary.
> > 
> > - you should split your patches into some small patches: one patch just
> >   does one tiny logic. Doing one bunch of stuff in one patch is really
> >   hard for review. For example, in patch 1, you did:
> > 
> >   * move bunch of code from here and there
> >   * besides that, you even modified the code you moved.
> >   * introduce virtio_dev_table
> >   * split virtio_net_dev and introduce virtio_dev
> >   * change some vhost user message handler, say
> > VHOST_USER_GET_QUEUE_NUM.
> >   * ...
> > 
> >   That's way too much for a single patch!
> 
> Agreed, the 2 patch set I sent as RFC purpose, I will break it into small patches at last. 

If you want to let others to get your point easily, you should breat it
in the beginning, even for RFC.

> 
> > 
> >   If you think some functions are not well placed, that you want to move
> >   them to somewhere else, fine, just move it. And if you want to modify
> >   few of them, that's fine, too. But you should make the changes in another
> >   patch.
> > 
> >   This helps review, and what's more importantly, it helps us to locate
> >   buggy code if any. Just assume you introduced a bug in patch 1, it's
> >   so big a patch that it's hard for human to spot it. Later, someone
> >   reported that something is broken and he make a bisect and show this
> >   patch is the culprit. However, it's so big a patch, that even we know
> >   there is a bug there, it may take a lot of time to figure out which
> >   change breaks it.
> > 
> >   If you're splitting patches properly, the bug code could even be spotted
> >   in review time.
> > 
> >   That are some generic comments about making patches to introduce something
> >   big.
> > 
> > 
> > Besides, I'd like to state again, it seems you are heading the wrong
> > direction: again, you touched way too much code than necessary to add
> > vhost-scsi support. In a rough thinking, it could be simple as:
> > 
> > - handle vring queues correctly for vhost-scsi; currently, it sticks to
> >   virtio-net queue pairs.
> > 
> > - add vring operation functions, such as dequeue/enqueue vrings, update
> >   used rings, ...
> > 
> > - add vhost-scsi messages
> > 
> > - may need change they way to trigger new_device() callback for
> >   vhost-scsi device.
> > 
> > Above should be enough (I guess). And again, please make one patch for each
> > item.  Besides the 2nd item may introduce some code, others should be small
> > changes.
> > 
> > And, let us forget about the names so far, just reuse what we have. Say,
> > don't bother to introduce virtio_dev, just use virtio_net (well, I don't
> > object to make the change now, only if you can do it elegantly). Also, let's
> > stick to the rte_virtio_net.h as well: let's make it right later.
> > 
> > So far, just let us focus on what's need be done to make vhost-scsi work.
> > Okay to you guys?
> 
> Cannot agree with this comments, as you already know that virtio_net and virtio_scsi
> are different devices, why should add SCSI related logic into virtio_net file,

Not really, I'd think most of them are common. Looking at your implemention,
you just added "struct vhost_scsi_target scsi_target" for vhost-scsi device,
and changed virt_qp_nb to virt_q_nb. You may say, I hid few more fields
from virtio_net for vhost_scsi. Well, you are using 'union', I see no big
difference.

> just because
> it's easy for code review?

No, and I said, "I don't object to make the change now, only if you can
do it elegantly". And unfortunately, you were not heading that way.

	--yliu
  

Patch

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;
+}