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_canceled we notify them. Signed-off-by: Fam Zheng <f...@redhat.com> --- hw/scsi/scsi-bus.c | 31 ++++++++++++++++++++++++++++--- include/hw/scsi/scsi.h | 3 +++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index fca4a9e..c1b05a1 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -553,9 +553,10 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, BusState *qbus = BUS(bus); const int memset_off = offsetof(SCSIRequest, sense) + sizeof(req->sense); + size_t reqops_size = reqops ? reqops->size : sizeof(SCSIRequest); - req = g_slice_alloc(reqops->size); - memset((uint8_t *)req + memset_off, 0, reqops->size - memset_off); + req = g_slice_alloc(reqops_size); + memset((uint8_t *)req + memset_off, 0, reqops_size - memset_off); req->refcount = 1; req->bus = bus; req->dev = d; @@ -566,6 +567,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; } @@ -1600,7 +1602,7 @@ void scsi_req_unref(SCSIRequest *req) if (bus->info->free_request && req->hba_private) { bus->info->free_request(bus, req->hba_private); } - if (req->ops->free_req) { + if (req->ops && req->ops->free_req) { req->ops->free_req(req); } object_unref(OBJECT(req->dev)); @@ -1725,9 +1727,32 @@ void scsi_req_canceled(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. + * @tmf_req is added to @req's cancellation dependency list, the bus will be + * notified with @tmf_req when all the requests it depends on are canceled. + * + * @red: The request to cancel. + * @tmf_req: The tmf request which cancels @req. + * */ +void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier) +{ + trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); + 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 0fa2a8a..6a051df 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; @@ -267,6 +269,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len); void scsi_req_abort(SCSIRequest *req, int status); void scsi_req_canceled(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); -- 1.9.3