cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

vhost-user-scsi.c (7346B)


      1/*
      2 * vhost-user-scsi host device
      3 *
      4 * Copyright (c) 2016 Nutanix Inc. All rights reserved.
      5 *
      6 * Author:
      7 *  Felipe Franciosi <felipe@nutanix.com>
      8 *
      9 * This work is largely based on the "vhost-scsi" implementation by:
     10 *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
     11 *  Nicholas Bellinger <nab@risingtidesystems.com>
     12 *
     13 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
     14 * See the COPYING.LIB file in the top-level directory.
     15 *
     16 */
     17
     18#include "qemu/osdep.h"
     19#include "qapi/error.h"
     20#include "qemu/error-report.h"
     21#include "hw/fw-path-provider.h"
     22#include "hw/qdev-core.h"
     23#include "hw/qdev-properties.h"
     24#include "hw/qdev-properties-system.h"
     25#include "hw/virtio/vhost.h"
     26#include "hw/virtio/vhost-backend.h"
     27#include "hw/virtio/vhost-user-scsi.h"
     28#include "hw/virtio/virtio.h"
     29#include "hw/virtio/virtio-access.h"
     30#include "chardev/char-fe.h"
     31#include "sysemu/sysemu.h"
     32
     33/* Features supported by the host application */
     34static const int user_feature_bits[] = {
     35    VIRTIO_F_NOTIFY_ON_EMPTY,
     36    VIRTIO_RING_F_INDIRECT_DESC,
     37    VIRTIO_RING_F_EVENT_IDX,
     38    VIRTIO_SCSI_F_HOTPLUG,
     39    VHOST_INVALID_FEATURE_BIT
     40};
     41
     42enum VhostUserProtocolFeature {
     43    VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13,
     44};
     45
     46static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
     47{
     48    VHostUserSCSI *s = (VHostUserSCSI *)vdev;
     49    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
     50    bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running;
     51
     52    if (vsc->dev.started == start) {
     53        return;
     54    }
     55
     56    if (start) {
     57        int ret;
     58
     59        ret = vhost_scsi_common_start(vsc);
     60        if (ret < 0) {
     61            error_report("unable to start vhost-user-scsi: %s", strerror(-ret));
     62            exit(1);
     63        }
     64    } else {
     65        vhost_scsi_common_stop(vsc);
     66    }
     67}
     68
     69static void vhost_user_scsi_reset(VirtIODevice *vdev)
     70{
     71    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev);
     72    struct vhost_dev *dev = &vsc->dev;
     73
     74    /*
     75     * Historically, reset was not implemented so only reset devices
     76     * that are expecting it.
     77     */
     78    if (!virtio_has_feature(dev->protocol_features,
     79                            VHOST_USER_PROTOCOL_F_RESET_DEVICE)) {
     80        return;
     81    }
     82
     83    if (dev->vhost_ops->vhost_reset_device) {
     84        dev->vhost_ops->vhost_reset_device(dev);
     85    }
     86}
     87
     88static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
     89{
     90}
     91
     92static void vhost_user_scsi_realize(DeviceState *dev, Error **errp)
     93{
     94    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
     95    VHostUserSCSI *s = VHOST_USER_SCSI(dev);
     96    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
     97    struct vhost_virtqueue *vqs = NULL;
     98    Error *err = NULL;
     99    int ret;
    100
    101    if (!vs->conf.chardev.chr) {
    102        error_setg(errp, "vhost-user-scsi: missing chardev");
    103        return;
    104    }
    105
    106    virtio_scsi_common_realize(dev, vhost_dummy_handle_output,
    107                               vhost_dummy_handle_output,
    108                               vhost_dummy_handle_output, &err);
    109    if (err != NULL) {
    110        error_propagate(errp, err);
    111        return;
    112    }
    113
    114    if (!vhost_user_init(&s->vhost_user, &vs->conf.chardev, errp)) {
    115        goto free_virtio;
    116    }
    117
    118    vsc->dev.nvqs = VIRTIO_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
    119    vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs);
    120    vsc->dev.vq_index = 0;
    121    vsc->dev.backend_features = 0;
    122    vqs = vsc->dev.vqs;
    123
    124    ret = vhost_dev_init(&vsc->dev, &s->vhost_user,
    125                         VHOST_BACKEND_TYPE_USER, 0, errp);
    126    if (ret < 0) {
    127        goto free_vhost;
    128    }
    129
    130    /* Channel and lun both are 0 for bootable vhost-user-scsi disk */
    131    vsc->channel = 0;
    132    vsc->lun = 0;
    133    vsc->target = vs->conf.boot_tpgt;
    134
    135    return;
    136
    137free_vhost:
    138    vhost_user_cleanup(&s->vhost_user);
    139    g_free(vqs);
    140free_virtio:
    141    virtio_scsi_common_unrealize(dev);
    142}
    143
    144static void vhost_user_scsi_unrealize(DeviceState *dev)
    145{
    146    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    147    VHostUserSCSI *s = VHOST_USER_SCSI(dev);
    148    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
    149    struct vhost_virtqueue *vqs = vsc->dev.vqs;
    150
    151    /* This will stop the vhost backend. */
    152    vhost_user_scsi_set_status(vdev, 0);
    153
    154    vhost_dev_cleanup(&vsc->dev);
    155    g_free(vqs);
    156
    157    virtio_scsi_common_unrealize(dev);
    158    vhost_user_cleanup(&s->vhost_user);
    159}
    160
    161static Property vhost_user_scsi_properties[] = {
    162    DEFINE_PROP_CHR("chardev", VirtIOSCSICommon, conf.chardev),
    163    DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
    164    DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues,
    165                       VIRTIO_SCSI_AUTO_NUM_QUEUES),
    166    DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
    167                       128),
    168    DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
    169                       0xFFFF),
    170    DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
    171    DEFINE_PROP_BIT64("hotplug", VHostSCSICommon, host_features,
    172                                                  VIRTIO_SCSI_F_HOTPLUG,
    173                                                  true),
    174    DEFINE_PROP_BIT64("param_change", VHostSCSICommon, host_features,
    175                                                       VIRTIO_SCSI_F_CHANGE,
    176                                                       true),
    177    DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
    178                                                 VIRTIO_SCSI_F_T10_PI,
    179                                                 false),
    180    DEFINE_PROP_END_OF_LIST(),
    181};
    182
    183static const VMStateDescription vmstate_vhost_scsi = {
    184    .name = "virtio-scsi",
    185    .minimum_version_id = 1,
    186    .version_id = 1,
    187    .fields = (VMStateField[]) {
    188        VMSTATE_VIRTIO_DEVICE,
    189        VMSTATE_END_OF_LIST()
    190    },
    191};
    192
    193static void vhost_user_scsi_class_init(ObjectClass *klass, void *data)
    194{
    195    DeviceClass *dc = DEVICE_CLASS(klass);
    196    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
    197    FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass);
    198
    199    device_class_set_props(dc, vhost_user_scsi_properties);
    200    dc->vmsd = &vmstate_vhost_scsi;
    201    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
    202    vdc->realize = vhost_user_scsi_realize;
    203    vdc->unrealize = vhost_user_scsi_unrealize;
    204    vdc->get_features = vhost_scsi_common_get_features;
    205    vdc->set_config = vhost_scsi_common_set_config;
    206    vdc->set_status = vhost_user_scsi_set_status;
    207    vdc->reset = vhost_user_scsi_reset;
    208    fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
    209}
    210
    211static void vhost_user_scsi_instance_init(Object *obj)
    212{
    213    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj);
    214
    215    vsc->feature_bits = user_feature_bits;
    216
    217    /* Add the bootindex property for this object */
    218    device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL,
    219                                  DEVICE(vsc));
    220}
    221
    222static const TypeInfo vhost_user_scsi_info = {
    223    .name = TYPE_VHOST_USER_SCSI,
    224    .parent = TYPE_VHOST_SCSI_COMMON,
    225    .instance_size = sizeof(VHostUserSCSI),
    226    .class_init = vhost_user_scsi_class_init,
    227    .instance_init = vhost_user_scsi_instance_init,
    228    .interfaces = (InterfaceInfo[]) {
    229        { TYPE_FW_PATH_PROVIDER },
    230        { }
    231    },
    232};
    233
    234static void virtio_register_types(void)
    235{
    236    type_register_static(&vhost_user_scsi_info);
    237}
    238
    239type_init(virtio_register_types)