diff options
author | Fam Zheng <famz@redhat.com> | 2014-09-28 09:48:00 +0800 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-09-30 13:30:51 +0200 |
commit | 8e0a9320e94930fd6e5c2906c478203b80392f5c (patch) | |
tree | 73d7bfb2fc1b5c0b1e5ec233fc5b64289a1edad3 /hw/scsi | |
parent | d5776465ee9a55815792efa34d79de240f4ffd99 (diff) |
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 <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/scsi')
-rw-r--r-- | hw/scsi/scsi-bus.c | 26 |
1 files changed, 26 insertions, 0 deletions
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); |