From 61e68b3fbd3e2b7beb636bc56f78d9c1ca25e8f9 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 16 Sep 2014 15:20:17 +0800 Subject: scsi: Optimize scsi_req_alloc Zeroing sense buffer for each scsi request is not efficient, we can just leave it uninitialized because sense_len is set to 0. Move the implicitly zeroed fields to the end of the structure and use a partial memset. The explicitly initialized fields (by scsi_req_alloc or scsi_req_new) are moved to the beginning of the structure, before sense buffer, to skip the memset. Also change g_malloc0 to g_slice_alloc. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/hw/scsi/scsi.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 2e3a8f987d..6271ad3034 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -50,17 +50,24 @@ struct SCSIRequest { uint32_t tag; uint32_t lun; uint32_t status; + void *hba_private; size_t resid; SCSICommand cmd; + + /* Note: + * - fields before sense are initialized by scsi_req_alloc; + * - sense[] is uninitialized; + * - fields after sense are memset to 0 by scsi_req_alloc. + * */ + + uint8_t sense[SCSI_SENSE_BUF_SIZE]; + uint32_t sense_len; + bool enqueued; + bool io_canceled; + bool retry; + bool dma_started; BlockDriverAIOCB *aiocb; QEMUSGList *sg; - bool dma_started; - uint8_t sense[SCSI_SENSE_BUF_SIZE]; - uint32_t sense_len; - bool enqueued; - bool io_canceled; - bool retry; - void *hba_private; QTAILQ_ENTRY(SCSIRequest) next; }; -- cgit v1.2.3-55-g7522 From bf359a445e780815866327891a845071197dfb63 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:00 +0800 Subject: virtio-scsi: Split virtio_scsi_handle_cmd_req from virtio_scsi_handle_cmd This is the "common part" to handle one cmd request. Refactor out for later usage of dataplane iothread code. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 117 +++++++++++++++------------------------- include/hw/virtio/virtio-scsi.h | 36 +++++++++++++ 2 files changed, 79 insertions(+), 74 deletions(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6953cbe6dd..57b2b7b3dc 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -21,41 +21,6 @@ #include #include "hw/virtio/virtio-access.h" -typedef struct VirtIOSCSIReq { - VirtIOSCSI *dev; - VirtQueue *vq; - QEMUSGList qsgl; - QEMUIOVector resp_iov; - - /* Note: - * - fields before elem are initialized by virtio_scsi_init_req; - * - elem is uninitialized at the time of allocation. - * - fields after elem are zeroed by virtio_scsi_init_req. - * */ - - VirtQueueElement elem; - SCSIRequest *sreq; - size_t resp_size; - enum SCSIXferMode mode; - union { - VirtIOSCSICmdResp cmd; - VirtIOSCSICtrlTMFResp tmf; - VirtIOSCSICtrlANResp an; - VirtIOSCSIEvent event; - } resp; - union { - struct { - VirtIOSCSICmdReq cmd; - uint8_t cdb[]; - } QEMU_PACKED; - VirtIOSCSICtrlTMFReq tmf; - VirtIOSCSICtrlANReq an; - } req; -} VirtIOSCSIReq; - -QEMU_BUILD_BUG_ON(offsetof(VirtIOSCSIReq, req.cdb) != - offsetof(VirtIOSCSIReq, req.cmd) + sizeof(VirtIOSCSICmdReq)); - static inline int virtio_scsi_get_lun(uint8_t *lun) { return ((lun[2] << 8) | lun[3]) & 0x3FFF; @@ -462,52 +427,56 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); } +void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) +{ + VirtIOSCSICommon *vs = &s->parent_obj; + int n; + SCSIDevice *d; + int rc; + + rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, + sizeof(VirtIOSCSICmdResp) + vs->sense_size); + if (rc < 0) { + if (rc == -ENOTSUP) { + virtio_scsi_fail_cmd_req(req); + } else { + virtio_scsi_bad_req(); + } + return; + } + + d = virtio_scsi_device_find(s, req->req.cmd.lun); + if (!d) { + req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; + virtio_scsi_complete_cmd_req(req); + return; + } + req->sreq = scsi_req_new(d, req->req.cmd.tag, + virtio_scsi_get_lun(req->req.cmd.lun), + req->req.cdb, req); + + if (req->sreq->cmd.mode != SCSI_XFER_NONE + && (req->sreq->cmd.mode != req->mode || + req->sreq->cmd.xfer > req->qsgl.size)) { + req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; + virtio_scsi_complete_cmd_req(req); + return; + } + + n = scsi_req_enqueue(req->sreq); + if (n) { + scsi_req_continue(req->sreq); + } +} + static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) { /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; - VirtIOSCSICommon *vs = &s->parent_obj; - VirtIOSCSIReq *req; - int n; while ((req = virtio_scsi_pop_req(s, vq))) { - SCSIDevice *d; - int rc; - - rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, - sizeof(VirtIOSCSICmdResp) + vs->sense_size); - if (rc < 0) { - if (rc == -ENOTSUP) { - virtio_scsi_fail_cmd_req(req); - } else { - virtio_scsi_bad_req(); - } - continue; - } - - d = virtio_scsi_device_find(s, req->req.cmd.lun); - if (!d) { - req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; - virtio_scsi_complete_cmd_req(req); - continue; - } - req->sreq = scsi_req_new(d, req->req.cmd.tag, - virtio_scsi_get_lun(req->req.cmd.lun), - req->req.cdb, req); - - if (req->sreq->cmd.mode != SCSI_XFER_NONE - && (req->sreq->cmd.mode != req->mode || - req->sreq->cmd.xfer > req->qsgl.size)) { - req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; - virtio_scsi_complete_cmd_req(req); - continue; - } - - n = scsi_req_enqueue(req->sreq); - if (n) { - scsi_req_continue(req->sreq); - } + virtio_scsi_handle_cmd_req(s, req); } } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 188a2d9144..7b65f5e6d9 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -172,6 +172,41 @@ typedef struct { bool events_dropped; } VirtIOSCSI; +typedef struct VirtIOSCSIReq { + VirtIOSCSI *dev; + VirtQueue *vq; + QEMUSGList qsgl; + QEMUIOVector resp_iov; + + /* Note: + * - fields before elem are initialized by virtio_scsi_init_req; + * - elem is uninitialized at the time of allocation. + * - fields after elem are zeroed by virtio_scsi_init_req. + * */ + + VirtQueueElement elem; + SCSIRequest *sreq; + size_t resp_size; + enum SCSIXferMode mode; + union { + VirtIOSCSICmdResp cmd; + VirtIOSCSICtrlTMFResp tmf; + VirtIOSCSICtrlANResp an; + VirtIOSCSIEvent event; + } resp; + union { + struct { + VirtIOSCSICmdReq cmd; + uint8_t cdb[]; + } QEMU_PACKED; + VirtIOSCSICtrlTMFReq tmf; + VirtIOSCSICtrlANReq an; + } req; +} VirtIOSCSIReq; + +QEMU_BUILD_BUG_ON(offsetof(VirtIOSCSIReq, req.cdb) != + offsetof(VirtIOSCSIReq, req.cmd) + sizeof(VirtIOSCSICmdReq)); + #define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field) \ DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \ DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF),\ @@ -192,5 +227,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, HandleOutput cmd); void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); +void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); #endif /* _QEMU_VIRTIO_SCSI_H */ -- cgit v1.2.3-55-g7522 From dc56b7c4fb0c95a9648ad5bf29e09e5676404077 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:01 +0800 Subject: virtio-scsi: Split virtio_scsi_handle_ctrl_req from virtio_scsi_handle_ctrl To share with dataplane code. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 60 ++++++++++++++++++++++------------------- include/hw/virtio/virtio-scsi.h | 1 + 2 files changed, 34 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 57b2b7b3dc..5f3c0c1087 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -308,40 +308,46 @@ fail: req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; } -static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) { - VirtIOSCSI *s = (VirtIOSCSI *)vdev; - VirtIOSCSIReq *req; + VirtIODevice *vdev = (VirtIODevice *)s; + int type; - while ((req = virtio_scsi_pop_req(s, vq))) { - int type; + if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, + &type, sizeof(type)) < sizeof(type)) { + virtio_scsi_bad_req(); + return; + } - if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, - &type, sizeof(type)) < sizeof(type)) { + virtio_tswap32s(vdev, &req->req.tmf.type); + if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) { + if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), + sizeof(VirtIOSCSICtrlTMFResp)) < 0) { virtio_scsi_bad_req(); - continue; + } else { + virtio_scsi_do_tmf(s, req); } - virtio_tswap32s(vdev, &req->req.tmf.type); - if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) { - if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), - sizeof(VirtIOSCSICtrlTMFResp)) < 0) { - virtio_scsi_bad_req(); - } else { - virtio_scsi_do_tmf(s, req); - } - - } else if (req->req.tmf.type == VIRTIO_SCSI_T_AN_QUERY || - req->req.tmf.type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { - if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq), - sizeof(VirtIOSCSICtrlANResp)) < 0) { - virtio_scsi_bad_req(); - } else { - req->resp.an.event_actual = 0; - req->resp.an.response = VIRTIO_SCSI_S_OK; - } + } else if (req->req.tmf.type == VIRTIO_SCSI_T_AN_QUERY || + req->req.tmf.type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { + if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq), + sizeof(VirtIOSCSICtrlANResp)) < 0) { + virtio_scsi_bad_req(); + } else { + req->resp.an.event_actual = 0; + req->resp.an.response = VIRTIO_SCSI_S_OK; } - virtio_scsi_complete_req(req); + } + virtio_scsi_complete_req(req); +} + +static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOSCSI *s = (VirtIOSCSI *)vdev; + VirtIOSCSIReq *req; + + while ((req = virtio_scsi_pop_req(s, vq))) { + virtio_scsi_handle_ctrl_req(s, req); } } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 7b65f5e6d9..b91d32633a 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -227,6 +227,7 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, HandleOutput cmd); void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); +void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); #endif /* _QEMU_VIRTIO_SCSI_H */ -- cgit v1.2.3-55-g7522 From c505333dab10cf7ffd3a30259c2df77d4d30343d Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:03 +0800 Subject: virtio-scsi: Make virtio_scsi_init_req public To share with datplane code later. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 2 +- include/hw/virtio/virtio-scsi.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 5f3c0c1087..8cab75b6d6 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -37,7 +37,7 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); } -static VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) +VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index b91d32633a..b99763c19c 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -229,5 +229,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); +VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); #endif /* _QEMU_VIRTIO_SCSI_H */ -- cgit v1.2.3-55-g7522 From aa8e8f83d0458a87e9a86ccfedfe68999d2d0fa6 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:04 +0800 Subject: virtio-scsi: Make virtio_scsi_free_req public To share with dataplane code later. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 2 +- include/hw/virtio/virtio-scsi.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 8cab75b6d6..c7ae83dc45 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -53,7 +53,7 @@ VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) return req; } -static void virtio_scsi_free_req(VirtIOSCSIReq *req) +void virtio_scsi_free_req(VirtIOSCSIReq *req) { VirtIOSCSICommon *vs = (VirtIOSCSICommon *)req->dev; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index b99763c19c..713df63ace 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -230,5 +230,6 @@ void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); +void virtio_scsi_free_req(VirtIOSCSIReq *req); #endif /* _QEMU_VIRTIO_SCSI_H */ -- cgit v1.2.3-55-g7522 From 20e6dca1df6b6ea74c3d6af74dc2184f464b3035 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:05 +0800 Subject: virtio-scsi: Make virtio_scsi_push_event public Later this will be called by dataplane code. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 4 ++-- include/hw/virtio/virtio-scsi.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index c7ae83dc45..58b420084e 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -561,8 +561,8 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, - uint32_t event, uint32_t reason) +void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + uint32_t event, uint32_t reason) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); VirtIOSCSIReq *req; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 713df63ace..6cd2f5764d 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -231,5 +231,7 @@ void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_free_req(VirtIOSCSIReq *req); +void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + uint32_t event, uint32_t reason); #endif /* _QEMU_VIRTIO_SCSI_H */ -- cgit v1.2.3-55-g7522 From c8075caf19b000b975349f8976958cedf7d2613a Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:38 +0800 Subject: virtio: add a wrapper for virtio-backend initialization For better code sharing, add a helper function that handles reference counting of the virtio backend for virtio proxy devices. Cc: Cornelia Huck Cc: Michael S. Tsirkin Signed-off-by: Gonglei Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 42 +++++++++++++++++---------------------- hw/s390x/virtio-ccw.c | 42 +++++++++++++++++---------------------- hw/virtio/virtio-pci.c | 49 ++++++++++++++++++++-------------------------- hw/virtio/virtio.c | 11 +++++++++++ include/hw/virtio/virtio.h | 3 +++ 5 files changed, 71 insertions(+), 76 deletions(-) (limited to 'include') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index ca682bb7e6..f451ca1ed3 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -159,10 +159,9 @@ static int s390_virtio_net_init(VirtIOS390Device *s390_dev) static void s390_virtio_net_instance_init(Object *obj) { VirtIONetS390 *dev = VIRTIO_NET_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_NET); } static int s390_virtio_blk_init(VirtIOS390Device *s390_dev) @@ -179,10 +178,9 @@ static int s390_virtio_blk_init(VirtIOS390Device *s390_dev) static void s390_virtio_blk_instance_init(Object *obj) { VirtIOBlkS390 *dev = VIRTIO_BLK_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread", &error_abort); } @@ -224,10 +222,9 @@ static int s390_virtio_serial_init(VirtIOS390Device *s390_dev) static void s390_virtio_serial_instance_init(Object *obj) { VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SERIAL); } static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev) @@ -258,10 +255,9 @@ static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev) static void s390_virtio_scsi_instance_init(Object *obj) { VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SCSI); } #ifdef CONFIG_VHOST_SCSI @@ -281,10 +277,9 @@ static int s390_vhost_scsi_init(VirtIOS390Device *s390_dev) static void s390_vhost_scsi_instance_init(Object *obj) { VHostSCSIS390 *dev = VHOST_SCSI_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); } #endif @@ -309,10 +304,9 @@ static int s390_virtio_rng_init(VirtIOS390Device *s390_dev) static void s390_virtio_rng_instance_init(Object *obj) { VirtIORNGS390 *dev = VIRTIO_RNG_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_RNG); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index c074f64e92..5175d57733 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -792,10 +792,9 @@ static int virtio_ccw_net_init(VirtioCcwDevice *ccw_dev) static void virtio_ccw_net_instance_init(Object *obj) { VirtIONetCcw *dev = VIRTIO_NET_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_NET); } static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev) @@ -813,10 +812,9 @@ static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev) static void virtio_ccw_blk_instance_init(Object *obj) { VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread", &error_abort); } @@ -850,10 +848,9 @@ static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev) static void virtio_ccw_serial_instance_init(Object *obj) { VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SERIAL); } static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev) @@ -938,10 +935,9 @@ static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev) static void virtio_ccw_scsi_instance_init(Object *obj) { VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SCSI); } #ifdef CONFIG_VHOST_SCSI @@ -961,10 +957,9 @@ static int vhost_ccw_scsi_init(VirtioCcwDevice *ccw_dev) static void vhost_ccw_scsi_instance_init(Object *obj) { VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); } #endif @@ -1540,10 +1535,9 @@ static const TypeInfo vhost_ccw_scsi = { static void virtio_ccw_rng_instance_init(Object *obj) { VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_RNG); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 8f3b79b03a..83a699fc23 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -947,10 +947,9 @@ static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) static void virtio_9p_pci_instance_init(Object *obj) { V9fsPCIState *dev = VIRTIO_9P_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_9P); } static const TypeInfo virtio_9p_pci_info = { @@ -1112,10 +1111,9 @@ static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) static void virtio_blk_pci_instance_init(Object *obj) { VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread", &error_abort); } @@ -1185,10 +1183,9 @@ static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) static void virtio_scsi_pci_instance_init(Object *obj) { VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SCSI); } static const TypeInfo virtio_scsi_pci_info = { @@ -1242,10 +1239,9 @@ static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) static void vhost_scsi_pci_instance_init(Object *obj) { VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); } static const TypeInfo vhost_scsi_pci_info = { @@ -1408,10 +1404,9 @@ static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) static void virtio_serial_pci_instance_init(Object *obj) { VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SERIAL); } static const TypeInfo virtio_serial_pci_info = { @@ -1467,10 +1462,9 @@ static void virtio_net_pci_class_init(ObjectClass *klass, void *data) static void virtio_net_pci_instance_init(Object *obj) { VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_NET); } static const TypeInfo virtio_net_pci_info = { @@ -1523,10 +1517,9 @@ static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) static void virtio_rng_initfn(Object *obj) { VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_RNG); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 5c981801f3..2c236bf271 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1123,6 +1123,17 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state) } } +void virtio_instance_init_common(Object *proxy_obj, void *data, + size_t vdev_size, const char *vdev_name) +{ + DeviceState *vdev = data; + + object_initialize(vdev, vdev_size, vdev_name); + object_property_add_child(proxy_obj, "virtio-backend", OBJECT(vdev), NULL); + object_unref(OBJECT(vdev)); + qdev_alias_all_properties(vdev, proxy_obj); +} + void virtio_init(VirtIODevice *vdev, const char *name, uint16_t device_id, size_t config_size) { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index a60104ca24..0726d76f49 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -161,6 +161,9 @@ typedef struct VirtioDeviceClass { int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id); } VirtioDeviceClass; +void virtio_instance_init_common(Object *proxy_obj, void *data, + size_t vdev_size, const char *vdev_name); + void virtio_init(VirtIODevice *vdev, const char *name, uint16_t device_id, size_t config_size); void virtio_cleanup(VirtIODevice *vdev); -- cgit v1.2.3-55-g7522 From 19d339f11d0768df2b4e0c40530bb4ab53e6bb05 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:06 +0800 Subject: virtio-scsi: Add 'iothread' property to virtio-scsi Similar to this property in virtio-blk for dataplane, add it as a QOM link in virtio-scsi and an alias in virtio-scsi-pci and virtio-scsi-ccw, in order to assign an iothread to the device. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/s390x/virtio-ccw.c | 2 ++ hw/scsi/virtio-scsi.c | 11 +++++++++++ hw/virtio/virtio-pci.c | 2 ++ include/hw/virtio/virtio-scsi.h | 1 + 4 files changed, 16 insertions(+) (limited to 'include') diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 5175d57733..e7d3ea178a 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -938,6 +938,8 @@ static void virtio_ccw_scsi_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); + object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread", + &error_abort); } #ifdef CONFIG_VHOST_SCSI diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 58b420084e..91ead26ff8 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -728,6 +728,16 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) virtio_scsi_save, virtio_scsi_load, s); } +static void virtio_scsi_instance_init(Object *obj) +{ + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(obj); + + object_property_add_link(obj, "iothread", TYPE_IOTHREAD, + (Object **)&vs->conf.iothread, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); +} + void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -786,6 +796,7 @@ static const TypeInfo virtio_scsi_info = { .name = TYPE_VIRTIO_SCSI, .parent = TYPE_VIRTIO_SCSI_COMMON, .instance_size = sizeof(VirtIOSCSI), + .instance_init = virtio_scsi_instance_init, .class_init = virtio_scsi_class_init, }; diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 83a699fc23..bae62c8f66 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1186,6 +1186,8 @@ static void virtio_scsi_pci_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); + object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread", + &error_abort); } static const TypeInfo virtio_scsi_pci_info = { diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 6cd2f5764d..2ff145a4ec 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -151,6 +151,7 @@ struct VirtIOSCSIConf { uint32_t cmd_per_lun; char *vhostfd; char *wwpn; + IOThread *iothread; }; typedef struct VirtIOSCSICommon { -- cgit v1.2.3-55-g7522 From 244e2898b7a7735b3da114c120abe206af56a167 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 15:21:41 +0800 Subject: virtio-scsi: Add VirtIOSCSIVring in VirtIOSCSIReq Move VirtIOSCSIReq to header and add one field "vring" as a wrapper structure of Vring, VirtIOSCSIVring. This is necessary for coming dataplane code that runs uses vring on iothread. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/hw/virtio/virtio-scsi.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 2ff145a4ec..e886517c6d 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -17,6 +17,8 @@ #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) \ @@ -154,6 +156,15 @@ struct VirtIOSCSIConf { 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; @@ -165,7 +176,7 @@ typedef struct VirtIOSCSICommon { VirtQueue **cmd_vqs; } VirtIOSCSICommon; -typedef struct { +typedef struct VirtIOSCSI { VirtIOSCSICommon parent_obj; SCSIBus bus; @@ -186,6 +197,8 @@ typedef struct VirtIOSCSIReq { * */ VirtQueueElement elem; + /* Set by dataplane code. */ + VirtIOSCSIVring *vring; SCSIRequest *sreq; size_t resp_size; enum SCSIXferMode mode; -- cgit v1.2.3-55-g7522 From 91cb1c9b56064e7cba27ab310c9c4c477694589e Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:24 +0800 Subject: virtio-scsi-dataplane: Code to run virtio-scsi on iothread This implements the core part of dataplane feature of virtio-scsi. A few fields are added in VirtIOSCSICommon to maintain the dataplane status. These fields are managed by a new source file: virtio-scsi-dataplane.c. Most code in this file will run on an iothread, unless otherwise commented as in a global mutex context, such as those functions to start, stop and setting the iothread property. Upon start, we set up guest/host event notifiers, in a same way as virtio-blk does. The handlers then pop request from vring and call into virtio-scsi.c functions to process it. So we need to make sure make all those called functions work with iothread, too. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/Makefile.objs | 2 +- hw/scsi/virtio-scsi-dataplane.c | 222 ++++++++++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-scsi.h | 19 ++++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 hw/scsi/virtio-scsi-dataplane.c (limited to 'include') diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs index 121ddc5cf4..40c79d34c9 100644 --- a/hw/scsi/Makefile.objs +++ b/hw/scsi/Makefile.objs @@ -8,6 +8,6 @@ common-obj-$(CONFIG_ESP_PCI) += esp-pci.o obj-$(CONFIG_PSERIES) += spapr_vscsi.o ifeq ($(CONFIG_VIRTIO),y) -obj-y += virtio-scsi.o +obj-y += virtio-scsi.o virtio-scsi-dataplane.o obj-$(CONFIG_VHOST_SCSI) += vhost-scsi.o endif diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c new file mode 100644 index 0000000000..acbf622ed8 --- /dev/null +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -0,0 +1,222 @@ +/* + * Virtio SCSI dataplane + * + * Copyright Red Hat, Inc. 2014 + * + * Authors: + * Fam Zheng + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "hw/virtio/virtio-scsi.h" +#include "qemu/error-report.h" +#include +#include +#include +#include "hw/virtio/virtio-access.h" +#include "stdio.h" + +/* Context: QEMU global mutex held */ +void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + + assert(!s->ctx); + s->ctx = iothread_get_aio_context(vs->conf.iothread); + + /* Don't try if transport does not support notifiers. */ + if (!k->set_guest_notifiers || !k->set_host_notifier) { + fprintf(stderr, "virtio-scsi: Failed to set iothread " + "(transport does not support notifiers)"); + exit(1); + } +} + +static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, + VirtQueue *vq, + EventNotifierHandler *handler, + int n) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIOSCSIVring *r = g_slice_new(VirtIOSCSIVring); + + /* Set up virtqueue notify */ + if (k->set_host_notifier(qbus->parent, n, true) != 0) { + fprintf(stderr, "virtio-scsi: Failed to set host notifier\n"); + exit(1); + } + r->host_notifier = *virtio_queue_get_host_notifier(vq); + r->guest_notifier = *virtio_queue_get_guest_notifier(vq); + aio_set_event_notifier(s->ctx, &r->host_notifier, handler); + + r->parent = s; + + if (!vring_setup(&r->vring, VIRTIO_DEVICE(s), n)) { + fprintf(stderr, "virtio-scsi: VRing setup failed\n"); + exit(1); + } + return r; +} + +VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, + VirtIOSCSIVring *vring) +{ + VirtIOSCSIReq *req = virtio_scsi_init_req(s, NULL); + int r; + + req->vring = vring; + r = vring_pop((VirtIODevice *)s, &vring->vring, &req->elem); + if (r < 0) { + virtio_scsi_free_req(req); + req = NULL; + } + return req; +} + +void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) +{ + vring_push(&req->vring->vring, &req->elem, + req->qsgl.size + req->resp_iov.size); + event_notifier_set(&req->vring->guest_notifier); +} + +static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier) +{ + VirtIOSCSIVring *vring = container_of(notifier, + VirtIOSCSIVring, host_notifier); + VirtIOSCSI *s = VIRTIO_SCSI(vring->parent); + VirtIOSCSIReq *req; + + event_notifier_test_and_clear(notifier); + while ((req = virtio_scsi_pop_req_vring(s, vring))) { + virtio_scsi_handle_ctrl_req(s, req); + } +} + +static void virtio_scsi_iothread_handle_event(EventNotifier *notifier) +{ + VirtIOSCSIVring *vring = container_of(notifier, + VirtIOSCSIVring, host_notifier); + VirtIOSCSI *s = vring->parent; + VirtIODevice *vdev = VIRTIO_DEVICE(s); + + event_notifier_test_and_clear(notifier); + + if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { + return; + } + + if (s->events_dropped) { + virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); + } +} + +static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier) +{ + VirtIOSCSIVring *vring = container_of(notifier, + VirtIOSCSIVring, host_notifier); + VirtIOSCSI *s = (VirtIOSCSI *)vring->parent; + VirtIOSCSIReq *req; + + event_notifier_test_and_clear(notifier); + while ((req = virtio_scsi_pop_req_vring(s, vring))) { + virtio_scsi_handle_cmd_req(s, req); + } +} + +/* Context: QEMU global mutex held */ +void virtio_scsi_dataplane_start(VirtIOSCSI *s) +{ + int i; + int rc; + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + + if (s->dataplane_started || + s->dataplane_starting || + s->ctx != iothread_get_aio_context(vs->conf.iothread)) { + return; + } + + s->dataplane_starting = true; + + /* Set up guest notifier (irq) */ + rc = k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, true); + if (rc != 0) { + fprintf(stderr, "virtio-scsi: Failed to set guest notifiers, " + "ensure -enable-kvm is set\n"); + exit(1); + } + + aio_context_acquire(s->ctx); + s->ctrl_vring = virtio_scsi_vring_init(s, vs->ctrl_vq, + virtio_scsi_iothread_handle_ctrl, + 0); + s->event_vring = virtio_scsi_vring_init(s, vs->event_vq, + virtio_scsi_iothread_handle_event, + 1); + s->cmd_vrings = g_malloc0(sizeof(VirtIOSCSIVring) * vs->conf.num_queues); + for (i = 0; i < vs->conf.num_queues; i++) { + s->cmd_vrings[i] = + virtio_scsi_vring_init(s, vs->cmd_vqs[i], + virtio_scsi_iothread_handle_cmd, + i + 2); + } + + aio_context_release(s->ctx); + s->dataplane_starting = false; + s->dataplane_started = true; +} + +/* Context: QEMU global mutex held */ +void virtio_scsi_dataplane_stop(VirtIOSCSI *s) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIODevice *vdev = VIRTIO_DEVICE(s); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + int i; + + if (!s->dataplane_started || s->dataplane_stopping) { + return; + } + s->dataplane_stopping = true; + assert(s->ctx == iothread_get_aio_context(vs->conf.iothread)); + + aio_context_acquire(s->ctx); + + aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier, NULL); + aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier, NULL); + for (i = 0; i < vs->conf.num_queues; i++) { + aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier, NULL); + } + + bdrv_drain_all(); /* ensure there are no in-flight requests */ + + aio_context_release(s->ctx); + + /* Sync vring state back to virtqueue so that non-dataplane request + * processing can continue when we disable the host notifier below. + */ + vring_teardown(&s->ctrl_vring->vring, vdev, 0); + vring_teardown(&s->event_vring->vring, vdev, 1); + for (i = 0; i < vs->conf.num_queues; i++) { + vring_teardown(&s->cmd_vrings[i]->vring, vdev, 2 + i); + } + + for (i = 0; i < vs->conf.num_queues + 2; i++) { + k->set_host_notifier(qbus->parent, i, false); + } + + /* Clean up guest notifier (irq) */ + k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); + s->dataplane_stopping = false; + s->dataplane_started = false; +} diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index e886517c6d..8e1968f9e8 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -182,6 +182,18 @@ typedef struct VirtIOSCSI { SCSIBus bus; int resetting; bool events_dropped; + + /* Fields for dataplane below */ + AioContext *ctx; /* one iothread per virtio-scsi-pci for now */ + + /* 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; } VirtIOSCSI; typedef struct VirtIOSCSIReq { @@ -248,4 +260,11 @@ 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 */ -- cgit v1.2.3-55-g7522 From dfb37cf7fa206afa6e212af16fee74427464f1d1 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:26 +0800 Subject: virtio-scsi: Add migration state notifier for dataplane code Similar to virtio-blk-dataplane, we stop the iothread while migration starts and restart it when migration finishes. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 35 ++++++++++++++++++++++++++++++++--- include/hw/virtio/virtio-scsi.h | 2 ++ 2 files changed, 34 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index dc705f0fa5..57efe65659 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -20,6 +20,7 @@ #include #include #include "hw/virtio/virtio-access.h" +#include "migration/migration.h" static inline int virtio_scsi_get_lun(uint8_t *lun) { @@ -357,7 +358,7 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req; - if (s->ctx) { + if (s->ctx && !s->dataplane_disabled) { virtio_scsi_dataplane_start(s); return; } @@ -501,7 +502,7 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req; - if (s->ctx) { + if (s->ctx && !s->dataplane_disabled) { virtio_scsi_dataplane_start(s); return; } @@ -651,7 +652,7 @@ static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = VIRTIO_SCSI(vdev); - if (s->ctx) { + if (s->ctx && !s->dataplane_disabled) { virtio_scsi_dataplane_start(s); return; } @@ -742,6 +743,31 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, } } +/* Disable dataplane thread during live migration since it does not + * update the dirty memory bitmap yet. + */ +static void virtio_scsi_migration_state_changed(Notifier *notifier, void *data) +{ + VirtIOSCSI *s = container_of(notifier, VirtIOSCSI, + migration_state_notifier); + MigrationState *mig = data; + + if (migration_in_setup(mig)) { + if (!s->dataplane_started) { + return; + } + virtio_scsi_dataplane_stop(s); + s->dataplane_disabled = true; + } else if (migration_has_finished(mig) || + migration_has_failed(mig)) { + if (s->dataplane_started) { + return; + } + bdrv_drain_all(); /* complete in-flight non-dataplane requests */ + s->dataplane_disabled = false; + } +} + static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -770,6 +796,8 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, virtio_scsi_save, virtio_scsi_load, s); + s->migration_state_notifier.notify = virtio_scsi_migration_state_changed; + add_migration_state_change_notifier(&s->migration_state_notifier); } static void virtio_scsi_instance_init(Object *obj) @@ -796,6 +824,7 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) VirtIOSCSI *s = VIRTIO_SCSI(dev); unregister_savevm(dev, "virtio-scsi", s); + remove_migration_state_change_notifier(&s->migration_state_notifier); virtio_scsi_common_unrealize(dev, errp); } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 8e1968f9e8..1a6a919960 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -194,6 +194,8 @@ typedef struct VirtIOSCSI { bool dataplane_started; bool dataplane_starting; bool dataplane_stopping; + bool dataplane_disabled; + Notifier migration_state_notifier; } VirtIOSCSI; typedef struct VirtIOSCSIReq { -- cgit v1.2.3-55-g7522 From 359eea71d98e7f2cf9efb5e65bb59a240bedb131 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:27 +0800 Subject: virtio-scsi: Two stages processing of cmd request Mechanical change, in preparation for bdrv_io_plug/bdrv_io_unplug. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi-dataplane.c | 4 +++- hw/scsi/virtio-scsi.c | 20 ++++++++++++-------- include/hw/virtio/virtio-scsi.h | 3 ++- 3 files changed, 17 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index acbf622ed8..11f5705407 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -126,7 +126,9 @@ static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier) event_notifier_test_and_clear(notifier); while ((req = virtio_scsi_pop_req_vring(s, vring))) { - virtio_scsi_handle_cmd_req(s, req); + if (virtio_scsi_handle_cmd_req_prepare(s, req)) { + virtio_scsi_handle_cmd_req_submit(s, req); + } } } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 57efe65659..6cf070f70e 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -449,10 +449,9 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); } -void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) +bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) { VirtIOSCSICommon *vs = &s->parent_obj; - int n; SCSIDevice *d; int rc; @@ -464,14 +463,14 @@ void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) } else { virtio_scsi_bad_req(); } - return; + return false; } d = virtio_scsi_device_find(s, req->req.cmd.lun); if (!d) { req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; virtio_scsi_complete_cmd_req(req); - return; + return false; } if (s->dataplane_started && bdrv_get_aio_context(d->conf.bs) != s->ctx) { aio_context_acquire(s->ctx); @@ -487,11 +486,14 @@ void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) req->sreq->cmd.xfer > req->qsgl.size)) { req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; virtio_scsi_complete_cmd_req(req); - return; + return false; } + return true; +} - n = scsi_req_enqueue(req->sreq); - if (n) { +void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) +{ + if (scsi_req_enqueue(req->sreq)) { scsi_req_continue(req->sreq); } } @@ -507,7 +509,9 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) return; } while ((req = virtio_scsi_pop_req(s, vq))) { - virtio_scsi_handle_cmd_req(s, req); + if (virtio_scsi_handle_cmd_req_prepare(s, req)) { + virtio_scsi_handle_cmd_req_submit(s, req); + } } } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 1a6a919960..1cc759a644 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -256,7 +256,8 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); -void virtio_scsi_handle_cmd_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); VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, -- cgit v1.2.3-55-g7522 From 1880ad4f4e3b49f15c55e816d66b9690b3ede00c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:28 +0800 Subject: virtio-scsi: Batched prepare for cmd reqs Queue the popped requests while calling virtio_scsi_handle_cmd_req_prepare(), then submit them after all prepared. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi-dataplane.c | 9 +++++++-- hw/scsi/virtio-scsi.c | 9 +++++++-- include/hw/virtio/virtio-scsi.h | 4 ++++ 3 files changed, 18 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 11f5705407..b778e051f8 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -122,14 +122,19 @@ static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier) VirtIOSCSIVring *vring = container_of(notifier, VirtIOSCSIVring, host_notifier); VirtIOSCSI *s = (VirtIOSCSI *)vring->parent; - VirtIOSCSIReq *req; + VirtIOSCSIReq *req, *next; + QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); event_notifier_test_and_clear(notifier); while ((req = virtio_scsi_pop_req_vring(s, vring))) { if (virtio_scsi_handle_cmd_req_prepare(s, req)) { - virtio_scsi_handle_cmd_req_submit(s, req); + QTAILQ_INSERT_TAIL(&reqs, req, next); } } + + QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { + virtio_scsi_handle_cmd_req_submit(s, req); + } } /* Context: QEMU global mutex held */ diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6cf070f70e..395178e949 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -502,7 +502,8 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) { /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; - VirtIOSCSIReq *req; + VirtIOSCSIReq *req, *next; + QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); if (s->ctx && !s->dataplane_disabled) { virtio_scsi_dataplane_start(s); @@ -510,9 +511,13 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) } while ((req = virtio_scsi_pop_req(s, vq))) { if (virtio_scsi_handle_cmd_req_prepare(s, req)) { - virtio_scsi_handle_cmd_req_submit(s, req); + QTAILQ_INSERT_TAIL(&reqs, req, next); } } + + QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { + virtio_scsi_handle_cmd_req_submit(s, req); + } } static void virtio_scsi_get_config(VirtIODevice *vdev, diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 1cc759a644..60dbfc99a8 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -213,6 +213,10 @@ typedef struct VirtIOSCSIReq { VirtQueueElement elem; /* Set by dataplane code. */ VirtIOSCSIVring *vring; + + /* Used for two-stage request submission */ + QTAILQ_ENTRY(VirtIOSCSIReq) next; + SCSIRequest *sreq; size_t resp_size; enum SCSIXferMode mode; -- cgit v1.2.3-55-g7522 From eda470e41a753070e057380a9a71e2ad7347f667 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:52 +0800 Subject: scsi: Drop scsi_req_abort The only user of this function is spapr_vscsi.c. We can convert to scsi_req_cancel plus adding a check in vscsi_request_cancelled. Suggested-by: Paolo Bonzini Signed-off-by: Fam Zheng [Drop prototype. - Paolo] Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 15 --------------- hw/scsi/spapr_vscsi.c | 13 ++++++++++--- include/hw/scsi/scsi.h | 1 - 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index af293b59da..f90a2040a8 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1736,21 +1736,6 @@ void scsi_req_cancel(SCSIRequest *req) scsi_req_unref(req); } -void scsi_req_abort(SCSIRequest *req, int status) -{ - if (!req->enqueued) { - return; - } - scsi_req_ref(req); - scsi_req_dequeue(req); - req->io_canceled = true; - if (req->ops->cancel_io) { - req->ops->cancel_io(req); - } - scsi_req_complete(req, status); - scsi_req_unref(req); -} - static int scsi_ua_precedence(SCSISense sense) { if (sense.key != UNIT_ATTENTION) { diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 048cfc7b05..20b20f0bae 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -77,8 +77,9 @@ typedef struct vscsi_req { SCSIRequest *sreq; uint32_t qtag; /* qemu tag != srp tag */ bool active; - uint32_t data_len; bool writing; + bool dma_error; + uint32_t data_len; uint32_t senselen; uint8_t sense[SCSI_SENSE_BUF_SIZE]; @@ -536,8 +537,8 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) } if (rc < 0) { fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc); - vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); - scsi_req_abort(req->sreq, CHECK_CONDITION); + req->dma_error = true; + scsi_req_cancel(req->sreq); return; } @@ -591,6 +592,12 @@ static void vscsi_request_cancelled(SCSIRequest *sreq) { vscsi_req *req = sreq->hba_private; + if (req->dma_error) { + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent); + + vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + } vscsi_put_req(req); } diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 6271ad3034..169e8dfd44 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -265,7 +265,6 @@ void scsi_req_data(SCSIRequest *req, int len); void scsi_req_complete(SCSIRequest *req, int status); uint8_t *scsi_req_get_buf(SCSIRequest *req); int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len); -void scsi_req_abort(SCSIRequest *req, int status); void scsi_req_cancel(SCSIRequest *req); void scsi_req_retry(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); -- cgit v1.2.3-55-g7522 From a83cfd12d9868b6732e3c6e5b2cbd69a2e0ab689 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:55 +0800 Subject: scsi: Drop SCSIReqOps.cancel_io The only two implementations are identical to each other, with nothing specific to device: they only call bdrv_aio_cancel with the SCSIRequest.aiocb. Let's move it to scsi-bus. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 4 ++-- hw/scsi/scsi-disk.c | 14 -------------- hw/scsi/scsi-generic.c | 13 ------------- include/hw/scsi/scsi.h | 1 - 4 files changed, 2 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index f90a2040a8..764f6cf3b5 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1727,8 +1727,8 @@ void scsi_req_cancel(SCSIRequest *req) scsi_req_ref(req); scsi_req_dequeue(req); req->io_canceled = true; - if (req->ops->cancel_io) { - req->ops->cancel_io(req); + if (req->aiocb) { + bdrv_aio_cancel(req->aiocb); } if (req->bus->info->cancel) { req->bus->info->cancel(req); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 2e45752da1..ef13e66160 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -105,18 +105,6 @@ static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense) scsi_req_complete(&r->req, CHECK_CONDITION); } -/* Cancel a pending data transfer. */ -static void scsi_cancel_io(SCSIRequest *req) -{ - SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); - - DPRINTF("Cancel tag=0x%x\n", req->tag); - if (r->req.aiocb) { - bdrv_aio_cancel(r->req.aiocb); - } - r->req.aiocb = NULL; -} - static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); @@ -2325,7 +2313,6 @@ static const SCSIReqOps scsi_disk_emulate_reqops = { .send_command = scsi_disk_emulate_command, .read_data = scsi_disk_emulate_read_data, .write_data = scsi_disk_emulate_write_data, - .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, }; @@ -2335,7 +2322,6 @@ static const SCSIReqOps scsi_disk_dma_reqops = { .send_command = scsi_disk_dma_command, .read_data = scsi_read_data, .write_data = scsi_write_data, - .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, .load_request = scsi_disk_load_request, .save_request = scsi_disk_save_request, diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index e92b418933..7e85047d7c 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -140,18 +140,6 @@ done: scsi_req_unref(&r->req); } -/* Cancel a pending data transfer. */ -static void scsi_cancel_io(SCSIRequest *req) -{ - SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); - - DPRINTF("Cancel tag=0x%x\n", req->tag); - if (r->req.aiocb) { - bdrv_aio_cancel(r->req.aiocb); - } - r->req.aiocb = NULL; -} - static int execute_command(BlockDriverState *bdrv, SCSIGenericReq *r, int direction, BlockDriverCompletionFunc *complete) @@ -458,7 +446,6 @@ const SCSIReqOps scsi_generic_req_ops = { .send_command = scsi_send_command, .read_data = scsi_read_data, .write_data = scsi_write_data, - .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, .load_request = scsi_generic_load_request, .save_request = scsi_generic_save_request, diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 169e8dfd44..0290873120 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -130,7 +130,6 @@ struct SCSIReqOps { int32_t (*send_command)(SCSIRequest *req, uint8_t *buf); void (*read_data)(SCSIRequest *req); void (*write_data)(SCSIRequest *req); - void (*cancel_io)(SCSIRequest *req); uint8_t *(*get_buf)(SCSIRequest *req); void (*save_request)(QEMUFile *f, SCSIRequest *req); -- cgit v1.2.3-55-g7522 From d5776465ee9a55815792efa34d79de240f4ffd99 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 25 Sep 2014 10:20:47 +0800 Subject: scsi: Introduce scsi_req_cancel_complete Let the aio cb do the clean up and notification job after scsi_req_cancel, in preparation for asynchronous cancellation. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 14 ++++++++++---- hw/scsi/scsi-disk.c | 8 ++++++++ hw/scsi/scsi-generic.c | 1 + include/hw/scsi/scsi.h | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 764f6cf3b5..c91db63696 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1718,6 +1718,16 @@ void scsi_req_complete(SCSIRequest *req, int status) scsi_req_unref(req); } +/* Called by the devices when the request is canceled. */ +void scsi_req_cancel_complete(SCSIRequest *req) +{ + assert(req->io_canceled); + if (req->bus->info->cancel) { + req->bus->info->cancel(req); + } + scsi_req_unref(req); +} + void scsi_req_cancel(SCSIRequest *req) { trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); @@ -1730,10 +1740,6 @@ void scsi_req_cancel(SCSIRequest *req) if (req->aiocb) { bdrv_aio_cancel(req->aiocb); } - if (req->bus->info->cancel) { - req->bus->info->cancel(req); - } - scsi_req_unref(req); } static int scsi_ua_precedence(SCSISense sense) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index ef13e66160..7a7938a5bf 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -168,6 +168,7 @@ static void scsi_aio_complete(void *opaque, int ret) r->req.aiocb = NULL; block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -214,6 +215,7 @@ static void scsi_write_do_fua(SCSIDiskReq *r) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -240,6 +242,7 @@ static void scsi_dma_complete_noio(void *opaque, int ret) block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); } if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -280,6 +283,7 @@ static void scsi_read_complete(void * opaque, int ret) r->req.aiocb = NULL; block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -312,6 +316,7 @@ static void scsi_do_read(void *opaque, int ret) block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); } if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -432,6 +437,7 @@ static void scsi_write_complete(void * opaque, int ret) block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); } if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -1524,6 +1530,7 @@ static void scsi_unmap_complete(void *opaque, int ret) r->req.aiocb = NULL; if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -1623,6 +1630,7 @@ static void scsi_write_same_complete(void *opaque, int ret) r->req.aiocb = NULL; block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 7e85047d7c..01bca084e6 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -94,6 +94,7 @@ static void scsi_command_complete(void *opaque, int ret) r->req.aiocb = NULL; if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 0290873120..2127a335ba 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -264,6 +264,7 @@ void scsi_req_data(SCSIRequest *req, int len); void scsi_req_complete(SCSIRequest *req, int status); uint8_t *scsi_req_get_buf(SCSIRequest *req); int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len); +void scsi_req_cancel_complete(SCSIRequest *req); void scsi_req_cancel(SCSIRequest *req); void scsi_req_retry(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); -- cgit v1.2.3-55-g7522 From 8e0a9320e94930fd6e5c2906c478203b80392f5c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Sun, 28 Sep 2014 09:48:00 +0800 Subject: scsi: Introduce scsi_req_cancel_async Devices will call this function to start an asynchronous cancellation. The bus->info->cancel will be called after the request is canceled. Devices will probably need to track a separate TMF request that triggers this cancellation, and wait until the cancellation is done before completing it. So we store a notifier list in SCSIRequest and in scsi_req_cancel_complete we notify them. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 26 ++++++++++++++++++++++++++ include/hw/scsi/scsi.h | 3 +++ 2 files changed, 29 insertions(+) (limited to 'include') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index c91db63696..0f3e0395f5 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -566,6 +566,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, req->ops = reqops; object_ref(OBJECT(d)); object_ref(OBJECT(qbus->parent)); + notifier_list_init(&req->cancel_notifiers); trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); return req; } @@ -1715,6 +1716,9 @@ void scsi_req_complete(SCSIRequest *req, int status) scsi_req_ref(req); scsi_req_dequeue(req); req->bus->info->complete(req, req->status, req->resid); + + /* Cancelled requests might end up being completed instead of cancelled */ + notifier_list_notify(&req->cancel_notifiers, req); scsi_req_unref(req); } @@ -1725,9 +1729,31 @@ void scsi_req_cancel_complete(SCSIRequest *req) if (req->bus->info->cancel) { req->bus->info->cancel(req); } + notifier_list_notify(&req->cancel_notifiers, req); scsi_req_unref(req); } +/* Cancel @req asynchronously. @notifier is added to @req's cancellation + * notifier list, the bus will be notified the requests cancellation is + * completed. + * */ +void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier) +{ + trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); + if (notifier) { + notifier_list_add(&req->cancel_notifiers, notifier); + } + if (req->io_canceled) { + return; + } + scsi_req_ref(req); + scsi_req_dequeue(req); + req->io_canceled = true; + if (req->aiocb) { + bdrv_aio_cancel_async(req->aiocb); + } +} + void scsi_req_cancel(SCSIRequest *req) { trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 2127a335ba..b61bedb28c 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -5,6 +5,7 @@ #include "block/block.h" #include "hw/block/block.h" #include "sysemu/sysemu.h" +#include "qemu/notify.h" #define MAX_SCSI_DEVS 255 @@ -53,6 +54,7 @@ struct SCSIRequest { void *hba_private; size_t resid; SCSICommand cmd; + NotifierList cancel_notifiers; /* Note: * - fields before sense are initialized by scsi_req_alloc; @@ -266,6 +268,7 @@ uint8_t *scsi_req_get_buf(SCSIRequest *req); int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len); void scsi_req_cancel_complete(SCSIRequest *req); void scsi_req_cancel(SCSIRequest *req); +void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier); void scsi_req_retry(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense); -- cgit v1.2.3-55-g7522 From 49e7e31aa00a9fb466203de19120fe5c4459cac0 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 30 Sep 2014 11:40:23 +0800 Subject: virtio-scsi: Handle TMF request cancellation asynchronously For VIRTIO_SCSI_T_TMF_ABORT_TASK and VIRTIO_SCSI_T_TMF_ABORT_TASK_SET, use scsi_req_cancel_async to start the cancellation. Because each tmf command may cancel multiple requests, we need to use a counter to track the number of remaining requests we still need to wait for. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 64 ++++++++++++++++++++++++++++++++++++----- include/hw/virtio/virtio-scsi.h | 9 ++++-- 2 files changed, 64 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index fa36e23a2d..203e62449a 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -208,12 +208,33 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) return req; } -static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) +typedef struct { + Notifier notifier; + VirtIOSCSIReq *tmf_req; +} VirtIOSCSICancelNotifier; + +static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) +{ + VirtIOSCSICancelNotifier *n = container_of(notifier, + VirtIOSCSICancelNotifier, + notifier); + + if (--n->tmf_req->remaining == 0) { + virtio_scsi_complete_req(n->tmf_req); + } + g_slice_free(VirtIOSCSICancelNotifier, n); +} + +/* Return 0 if the request is ready to be completed and return to guest; + * -EINPROGRESS if the request is submitted and will be completed later, in the + * case of async cancellation. */ +static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) { SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf.lun); SCSIRequest *r, *next; BusChild *kid; int target; + int ret = 0; if (s->dataplane_started && bdrv_get_aio_context(d->conf.bs) != s->ctx) { aio_context_acquire(s->ctx); @@ -251,7 +272,14 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) */ req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; } else { - scsi_req_cancel(r); + VirtIOSCSICancelNotifier *notifier; + + req->remaining = 1; + notifier = g_slice_new(VirtIOSCSICancelNotifier); + notifier->tmf_req = req; + notifier->notifier.notify = virtio_scsi_cancel_notify; + scsi_req_cancel_async(r, ¬ifier->notifier); + ret = -EINPROGRESS; } } break; @@ -277,6 +305,13 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { goto incorrect_lun; } + + /* Add 1 to "remaining" until virtio_scsi_do_tmf returns. + * This way, if the bus starts calling back to the notifiers + * even before we finish the loop, virtio_scsi_cancel_notify + * will not complete the TMF too early. + */ + req->remaining = 1; QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { if (r->hba_private) { if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) { @@ -286,10 +321,19 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; break; } else { - scsi_req_cancel(r); + VirtIOSCSICancelNotifier *notifier; + + req->remaining++; + notifier = g_slice_new(VirtIOSCSICancelNotifier); + notifier->notifier.notify = virtio_scsi_cancel_notify; + notifier->tmf_req = req; + scsi_req_cancel_async(r, ¬ifier->notifier); } } } + if (--req->remaining > 0) { + ret = -EINPROGRESS; + } break; case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: @@ -310,20 +354,22 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) break; } - return; + return ret; incorrect_lun: req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN; - return; + return ret; fail: req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; + return ret; } void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) { VirtIODevice *vdev = (VirtIODevice *)s; int type; + int r = 0; if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, &type, sizeof(type)) < sizeof(type)) { @@ -337,7 +383,7 @@ void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) sizeof(VirtIOSCSICtrlTMFResp)) < 0) { virtio_scsi_bad_req(); } else { - virtio_scsi_do_tmf(s, req); + r = virtio_scsi_do_tmf(s, req); } } else if (req->req.tmf.type == VIRTIO_SCSI_T_AN_QUERY || @@ -350,7 +396,11 @@ void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) req->resp.an.response = VIRTIO_SCSI_S_OK; } } - virtio_scsi_complete_req(req); + if (r == 0) { + virtio_scsi_complete_req(req); + } else { + assert(r == -EINPROGRESS); + } } static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 60dbfc99a8..d6e5e7935c 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -214,8 +214,13 @@ typedef struct VirtIOSCSIReq { /* Set by dataplane code. */ VirtIOSCSIVring *vring; - /* Used for two-stage request submission */ - QTAILQ_ENTRY(VirtIOSCSIReq) next; + 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; -- cgit v1.2.3-55-g7522 From be4d57c1ea7f17b9cadb0150b330efd9b6026972 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 30 Sep 2014 09:09:11 +0200 Subject: util: introduce bitmap_try_new regular bitmap_new simply aborts if the memory allocation fails. bitmap_try_new returns NULL on failure and allows for proper error handling. Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini --- include/qemu/bitmap.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 1babd5d812..edf4f17d9c 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -88,10 +88,19 @@ int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, int slow_bitmap_intersects(const unsigned long *bitmap1, const unsigned long *bitmap2, long bits); -static inline unsigned long *bitmap_new(long nbits) +static inline unsigned long *bitmap_try_new(long nbits) { long len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); - return g_malloc0(len); + return g_try_malloc0(len); +} + +static inline unsigned long *bitmap_new(long nbits) +{ + unsigned long *ptr = bitmap_try_new(nbits); + if (ptr == NULL) { + abort(); + } + return ptr; } static inline void bitmap_zero(unsigned long *dst, long nbits) -- cgit v1.2.3-55-g7522