aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorFam Zheng <famz@redhat.com>2014-09-28 09:48:00 +0800
committerPaolo Bonzini <pbonzini@redhat.com>2014-09-30 13:30:51 +0200
commit8e0a9320e94930fd6e5c2906c478203b80392f5c (patch)
tree73d7bfb2fc1b5c0b1e5ec233fc5b64289a1edad3 /hw
parentd5776465ee9a55815792efa34d79de240f4ffd99 (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')
-rw-r--r--hw/scsi/scsi-bus.c26
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);