195615ce5SFelipe Franciosi /* 295615ce5SFelipe Franciosi * vhost-scsi-common 395615ce5SFelipe Franciosi * 495615ce5SFelipe Franciosi * Copyright (c) 2016 Nutanix Inc. All rights reserved. 595615ce5SFelipe Franciosi * 695615ce5SFelipe Franciosi * Author: 795615ce5SFelipe Franciosi * Felipe Franciosi <felipe@nutanix.com> 895615ce5SFelipe Franciosi * 995615ce5SFelipe Franciosi * This work is largely based on the "vhost-scsi" implementation by: 1095615ce5SFelipe Franciosi * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> 1195615ce5SFelipe Franciosi * Nicholas Bellinger <nab@risingtidesystems.com> 1295615ce5SFelipe Franciosi * 1395615ce5SFelipe Franciosi * This work is licensed under the terms of the GNU LGPL, version 2 or later. 1495615ce5SFelipe Franciosi * See the COPYING.LIB file in the top-level directory. 1595615ce5SFelipe Franciosi * 1695615ce5SFelipe Franciosi */ 1795615ce5SFelipe Franciosi 1895615ce5SFelipe Franciosi #include "qemu/osdep.h" 1995615ce5SFelipe Franciosi #include "qemu/error-report.h" 200b8fa32fSMarkus Armbruster #include "qemu/module.h" 2195615ce5SFelipe Franciosi #include "hw/virtio/vhost.h" 2295615ce5SFelipe Franciosi #include "hw/virtio/vhost-scsi-common.h" 2395615ce5SFelipe Franciosi #include "hw/virtio/virtio-scsi.h" 2495615ce5SFelipe Franciosi #include "hw/virtio/virtio-bus.h" 2595615ce5SFelipe Franciosi #include "hw/virtio/virtio-access.h" 2695615ce5SFelipe Franciosi #include "hw/fw-path-provider.h" 2795615ce5SFelipe Franciosi 2895615ce5SFelipe Franciosi int vhost_scsi_common_start(VHostSCSICommon *vsc) 2995615ce5SFelipe Franciosi { 3095615ce5SFelipe Franciosi int ret, i; 3195615ce5SFelipe Franciosi VirtIODevice *vdev = VIRTIO_DEVICE(vsc); 3295615ce5SFelipe Franciosi BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 3395615ce5SFelipe Franciosi VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 3495615ce5SFelipe Franciosi 35*b82526c7SLi Feng VirtIOSCSICommon *vs = (VirtIOSCSICommon *)vsc; 36*b82526c7SLi Feng 3795615ce5SFelipe Franciosi if (!k->set_guest_notifiers) { 3895615ce5SFelipe Franciosi error_report("binding does not support guest notifiers"); 3995615ce5SFelipe Franciosi return -ENOSYS; 4095615ce5SFelipe Franciosi } 4195615ce5SFelipe Franciosi 4295615ce5SFelipe Franciosi ret = vhost_dev_enable_notifiers(&vsc->dev, vdev); 4395615ce5SFelipe Franciosi if (ret < 0) { 4495615ce5SFelipe Franciosi return ret; 4595615ce5SFelipe Franciosi } 4695615ce5SFelipe Franciosi 4795615ce5SFelipe Franciosi ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, true); 4895615ce5SFelipe Franciosi if (ret < 0) { 4995615ce5SFelipe Franciosi error_report("Error binding guest notifier"); 5095615ce5SFelipe Franciosi goto err_host_notifiers; 5195615ce5SFelipe Franciosi } 5295615ce5SFelipe Franciosi 5395615ce5SFelipe Franciosi vsc->dev.acked_features = vdev->guest_features; 54*b82526c7SLi Feng 55*b82526c7SLi Feng assert(vsc->inflight == NULL); 56*b82526c7SLi Feng vsc->inflight = g_new0(struct vhost_inflight, 1); 57*b82526c7SLi Feng ret = vhost_dev_get_inflight(&vsc->dev, 58*b82526c7SLi Feng vs->conf.virtqueue_size, 59*b82526c7SLi Feng vsc->inflight); 60*b82526c7SLi Feng if (ret < 0) { 61*b82526c7SLi Feng error_report("Error get inflight: %d", -ret); 62*b82526c7SLi Feng goto err_guest_notifiers; 63*b82526c7SLi Feng } 64*b82526c7SLi Feng 65*b82526c7SLi Feng ret = vhost_dev_set_inflight(&vsc->dev, vsc->inflight); 66*b82526c7SLi Feng if (ret < 0) { 67*b82526c7SLi Feng error_report("Error set inflight: %d", -ret); 68*b82526c7SLi Feng goto err_guest_notifiers; 69*b82526c7SLi Feng } 70*b82526c7SLi Feng 7195615ce5SFelipe Franciosi ret = vhost_dev_start(&vsc->dev, vdev); 7295615ce5SFelipe Franciosi if (ret < 0) { 7395615ce5SFelipe Franciosi error_report("Error start vhost dev"); 7495615ce5SFelipe Franciosi goto err_guest_notifiers; 7595615ce5SFelipe Franciosi } 7695615ce5SFelipe Franciosi 7795615ce5SFelipe Franciosi /* guest_notifier_mask/pending not used yet, so just unmask 7895615ce5SFelipe Franciosi * everything here. virtio-pci will do the right thing by 7995615ce5SFelipe Franciosi * enabling/disabling irqfd. 8095615ce5SFelipe Franciosi */ 8195615ce5SFelipe Franciosi for (i = 0; i < vsc->dev.nvqs; i++) { 8295615ce5SFelipe Franciosi vhost_virtqueue_mask(&vsc->dev, vdev, vsc->dev.vq_index + i, false); 8395615ce5SFelipe Franciosi } 8495615ce5SFelipe Franciosi 8595615ce5SFelipe Franciosi return ret; 8695615ce5SFelipe Franciosi 8795615ce5SFelipe Franciosi err_guest_notifiers: 88*b82526c7SLi Feng g_free(vsc->inflight); 89*b82526c7SLi Feng vsc->inflight = NULL; 90*b82526c7SLi Feng 9195615ce5SFelipe Franciosi k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); 9295615ce5SFelipe Franciosi err_host_notifiers: 9395615ce5SFelipe Franciosi vhost_dev_disable_notifiers(&vsc->dev, vdev); 9495615ce5SFelipe Franciosi return ret; 9595615ce5SFelipe Franciosi } 9695615ce5SFelipe Franciosi 9795615ce5SFelipe Franciosi void vhost_scsi_common_stop(VHostSCSICommon *vsc) 9895615ce5SFelipe Franciosi { 9995615ce5SFelipe Franciosi VirtIODevice *vdev = VIRTIO_DEVICE(vsc); 10095615ce5SFelipe Franciosi BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 10195615ce5SFelipe Franciosi VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 10295615ce5SFelipe Franciosi int ret = 0; 10395615ce5SFelipe Franciosi 10495615ce5SFelipe Franciosi vhost_dev_stop(&vsc->dev, vdev); 10595615ce5SFelipe Franciosi 10695615ce5SFelipe Franciosi if (k->set_guest_notifiers) { 10795615ce5SFelipe Franciosi ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); 10895615ce5SFelipe Franciosi if (ret < 0) { 10995615ce5SFelipe Franciosi error_report("vhost guest notifier cleanup failed: %d", ret); 11095615ce5SFelipe Franciosi } 11195615ce5SFelipe Franciosi } 11295615ce5SFelipe Franciosi assert(ret >= 0); 11395615ce5SFelipe Franciosi 114*b82526c7SLi Feng if (vsc->inflight) { 115*b82526c7SLi Feng vhost_dev_free_inflight(vsc->inflight); 116*b82526c7SLi Feng vsc->inflight = NULL; 117*b82526c7SLi Feng } 118*b82526c7SLi Feng 11995615ce5SFelipe Franciosi vhost_dev_disable_notifiers(&vsc->dev, vdev); 12095615ce5SFelipe Franciosi } 12195615ce5SFelipe Franciosi 12295615ce5SFelipe Franciosi uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features, 12395615ce5SFelipe Franciosi Error **errp) 12495615ce5SFelipe Franciosi { 12595615ce5SFelipe Franciosi VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev); 12695615ce5SFelipe Franciosi 127b1110d83SGreg Edwards /* Turn on predefined features supported by this device */ 128b1110d83SGreg Edwards features |= vsc->host_features; 129b1110d83SGreg Edwards 13095615ce5SFelipe Franciosi return vhost_get_features(&vsc->dev, vsc->feature_bits, features); 13195615ce5SFelipe Franciosi } 13295615ce5SFelipe Franciosi 13395615ce5SFelipe Franciosi void vhost_scsi_common_set_config(VirtIODevice *vdev, const uint8_t *config) 13495615ce5SFelipe Franciosi { 13595615ce5SFelipe Franciosi VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; 13695615ce5SFelipe Franciosi VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); 13795615ce5SFelipe Franciosi 13895615ce5SFelipe Franciosi if ((uint32_t)virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size || 13995615ce5SFelipe Franciosi (uint32_t)virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) { 14095615ce5SFelipe Franciosi error_report("vhost-scsi does not support changing the sense data and " 14195615ce5SFelipe Franciosi "CDB sizes"); 14295615ce5SFelipe Franciosi exit(1); 14395615ce5SFelipe Franciosi } 14495615ce5SFelipe Franciosi } 14595615ce5SFelipe Franciosi 14695615ce5SFelipe Franciosi /* 14795615ce5SFelipe Franciosi * Implementation of an interface to adjust firmware path 14895615ce5SFelipe Franciosi * for the bootindex property handling. 14995615ce5SFelipe Franciosi */ 15095615ce5SFelipe Franciosi char *vhost_scsi_common_get_fw_dev_path(FWPathProvider *p, BusState *bus, 15195615ce5SFelipe Franciosi DeviceState *dev) 15295615ce5SFelipe Franciosi { 15395615ce5SFelipe Franciosi VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev); 15495615ce5SFelipe Franciosi /* format: /channel@channel/vhost-scsi@target,lun */ 15595615ce5SFelipe Franciosi return g_strdup_printf("/channel@%x/%s@%x,%x", vsc->channel, 15695615ce5SFelipe Franciosi qdev_fw_name(dev), vsc->target, vsc->lun); 15795615ce5SFelipe Franciosi } 15895615ce5SFelipe Franciosi 15995615ce5SFelipe Franciosi static const TypeInfo vhost_scsi_common_info = { 16095615ce5SFelipe Franciosi .name = TYPE_VHOST_SCSI_COMMON, 16195615ce5SFelipe Franciosi .parent = TYPE_VIRTIO_SCSI_COMMON, 16295615ce5SFelipe Franciosi .instance_size = sizeof(VHostSCSICommon), 16395615ce5SFelipe Franciosi .abstract = true, 16495615ce5SFelipe Franciosi }; 16595615ce5SFelipe Franciosi 16695615ce5SFelipe Franciosi static void virtio_register_types(void) 16795615ce5SFelipe Franciosi { 16895615ce5SFelipe Franciosi type_register_static(&vhost_scsi_common_info); 16995615ce5SFelipe Franciosi } 17095615ce5SFelipe Franciosi 17195615ce5SFelipe Franciosi type_init(virtio_register_types) 172