@@ -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
@@ -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.
new file mode 100644
@@ -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
@@ -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:
@@ -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
@@ -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;
new file mode 100644
@@ -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
new file mode 100644
@@ -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
@@ -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;
@@ -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;
new file mode 100644
@@ -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;
+}
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