aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2011-04-18 22:53:08 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2011-05-26 12:14:15 +0200
commit94d3f98a3f3caddd7875f9a11776daeb84962a7b (patch)
tree54c5dd9f137b66c31087affaf6db2d07787b681c
parent19d110ab8af3308ce58d0936f085f0124930e7e7 (diff)
scsi: introduce scsi_req_cancel
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 <pbonzini@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--hw/esp.c16
-rw-r--r--hw/lsi53c895a.c30
-rw-r--r--hw/scsi-bus.c17
-rw-r--r--hw/scsi-disk.c1
-rw-r--r--hw/scsi-generic.c1
-rw-r--r--hw/scsi.h2
-rw-r--r--hw/spapr_vscsi.c11
-rw-r--r--hw/usb-msd.c19
8 files changed, 80 insertions, 17 deletions
diff --git a/hw/esp.c b/hw/esp.c
index 57061ca8c4..f2677dc88e 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 const 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 56234f836c..bca889a880 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 (s->current && 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)
@@ -931,7 +951,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 +976,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 +989,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 +2246,8 @@ static int lsi_scsi_uninit(PCIDevice *d)
}
static const 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 d6a055fa54..fd1d60fdbb 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -549,6 +549,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;
@@ -564,9 +577,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 38fbb05ab8..08633db169 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -143,7 +143,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 72c4cc702d..c008e9c59f 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 970e8129c9..e2dc7cb5e1 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 24cebd1843..5aaf95b974 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 const 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 8e6d48bf25..ce926828ec 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 const 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)