From 860f78da013e7325a9d6b1155e05db2c4bf56808 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Wed, 22 Feb 2012 14:12:51 +0100
Subject: [PATCH 095/109] virtio-scsi: Add virtio-scsi stub device

RH-Author: Paolo Bonzini <pbonzini@redhat.com>
Message-id: <1329919979-20948-95-git-send-email-pbonzini@redhat.com>
Patchwork-id: 37575
O-Subject: [RHEL 6.3 qemu-kvm PATCH v2 094/102] virtio-scsi: Add virtio-scsi stub device
Bugzilla: 782029
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Orit Wasserman <owasserm@redhat.com>
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>

From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>

Add a useless virtio SCSI HBA device:

  qemu -device virtio-scsi-pci

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile.target  |    2 +-
 hw/pci.h         |    1 +
 hw/virtio-pci.c  |   43 ++++++++++
 hw/virtio-scsi.c |  228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/virtio-scsi.h |   36 +++++++++
 hw/virtio.h      |    3 +
 6 files changed, 312 insertions(+), 1 deletions(-)
 delete mode 100644 default-configs/s390x-softmmu.mak
 create mode 100644 hw/virtio-scsi.c
 create mode 100644 hw/virtio-scsi.h

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 Makefile.target  |    2 +-
 hw/pci.h         |    1 +
 hw/virtio-pci.c  |   43 ++++++++++
 hw/virtio-scsi.c |  228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/virtio-scsi.h |   36 +++++++++
 hw/virtio.h      |    3 +
 6 files changed, 312 insertions(+), 1 deletions(-)
 delete mode 100644 default-configs/s390x-softmmu.mak
 create mode 100644 hw/virtio-scsi.c
 create mode 100644 hw/virtio-scsi.h

diff --git a/Makefile.target b/Makefile.target
index fc593f7..78af60a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -205,7 +205,7 @@ obj-y = vl.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o balloon.
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
 obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o
-obj-y += event_notifier.o
+obj-y += virtio-scsi.o event_notifier.o
 obj-y += vhost_net.o
 obj-$(CONFIG_VHOST_NET) += vhost.o
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
deleted file mode 100644
index e69de29..0000000
diff --git a/hw/pci.h b/hw/pci.h
index d921702..6002492 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -76,6 +76,7 @@ extern target_phys_addr_t pci_mem_base;
 #define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
 #define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
 #define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
+#define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
 
 typedef uint64_t pcibus_t;
 #define FMT_PCIBUS                      PRIx64
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 6023196..3e7bc71 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -19,6 +19,7 @@
 #include "virtio-blk.h"
 #include "virtio-net.h"
 #include "virtio-serial.h"
+#include "virtio-scsi.h"
 #include "pci.h"
 #include "qemu-error.h"
 #include "msix.h"
@@ -105,6 +106,7 @@ typedef struct {
     uint32_t nvectors;
     BlockConf block;
     NICConf nic;
+    VirtIOSCSIConf scsi;
     uint32_t host_features;
     virtio_serial_conf serial;
     virtio_net_conf net;
@@ -924,6 +926,36 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
     return virtio_exit_pci(pci_dev);
 }
 
+static int virtio_scsi_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    vdev = virtio_scsi_init(&pci_dev->qdev, &proxy->scsi);
+    if (!vdev) {
+        return -EINVAL;
+    }
+
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev,
+                    PCI_VENDOR_ID_REDHAT_QUMRANET,
+                    PCI_DEVICE_ID_VIRTIO_SCSI,
+                    PCI_CLASS_STORAGE_SCSI,
+                    0x00);
+
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static int virtio_scsi_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_scsi_exit(proxy->vdev);
+    return virtio_exit_pci(pci_dev);
+}
+
 static PCIDeviceInfo virtio_info[] = {
     {
         .qdev.name = "virtio-blk-pci",
@@ -990,6 +1022,17 @@ static PCIDeviceInfo virtio_info[] = {
         },
         .qdev.reset = virtio_pci_reset,
     },{
+        .qdev.name = "virtio-scsi-pci",
+        .qdev.alias = "virtio-scsi",
+        .qdev.size = sizeof(VirtIOPCIProxy),
+        .init      = virtio_scsi_init_pci,
+        .exit      = virtio_scsi_exit_pci,
+        .qdev.props = (Property[]) {
+            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+            DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi),
+            DEFINE_PROP_END_OF_LIST(),
+        },
+    }, {
         /* end of list */
     }
 };
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
new file mode 100644
index 0000000..cd67281
--- /dev/null
+++ b/hw/virtio-scsi.c
@@ -0,0 +1,228 @@
+/*
+ * Virtio SCSI HBA
+ *
+ * Copyright IBM, Corp. 2010
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ *   Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *   Paolo Bonzini      <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio-scsi.h"
+#include <hw/scsi.h>
+#include <hw/scsi-defs.h>
+
+#define VIRTIO_SCSI_VQ_SIZE     128
+#define VIRTIO_SCSI_CDB_SIZE    32
+#define VIRTIO_SCSI_SENSE_SIZE  96
+#define VIRTIO_SCSI_MAX_CHANNEL	0
+#define VIRTIO_SCSI_MAX_TARGET  255
+#define VIRTIO_SCSI_MAX_LUN     16383
+
+/* Response codes */
+#define VIRTIO_SCSI_S_OK                       0
+#define VIRTIO_SCSI_S_OVERRUN                  1
+#define VIRTIO_SCSI_S_ABORTED                  2
+#define VIRTIO_SCSI_S_BAD_TARGET               3
+#define VIRTIO_SCSI_S_RESET                    4
+#define VIRTIO_SCSI_S_BUSY                     5
+#define VIRTIO_SCSI_S_TRANSPORT_FAILURE        6
+#define VIRTIO_SCSI_S_TARGET_FAILURE           7
+#define VIRTIO_SCSI_S_NEXUS_FAILURE            8
+#define VIRTIO_SCSI_S_FAILURE                  9
+#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED       10
+#define VIRTIO_SCSI_S_FUNCTION_REJECTED        11
+#define VIRTIO_SCSI_S_INCORRECT_LUN            12
+
+/* Controlq type codes.  */
+#define VIRTIO_SCSI_T_TMF                      0
+#define VIRTIO_SCSI_T_AN_QUERY                 1
+#define VIRTIO_SCSI_T_AN_SUBSCRIBE             2
+
+/* Valid TMF subtypes.  */
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK           0
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET       1
+#define VIRTIO_SCSI_T_TMF_CLEAR_ACA            2
+#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET       3
+#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET      4
+#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET   5
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK           6
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET       7
+
+/* Events.  */
+#define VIRTIO_SCSI_T_EVENTS_MISSED            0x80000000
+#define VIRTIO_SCSI_T_NO_EVENT                 0
+#define VIRTIO_SCSI_T_TRANSPORT_RESET          1
+#define VIRTIO_SCSI_T_ASYNC_NOTIFY             2
+
+/* SCSI command request, followed by data-out */
+typedef struct {
+    uint8_t lun[8];              /* Logical Unit Number */
+    uint64_t tag;                /* Command identifier */
+    uint8_t task_attr;           /* Task attribute */
+    uint8_t prio;
+    uint8_t crn;
+    uint8_t cdb[];
+} __attribute__((packed)) VirtIOSCSICmdReq;
+
+/* Response, followed by sense data and data-in */
+typedef struct {
+    uint32_t sense_len;          /* Sense data length */
+    uint32_t resid;              /* Residual bytes in data buffer */
+    uint16_t status_qualifier;   /* Status qualifier */
+    uint8_t status;              /* Command completion status */
+    uint8_t response;            /* Response values */
+    uint8_t sense[];
+} __attribute__((packed)) VirtIOSCSICmdResp;
+
+/* Task Management Request */
+typedef struct {
+    uint32_t type;
+    uint32_t subtype;
+    uint8_t lun[8];
+    uint64_t tag;
+} __attribute__((packed)) VirtIOSCSICtrlTMFReq;
+
+typedef struct {
+    uint8_t response;
+} __attribute__((packed)) VirtIOSCSICtrlTMFResp;
+
+/* Asynchronous notification query/subscription */
+typedef struct {
+    uint32_t type;
+    uint8_t lun[8];
+    uint32_t event_requested;
+} __attribute__((packed)) VirtIOSCSICtrlANReq;
+
+typedef struct {
+    uint32_t event_actual;
+    uint8_t response;
+} __attribute__((packed)) VirtIOSCSICtrlANResp;
+
+typedef struct {
+    uint32_t event;
+    uint8_t lun[8];
+    uint32_t reason;
+} __attribute__((packed)) VirtIOSCSIEvent;
+
+typedef struct {
+    uint32_t num_queues;
+    uint32_t seg_max;
+    uint32_t max_sectors;
+    uint32_t cmd_per_lun;
+    uint32_t event_info_size;
+    uint32_t sense_size;
+    uint32_t cdb_size;
+    uint16_t max_channel;
+    uint16_t max_target;
+    uint32_t max_lun;
+} __attribute__((packed)) VirtIOSCSIConfig;
+
+typedef struct {
+    VirtIODevice vdev;
+    DeviceState *qdev;
+    VirtIOSCSIConf *conf;
+
+    VirtQueue *ctrl_vq;
+    VirtQueue *event_vq;
+    VirtQueue *cmd_vq;
+    uint32_t sense_size;
+    uint32_t cdb_size;
+} VirtIOSCSI;
+
+static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /* TODO */
+}
+
+static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /* TODO */
+}
+
+static void virtio_scsi_get_config(VirtIODevice *vdev,
+                                   uint8_t *config)
+{
+    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    stl_raw(&scsiconf->num_queues, s->conf->num_queues);
+    stl_raw(&scsiconf->seg_max, 128 - 2);
+    stl_raw(&scsiconf->max_sectors, s->conf->max_sectors);
+    stl_raw(&scsiconf->cmd_per_lun, s->conf->cmd_per_lun);
+    stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
+    stl_raw(&scsiconf->sense_size, s->sense_size);
+    stl_raw(&scsiconf->cdb_size, s->cdb_size);
+    stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
+    stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
+    stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
+}
+
+static void virtio_scsi_set_config(VirtIODevice *vdev,
+                                   const uint8_t *config)
+{
+    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 ||
+        (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) {
+        error_report("bad data written to virtio-scsi configuration space");
+        exit(1);
+    }
+
+    s->sense_size = ldl_raw(&scsiconf->sense_size);
+    s->cdb_size = ldl_raw(&scsiconf->cdb_size);
+}
+
+static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
+                                         uint32_t requested_features)
+{
+    return requested_features;
+}
+
+static void virtio_scsi_reset(VirtIODevice *vdev)
+{
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
+    s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
+}
+
+VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
+{
+    VirtIOSCSI *s;
+
+    s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
+                                         sizeof(VirtIOSCSIConfig),
+                                         sizeof(VirtIOSCSI));
+
+    s->qdev = dev;
+    s->conf = proxyconf;
+
+    /* TODO set up vdev function pointers */
+    s->vdev.get_config = virtio_scsi_get_config;
+    s->vdev.set_config = virtio_scsi_set_config;
+    s->vdev.get_features = virtio_scsi_get_features;
+    s->vdev.reset = virtio_scsi_reset;
+
+    s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+                                   virtio_scsi_handle_ctrl);
+    s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+                                   NULL);
+    s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+                                   virtio_scsi_handle_cmd);
+
+    /* TODO savevm */
+
+    return &s->vdev;
+}
+
+void virtio_scsi_exit(VirtIODevice *vdev)
+{
+    virtio_cleanup(vdev);
+}
diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h
new file mode 100644
index 0000000..4bc889d
--- /dev/null
+++ b/hw/virtio-scsi.h
@@ -0,0 +1,36 @@
+/*
+ * Virtio SCSI HBA
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_SCSI_H
+#define _QEMU_VIRTIO_SCSI_H
+
+#include "virtio.h"
+#include "net.h"
+#include "pci.h"
+
+/* The ID for virtio_scsi */
+#define VIRTIO_ID_SCSI  8
+
+struct VirtIOSCSIConf {
+    uint32_t num_queues;
+    uint32_t max_sectors;
+    uint32_t cmd_per_lun;
+};
+
+#define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _features_field, _conf_field) \
+    DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \
+    DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \
+    DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \
+    DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128)
+
+#endif /* _QEMU_VIRTIO_SCSI_H */
diff --git a/hw/virtio.h b/hw/virtio.h
index 95bcb90..7ce62c9 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -200,11 +200,14 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
 typedef struct virtio_serial_conf virtio_serial_conf;
 VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
 VirtIODevice *virtio_balloon_init(DeviceState *dev);
+typedef struct VirtIOSCSIConf VirtIOSCSIConf;
+VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
 
 void virtio_net_exit(VirtIODevice *vdev);
 void virtio_blk_exit(VirtIODevice *vdev);
 void virtio_serial_exit(VirtIODevice *vdev);
 void virtio_balloon_exit(VirtIODevice *vdev);
+void virtio_scsi_exit(VirtIODevice *vdev);
 
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
-- 
1.7.7.6

