qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v3 10/21] scsi: introduce scsi_req_cancel


From: Paolo Bonzini
Subject: [Qemu-devel] [PATCH v3 10/21] scsi: introduce scsi_req_cancel
Date: Tue, 17 May 2011 13:00:56 +0200

This is for when the request must be dropped in the void,
but still memory should be freed.  To this end, the devices
register a second callback in SCSIBusOps.

Signed-off-by: Paolo Bonzini <address@hidden>
Signed-off-by: Jonathan Nieder <address@hidden>
---
 hw/esp.c          |   16 ++++++++++++++--
 hw/lsi53c895a.c   |   33 +++++++++++++++++++++++++--------
 hw/scsi-bus.c     |   17 ++++++++++++++---
 hw/scsi-disk.c    |    1 -
 hw/scsi-generic.c |    1 -
 hw/scsi.h         |    2 ++
 hw/spapr_vscsi.c  |   11 ++++++++++-
 hw/usb-msd.c      |   19 +++++++++++++++----
 8 files changed, 80 insertions(+), 20 deletions(-)

diff --git a/hw/esp.c b/hw/esp.c
index 096f4dc..46157a8 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -188,6 +188,17 @@ static void esp_dma_enable(void *opaque, int irq, int 
level)
     }
 }
 
+static void esp_request_cancelled(SCSIRequest *req)
+{
+    ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
+
+    if (req == s->current_req) {
+        scsi_req_unref(s->current_req);
+        s->current_req = NULL;
+        s->current_dev = NULL;
+    }
+}
+
 static uint32_t get_cmd(ESPState *s, uint8_t *buf)
 {
     uint32_t dmalen;
@@ -210,7 +221,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
 
     if (s->current_dev) {
         /* Started a new command before the old one finished.  Cancel it.  */
-        s->current_dev->info->cancel_io(s->current_req);
+        scsi_req_cancel(s->current_req);
         s->async_len = 0;
     }
 
@@ -720,7 +731,8 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
 }
 
 static struct SCSIBusOps esp_scsi_ops = {
-    .complete = esp_command_complete
+    .complete = esp_command_complete,
+    .cancel = esp_request_cancelled
 };
 
 static int esp_init1(SysBusDevice *dev)
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index b9febae..f78b85f 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -664,6 +664,26 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t 
tag)
     return NULL;
 }
 
+static void lsi_request_cancelled(SCSIRequest *req)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    lsi_request *p;
+
+    if (req == s->current->req) {
+        scsi_req_unref(req);
+        qemu_free(s->current);
+        s->current = NULL;
+        return;
+    }
+
+    p = lsi_find_by_tag(s, req->tag);
+    if (p) {
+        QTAILQ_REMOVE(&s->queue, p, next);
+        scsi_req_unref(req);
+        qemu_free(p);
+    }
+}
+
 /* Record that data is available for a queued command.  Returns zero if
    the device was reselected, nonzero if the IO is deferred.  */
 static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
@@ -869,7 +889,6 @@ static void lsi_do_msgout(LSIState *s)
     uint8_t msg;
     int len;
     uint32_t current_tag;
-    SCSIDevice *current_dev;
     lsi_request *current_req, *p, *p_next;
     int id;
 
@@ -880,8 +899,6 @@ static void lsi_do_msgout(LSIState *s)
         current_tag = s->select_tag;
         current_req = lsi_find_by_tag(s, current_tag);
     }
-    id = (current_tag >> 8) & 0xf;
-    current_dev = s->bus.devs[id];
 
     DPRINTF("MSG out len=%d\n", s->dbc);
     while (s->dbc) {
@@ -931,7 +948,7 @@ static void lsi_do_msgout(LSIState *s)
             /* The ABORT TAG message clears the current I/O process only. */
             DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
             if (current_req) {
-                current_dev->info->cancel_io(current_req->req);
+                scsi_req_cancel(current_req->req);
             }
             lsi_disconnect(s);
             break;
@@ -956,7 +973,7 @@ static void lsi_do_msgout(LSIState *s)
 
             /* clear the current I/O process */
             if (s->current) {
-                current_dev->info->cancel_io(s->current->req);
+                scsi_req_cancel(s->current->req);
             }
 
             /* As the current implemented devices scsi_disk and scsi_generic
@@ -969,8 +986,7 @@ static void lsi_do_msgout(LSIState *s)
             id = current_tag & 0x0000ff00;
             QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
                 if ((p->tag & 0x0000ff00) == id) {
-                    current_dev->info->cancel_io(p->req);
-                    QTAILQ_REMOVE(&s->queue, p, next);
+                    scsi_req_cancel(p->req);
                 }
             }
 
@@ -2227,7 +2243,8 @@ static int lsi_scsi_uninit(PCIDevice *d)
 }
 
 static struct SCSIBusOps lsi_scsi_ops = {
-    .complete = lsi_command_complete
+    .complete = lsi_command_complete,
+    .cancel = lsi_request_cancelled
 };
 
 static int lsi_scsi_init(PCIDevice *dev)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 1d7da9e..6a8ea0b 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -548,6 +548,19 @@ void scsi_req_complete(SCSIRequest *req)
     scsi_req_unref(req);
 }
 
+void scsi_req_cancel(SCSIRequest *req)
+{
+    if (req->dev && req->dev->info->cancel_io) {
+        req->dev->info->cancel_io(req);
+    }
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    if (req->bus->ops.cancel) {
+        req->bus->ops.cancel(req);
+    }
+    scsi_req_unref(req);
+}
+
 void scsi_req_abort(SCSIRequest *req, int status)
 {
     req->status = status;
@@ -563,9 +576,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev)
 
     while (!QTAILQ_EMPTY(&sdev->requests)) {
         req = QTAILQ_FIRST(&sdev->requests);
-        sdev->info->cancel_io(req);
-        scsi_req_dequeue(req);
-        scsi_req_unref(req);
+        scsi_req_cancel(req);
     }
 }
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 8962c33..0921c62 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -141,7 +141,6 @@ static void scsi_cancel_io(SCSIRequest *req)
         bdrv_aio_cancel(r->req.aiocb);
     }
     r->req.aiocb = NULL;
-    scsi_req_dequeue(&r->req);
 }
 
 static void scsi_read_complete(void * opaque, int ret)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 896797c..5bfbb8a 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -121,7 +121,6 @@ static void scsi_cancel_io(SCSIRequest *req)
         bdrv_aio_cancel(r->req.aiocb);
     }
     r->req.aiocb = NULL;
-    scsi_req_dequeue(&r->req);
 }
 
 static int execute_command(BlockDriverState *bdrv,
diff --git a/hw/scsi.h b/hw/scsi.h
index 6221fff..ee16638 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -78,6 +78,7 @@ struct SCSIDeviceInfo {
 
 struct SCSIBusOps {
     void (*complete)(SCSIRequest *req, int reason, uint32_t arg);
+    void (*cancel)(SCSIRequest *req);
 };
 
 struct SCSIBus {
@@ -115,6 +116,7 @@ void scsi_req_print(SCSIRequest *req);
 void scsi_req_data(SCSIRequest *req, int len);
 void scsi_req_complete(SCSIRequest *req);
 void scsi_req_abort(SCSIRequest *req, int status);
+void scsi_req_cancel(SCSIRequest *req);
 void scsi_device_purge_requests(SCSIDevice *sdev);
 
 #endif
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 678cd00..5b97a83 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -559,6 +559,14 @@ static void vscsi_command_complete(SCSIRequest *sreq, int 
reason, uint32_t arg)
     }
 }
 
+static void vscsi_request_cancelled(SCSIRequest *sreq)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
+    vscsi_req *req = vscsi_find_req(s, sreq);
+
+    vscsi_put_req(s, req);
+}
+
 static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
 {
     union viosrp_iu *iu = &req->iu;
@@ -910,7 +918,8 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t 
*crq_data)
 }
 
 static struct SCSIBusOps vscsi_scsi_ops = {
-    .complete = vscsi_command_complete
+    .complete = vscsi_command_complete,
+    .cancel = vscsi_request_cancelled
 };
 
 static int spapr_vscsi_init(VIOsPAPRDevice *dev)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 38f97d0..9b238e8 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -264,6 +264,18 @@ static void usb_msd_command_complete(SCSIRequest *req, int 
reason, uint32_t arg)
     }
 }
 
+static void usb_msd_request_cancelled(SCSIRequest *req)
+{
+    MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
+
+    if (req == s->req) {
+        scsi_req_unref(s->req);
+        s->req = NULL;
+        s->packet = NULL;
+        s->scsi_len = 0;
+    }
+}
+
 static void usb_msd_handle_reset(USBDevice *dev)
 {
     MSDState *s = (MSDState *)dev;
@@ -318,9 +330,7 @@ static int usb_msd_handle_control(USBDevice *dev, int 
request, int value,
 static void usb_msd_cancel_io(USBPacket *p, void *opaque)
 {
     MSDState *s = opaque;
-    s->scsi_dev->info->cancel_io(s->req);
-    s->packet = NULL;
-    s->scsi_len = 0;
+    scsi_req_cancel(s->req);
 }
 
 static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
@@ -491,7 +501,8 @@ static void usb_msd_password_cb(void *opaque, int err)
 }
 
 static struct SCSIBusOps usb_msd_scsi_ops = {
-    .complete = usb_msd_command_complete
+    .complete = usb_msd_command_complete,
+    .cancel = usb_msd_request_cancelled
 };
 
 static int usb_msd_initfn(USBDevice *dev)
-- 
1.7.4.4





reply via email to

[Prev in Thread] Current Thread [Next in Thread]