qemu-patch-raspberry4/include/hw/virtio/virtio-scsi.h
Paolo Bonzini 51b19ebe43 virtio: move allocation to virtqueue_pop/vring_pop
The return code of virtqueue_pop/vring_pop is unused except to check for
errors or 0.  We can thus easily move allocation inside the functions
and just return a pointer to the VirtQueueElement.

The advantage is that we will be able to allocate only the space that
is needed for the actual size of the s/g list instead of the full
VIRTQUEUE_MAX_SIZE items.  Currently VirtQueueElement takes about 48K
of memory, and this kind of allocation puts a lot of stress on malloc.
By cutting the size by two or three orders of magnitude, malloc can
use much more efficient algorithms.

The patch is pretty large, but changes to each device are testable
more or less independently.  Splitting it would mostly add churn.

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>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2016-02-06 20:39:07 +02:00

176 lines
5.1 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"
#include "hw/virtio/dataplane/vring.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 {
struct VirtIOSCSI *parent;
Vring vring;
EventNotifier host_notifier;
EventNotifier guest_notifier;
} VirtIOSCSIVring;
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 VirtIOSCSIBlkChangeNotifier {
Notifier n;
struct VirtIOSCSI *s;
SCSIDevice *sd;
QTAILQ_ENTRY(VirtIOSCSIBlkChangeNotifier) next;
} VirtIOSCSIBlkChangeNotifier;
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 */
QTAILQ_HEAD(, VirtIOSCSIBlkChangeNotifier) insert_notifiers;
QTAILQ_HEAD(, VirtIOSCSIBlkChangeNotifier) remove_notifiers;
/* Vring is used instead of vq in dataplane code, because of the underlying
* memory layer thread safety */
VirtIOSCSIVring *ctrl_vring;
VirtIOSCSIVring *event_vring;
VirtIOSCSIVring **cmd_vrings;
bool dataplane_started;
bool dataplane_starting;
bool dataplane_stopping;
bool dataplane_disabled;
bool dataplane_fenced;
Error *blocker;
Notifier migration_state_notifier;
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;
/* Set by dataplane code. */
VirtIOSCSIVring *vring;
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;
typedef void (*HandleOutput)(VirtIODevice *, VirtQueue *);
void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
HandleOutput ctrl, HandleOutput evt,
HandleOutput cmd);
void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp);
void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req);
bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req);
void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req);
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_set_iothread(VirtIOSCSI *s, IOThread *iothread);
void virtio_scsi_dataplane_start(VirtIOSCSI *s);
void virtio_scsi_dataplane_stop(VirtIOSCSI *s);
void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req);
VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s,
VirtIOSCSIVring *vring);
#endif /* _QEMU_VIRTIO_SCSI_H */