@@ -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
@@ -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! */
@@ -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() \
{}
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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
@@ -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;
@@ -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,
};
@@ -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:)
@@ -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();