From patchwork Thu Sep 15 00:28:18 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Liu, Changpeng" X-Patchwork-Id: 15792 X-Patchwork-Delegate: yuanhan.liu@linux.intel.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id E171E7F2D; Wed, 14 Sep 2016 02:20:26 +0200 (CEST) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by dpdk.org (Postfix) with ESMTP id BA93F72FB for ; Wed, 14 Sep 2016 02:20:21 +0200 (CEST) Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga103.fm.intel.com with ESMTP; 13 Sep 2016 17:20:20 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.30,331,1470726000"; d="scan'208";a="8082918" Received: from fedora.sh.intel.com ([10.239.67.161]) by fmsmga006.fm.intel.com with ESMTP; 13 Sep 2016 17:20:18 -0700 From: Changpeng Liu To: dev@dpdk.org Cc: yuanhan.liu@intel.com, james.r.harris@intel.com Date: Thu, 15 Sep 2016 08:28:18 +0800 Message-Id: <1473899298-4580-2-git-send-email-changpeng.liu@intel.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1473899298-4580-1-git-send-email-changpeng.liu@intel.com> References: <1473855300-3066-1-git-send-email-changpeng.liu@intel.com> <1473899298-4580-1-git-send-email-changpeng.liu@intel.com> Subject: [dpdk-dev] [PATCH v2 2/2] vhost: add vhost-scsi support to vhost library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 --- 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +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 #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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#include + +#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 +#include +#include +#include +#include + +#include +#include +#include + +#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; +}