83d768b564
Dataplane has been omitting forever the step of setting ISR when an interrupt is raised. This caused little breakage, because the specification actually says that ISR may not be updated in MSI mode. Some versions of the Windows drivers however didn't clear MSI mode correctly, and proceeded using polling mode (using ISR, not the used ring index!) for crashdump and hibernation. If it were just crashdump and hibernation it would not be a big deal, but recent releases of Windows do not really shut down, but rather log out and hibernate to make the next startup faster. Hence, this manifested as a more serious hang during shutdown with e.g. Windows 8.1 and virtio-win 1.8.0 RPMs. Newer versions fixed this, while older versions do not use MSI at all. The failure has always been there for virtio dataplane, but it became visible after commits9ffe337
("virtio-blk: always use dataplane path if ioeventfd is active", 2016-10-30) andad07cd6
("virtio-scsi: always use dataplane path if ioeventfd is active", 2016-10-30) made virtio-blk and virtio-scsi always use the dataplane code under KVM. The good news therefore is that it was not a bug in the patches---they were doing exactly what they were meant for, i.e. shake out remaining dataplane bugs. The fix is not hard, so it's worth arranging for the broken drivers. The virtio_should_notify+event_notifier_set pair that is common to virtio-blk and virtio-scsi dataplane is replaced with a new public function virtio_notify_irqfd that also sets ISR. The irqfd emulation code now need not set ISR anymore, so virtio_irq is removed. Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Tested-by: Farhan Ali <alifm@linux.vnet.ibm.com> Tested-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
142 lines
4.0 KiB
C
142 lines
4.0 KiB
C
/*
|
|
* 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
|
|
|
|
/* Override CDB/sense data size: they are dynamic (guest controlled) in QEMU */
|
|
#define VIRTIO_SCSI_CDB_SIZE 0
|
|
#define VIRTIO_SCSI_SENSE_SIZE 0
|
|
#include "standard-headers/linux/virtio_scsi.h"
|
|
#include "hw/virtio/virtio.h"
|
|
#include "hw/pci/pci.h"
|
|
#include "hw/scsi/scsi.h"
|
|
#include "sysemu/iothread.h"
|
|
|
|
#define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common"
|
|
#define VIRTIO_SCSI_COMMON(obj) \
|
|
OBJECT_CHECK(VirtIOSCSICommon, (obj), TYPE_VIRTIO_SCSI_COMMON)
|
|
|
|
#define TYPE_VIRTIO_SCSI "virtio-scsi-device"
|
|
#define VIRTIO_SCSI(obj) \
|
|
OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI)
|
|
|
|
#define VIRTIO_SCSI_VQ_SIZE 128
|
|
#define VIRTIO_SCSI_MAX_CHANNEL 0
|
|
#define VIRTIO_SCSI_MAX_TARGET 255
|
|
#define VIRTIO_SCSI_MAX_LUN 16383
|
|
|
|
typedef struct virtio_scsi_cmd_req VirtIOSCSICmdReq;
|
|
typedef struct virtio_scsi_cmd_resp VirtIOSCSICmdResp;
|
|
typedef struct virtio_scsi_ctrl_tmf_req VirtIOSCSICtrlTMFReq;
|
|
typedef struct virtio_scsi_ctrl_tmf_resp VirtIOSCSICtrlTMFResp;
|
|
typedef struct virtio_scsi_ctrl_an_req VirtIOSCSICtrlANReq;
|
|
typedef struct virtio_scsi_ctrl_an_resp VirtIOSCSICtrlANResp;
|
|
typedef struct virtio_scsi_event VirtIOSCSIEvent;
|
|
typedef struct virtio_scsi_config VirtIOSCSIConfig;
|
|
|
|
struct VirtIOSCSIConf {
|
|
uint32_t num_queues;
|
|
uint32_t max_sectors;
|
|
uint32_t cmd_per_lun;
|
|
char *vhostfd;
|
|
char *wwpn;
|
|
uint32_t boot_tpgt;
|
|
IOThread *iothread;
|
|
};
|
|
|
|
struct VirtIOSCSI;
|
|
|
|
typedef struct VirtIOSCSICommon {
|
|
VirtIODevice parent_obj;
|
|
VirtIOSCSIConf conf;
|
|
|
|
uint32_t sense_size;
|
|
uint32_t cdb_size;
|
|
VirtQueue *ctrl_vq;
|
|
VirtQueue *event_vq;
|
|
VirtQueue **cmd_vqs;
|
|
} VirtIOSCSICommon;
|
|
|
|
typedef struct VirtIOSCSI {
|
|
VirtIOSCSICommon parent_obj;
|
|
|
|
SCSIBus bus;
|
|
int resetting;
|
|
bool events_dropped;
|
|
|
|
/* Fields for dataplane below */
|
|
AioContext *ctx; /* one iothread per virtio-scsi-pci for now */
|
|
|
|
bool dataplane_started;
|
|
bool dataplane_starting;
|
|
bool dataplane_stopping;
|
|
bool dataplane_fenced;
|
|
uint32_t host_features;
|
|
} VirtIOSCSI;
|
|
|
|
typedef struct VirtIOSCSIReq {
|
|
/* Note:
|
|
* - fields up to resp_iov are initialized by virtio_scsi_init_req;
|
|
* - fields starting at vring are zeroed by virtio_scsi_init_req.
|
|
* */
|
|
VirtQueueElement elem;
|
|
|
|
VirtIOSCSI *dev;
|
|
VirtQueue *vq;
|
|
QEMUSGList qsgl;
|
|
QEMUIOVector resp_iov;
|
|
|
|
union {
|
|
/* Used for two-stage request submission */
|
|
QTAILQ_ENTRY(VirtIOSCSIReq) next;
|
|
|
|
/* Used for cancellation of request during TMFs */
|
|
int remaining;
|
|
};
|
|
|
|
SCSIRequest *sreq;
|
|
size_t resp_size;
|
|
enum SCSIXferMode mode;
|
|
union {
|
|
VirtIOSCSICmdResp cmd;
|
|
VirtIOSCSICtrlTMFResp tmf;
|
|
VirtIOSCSICtrlANResp an;
|
|
VirtIOSCSIEvent event;
|
|
} resp;
|
|
union {
|
|
VirtIOSCSICmdReq cmd;
|
|
VirtIOSCSICtrlTMFReq tmf;
|
|
VirtIOSCSICtrlANReq an;
|
|
} req;
|
|
} VirtIOSCSIReq;
|
|
|
|
void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
|
|
VirtIOHandleOutput ctrl, VirtIOHandleOutput evt,
|
|
VirtIOHandleOutput cmd);
|
|
|
|
void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp);
|
|
void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq);
|
|
void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq);
|
|
void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq);
|
|
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
|
|
void virtio_scsi_free_req(VirtIOSCSIReq *req);
|
|
void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
|
uint32_t event, uint32_t reason);
|
|
|
|
void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp);
|
|
int virtio_scsi_dataplane_start(VirtIODevice *s);
|
|
void virtio_scsi_dataplane_stop(VirtIODevice *s);
|
|
|
|
#endif /* QEMU_VIRTIO_SCSI_H */
|