Patchwork [11/16] vhost-scsi: add -vhost-scsi host device

login
register
mail settings
Submitter Zhiyong Wu
Date April 19, 2012, 2:39 a.m.
Message ID <1334803149-27379-12-git-send-email-zwu.kernel@gmail.com>
Download mbox | patch
Permalink /patch/153643/
State New
Headers show

Comments

Zhiyong Wu - April 19, 2012, 2:39 a.m.
From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>

This patch adds a new type of host device that drives the vhost_scsi
device.  The syntax to add vhost-scsi is:

  qemu -vhost-scsi id=vhost-scsi0,wwpn=...,tpgt=123

The virtio-scsi emulated device will make use of vhost-scsi to process
virtio-scsi requests inside the kernel and hand them to the in-kernel
SCSI target stack.

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com>
---
 Makefile.target      |    2 +-
 hw/qdev-properties.c |   32 ++++++++++++
 hw/qdev.h            |    3 +
 hw/vhost-scsi.c      |  131 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/vhost-scsi.h      |   28 +++++++++++
 qemu-common.h        |    1 +
 qemu-config.c        |   16 ++++++
 qemu-options.hx      |    4 ++
 vl.c                 |   18 +++++++
 9 files changed, 234 insertions(+), 1 deletions(-)
 create mode 100644 hw/vhost-scsi.c
 create mode 100644 hw/vhost-scsi.h

Patch

diff --git a/Makefile.target b/Makefile.target
index 84951a0..d748f94 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -219,7 +219,7 @@  obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o
 obj-$(CONFIG_NO_PCI) += pci-stub.o
 obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
 obj-$(CONFIG_VIRTIO) += virtio-scsi.o
-obj-y += vhost_net.o
+obj-y += vhost_net.o vhost-scsi.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
 obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 98dd06a..2a108a0 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -2,6 +2,7 @@ 
 #include "qdev.h"
 #include "qerror.h"
 #include "blockdev.h"
+#include "vhost-scsi.h"
 
 void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
 {
@@ -688,6 +689,37 @@  PropertyInfo qdev_prop_vlan = {
     .set   = set_vlan,
 };
 
+/* --- vhost-scsi --- */
+
+static int parse_vhost_scsi(DeviceState *dev, Property *prop, const char *str)
+{
+    VHostSCSI **ptr = qdev_get_prop_ptr(dev, prop);
+
+    *ptr = find_vhost_scsi(str);
+    if (*ptr == NULL) {
+        return -ENOENT;
+    }
+    return 0;
+}
+
+static int print_vhost_scsi(DeviceState *dev, Property *prop,
+                            char *dest, size_t len)
+{
+    VHostSCSI **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr) {
+        return snprintf(dest, len, "%s", vhost_scsi_get_id(*ptr));
+    } else {
+        return snprintf(dest, len, "<null>");
+    }
+}
+
+PropertyInfo qdev_prop_vhost_scsi = {
+    .name  = "vhost-scsi",
+    .parse = parse_vhost_scsi,
+    .print = print_vhost_scsi,
+};
+
 /* --- pointer --- */
 
 /* Not a proper property, just for dirty hacks.  TODO Remove it!  */
diff --git a/hw/qdev.h b/hw/qdev.h
index 4e90119..dc51678 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -225,6 +225,7 @@  extern PropertyInfo qdev_prop_netdev;
 extern PropertyInfo qdev_prop_vlan;
 extern PropertyInfo qdev_prop_pci_devfn;
 extern PropertyInfo qdev_prop_blocksize;
+extern PropertyInfo qdev_prop_vhost_scsi;
 
 #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
         .name      = (_name),                                    \
@@ -288,6 +289,8 @@  extern PropertyInfo qdev_prop_blocksize;
                         LostTickPolicy)
 #define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
     DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
+#define DEFINE_PROP_VHOST_SCSI(_n, _s, _f)      \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_vhost_scsi, VHostSCSI*)
 
 #define DEFINE_PROP_END_OF_LIST()               \
     {}
diff --git a/hw/vhost-scsi.c b/hw/vhost-scsi.c
new file mode 100644
index 0000000..6e3645f
--- /dev/null
+++ b/hw/vhost-scsi.c
@@ -0,0 +1,131 @@ 
+/*
+ * vhost_scsi host device
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "config.h"
+#include "qemu-queue.h"
+#include "vhost-scsi.h"
+#include "vhost.h"
+
+struct VHostSCSI {
+    const char *id;
+    const char *wwpn;
+    uint16_t tpgt;
+    struct vhost_dev dev;
+    struct vhost_virtqueue vqs[3];
+    QLIST_ENTRY(VHostSCSI) list;
+};
+
+static QLIST_HEAD(, VHostSCSI) vhost_scsi_list =
+    QLIST_HEAD_INITIALIZER(vhost_scsi_list);
+
+VHostSCSI *find_vhost_scsi(const char *id)
+{
+    VHostSCSI *vs;
+
+    QLIST_FOREACH(vs, &vhost_scsi_list, list) {
+        if (strcmp(id, vs->id) == 0) {
+            return vs;
+        }
+    }
+    return NULL;
+}
+
+const char *vhost_scsi_get_id(VHostSCSI *vs)
+{
+    return vs->id;
+}
+
+int vhost_scsi_start(VHostSCSI *vs, VirtIODevice *vdev)
+{
+    int ret;
+
+    if (!vhost_dev_query(&vs->dev, vdev)) {
+        return -ENOTSUP;
+    }
+
+    vs->dev.nvqs = 3;
+    vs->dev.vqs = vs->vqs;
+    ret = vhost_dev_start(&vs->dev, vdev);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* TODO set wwpn and tpgt */
+    fprintf(stderr, "vhost_scsi_start\n");
+    return 0;
+}
+
+void vhost_scsi_stop(VHostSCSI *vs, VirtIODevice *vdev)
+{
+    fprintf(stderr, "vhost_scsi_stop\n");
+    /* TODO clear wwpn and tpgt */
+
+    vhost_dev_stop(&vs->dev, vdev);
+}
+
+static VHostSCSI *vhost_scsi_add(const char *id, const char *wwpn,
+                                 uint16_t tpgt)
+{
+    VHostSCSI *vs = g_malloc0(sizeof(*vs));
+    int ret;
+
+    /* TODO set up vhost-scsi device and bind to tcm_vhost/$wwpm/tpgt_$tpgt */
+    fprintf(stderr, "wwpn = \"%s\" tpgt = \"%u\"\n", id, tpgt);
+
+    ret = vhost_dev_init(&vs->dev, -1, "/dev/vhost-scsi", false);
+    if (ret < 0) {
+        fprintf(stderr, "vhost-scsi: vhost initialization failed: %s\n",
+                strerror(-ret));
+        return NULL;
+    }
+    vs->dev.backend_features = 0;
+    vs->dev.acked_features = 0;
+
+    vs->id = g_strdup(id);
+    vs->wwpn = g_strdup(wwpn);
+    vs->tpgt = tpgt;
+    QLIST_INSERT_HEAD(&vhost_scsi_list, vs, list);
+
+    return vs;
+}
+
+VHostSCSI *vhost_scsi_add_opts(QemuOpts *opts)
+{
+    const char *id;
+    const char *wwpn;
+    uint64_t tpgt;
+
+    id = qemu_opts_id(opts);
+    if (!id) {
+        fprintf(stderr, "vhost-scsi: no id specified\n");
+        return NULL;
+    }
+    if (find_vhost_scsi(id)) {
+        fprintf(stderr, "duplicate vhost-scsi: \"%s\"\n", id);
+        return NULL;
+    }
+
+    wwpn = qemu_opt_get(opts, "wwpn");
+    if (!wwpn) {
+        fprintf(stderr, "vhost-scsi: \"%s\" missing wwpn\n", id);
+        return NULL;
+    }
+
+    tpgt = qemu_opt_get_number(opts, "tpgt", UINT64_MAX);
+    if (tpgt > UINT16_MAX) {
+        fprintf(stderr, "vhost-scsi: \"%s\" needs a 16-bit tpgt\n", id);
+        return NULL;
+    }
+
+    return vhost_scsi_add(id, wwpn, tpgt);
+}
diff --git a/hw/vhost-scsi.h b/hw/vhost-scsi.h
new file mode 100644
index 0000000..e5e67e3
--- /dev/null
+++ b/hw/vhost-scsi.h
@@ -0,0 +1,28 @@ 
+/*
+ * vhost_scsi host device
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#ifndef VHOST_SCSI_H
+#define VHOST_SCSI_H
+
+#include "qemu-common.h"
+#include "qemu-option.h"
+
+VHostSCSI *find_vhost_scsi(const char *id);
+const char *vhost_scsi_get_id(VHostSCSI *vs);
+
+VHostSCSI *vhost_scsi_add_opts(QemuOpts *opts);
+
+int vhost_scsi_start(VHostSCSI *vs, VirtIODevice *vdev);
+void vhost_scsi_stop(VHostSCSI *vs, VirtIODevice *vdev);
+
+#endif
diff --git a/qemu-common.h b/qemu-common.h
index 50f659a..3bf4895 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -259,6 +259,7 @@  typedef struct EventNotifier EventNotifier;
 typedef struct VirtIODevice VirtIODevice;
 typedef struct QEMUSGList QEMUSGList;
 typedef struct SHPCDevice SHPCDevice;
+typedef struct VHostSCSI VHostSCSI;
 
 typedef uint64_t pcibus_t;
 
diff --git a/qemu-config.c b/qemu-config.c
index be84a03..fffcbcc 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -613,6 +613,21 @@  QemuOptsList qemu_boot_opts = {
     },
 };
 
+QemuOptsList qemu_vhost_scsi_opts = {
+    .name = "vhost-scsi",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_vhost_scsi_opts.head),
+    .desc = {
+        {
+            .name = "wwpn",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "tpgt",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
 static QemuOptsList *vm_config_groups[32] = {
     &qemu_drive_opts,
     &qemu_chardev_opts,
@@ -628,6 +643,7 @@  static QemuOptsList *vm_config_groups[32] = {
     &qemu_machine_opts,
     &qemu_boot_opts,
     &qemu_iscsi_opts,
+    &qemu_vhost_scsi_opts,
     NULL,
 };
 
diff --git a/qemu-options.hx b/qemu-options.hx
index a169792..1a580d8 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -561,6 +561,10 @@  possible drivers and properties, use @code{-device ?} and
 ETEXI
 
 DEFHEADING()
+DEF("vhost-scsi", HAS_ARG, QEMU_OPTION_vhost_scsi,
+    "-virtio-scsi wwpn=string0,tpgt=number0\n"
+    "                add vhost-scsi device\n",
+    QEMU_ARCH_ALL)
 
 DEFHEADING(File system options:)
 
diff --git a/vl.c b/vl.c
index ae91a8a..221a294 100644
--- a/vl.c
+++ b/vl.c
@@ -149,6 +149,7 @@  int main(int argc, char **argv)
 #include "qemu-options.h"
 #include "qmp-commands.h"
 #include "main-loop.h"
+#include "hw/vhost-scsi.h"
 #ifdef CONFIG_VIRTFS
 #include "fsdev/qemu-fsdev.h"
 #endif
@@ -1850,6 +1851,14 @@  static int fsdev_init_func(QemuOpts *opts, void *opaque)
 }
 #endif
 
+static int vhost_scsi_init_func(QemuOpts *opts, void *opaque)
+{
+    if (!vhost_scsi_add_opts(opts)) {
+        return -1;
+    }
+    return 0;
+}
+
 static int mon_init_func(QemuOpts *opts, void *opaque)
 {
     CharDriverState *chr;
@@ -2611,6 +2620,11 @@  int main(int argc, char **argv, char **envp)
                 }
                 break;
 #endif
+            case QEMU_OPTION_vhost_scsi:
+                if (!qemu_opts_parse(qemu_find_opts("vhost-scsi"), optarg, 0)) {
+                    exit(1);
+                }
+                break;
 #ifdef CONFIG_SLIRP
             case QEMU_OPTION_tftp:
                 legacy_tftp_prefix = optarg;
@@ -3322,6 +3336,10 @@  int main(int argc, char **argv, char **envp)
         exit(1);
     }
 #endif
+    if (qemu_opts_foreach(qemu_find_opts("vhost-scsi"),
+                          vhost_scsi_init_func, NULL, 1)) {
+        exit(1);
+    }
 
     os_daemonize();