qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vhost-user-scsi.c (7386B)


      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 */
     34 static 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     VIRTIO_F_RING_RESET,
     40     VHOST_INVALID_FEATURE_BIT
     41 };
     42 
     43 enum VhostUserProtocolFeature {
     44     VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13,
     45 };
     46 
     47 static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
     48 {
     49     VHostUserSCSI *s = (VHostUserSCSI *)vdev;
     50     VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
     51     bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running;
     52 
     53     if (vhost_dev_is_started(&vsc->dev) == start) {
     54         return;
     55     }
     56 
     57     if (start) {
     58         int ret;
     59 
     60         ret = vhost_scsi_common_start(vsc);
     61         if (ret < 0) {
     62             error_report("unable to start vhost-user-scsi: %s", strerror(-ret));
     63             exit(1);
     64         }
     65     } else {
     66         vhost_scsi_common_stop(vsc);
     67     }
     68 }
     69 
     70 static void vhost_user_scsi_reset(VirtIODevice *vdev)
     71 {
     72     VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev);
     73     struct vhost_dev *dev = &vsc->dev;
     74 
     75     /*
     76      * Historically, reset was not implemented so only reset devices
     77      * that are expecting it.
     78      */
     79     if (!virtio_has_feature(dev->protocol_features,
     80                             VHOST_USER_PROTOCOL_F_RESET_DEVICE)) {
     81         return;
     82     }
     83 
     84     if (dev->vhost_ops->vhost_reset_device) {
     85         dev->vhost_ops->vhost_reset_device(dev);
     86     }
     87 }
     88 
     89 static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
     90 {
     91 }
     92 
     93 static void vhost_user_scsi_realize(DeviceState *dev, Error **errp)
     94 {
     95     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
     96     VHostUserSCSI *s = VHOST_USER_SCSI(dev);
     97     VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
     98     struct vhost_virtqueue *vqs = NULL;
     99     Error *err = NULL;
    100     int ret;
    101 
    102     if (!vs->conf.chardev.chr) {
    103         error_setg(errp, "vhost-user-scsi: missing chardev");
    104         return;
    105     }
    106 
    107     virtio_scsi_common_realize(dev, vhost_dummy_handle_output,
    108                                vhost_dummy_handle_output,
    109                                vhost_dummy_handle_output, &err);
    110     if (err != NULL) {
    111         error_propagate(errp, err);
    112         return;
    113     }
    114 
    115     if (!vhost_user_init(&s->vhost_user, &vs->conf.chardev, errp)) {
    116         goto free_virtio;
    117     }
    118 
    119     vsc->dev.nvqs = VIRTIO_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
    120     vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs);
    121     vsc->dev.vq_index = 0;
    122     vsc->dev.backend_features = 0;
    123     vqs = vsc->dev.vqs;
    124 
    125     ret = vhost_dev_init(&vsc->dev, &s->vhost_user,
    126                          VHOST_BACKEND_TYPE_USER, 0, errp);
    127     if (ret < 0) {
    128         goto free_vhost;
    129     }
    130 
    131     /* Channel and lun both are 0 for bootable vhost-user-scsi disk */
    132     vsc->channel = 0;
    133     vsc->lun = 0;
    134     vsc->target = vs->conf.boot_tpgt;
    135 
    136     return;
    137 
    138 free_vhost:
    139     vhost_user_cleanup(&s->vhost_user);
    140     g_free(vqs);
    141 free_virtio:
    142     virtio_scsi_common_unrealize(dev);
    143 }
    144 
    145 static void vhost_user_scsi_unrealize(DeviceState *dev)
    146 {
    147     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    148     VHostUserSCSI *s = VHOST_USER_SCSI(dev);
    149     VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
    150     struct vhost_virtqueue *vqs = vsc->dev.vqs;
    151 
    152     /* This will stop the vhost backend. */
    153     vhost_user_scsi_set_status(vdev, 0);
    154 
    155     vhost_dev_cleanup(&vsc->dev);
    156     g_free(vqs);
    157 
    158     virtio_scsi_common_unrealize(dev);
    159     vhost_user_cleanup(&s->vhost_user);
    160 }
    161 
    162 static Property vhost_user_scsi_properties[] = {
    163     DEFINE_PROP_CHR("chardev", VirtIOSCSICommon, conf.chardev),
    164     DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
    165     DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues,
    166                        VIRTIO_SCSI_AUTO_NUM_QUEUES),
    167     DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
    168                        128),
    169     DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
    170                        0xFFFF),
    171     DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
    172     DEFINE_PROP_BIT64("hotplug", VHostSCSICommon, host_features,
    173                                                   VIRTIO_SCSI_F_HOTPLUG,
    174                                                   true),
    175     DEFINE_PROP_BIT64("param_change", VHostSCSICommon, host_features,
    176                                                        VIRTIO_SCSI_F_CHANGE,
    177                                                        true),
    178     DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
    179                                                  VIRTIO_SCSI_F_T10_PI,
    180                                                  false),
    181     DEFINE_PROP_END_OF_LIST(),
    182 };
    183 
    184 static const VMStateDescription vmstate_vhost_scsi = {
    185     .name = "virtio-scsi",
    186     .minimum_version_id = 1,
    187     .version_id = 1,
    188     .fields = (VMStateField[]) {
    189         VMSTATE_VIRTIO_DEVICE,
    190         VMSTATE_END_OF_LIST()
    191     },
    192 };
    193 
    194 static void vhost_user_scsi_class_init(ObjectClass *klass, void *data)
    195 {
    196     DeviceClass *dc = DEVICE_CLASS(klass);
    197     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
    198     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass);
    199 
    200     device_class_set_props(dc, vhost_user_scsi_properties);
    201     dc->vmsd = &vmstate_vhost_scsi;
    202     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
    203     vdc->realize = vhost_user_scsi_realize;
    204     vdc->unrealize = vhost_user_scsi_unrealize;
    205     vdc->get_features = vhost_scsi_common_get_features;
    206     vdc->set_config = vhost_scsi_common_set_config;
    207     vdc->set_status = vhost_user_scsi_set_status;
    208     vdc->reset = vhost_user_scsi_reset;
    209     fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
    210 }
    211 
    212 static void vhost_user_scsi_instance_init(Object *obj)
    213 {
    214     VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj);
    215 
    216     vsc->feature_bits = user_feature_bits;
    217 
    218     /* Add the bootindex property for this object */
    219     device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL,
    220                                   DEVICE(vsc));
    221 }
    222 
    223 static const TypeInfo vhost_user_scsi_info = {
    224     .name = TYPE_VHOST_USER_SCSI,
    225     .parent = TYPE_VHOST_SCSI_COMMON,
    226     .instance_size = sizeof(VHostUserSCSI),
    227     .class_init = vhost_user_scsi_class_init,
    228     .instance_init = vhost_user_scsi_instance_init,
    229     .interfaces = (InterfaceInfo[]) {
    230         { TYPE_FW_PATH_PROVIDER },
    231         { }
    232     },
    233 };
    234 
    235 static void virtio_register_types(void)
    236 {
    237     type_register_static(&vhost_user_scsi_info);
    238 }
    239 
    240 type_init(virtio_register_types)