From 13a9a0d3e253e272744b523e39642c9b6d564f4d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 16 Dec 2010 17:03:44 +0100 Subject: usb: move complete callback to port ops --- hw/usb-msd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 947fd3f83c..93f4b78f3c 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -241,7 +241,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, s->mode = USB_MSDM_CSW; } s->packet = NULL; - usb_packet_complete(p); + usb_packet_complete(&s->dev, p); } else if (s->data_len == 0) { s->mode = USB_MSDM_CSW; } @@ -257,7 +257,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, usb_packet_complete returns. */ DPRINTF("Packet complete %p\n", p); s->packet = NULL; - usb_packet_complete(p); + usb_packet_complete(&s->dev, p); } } } -- cgit v1.2.3-55-g7522 From ef0bdf77d7070494692cbccd80c4c8f08c85c240 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 4 May 2011 16:49:56 +0200 Subject: usb: mass storage fix Initialize scsi_len with zero when starting a new request, so any stuff leftover from the previous request is cleared out. This may happen in case the data returned by the scsi command doesn't fit into the buffer provided by the guest. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw/usb-msd.c') diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 93f4b78f3c..bd1c3a415f 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -364,6 +364,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->residue = 0; + s->scsi_len = 0; s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0); /* ??? Should check that USB and SCSI data transfer directions match. */ -- cgit v1.2.3-55-g7522 From add750882f327db813af0795727efe5e4579ca5c Mon Sep 17 00:00:00 2001 From: Brad Hards Date: Sun, 3 Apr 2011 15:33:19 +1000 Subject: usb: update config descriptors to identify number of interfaces Previously we relied on the .bNumInterfaces, but that won't always be accurate after the introduction of grouped interfaces. Signed-off-by: Brad Hards Signed-off-by: Gerd Hoffmann --- hw/usb-hid.c | 3 +++ hw/usb-hub.c | 1 + hw/usb-msd.c | 2 ++ hw/usb-serial.c | 1 + hw/usb-wacom.c | 1 + 5 files changed, 8 insertions(+) (limited to 'hw/usb-msd.c') diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 89c293c466..bf59a7d748 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -211,6 +211,7 @@ static const USBDescDevice desc_device_mouse = { .iConfiguration = STR_CONFIG_MOUSE, .bmAttributes = 0xa0, .bMaxPower = 50, + .nif = 1, .ifs = &desc_iface_mouse, }, }, @@ -227,6 +228,7 @@ static const USBDescDevice desc_device_tablet = { .iConfiguration = STR_CONFIG_TABLET, .bmAttributes = 0xa0, .bMaxPower = 50, + .nif = 1, .ifs = &desc_iface_tablet, }, }, @@ -243,6 +245,7 @@ static const USBDescDevice desc_device_keyboard = { .iConfiguration = STR_CONFIG_KEYBOARD, .bmAttributes = 0xa0, .bMaxPower = 50, + .nif = 1, .ifs = &desc_iface_keyboard, }, }, diff --git a/hw/usb-hub.c b/hw/usb-hub.c index e0588f891d..7c1f1597d4 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -119,6 +119,7 @@ static const USBDescDevice desc_device_hub = { .bNumInterfaces = 1, .bConfigurationValue = 1, .bmAttributes = 0xe0, + .nif = 1, .ifs = &desc_iface_hub, }, }, diff --git a/hw/usb-msd.c b/hw/usb-msd.c index bd1c3a415f..040ea7a4c7 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -119,6 +119,7 @@ static const USBDescDevice desc_device_full = { .bConfigurationValue = 1, .iConfiguration = STR_CONFIG_FULL, .bmAttributes = 0xc0, + .nif = 1, .ifs = &desc_iface_full, }, }, @@ -153,6 +154,7 @@ static const USBDescDevice desc_device_high = { .bConfigurationValue = 1, .iConfiguration = STR_CONFIG_HIGH, .bmAttributes = 0xc0, + .nif = 1, .ifs = &desc_iface_high, }, }, diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 6763d52040..48ea0d8587 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -146,6 +146,7 @@ static const USBDescDevice desc_device = { .bConfigurationValue = 1, .bmAttributes = 0x80, .bMaxPower = 50, + .nif = 1, .ifs = &desc_iface0, }, }, diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index 16be7a20cf..57041a1b6e 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -108,6 +108,7 @@ static const USBDescDevice desc_device_wacom = { .bConfigurationValue = 1, .bmAttributes = 0x80, .bMaxPower = 40, + .nif = 1, .ifs = &desc_iface_wacom, }, }, -- cgit v1.2.3-55-g7522 From 007fd62f4d3959f2a61abe61a34a54c9f99560b0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 2 Feb 2011 16:33:13 +0100 Subject: usb: Pass the packet to the device's handle_control callback This allows using the generic usb_generic_handle_packet function from device code which does ASYNC control requests (such as the linux host pass through code). Signed-off-by: Hans de Goede --- hw/bt-hid.c | 6 +++--- hw/usb-bt.c | 6 +++--- hw/usb-ccid.c | 4 ++-- hw/usb-desc.c | 4 ++-- hw/usb-desc.h | 4 ++-- hw/usb-hid.c | 6 +++--- hw/usb-hub.c | 6 +++--- hw/usb-msd.c | 6 +++--- hw/usb-net.c | 6 +++--- hw/usb-serial.c | 6 +++--- hw/usb-wacom.c | 6 +++--- hw/usb.c | 11 +++++++---- hw/usb.h | 2 +- usb-bsd.c | 1 + 14 files changed, 39 insertions(+), 35 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/bt-hid.c b/hw/bt-hid.c index abdfd35e86..09120af074 100644 --- a/hw/bt-hid.c +++ b/hw/bt-hid.c @@ -323,7 +323,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s, break; } s->proto = parameter; - s->usbdev->info->handle_control(s->usbdev, SET_PROTOCOL, s->proto, 0, 0, + s->usbdev->info->handle_control(s->usbdev, NULL, SET_PROTOCOL, s->proto, 0, 0, NULL); ret = BT_HS_SUCCESSFUL; break; @@ -333,7 +333,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s, ret = BT_HS_ERR_INVALID_PARAMETER; break; } - s->usbdev->info->handle_control(s->usbdev, GET_IDLE, 0, 0, 1, + s->usbdev->info->handle_control(s->usbdev, NULL, GET_IDLE, 0, 0, 1, s->control->sdu_out(s->control, 1)); s->control->sdu_submit(s->control); break; @@ -346,7 +346,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s, /* We don't need to know about the Idle Rate here really, * so just pass it on to the device. */ - ret = s->usbdev->info->handle_control(s->usbdev, + ret = s->usbdev->info->handle_control(s->usbdev, NULL, SET_IDLE, data[1], 0, 0, NULL) ? BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER; /* XXX: Does this generate a handshake? */ diff --git a/hw/usb-bt.c b/hw/usb-bt.c index 22e6845049..baae4876ea 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -372,13 +372,13 @@ static void usb_bt_handle_reset(USBDevice *dev) s->altsetting = 0; } -static int usb_bt_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { struct USBBtState *s = (struct USBBtState *) dev->opaque; int ret; - ret = usb_desc_handle_control(dev, request, value, index, length, data); + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { switch (request) { case DeviceRequest | USB_REQ_GET_CONFIGURATION: diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index 079b4a2555..5b6878bea4 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -602,8 +602,8 @@ static void ccid_handle_reset(USBDevice *dev) ccid_reset(s); } -static int ccid_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, + int value, int index, int length, uint8_t *data) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); int ret = 0; diff --git a/hw/usb-desc.c b/hw/usb-desc.c index 8367c450d7..e4a4680fee 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -390,8 +390,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len return ret; } -int usb_desc_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +int usb_desc_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { const USBDesc *desc = dev->info->usb_desc; int i, ret = -1; diff --git a/hw/usb-desc.h b/hw/usb-desc.h index a612515c43..9d7ed599ce 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -106,7 +106,7 @@ void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str); const char *usb_desc_get_string(USBDevice *dev, uint8_t index); int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len); int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len); -int usb_desc_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data); +int usb_desc_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data); #endif /* QEMU_HW_USB_DESC_H */ diff --git a/hw/usb-hid.c b/hw/usb-hid.c index bf59a7d748..53b261c3b9 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -727,13 +727,13 @@ static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime) s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000; } -static int usb_hid_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { USBHIDState *s = (USBHIDState *)dev; int ret; - ret = usb_desc_handle_control(dev, request, value, index, length, data); + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return ret; } diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 7c1f1597d4..477927b653 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -285,13 +285,13 @@ static void usb_hub_handle_reset(USBDevice *dev) /* XXX: do it */ } -static int usb_hub_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { USBHubState *s = (USBHubState *)dev; int ret; - ret = usb_desc_handle_control(dev, request, value, index, length, data); + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return ret; } diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 040ea7a4c7..c3a197a10c 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -272,13 +272,13 @@ static void usb_msd_handle_reset(USBDevice *dev) s->mode = USB_MSDM_CBW; } -static int usb_msd_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { MSDState *s = (MSDState *)dev; int ret; - ret = usb_desc_handle_control(dev, request, value, index, length, data); + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return ret; } diff --git a/hw/usb-net.c b/hw/usb-net.c index bf51bb3890..9be709f7cf 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1042,13 +1042,13 @@ static void usb_net_handle_reset(USBDevice *dev) { } -static int usb_net_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int usb_net_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { USBNetState *s = (USBNetState *) dev; int ret; - ret = usb_desc_handle_control(dev, request, value, index, length, data); + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return ret; } diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 48ea0d8587..59cb0fb2f7 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -219,14 +219,14 @@ static uint8_t usb_get_modem_lines(USBSerialState *s) return ret; } -static int usb_serial_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { USBSerialState *s = (USBSerialState *)dev; int ret; DPRINTF("got control %x, value %x\n",request, value); - ret = usb_desc_handle_control(dev, request, value, index, length, data); + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return ret; } diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index 57041a1b6e..9d348e170e 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -250,13 +250,13 @@ static void usb_wacom_handle_reset(USBDevice *dev) s->mode = WACOM_MODE_HID; } -static int usb_wacom_handle_control(USBDevice *dev, int request, int value, - int index, int length, uint8_t *data) +static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, int length, uint8_t *data) { USBWacomState *s = (USBWacomState *) dev; int ret; - ret = usb_desc_handle_control(dev, request, value, index, length, data); + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return ret; } diff --git a/hw/usb.c b/hw/usb.c index d8c0a75c3a..f503b7a442 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -82,9 +82,9 @@ static int do_token_setup(USBDevice *s, USBPacket *p) request = (s->setup_buf[0] << 8) | s->setup_buf[1]; value = (s->setup_buf[3] << 8) | s->setup_buf[2]; index = (s->setup_buf[5] << 8) | s->setup_buf[4]; - + if (s->setup_buf[0] & USB_DIR_IN) { - ret = s->info->handle_control(s, request, value, index, + ret = s->info->handle_control(s, p, request, value, index, s->setup_len, s->data_buf); if (ret < 0) return ret; @@ -123,9 +123,12 @@ static int do_token_in(USBDevice *s, USBPacket *p) switch(s->setup_state) { case SETUP_STATE_ACK: if (!(s->setup_buf[0] & USB_DIR_IN)) { - s->setup_state = SETUP_STATE_IDLE; - ret = s->info->handle_control(s, request, value, index, + ret = s->info->handle_control(s, p, request, value, index, s->setup_len, s->data_buf); + if (ret == USB_RET_ASYNC) { + return USB_RET_ASYNC; + } + s->setup_state = SETUP_STATE_IDLE; if (ret > 0) return 0; return ret; diff --git a/hw/usb.h b/hw/usb.h index e0961ac135..b52fa34e84 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -214,7 +214,7 @@ struct USBDeviceInfo { * * Returns length or one of the USB_RET_ codes. */ - int (*handle_control)(USBDevice *dev, int request, int value, + int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data); /* diff --git a/usb-bsd.c b/usb-bsd.c index 50ccd489fe..9bab6e353b 100644 --- a/usb-bsd.c +++ b/usb-bsd.c @@ -126,6 +126,7 @@ static void usb_host_handle_reset(USBDevice *dev) * and return appropriate response */ static int usb_host_handle_control(USBDevice *dev, + USBPacket *p, int request, int value, int index, -- cgit v1.2.3-55-g7522 From ebd669a19f00d0ff8370e1edfb6232f50e42110d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 16 May 2011 14:25:59 +0200 Subject: usb-storage: don't call usb_packet_complete twice usb_msd_copy_data() may cause a recursive call to usb_msd_command_complete() which in turn may complete the packet, setting s->packet to NULL in case it does. Recheck s->packet before calling usb_packet_complete() to fix the double call. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/usb-msd.c') diff --git a/hw/usb-msd.c b/hw/usb-msd.c index c3a197a10c..1064920ac5 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -253,7 +253,7 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, s->scsi_buf = s->scsi_dev->info->get_buf(s->scsi_dev, tag); if (p) { usb_msd_copy_data(s); - if (s->usb_len == 0) { + if (s->packet && s->usb_len == 0) { /* Set s->packet to NULL before calling usb_packet_complete because another request may be issued before usb_packet_complete returns. */ -- cgit v1.2.3-55-g7522 From eb5e680ae5a72b999946e5618c501648367734a8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 16 May 2011 10:34:53 +0200 Subject: usb: move cancel callback to USBDeviceInfo Remove the cancel callback from the USBPacket struct, move it over to USBDeviceInfo. Zap usb_defer_packet() which is obsolete now. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 8 +++----- hw/usb.c | 2 +- hw/usb.h | 17 +++++------------ usb-linux.c | 7 +++---- 4 files changed, 12 insertions(+), 22 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 1064920ac5..141da2ce8a 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -315,9 +315,9 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, return ret; } -static void usb_msd_cancel_io(USBPacket *p, void *opaque) +static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p) { - MSDState *s = opaque; + MSDState *s = DO_UPCAST(MSDState, dev, dev); s->scsi_dev->info->cancel_io(s->scsi_dev, s->tag); s->packet = NULL; s->scsi_len = 0; @@ -398,7 +398,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } if (s->usb_len) { DPRINTF("Deferring packet %p\n", p); - usb_defer_packet(p, usb_msd_cancel_io, s); s->packet = p; ret = USB_RET_ASYNC; } else { @@ -421,7 +420,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (s->data_len != 0 || len < 13) goto fail; /* Waiting for SCSI write to complete. */ - usb_defer_packet(p, usb_msd_cancel_io, s); s->packet = p; ret = USB_RET_ASYNC; break; @@ -455,7 +453,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } if (s->usb_len) { DPRINTF("Deferring packet %p\n", p); - usb_defer_packet(p, usb_msd_cancel_io, s); s->packet = p; ret = USB_RET_ASYNC; } else { @@ -604,6 +601,7 @@ static struct USBDeviceInfo msd_info = { .usb_desc = &desc, .init = usb_msd_initfn, .handle_packet = usb_generic_handle_packet, + .cancel_packet = usb_msd_cancel_io, .handle_attach = usb_desc_attach, .handle_reset = usb_msd_handle_reset, .handle_control = usb_msd_handle_control, diff --git a/hw/usb.c b/hw/usb.c index 8a9a7fcb25..4a39cbcc7d 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -345,6 +345,6 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p) void usb_cancel_packet(USBPacket * p) { assert(p->owner != NULL); - p->cancel_cb(p, p->cancel_opaque); + p->owner->info->cancel_packet(p->owner, p); p->owner = NULL; } diff --git a/hw/usb.h b/hw/usb.h index 80e8e902c6..98824009b9 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -193,6 +193,11 @@ struct USBDeviceInfo { */ int (*handle_packet)(USBDevice *dev, USBPacket *p); + /* + * Called when a packet is canceled. + */ + void (*cancel_packet)(USBDevice *dev, USBPacket *p); + /* * Called when device is destroyed. */ @@ -263,24 +268,12 @@ struct USBPacket { int len; /* Internal use by the USB layer. */ USBDevice *owner; - USBCallback *cancel_cb; - void *cancel_opaque; }; int usb_handle_packet(USBDevice *dev, USBPacket *p); void usb_packet_complete(USBDevice *dev, USBPacket *p); void usb_cancel_packet(USBPacket * p); -/* Defer completion of a USB packet. The hadle_packet routine should then - return USB_RET_ASYNC. Packets that complete immediately (before - handle_packet returns) should not call this method. */ -static inline void usb_defer_packet(USBPacket *p, USBCallback *cancel, - void * opaque) -{ - p->cancel_cb = cancel; - p->cancel_opaque = opaque; -} - void usb_attach(USBPort *port, USBDevice *dev); void usb_wakeup(USBDevice *dev); int usb_generic_handle_packet(USBDevice *s, USBPacket *p); diff --git a/usb-linux.c b/usb-linux.c index c7e96c3e63..baa6574ef5 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -335,9 +335,9 @@ static void async_complete(void *opaque) } } -static void async_cancel(USBPacket *p, void *opaque) +static void usb_host_async_cancel(USBDevice *dev, USBPacket *p) { - USBHostDevice *s = opaque; + USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); AsyncURB *aurb; QLIST_FOREACH(aurb, &s->aurbs, next) { @@ -736,7 +736,6 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) } } - usb_defer_packet(p, async_cancel, s); return USB_RET_ASYNC; } @@ -868,7 +867,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, } } - usb_defer_packet(p, async_cancel, s); return USB_RET_ASYNC; } @@ -1197,6 +1195,7 @@ static struct USBDeviceInfo usb_host_dev_info = { .qdev.size = sizeof(USBHostDevice), .init = usb_host_initfn, .handle_packet = usb_generic_handle_packet, + .cancel_packet = usb_host_async_cancel, .handle_data = usb_host_handle_data, .handle_control = usb_host_handle_control, .handle_reset = usb_host_handle_reset, -- cgit v1.2.3-55-g7522 From cfdc1bb06ee4cd3a7e4aa0ebf14b00c0ce3a5e94 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 18 Apr 2011 17:11:14 +0200 Subject: scsi: introduce SCSIBusOps There are more operations than a SCSI bus can handle, besides completing commands. One example, which this series will introduce, is cleaning up after a request is cancelled. More long term, a "SCSI bus" can represent the LUNs attached to a target; in this case, while all commands will ultimately reach a logical unit, it is the target who is in charge of answering REPORT LUNs. Signed-off-by: Paolo Bonzini Cc: Christoph Hellwig --- hw/esp.c | 6 +++++- hw/lsi53c895a.c | 6 +++++- hw/scsi-bus.c | 12 ++++++------ hw/scsi-generic.c | 2 +- hw/scsi.h | 13 +++++++------ hw/spapr_vscsi.c | 6 +++++- hw/usb-msd.c | 6 +++++- 7 files changed, 34 insertions(+), 17 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/esp.c b/hw/esp.c index fa9d2a2706..ae18401a25 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -714,6 +714,10 @@ void esp_init(target_phys_addr_t espaddr, int it_shift, *dma_enable = qdev_get_gpio_in(dev, 1); } +static const struct SCSIBusOps esp_scsi_ops = { + .complete = esp_command_complete +}; + static int esp_init1(SysBusDevice *dev) { ESPState *s = FROM_SYSBUS(ESPState, dev); @@ -728,7 +732,7 @@ static int esp_init1(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2); - scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete); + scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, &esp_scsi_ops); return scsi_bus_legacy_handle_cmdline(&s->bus); } diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 2ce38a97ae..704e8ad2d4 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -2205,6 +2205,10 @@ static int lsi_scsi_uninit(PCIDevice *d) return 0; } +static const struct SCSIBusOps lsi_scsi_ops = { + .complete = lsi_command_complete +}; + static int lsi_scsi_init(PCIDevice *dev) { LSIState *s = DO_UPCAST(LSIState, dev, dev); @@ -2241,7 +2245,7 @@ static int lsi_scsi_init(PCIDevice *dev) PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc); QTAILQ_INIT(&s->queue); - scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, lsi_command_complete); + scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, &lsi_scsi_ops); if (!dev->qdev.hotplugged) { return scsi_bus_legacy_handle_cmdline(&s->bus); } diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 191cbabc44..1850a87da0 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -21,13 +21,13 @@ static int next_scsi_bus; /* Create a scsi bus, and attach devices to it. */ void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev, - scsi_completionfn complete) + const SCSIBusOps *ops) { qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL); bus->busnr = next_scsi_bus++; bus->tcq = tcq; bus->ndev = ndev; - bus->complete = complete; + bus->ops = ops; bus->qbus.allow_hotplug = 1; } @@ -503,7 +503,7 @@ static const char *scsi_command_name(uint8_t cmd) void scsi_req_data(SCSIRequest *req, int len) { trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); - req->bus->complete(req->bus, SCSI_REASON_DATA, req->tag, len); + req->bus->ops->complete(req->bus, SCSI_REASON_DATA, req->tag, len); } void scsi_req_print(SCSIRequest *req) @@ -538,9 +538,9 @@ void scsi_req_complete(SCSIRequest *req) { assert(req->status != -1); scsi_req_dequeue(req); - req->bus->complete(req->bus, SCSI_REASON_DONE, - req->tag, - req->status); + req->bus->ops->complete(req->bus, SCSI_REASON_DONE, + req->tag, + req->status); } static char *scsibus_get_fw_dev_path(DeviceState *dev) diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index e4f1f3079e..f09458bec1 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -335,7 +335,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, s->senselen = 7; s->driver_status = SG_ERR_DRIVER_SENSE; bus = scsi_bus_from_device(d); - bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION); + bus->ops->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION); return 0; } diff --git a/hw/scsi.h b/hw/scsi.h index 7c09f32d4d..d4ecc9bec4 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -16,10 +16,9 @@ enum scsi_reason { }; typedef struct SCSIBus SCSIBus; +typedef struct SCSIBusOps SCSIBusOps; typedef struct SCSIDevice SCSIDevice; typedef struct SCSIDeviceInfo SCSIDeviceInfo; -typedef void (*scsi_completionfn)(SCSIBus *bus, int reason, uint32_t tag, - uint32_t arg); enum SCSIXferMode { SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */ @@ -74,20 +73,22 @@ struct SCSIDeviceInfo { uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag); }; -typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv, - int unit); +struct SCSIBusOps { + void (*complete)(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg); +}; + struct SCSIBus { BusState qbus; int busnr; int tcq, ndev; - scsi_completionfn complete; + const SCSIBusOps *ops; SCSIDevice *devs[MAX_SCSI_DEVS]; }; void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev, - scsi_completionfn complete); + const SCSIBusOps *ops); void scsi_qdev_register(SCSIDeviceInfo *info); static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 992833450c..c183008e42 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -907,6 +907,10 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) return 0; } +static const struct SCSIBusOps vscsi_scsi_ops = { + .complete = vscsi_command_complete +}; + static int spapr_vscsi_init(VIOsPAPRDevice *dev) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); @@ -923,7 +927,7 @@ static int spapr_vscsi_init(VIOsPAPRDevice *dev) dev->crq.SendFunc = vscsi_do_crq; scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT, - vscsi_command_complete); + &vscsi_scsi_ops); if (!dev->qdev.hotplugged) { scsi_bus_legacy_handle_cmdline(&s->bus); } diff --git a/hw/usb-msd.c b/hw/usb-msd.c index bd1c3a415f..c0a381abb3 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -487,6 +487,10 @@ static void usb_msd_password_cb(void *opaque, int err) qdev_unplug(&s->dev.qdev); } +static const struct SCSIBusOps usb_msd_scsi_ops = { + .complete = usb_msd_command_complete +}; + static int usb_msd_initfn(USBDevice *dev) { MSDState *s = DO_UPCAST(MSDState, dev, dev); @@ -516,7 +520,7 @@ static int usb_msd_initfn(USBDevice *dev) } usb_desc_init(dev); - scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete); + scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, &usb_msd_scsi_ops); s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable); if (!s->scsi_dev) { return -1; -- cgit v1.2.3-55-g7522 From 5c6c0e513600ba57c3e73b7151d3c0664438f7b5 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 18 Apr 2011 12:35:39 +0200 Subject: scsi: Use 'SCSIRequest' directly Currently the SCSIRequest structure is abstracted away and cannot accessed directly from the driver. This requires the handler to do a lookup on an abstract 'tag' which identifies the SCSIRequest structure. With this patch the SCSIRequest structure is exposed to the driver. This allows use to use it directly as an argument to the SCSIDeviceInfo callback functions and remove the lookup. A new callback function 'alloc_req' is introduced matching 'free req'; unref'ing to free up resources after use is moved into the scsi_command_complete callbacks. This temporarily introduces a leak of requests that are cancelled, when they are removed from the queue and not from the driver. This is fixed later by introducing scsi_req_cancel. That patch in turn depends on this one, because the argument to scsi_req_cancel is a SCSIRequest. Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini Reviewed-by: Christoph Hellwig --- hw/esp.c | 27 ++++++++----- hw/lsi53c895a.c | 56 +++++++++++++++----------- hw/scsi-bus.c | 25 ++++-------- hw/scsi-disk.c | 118 +++++++++++++++--------------------------------------- hw/scsi-generic.c | 107 +++++++++++++++---------------------------------- hw/scsi.h | 21 +++++----- hw/spapr_vscsi.c | 44 +++++++++++--------- hw/usb-msd.c | 27 +++++++------ 8 files changed, 173 insertions(+), 252 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/esp.c b/hw/esp.c index ae18401a25..57061ca8c4 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -65,6 +65,7 @@ struct ESPState { uint32_t dma; SCSIBus bus; SCSIDevice *current_dev; + SCSIRequest *current_req; uint8_t cmdbuf[TI_BUFSZ]; uint32_t cmdlen; uint32_t do_cmd; @@ -209,7 +210,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_dev, 0); + s->current_dev->info->cancel_io(s->current_req); s->async_len = 0; } @@ -232,7 +233,8 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) DPRINTF("do_busid_cmd: busid 0x%x\n", busid); lun = busid & 7; - datalen = s->current_dev->info->send_command(s->current_dev, 0, buf, lun); + s->current_req = s->current_dev->info->alloc_req(s->current_dev, 0, lun); + datalen = s->current_dev->info->send_command(s->current_req, buf); s->ti_size = datalen; if (datalen != 0) { s->rregs[ESP_RSTAT] = STAT_TC; @@ -240,10 +242,10 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) s->dma_counter = 0; if (datalen > 0) { s->rregs[ESP_RSTAT] |= STAT_DI; - s->current_dev->info->read_data(s->current_dev, 0); + s->current_dev->info->read_data(s->current_req); } else { s->rregs[ESP_RSTAT] |= STAT_DO; - s->current_dev->info->write_data(s->current_dev, 0); + s->current_dev->info->write_data(s->current_req); } } s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; @@ -372,9 +374,9 @@ static void esp_do_dma(ESPState *s) if (s->async_len == 0) { if (to_device) { // ti_size is negative - s->current_dev->info->write_data(s->current_dev, 0); + s->current_dev->info->write_data(s->current_req); } else { - s->current_dev->info->read_data(s->current_dev, 0); + s->current_dev->info->read_data(s->current_req); /* If there is still data to be read from the device then complete the DMA operation immediately. Otherwise defer until the scsi layer has completed. */ @@ -388,10 +390,9 @@ static void esp_do_dma(ESPState *s) } } -static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag, - uint32_t arg) +static void esp_command_complete(SCSIRequest *req, int reason, uint32_t arg) { - ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent); + ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); if (reason == SCSI_REASON_DONE) { DPRINTF("SCSI Command complete\n"); @@ -405,11 +406,15 @@ static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag, s->sense = arg; s->rregs[ESP_RSTAT] = STAT_ST; esp_dma_done(s); - s->current_dev = NULL; + if (s->current_req) { + scsi_req_unref(s->current_req); + s->current_req = NULL; + s->current_dev = NULL; + } } else { DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); s->async_len = arg; - s->async_buf = s->current_dev->info->get_buf(s->current_dev, 0); + s->async_buf = s->current_dev->info->get_buf(req); if (s->dma_left) { esp_do_dma(s); } else if (s->dma_counter != 0 && s->ti_size <= 0) { diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 1ebcde74ef..56234f836c 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -174,6 +174,7 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #define LSI_TAG_VALID (1 << 16) typedef struct lsi_request { + SCSIRequest *req; uint32_t tag; uint32_t dma_len; uint8_t *dma_buf; @@ -567,11 +568,9 @@ static void lsi_do_dma(LSIState *s, int out) s->csbc += count; s->dnad += count; s->dbc -= count; - - if (s->current->dma_buf == NULL) { - s->current->dma_buf = dev->info->get_buf(dev, s->current->tag); + if (s->current->dma_buf == NULL) { + s->current->dma_buf = dev->info->get_buf(s->current->req); } - /* ??? Set SFBR to first data byte. */ if (out) { cpu_physical_memory_read(addr, s->current->dma_buf, count); @@ -583,10 +582,10 @@ static void lsi_do_dma(LSIState *s, int out) s->current->dma_buf = NULL; if (out) { /* Write the data. */ - dev->info->write_data(dev, s->current->tag); + dev->info->write_data(s->current->req); } else { /* Request any remaining data. */ - dev->info->read_data(dev, s->current->tag); + dev->info->read_data(s->current->req); } } else { s->current->dma_buf += count; @@ -698,12 +697,10 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) return 1; } } - -/* Callback to indicate that the SCSI layer has completed a transfer. */ -static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, - uint32_t arg) + /* Callback to indicate that the SCSI layer has completed a transfer. */ +static void lsi_command_complete(SCSIRequest *req, int reason, uint32_t arg) { - LSIState *s = DO_UPCAST(LSIState, dev.qdev, bus->qbus.parent); + LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); int out; out = (s->sstat1 & PHASE_MASK) == PHASE_DO; @@ -718,21 +715,24 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, lsi_set_phase(s, PHASE_ST); } - qemu_free(s->current); - s->current = NULL; - + if (s->current && req == s->current->req) { + scsi_req_unref(s->current->req); + qemu_free(s->current); + s->current = NULL; + } lsi_resume_script(s); return; } - if (s->waiting == 1 || !s->current || tag != s->current->tag || + if (s->waiting == 1 || !s->current || req->tag != s->current->tag || (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { - if (lsi_queue_tag(s, tag, arg)) + if (lsi_queue_tag(s, req->tag, arg)) { return; + } } /* host adapter (re)connected */ - DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); + DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, arg); s->current->dma_len = arg; s->command_complete = 1; if (!s->waiting) @@ -768,14 +768,16 @@ static void lsi_do_command(LSIState *s) assert(s->current == NULL); s->current = qemu_mallocz(sizeof(lsi_request)); s->current->tag = s->select_tag; + s->current->req = dev->info->alloc_req(dev, s->current->tag, + s->current_lun); - n = dev->info->send_command(dev, s->current->tag, buf, s->current_lun); + n = dev->info->send_command(s->current->req, buf); if (n > 0) { lsi_set_phase(s, PHASE_DI); - dev->info->read_data(dev, s->current->tag); + dev->info->read_data(s->current->req); } else if (n < 0) { lsi_set_phase(s, PHASE_DO); - dev->info->write_data(dev, s->current->tag); + dev->info->write_data(s->current->req); } if (!s->command_complete) { @@ -868,13 +870,15 @@ static void lsi_do_msgout(LSIState *s) int len; uint32_t current_tag; SCSIDevice *current_dev; - lsi_request *p, *p_next; + lsi_request *current_req, *p, *p_next; int id; if (s->current) { current_tag = s->current->tag; + current_req = s->current; } else { 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]; @@ -926,7 +930,9 @@ static void lsi_do_msgout(LSIState *s) case 0x0d: /* The ABORT TAG message clears the current I/O process only. */ DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag); - current_dev->info->cancel_io(current_dev, current_tag); + if (current_req) { + current_dev->info->cancel_io(current_req->req); + } lsi_disconnect(s); break; case 0x06: @@ -949,7 +955,9 @@ static void lsi_do_msgout(LSIState *s) } /* clear the current I/O process */ - current_dev->info->cancel_io(current_dev, current_tag); + if (s->current) { + current_dev->info->cancel_io(s->current->req); + } /* As the current implemented devices scsi_disk and scsi_generic only support one LUN, we don't need to keep track of LUNs. @@ -961,7 +969,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(current_dev, p->tag); + current_dev->info->cancel_io(p->req); QTAILQ_REMOVE(&s->queue, p, next); } } diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index e7fd903621..c7748d0ead 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -136,29 +136,22 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l SCSIRequest *req; req = qemu_mallocz(size); - /* Two references: one is passed back to the HBA, one is in d->requests. */ - req->refcount = 2; + req->refcount = 1; req->bus = scsi_bus_from_device(d); req->dev = d; req->tag = tag; req->lun = lun; req->status = -1; - req->enqueued = true; trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); - QTAILQ_INSERT_TAIL(&d->requests, req, next); return req; } -SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag) +void scsi_req_enqueue(SCSIRequest *req) { - SCSIRequest *req; - - QTAILQ_FOREACH(req, &d->requests, next) { - if (req->tag == tag) { - return req; - } - } - return NULL; + assert(!req->enqueued); + scsi_req_ref(req); + req->enqueued = true; + QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); } void scsi_req_dequeue(SCSIRequest *req) @@ -516,7 +509,7 @@ void scsi_req_unref(SCSIRequest *req) void scsi_req_data(SCSIRequest *req, int len) { trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); - req->bus->ops->complete(req->bus, SCSI_REASON_DATA, req->tag, len); + req->bus->ops->complete(req, SCSI_REASON_DATA, len); } void scsi_req_print(SCSIRequest *req) @@ -552,9 +545,7 @@ void scsi_req_complete(SCSIRequest *req) assert(req->status != -1); scsi_req_ref(req); scsi_req_dequeue(req); - req->bus->ops->complete(req->bus, SCSI_REASON_DONE, - req->tag, - req->status); + req->bus->ops->complete(req, SCSI_REASON_DONE, req->status); scsi_req_unref(req); } diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 87d7b9305d..f7c09c9b79 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -86,16 +86,17 @@ struct SCSIDiskState static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf); -static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag, +static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIRequest *req; SCSIDiskReq *r; req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun); r = DO_UPCAST(SCSIDiskReq, req, req); r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE); - return r; + return req; } static void scsi_free_request(SCSIRequest *req) @@ -105,11 +106,6 @@ static void scsi_free_request(SCSIRequest *req) qemu_vfree(r->iov.iov_base); } -static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag) -{ - return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag)); -} - static void scsi_disk_clear_sense(SCSIDiskState *s) { memset(&s->sense, 0, sizeof(s->sense)); @@ -138,18 +134,16 @@ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense) } /* Cancel a pending data transfer. */ -static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) +static void scsi_cancel_io(SCSIRequest *req) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIDiskReq *r; - DPRINTF("Cancel tag=0x%x\n", tag); - r = scsi_find_request(s, tag); - if (r) { - if (r->req.aiocb) - bdrv_aio_cancel(r->req.aiocb); - r->req.aiocb = NULL; - scsi_req_dequeue(&r->req); + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); + + DPRINTF("Cancel tag=0x%x\n", req->tag); + if (r->req.aiocb) { + bdrv_aio_cancel(r->req.aiocb); } + r->req.aiocb = NULL; + scsi_req_dequeue(&r->req); } static void scsi_read_complete(void * opaque, int ret) @@ -174,8 +168,10 @@ static void scsi_read_complete(void * opaque, int ret) } -static void scsi_read_request(SCSIDiskReq *r) +/* Read more data from scsi device into buffer. */ +static void scsi_read_data(SCSIRequest *req) { + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint32_t n; @@ -207,23 +203,6 @@ static void scsi_read_request(SCSIDiskReq *r) } } -/* Read more data from scsi device into buffer. */ -static void scsi_read_data(SCSIDevice *d, uint32_t tag) -{ - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIDiskReq *r; - - r = scsi_find_request(s, tag); - if (!r) { - BADF("Bad read tag 0x%x\n", tag); - /* ??? This is the wrong error. */ - scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - return; - } - - scsi_read_request(r); -} - static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) { int is_read = (type == SCSI_REQ_STATUS_RETRY_READ); @@ -285,8 +264,9 @@ static void scsi_write_complete(void * opaque, int ret) } } -static void scsi_write_request(SCSIDiskReq *r) +static int scsi_write_data(SCSIRequest *req) { + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint32_t n; @@ -305,24 +285,6 @@ static void scsi_write_request(SCSIDiskReq *r) /* Invoke completion routine to fetch data from host. */ scsi_write_complete(r, 0); } -} - -/* Write data to a scsi device. Returns nonzero on failure. - The transfer may complete asynchronously. */ -static int scsi_write_data(SCSIDevice *d, uint32_t tag) -{ - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIDiskReq *r; - - DPRINTF("Write data tag=0x%x\n", tag); - r = scsi_find_request(s, tag); - if (!r) { - BADF("Bad write tag 0x%x\n", tag); - scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - return 1; - } - - scsi_write_request(r); return 0; } @@ -347,10 +309,10 @@ static void scsi_dma_restart_bh(void *opaque) switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) { case SCSI_REQ_STATUS_RETRY_READ: - scsi_read_request(r); + scsi_read_data(&r->req); break; case SCSI_REQ_STATUS_RETRY_WRITE: - scsi_write_request(r); + scsi_write_data(&r->req); break; case SCSI_REQ_STATUS_RETRY_FLUSH: ret = scsi_disk_emulate_command(r, r->iov.iov_base); @@ -376,16 +338,10 @@ static void scsi_dma_restart_cb(void *opaque, int running, int reason) } /* Return a pointer to the data buffer. */ -static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) +static uint8_t *scsi_get_buf(SCSIRequest *req) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); - SCSIDiskReq *r; + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); - r = scsi_find_request(s, tag); - if (!r) { - BADF("Bad buffer tag 0x%x\n", tag); - return NULL; - } return (uint8_t *)r->iov.iov_base; } @@ -1029,26 +985,18 @@ illegal_request: (eg. disk reads), negative for transfers to the device (eg. disk writes), and zero if the command does not transfer any data. */ -static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, - uint8_t *buf, int lun) +static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); int32_t len; int is_write; uint8_t command; uint8_t *outbuf; - SCSIDiskReq *r; int rc; + scsi_req_enqueue(req); command = buf[0]; - r = scsi_find_request(s, tag); - if (r) { - BADF("Tag 0x%x already in use\n", tag); - scsi_cancel_io(d, tag); - } - /* ??? Tags are not unique for different luns. We only implement a - single lun, so this should not matter. */ - r = scsi_new_request(s, tag, lun); outbuf = (uint8_t *)r->iov.iov_base; is_write = 0; DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); @@ -1067,9 +1015,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } #endif - if (lun || buf[1] >> 5) { + if (req->lun || buf[1] >> 5) { /* Only LUN 0 supported. */ - DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); + DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : buf[1] >> 5); if (command != REQUEST_SENSE && command != INQUIRY) goto fail; } @@ -1095,7 +1043,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case REZERO_UNIT: rc = scsi_disk_emulate_command(r, outbuf); if (rc < 0) { - scsi_req_unref(&r->req); return 0; } @@ -1105,7 +1052,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case READ_10: case READ_12: case READ_16: - len = r->req.cmd.xfer / d->blocksize; + len = r->req.cmd.xfer / s->qdev.blocksize; DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); if (r->req.cmd.lba > s->max_lba) goto illegal_lba; @@ -1119,7 +1066,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, case WRITE_VERIFY: case WRITE_VERIFY_12: case WRITE_VERIFY_16: - len = r->req.cmd.xfer / d->blocksize; + len = r->req.cmd.xfer / s->qdev.blocksize; DPRINTF("Write %s(sector %" PRId64 ", count %d)\n", (command & 0xe) == 0xe ? "And Verify " : "", r->req.cmd.lba, len); @@ -1154,7 +1101,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } break; case WRITE_SAME_16: - len = r->req.cmd.xfer / d->blocksize; + len = r->req.cmd.xfer / s->qdev.blocksize; DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); @@ -1182,11 +1129,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); fail: scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST); - scsi_req_unref(&r->req); return 0; illegal_lba: scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); - scsi_req_unref(&r->req); return 0; } if (r->sector_count == 0 && r->iov.iov_len == 0) { @@ -1199,7 +1144,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, if (!r->sector_count) r->sector_count = -1; } - scsi_req_unref(&r->req); return len; } @@ -1213,6 +1157,7 @@ static void scsi_disk_purge_requests(SCSIDiskState *s) bdrv_aio_cancel(r->req.aiocb); } scsi_req_dequeue(&r->req); + scsi_req_unref(&r->req); } } @@ -1325,6 +1270,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .qdev.reset = scsi_disk_reset, .init = scsi_hd_initfn, .destroy = scsi_destroy, + .alloc_req = scsi_new_request, .free_req = scsi_free_request, .send_command = scsi_send_command, .read_data = scsi_read_data, @@ -1344,6 +1290,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .qdev.reset = scsi_disk_reset, .init = scsi_cd_initfn, .destroy = scsi_destroy, + .alloc_req = scsi_new_request, .free_req = scsi_free_request, .send_command = scsi_send_command, .read_data = scsi_read_data, @@ -1362,6 +1309,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .qdev.reset = scsi_disk_reset, .init = scsi_disk_initfn, .destroy = scsi_destroy, + .alloc_req = scsi_new_request, .free_req = scsi_free_request, .send_command = scsi_send_command, .read_data = scsi_read_data, diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 06e9dfea8b..3740432d9e 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -66,12 +66,12 @@ struct SCSIGenericState uint8_t senselen; }; -static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) +static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) { SCSIRequest *req; req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun); - return DO_UPCAST(SCSIGenericReq, req, req); + return req; } static void scsi_free_request(SCSIRequest *req) @@ -81,11 +81,6 @@ static void scsi_free_request(SCSIRequest *req) qemu_free(r->buf); } -static SCSIGenericReq *scsi_find_request(SCSIGenericState *s, uint32_t tag) -{ - return DO_UPCAST(SCSIGenericReq, req, scsi_req_find(&s->qdev, tag)); -} - /* Helper function for command completion. */ static void scsi_command_complete(void *opaque, int ret) { @@ -117,19 +112,16 @@ static void scsi_command_complete(void *opaque, int ret) } /* Cancel a pending data transfer. */ -static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) +static void scsi_cancel_io(SCSIRequest *req) { - DPRINTF("scsi_cancel_io 0x%x\n", tag); - SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIGenericReq *r; - DPRINTF("Cancel tag=0x%x\n", tag); - r = scsi_find_request(s, tag); - if (r) { - if (r->req.aiocb) - bdrv_aio_cancel(r->req.aiocb); - r->req.aiocb = NULL; - scsi_req_dequeue(&r->req); + SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); + + DPRINTF("Cancel tag=0x%x\n", req->tag); + if (r->req.aiocb) { + bdrv_aio_cancel(r->req.aiocb); } + r->req.aiocb = NULL; + scsi_req_dequeue(&r->req); } static int execute_command(BlockDriverState *bdrv, @@ -182,21 +174,13 @@ static void scsi_read_complete(void * opaque, int ret) } /* Read more data from scsi device into buffer. */ -static void scsi_read_data(SCSIDevice *d, uint32_t tag) +static void scsi_read_data(SCSIRequest *req) { - SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIGenericReq *r; + SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev); int ret; - DPRINTF("scsi_read_data 0x%x\n", tag); - r = scsi_find_request(s, tag); - if (!r) { - BADF("Bad read tag 0x%x\n", tag); - /* ??? This is the wrong error. */ - scsi_command_complete(r, -EINVAL); - return; - } - + DPRINTF("scsi_read_data 0x%x\n", req->tag); if (r->len == -1) { scsi_command_complete(r, 0); return; @@ -249,21 +233,13 @@ static void scsi_write_complete(void * opaque, int ret) /* Write data to a scsi device. Returns nonzero on failure. The transfer may complete asynchronously. */ -static int scsi_write_data(SCSIDevice *d, uint32_t tag) +static int scsi_write_data(SCSIRequest *req) { - SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIGenericReq *r; + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev); + SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); int ret; - DPRINTF("scsi_write_data 0x%x\n", tag); - r = scsi_find_request(s, tag); - if (!r) { - BADF("Bad write tag 0x%x\n", tag); - /* ??? This is the wrong error. */ - scsi_command_complete(r, -EINVAL); - return 0; - } - + DPRINTF("scsi_write_data 0x%x\n", req->tag); if (r->len == 0) { r->len = r->buflen; scsi_req_data(&r->req, r->len); @@ -280,15 +256,10 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) } /* Return a pointer to the data buffer. */ -static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) +static uint8_t *scsi_get_buf(SCSIRequest *req) { - SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIGenericReq *r; - r = scsi_find_request(s, tag); - if (!r) { - BADF("Bad buffer tag 0x%x\n", tag); - return NULL; - } + SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); + return r->buf; } @@ -316,18 +287,17 @@ static void scsi_req_fixup(SCSIRequest *req) (eg. disk reads), negative for transfers to the device (eg. disk writes), and zero if the command does not transfer any data. */ -static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, - uint8_t *cmd, int lun) +static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) { - SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); - SCSIGenericReq *r; + SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev); + SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); SCSIBus *bus; int ret; - int32_t len; + scsi_req_enqueue(req); if (cmd[0] != REQUEST_SENSE && - (lun != s->lun || (cmd[1] >> 5) != s->lun)) { - DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5); + (req->lun != s->lun || (cmd[1] >> 5) != s->lun)) { + DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : cmd[1] >> 5); s->sensebuf[0] = 0x70; s->sensebuf[1] = 0x00; @@ -338,18 +308,11 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, s->sensebuf[6] = 0x00; s->senselen = 7; s->driver_status = SG_ERR_DRIVER_SENSE; - bus = scsi_bus_from_device(d); - bus->ops->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION); + bus = scsi_bus_from_device(&s->qdev); + bus->ops->complete(req, SCSI_REASON_DONE, CHECK_CONDITION); return 0; } - r = scsi_find_request(s, tag); - if (r) { - BADF("Tag 0x%x already in use %p\n", tag, r); - scsi_cancel_io(d, tag); - } - r = scsi_new_request(d, tag, lun); - if (-1 == scsi_req_parse(&r->req, cmd)) { BADF("Unsupported command length, command %x\n", cmd[0]); scsi_req_dequeue(&r->req); @@ -379,10 +342,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete); if (ret == -1) { scsi_command_complete(r, -EINVAL); - scsi_req_unref(&r->req); - return 0; } - scsi_req_unref(&r->req); return 0; } @@ -397,13 +357,10 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, r->len = r->req.cmd.xfer; if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { r->len = 0; - len = -r->req.cmd.xfer; + return -r->req.cmd.xfer; } else { - len = r->req.cmd.xfer; + return r->req.cmd.xfer; } - - scsi_req_unref(&r->req); - return len; } static int get_blocksize(BlockDriverState *bdrv) @@ -477,6 +434,7 @@ static void scsi_generic_purge_requests(SCSIGenericState *s) bdrv_aio_cancel(r->req.aiocb); } scsi_req_dequeue(&r->req); + scsi_req_unref(&r->req); } } @@ -568,6 +526,7 @@ static SCSIDeviceInfo scsi_generic_info = { .qdev.reset = scsi_generic_reset, .init = scsi_generic_initfn, .destroy = scsi_destroy, + .alloc_req = scsi_new_request, .free_req = scsi_free_request, .send_command = scsi_send_command, .read_data = scsi_read_data, diff --git a/hw/scsi.h b/hw/scsi.h index a1d0e7451f..19bd1ae774 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -19,6 +19,7 @@ typedef struct SCSIBus SCSIBus; typedef struct SCSIBusOps SCSIBusOps; typedef struct SCSIDevice SCSIDevice; typedef struct SCSIDeviceInfo SCSIDeviceInfo; +typedef struct SCSIRequest SCSIRequest; enum SCSIXferMode { SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */ @@ -26,7 +27,7 @@ enum SCSIXferMode { SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ }; -typedef struct SCSIRequest { +struct SCSIRequest { SCSIBus *bus; SCSIDevice *dev; uint32_t refcount; @@ -43,7 +44,7 @@ typedef struct SCSIRequest { BlockDriverAIOCB *aiocb; bool enqueued; QTAILQ_ENTRY(SCSIRequest) next; -} SCSIRequest; +}; struct SCSIDevice { @@ -66,17 +67,17 @@ struct SCSIDeviceInfo { DeviceInfo qdev; scsi_qdev_initfn init; void (*destroy)(SCSIDevice *s); + SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun); void (*free_req)(SCSIRequest *req); - int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf, - int lun); - void (*read_data)(SCSIDevice *s, uint32_t tag); - int (*write_data)(SCSIDevice *s, uint32_t tag); - void (*cancel_io)(SCSIDevice *s, uint32_t tag); - uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag); + int32_t (*send_command)(SCSIRequest *req, uint8_t *buf); + void (*read_data)(SCSIRequest *req); + int (*write_data)(SCSIRequest *req); + void (*cancel_io)(SCSIRequest *req); + uint8_t *(*get_buf)(SCSIRequest *req); }; struct SCSIBusOps { - void (*complete)(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg); + void (*complete)(SCSIRequest *req, int reason, uint32_t arg); }; struct SCSIBus { @@ -103,7 +104,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int scsi_bus_legacy_handle_cmdline(SCSIBus *bus); SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); -SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); +void scsi_req_enqueue(SCSIRequest *req); void scsi_req_free(SCSIRequest *req); void scsi_req_dequeue(SCSIRequest *req); SCSIRequest *scsi_req_ref(SCSIRequest *req); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index c183008e42..36dd7445af 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -75,6 +75,7 @@ typedef struct vscsi_req { /* SCSI request tracking */ SCSIDevice *sdev; + SCSIRequest *sreq; uint32_t qtag; /* qemu tag != srp tag */ int lun; int active; @@ -123,11 +124,16 @@ static struct vscsi_req *vscsi_get_req(VSCSIState *s) static void vscsi_put_req(VSCSIState *s, vscsi_req *req) { + if (req->sreq != NULL) { + scsi_req_unref(req->sreq); + } + req->sreq = NULL; req->active = 0; } -static vscsi_req *vscsi_find_req(VSCSIState *s, uint32_t tag) +static vscsi_req *vscsi_find_req(VSCSIState *s, SCSIRequest *req) { + uint32_t tag = req->tag; if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) { return NULL; } @@ -453,11 +459,11 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) cdb[4] = 96; cdb[5] = 0; req->sensing = 1; - n = sdev->info->send_command(sdev, req->qtag, cdb, req->lun); + n = sdev->info->send_command(req->sreq, cdb); dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag); if (n < 0) { fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n"); - sdev->info->cancel_io(sdev, req->qtag); + sdev->info->cancel_io(req->sreq); vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); vscsi_put_req(s, req); @@ -465,24 +471,23 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) } else if (n == 0) { return; } - sdev->info->read_data(sdev, req->qtag); + sdev->info->read_data(req->sreq); } /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, - uint32_t arg) +static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, bus->qbus.parent); - vscsi_req *req = vscsi_find_req(s, tag); + VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); + vscsi_req *req = vscsi_find_req(s, sreq); SCSIDevice *sdev; uint8_t *buf; int32_t res_in = 0, res_out = 0; int len, rc = 0; dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n", - reason, tag, arg, req); + reason, sreq->tag, arg, req); if (req == NULL) { - fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", tag); + fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; } sdev = req->sdev; @@ -493,7 +498,7 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); vscsi_put_req(s, req); } else { - uint8_t *buf = sdev->info->get_buf(sdev, tag); + uint8_t *buf = sdev->info->get_buf(sreq); len = MIN(arg, SCSI_SENSE_BUF_SIZE); dprintf("VSCSI: Sense data, %d bytes:\n", len); @@ -505,7 +510,7 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, buf[12], buf[13], buf[14], buf[15]); memcpy(req->sense, buf, len); req->senselen = len; - sdev->info->read_data(sdev, req->qtag); + sdev->info->read_data(sreq); } return; } @@ -537,12 +542,12 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, * to write for writes (ie, how much is to be DMA'd) */ if (arg) { - buf = sdev->info->get_buf(sdev, tag); + buf = sdev->info->get_buf(sreq); rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg); } if (rc < 0) { fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc); - sdev->info->cancel_io(sdev, req->qtag); + sdev->info->cancel_io(sreq); vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); vscsi_put_req(s, req); @@ -552,9 +557,9 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, /* Start next chunk */ req->data_len -= rc; if (req->writing) { - sdev->info->write_data(sdev, req->qtag); + sdev->info->write_data(sreq); } else { - sdev->info->read_data(sdev, req->qtag); + sdev->info->read_data(sreq); } } @@ -644,7 +649,8 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) req->sdev = sdev; req->lun = lun; - n = sdev->info->send_command(sdev, req->qtag, srp->cmd.cdb, lun); + req->sreq = sdev->info->alloc_req(sdev, req->qtag, lun); + n = sdev->info->send_command(req->sreq, srp->cmd.cdb); dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", req->qtag, srp->cmd.cdb[0], id, lun, n); @@ -662,10 +668,10 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) /* Get transfer direction and initiate transfer */ if (n > 0) { req->data_len = n; - sdev->info->read_data(sdev, req->qtag); + sdev->info->read_data(req->sreq); } else if (n < 0) { req->data_len = -n; - sdev->info->write_data(sdev, req->qtag); + sdev->info->write_data(req->sreq); } /* Don't touch req here, it may have been recycled already */ diff --git a/hw/usb-msd.c b/hw/usb-msd.c index c0a381abb3..8e6d48bf25 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -48,6 +48,7 @@ typedef struct { uint32_t data_len; uint32_t residue; uint32_t tag; + SCSIRequest *req; SCSIBus bus; BlockConf conf; SCSIDevice *scsi_dev; @@ -190,9 +191,9 @@ static void usb_msd_copy_data(MSDState *s) s->data_len -= len; if (s->scsi_len == 0 || s->data_len == 0) { if (s->mode == USB_MSDM_DATAIN) { - s->scsi_dev->info->read_data(s->scsi_dev, s->tag); + s->scsi_dev->info->read_data(s->req); } else if (s->mode == USB_MSDM_DATAOUT) { - s->scsi_dev->info->write_data(s->scsi_dev, s->tag); + s->scsi_dev->info->write_data(s->req); } } } @@ -211,14 +212,13 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p) memcpy(p->data, &csw, len); } -static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, - uint32_t arg) +static void usb_msd_command_complete(SCSIRequest *req, int reason, uint32_t arg) { - MSDState *s = DO_UPCAST(MSDState, dev.qdev, bus->qbus.parent); + MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); USBPacket *p = s->packet; - if (tag != s->tag) { - fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", tag); + if (req->tag != s->tag) { + fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag); } if (reason == SCSI_REASON_DONE) { DPRINTF("Command complete %d\n", arg); @@ -245,10 +245,12 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, } else if (s->data_len == 0) { s->mode = USB_MSDM_CSW; } + scsi_req_unref(req); + s->req = NULL; return; } s->scsi_len = arg; - s->scsi_buf = s->scsi_dev->info->get_buf(s->scsi_dev, tag); + s->scsi_buf = s->scsi_dev->info->get_buf(req); if (p) { usb_msd_copy_data(s); if (s->usb_len == 0) { @@ -316,7 +318,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->scsi_dev, s->tag); + s->scsi_dev->info->cancel_io(s->req); s->packet = NULL; s->scsi_len = 0; } @@ -365,14 +367,15 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->residue = 0; s->scsi_len = 0; - s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0); + s->req = s->scsi_dev->info->alloc_req(s->scsi_dev, s->tag, 0); + s->scsi_dev->info->send_command(s->req, cbw.cmd); /* ??? Should check that USB and SCSI data transfer directions match. */ if (s->residue == 0) { if (s->mode == USB_MSDM_DATAIN) { - s->scsi_dev->info->read_data(s->scsi_dev, s->tag); + s->scsi_dev->info->read_data(s->req); } else if (s->mode == USB_MSDM_DATAOUT) { - s->scsi_dev->info->write_data(s->scsi_dev, s->tag); + s->scsi_dev->info->write_data(s->req); } } ret = len; -- cgit v1.2.3-55-g7522 From 94d3f98a3f3caddd7875f9a11776daeb84962a7b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 18 Apr 2011 22:53:08 +0200 Subject: 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 Reviewed-by: Christoph Hellwig --- hw/esp.c | 16 ++++++++++++++-- hw/lsi53c895a.c | 30 +++++++++++++++++++++++++----- 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(+), 17 deletions(-) (limited to 'hw/usb-msd.c') 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) -- cgit v1.2.3-55-g7522 From fc4f0754c775d4b5e0fb90e503f7e505f62fb8ed Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 18 Apr 2011 19:07:23 +0200 Subject: scsi: do not call send_command directly Move the common part of scsi-disk.c and scsi-generic.c to the SCSI layer. Signed-off-by: Paolo Bonzini Reviewed-by: Christoph Hellwig --- hw/esp.c | 2 +- hw/lsi53c895a.c | 2 +- hw/scsi-bus.c | 9 ++++++++- hw/scsi-disk.c | 1 - hw/scsi-generic.c | 1 - hw/scsi.h | 2 +- hw/spapr_vscsi.c | 4 ++-- hw/usb-msd.c | 2 +- 8 files changed, 14 insertions(+), 9 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/esp.c b/hw/esp.c index f2677dc88e..238422a81d 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -245,7 +245,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) DPRINTF("do_busid_cmd: busid 0x%x\n", busid); lun = busid & 7; s->current_req = s->current_dev->info->alloc_req(s->current_dev, 0, lun); - datalen = s->current_dev->info->send_command(s->current_req, buf); + datalen = scsi_req_enqueue(s->current_req, buf); s->ti_size = datalen; if (datalen != 0) { s->rregs[ESP_RSTAT] = STAT_TC; diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index bca889a880..185622dc94 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -791,7 +791,7 @@ static void lsi_do_command(LSIState *s) s->current->req = dev->info->alloc_req(dev, s->current->tag, s->current_lun); - n = dev->info->send_command(s->current->req, buf); + n = scsi_req_enqueue(s->current->req, buf); if (n > 0) { lsi_set_phase(s, PHASE_DI); dev->info->read_data(s->current->req); diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index d322f3a326..2e6e7c89b9 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -146,12 +146,19 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l return req; } -void scsi_req_enqueue(SCSIRequest *req) +int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf) { + int32_t rc; + assert(!req->enqueued); scsi_req_ref(req); req->enqueued = true; QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); + + scsi_req_ref(req); + rc = req->dev->info->send_command(req, buf); + scsi_req_unref(req); + return rc; } static void scsi_req_dequeue(SCSIRequest *req) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 63aa8f1138..adee8feb91 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -984,7 +984,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) uint8_t *outbuf; int rc; - scsi_req_enqueue(req); command = buf[0]; outbuf = (uint8_t *)r->iov.iov_base; is_write = 0; diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 64cbe8b8c0..90f2a4af1b 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -320,7 +320,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); int ret; - scsi_req_enqueue(req); if (cmd[0] != REQUEST_SENSE && (req->lun != s->lun || (cmd[1] >> 5) != s->lun)) { DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : cmd[1] >> 5); diff --git a/hw/scsi.h b/hw/scsi.h index 7a7c9efb57..839bc0b3dd 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -143,7 +143,7 @@ int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed); int scsi_sense_valid(SCSISense sense); SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); -void scsi_req_enqueue(SCSIRequest *req); +int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf); void scsi_req_free(SCSIRequest *req); SCSIRequest *scsi_req_ref(SCSIRequest *req); void scsi_req_unref(SCSIRequest *req); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 5aaf95b974..54fd4e891f 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -459,7 +459,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) cdb[4] = 96; cdb[5] = 0; req->sensing = 1; - n = sdev->info->send_command(req->sreq, cdb); + n = scsi_req_enqueue(req->sreq, cdb); dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag); if (n < 0) { fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n"); @@ -654,7 +654,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) req->sdev = sdev; req->lun = lun; req->sreq = sdev->info->alloc_req(sdev, req->qtag, lun); - n = sdev->info->send_command(req->sreq, srp->cmd.cdb); + n = scsi_req_enqueue(req->sreq, srp->cmd.cdb); dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", req->qtag, srp->cmd.cdb[0], id, lun, n); diff --git a/hw/usb-msd.c b/hw/usb-msd.c index ce926828ec..ccfae61247 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -378,7 +378,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) s->residue = 0; s->scsi_len = 0; s->req = s->scsi_dev->info->alloc_req(s->scsi_dev, s->tag, 0); - s->scsi_dev->info->send_command(s->req, cbw.cmd); + scsi_req_enqueue(s->req, cbw.cmd); /* ??? Should check that USB and SCSI data transfer directions match. */ if (s->residue == 0) { -- cgit v1.2.3-55-g7522 From 43a2b33957697347e4e6d00557221538231bfe4d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 18 Apr 2011 19:09:55 +0200 Subject: scsi: introduce scsi_req_new Signed-off-by: Paolo Bonzini Reviewed-by: Christoph Hellwig --- hw/esp.c | 2 +- hw/lsi53c895a.c | 3 +-- hw/scsi-bus.c | 5 +++++ hw/scsi.h | 1 + hw/spapr_vscsi.c | 2 +- hw/usb-msd.c | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/esp.c b/hw/esp.c index 238422a81d..6e216848b9 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -244,7 +244,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) DPRINTF("do_busid_cmd: busid 0x%x\n", busid); lun = busid & 7; - s->current_req = s->current_dev->info->alloc_req(s->current_dev, 0, lun); + s->current_req = scsi_req_new(s->current_dev, 0, lun); datalen = scsi_req_enqueue(s->current_req, buf); s->ti_size = datalen; if (datalen != 0) { diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 185622dc94..6b78f2aaf9 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -788,8 +788,7 @@ static void lsi_do_command(LSIState *s) assert(s->current == NULL); s->current = qemu_mallocz(sizeof(lsi_request)); s->current->tag = s->select_tag; - s->current->req = dev->info->alloc_req(dev, s->current->tag, - s->current_lun); + s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun); n = scsi_req_enqueue(s->current->req, buf); if (n > 0) { diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 2e6e7c89b9..6ac265022f 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -146,6 +146,11 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l return req; } +SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun) +{ + return d->info->alloc_req(d, tag, lun); +} + int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf) { int32_t rc; diff --git a/hw/scsi.h b/hw/scsi.h index 839bc0b3dd..928cbf3e62 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -143,6 +143,7 @@ int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed); int scsi_sense_valid(SCSISense sense); SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); +SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun); int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf); void scsi_req_free(SCSIRequest *req); SCSIRequest *scsi_req_ref(SCSIRequest *req); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 54fd4e891f..fcdfad405b 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -653,7 +653,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) req->sdev = sdev; req->lun = lun; - req->sreq = sdev->info->alloc_req(sdev, req->qtag, lun); + req->sreq = scsi_req_new(sdev, req->qtag, lun); n = scsi_req_enqueue(req->sreq, srp->cmd.cdb); dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", diff --git a/hw/usb-msd.c b/hw/usb-msd.c index ccfae61247..efb15b00a3 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -377,7 +377,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->residue = 0; s->scsi_len = 0; - s->req = s->scsi_dev->info->alloc_req(s->scsi_dev, s->tag, 0); + s->req = scsi_req_new(s->scsi_dev, s->tag, 0); scsi_req_enqueue(s->req, cbw.cmd); /* ??? Should check that USB and SCSI data transfer directions match. */ -- cgit v1.2.3-55-g7522 From ad3376cc558f69606ac25ab6d597db71c969d8b6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 18 Apr 2011 15:28:11 +0200 Subject: scsi: introduce scsi_req_continue Signed-off-by: Paolo Bonzini Cc: Christoph Hellwig --- hw/esp.c | 26 ++++++++++---------------- hw/lsi53c895a.c | 22 ++++++++-------------- hw/scsi-bus.c | 16 +++++++++++++--- hw/scsi.h | 1 + hw/spapr_vscsi.c | 26 ++++++++++---------------- hw/usb-msd.c | 15 ++++----------- trace-events | 1 + 7 files changed, 47 insertions(+), 60 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/esp.c b/hw/esp.c index 6e216848b9..ce2d3b070e 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -253,11 +253,10 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) s->dma_counter = 0; if (datalen > 0) { s->rregs[ESP_RSTAT] |= STAT_DI; - s->current_dev->info->read_data(s->current_req); } else { s->rregs[ESP_RSTAT] |= STAT_DO; - s->current_dev->info->write_data(s->current_req); } + scsi_req_continue(s->current_req); } s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RSEQ] = SEQ_CD; @@ -383,22 +382,17 @@ static void esp_do_dma(ESPState *s) else s->ti_size -= len; if (s->async_len == 0) { - if (to_device) { - // ti_size is negative - s->current_dev->info->write_data(s->current_req); - } else { - s->current_dev->info->read_data(s->current_req); - /* If there is still data to be read from the device then - complete the DMA operation immediately. Otherwise defer - until the scsi layer has completed. */ - if (s->dma_left == 0 && s->ti_size > 0) { - esp_dma_done(s); - } + scsi_req_continue(s->current_req); + /* If there is still data to be read from the device then + complete the DMA operation immediately. Otherwise defer + until the scsi layer has completed. */ + if (to_device || s->dma_left != 0 || s->ti_size == 0) { + return; } - } else { - /* Partially filled a scsi buffer. Complete immediately. */ - esp_dma_done(s); } + + /* Partially filled a scsi buffer. Complete immediately. */ + esp_dma_done(s); } static void esp_command_complete(SCSIRequest *req, int reason, uint32_t arg) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 6b78f2aaf9..e8409b720c 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -580,13 +580,7 @@ static void lsi_do_dma(LSIState *s, int out) s->current->dma_len -= count; if (s->current->dma_len == 0) { s->current->dma_buf = NULL; - if (out) { - /* Write the data. */ - dev->info->write_data(s->current->req); - } else { - /* Request any remaining data. */ - dev->info->read_data(s->current->req); - } + scsi_req_continue(s->current->req); } else { s->current->dma_buf += count; lsi_resume_script(s); @@ -791,14 +785,14 @@ static void lsi_do_command(LSIState *s) s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun); n = scsi_req_enqueue(s->current->req, buf); - if (n > 0) { - lsi_set_phase(s, PHASE_DI); - dev->info->read_data(s->current->req); - } else if (n < 0) { - lsi_set_phase(s, PHASE_DO); - dev->info->write_data(s->current->req); + if (n) { + if (n > 0) { + lsi_set_phase(s, PHASE_DI); + } else if (n < 0) { + lsi_set_phase(s, PHASE_DO); + } + scsi_req_continue(s->current->req); } - if (!s->command_complete) { if (n) { /* Command did not complete immediately so disconnect. */ diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 6ac265022f..fb96bdee51 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -602,11 +602,21 @@ void scsi_req_unref(SCSIRequest *req) } } +/* Tell the device that we finished processing this chunk of I/O. It + will start the next chunk or complete the command. */ +void scsi_req_continue(SCSIRequest *req) +{ + trace_scsi_req_continue(req->dev->id, req->lun, req->tag); + if (req->cmd.mode == SCSI_XFER_TO_DEV) { + req->dev->info->write_data(req); + } else { + req->dev->info->read_data(req); + } +} + /* Called by the devices when data is ready for the HBA. The HBA should start a DMA operation to read or fill the device's data buffer. - Once it completes, calling one of req->dev->info->read_data or - req->dev->info->write_data (depending on the direction of the - transfer) will restart I/O. */ + Once it completes, calling scsi_req_continue will restart I/O. */ void scsi_req_data(SCSIRequest *req, int len) { trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); diff --git a/hw/scsi.h b/hw/scsi.h index 928cbf3e62..6fd75dd660 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -151,6 +151,7 @@ void scsi_req_unref(SCSIRequest *req); int scsi_req_parse(SCSIRequest *req, uint8_t *buf); void scsi_req_print(SCSIRequest *req); +void scsi_req_continue(SCSIRequest *req); void scsi_req_data(SCSIRequest *req, int len); void scsi_req_complete(SCSIRequest *req); void scsi_req_abort(SCSIRequest *req, int status); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index fcdfad405b..1e47fb912e 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -448,7 +448,6 @@ static int vscsi_preprocess_desc(vscsi_req *req) static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) { - SCSIDevice *sdev = req->sdev; uint8_t *cdb = req->iu.srp.cmd.cdb; int n; @@ -469,7 +468,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) } else if (n == 0) { return; } - sdev->info->read_data(req->sreq); + scsi_req_continue(req->sreq); } /* Callback to indicate that the SCSI layer has completed a transfer. */ @@ -508,7 +507,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) buf[12], buf[13], buf[14], buf[15]); memcpy(req->sense, buf, len); req->senselen = len; - sdev->info->read_data(sreq); + scsi_req_continue(req->sreq); } return; } @@ -552,11 +551,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) /* Start next chunk */ req->data_len -= rc; - if (req->writing) { - sdev->info->write_data(sreq); - } else { - sdev->info->read_data(sreq); - } + scsi_req_continue(sreq); } static void vscsi_request_cancelled(SCSIRequest *sreq) @@ -667,15 +662,14 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) /* Preprocess RDMA descriptors */ vscsi_preprocess_desc(req); - } - /* Get transfer direction and initiate transfer */ - if (n > 0) { - req->data_len = n; - sdev->info->read_data(req->sreq); - } else if (n < 0) { - req->data_len = -n; - sdev->info->write_data(req->sreq); + /* Get transfer direction and initiate transfer */ + if (n > 0) { + req->data_len = n; + } else if (n < 0) { + req->data_len = -n; + } + scsi_req_continue(req->sreq); } /* Don't touch req here, it may have been recycled already */ diff --git a/hw/usb-msd.c b/hw/usb-msd.c index efb15b00a3..d4c2234e81 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -190,11 +190,7 @@ static void usb_msd_copy_data(MSDState *s) s->scsi_buf += len; s->data_len -= len; if (s->scsi_len == 0 || s->data_len == 0) { - if (s->mode == USB_MSDM_DATAIN) { - s->scsi_dev->info->read_data(s->req); - } else if (s->mode == USB_MSDM_DATAOUT) { - s->scsi_dev->info->write_data(s->req); - } + scsi_req_continue(s->req); } } @@ -249,6 +245,7 @@ static void usb_msd_command_complete(SCSIRequest *req, int reason, uint32_t arg) s->req = NULL; return; } + assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); s->scsi_len = arg; s->scsi_buf = s->scsi_dev->info->get_buf(req); if (p) { @@ -381,12 +378,8 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) scsi_req_enqueue(s->req, cbw.cmd); /* ??? Should check that USB and SCSI data transfer directions match. */ - if (s->residue == 0) { - if (s->mode == USB_MSDM_DATAIN) { - s->scsi_dev->info->read_data(s->req); - } else if (s->mode == USB_MSDM_DATAOUT) { - s->scsi_dev->info->write_data(s->req); - } + if (s->mode != USB_MSDM_CSW && s->residue == 0) { + scsi_req_continue(s->req); } ret = len; break; diff --git a/trace-events b/trace-events index 0340eb2d77..3137a1518f 100644 --- a/trace-events +++ b/trace-events @@ -209,6 +209,7 @@ disable usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature disable scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d" disable scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d" disable scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d" +disable scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d" disable scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer, uint64_t lba) "target %d lun %d tag %d command %d dir %d length %d lba %"PRIu64"" disable scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d" -- cgit v1.2.3-55-g7522 From 0c34459b6af1b7ed2f000995b9bcb1c722646fbb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 21 Apr 2011 13:21:02 +0200 Subject: scsi: introduce scsi_req_get_buf ... and remove some SCSIDevice variables or fields that now become unused. Signed-off-by: Paolo Bonzini Reviewed-by: Christoph Hellwig --- hw/esp.c | 2 +- hw/lsi53c895a.c | 2 +- hw/scsi-bus.c | 5 +++++ hw/scsi.h | 1 + hw/spapr_vscsi.c | 8 ++------ hw/usb-msd.c | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/esp.c b/hw/esp.c index ce2d3b070e..d4847dbc5f 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -419,7 +419,7 @@ static void esp_command_complete(SCSIRequest *req, int reason, uint32_t arg) } else { DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); s->async_len = arg; - s->async_buf = s->current_dev->info->get_buf(req); + s->async_buf = scsi_req_get_buf(req); if (s->dma_left) { esp_do_dma(s); } else if (s->dma_counter != 0 && s->ti_size <= 0) { diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index e8409b720c..43113a17a7 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -569,7 +569,7 @@ static void lsi_do_dma(LSIState *s, int out) s->dnad += count; s->dbc -= count; if (s->current->dma_buf == NULL) { - s->current->dma_buf = dev->info->get_buf(s->current->req); + s->current->dma_buf = scsi_req_get_buf(s->current->req); } /* ??? Set SFBR to first data byte. */ if (out) { diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index fb96bdee51..686d59d818 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -151,6 +151,11 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun) return d->info->alloc_req(d, tag, lun); } +uint8_t *scsi_req_get_buf(SCSIRequest *req) +{ + return req->dev->info->get_buf(req); +} + int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf) { int32_t rc; diff --git a/hw/scsi.h b/hw/scsi.h index 6fd75dd660..edf68283c1 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -154,6 +154,7 @@ void scsi_req_print(SCSIRequest *req); void scsi_req_continue(SCSIRequest *req); void scsi_req_data(SCSIRequest *req, int len); void scsi_req_complete(SCSIRequest *req); +uint8_t *scsi_req_get_buf(SCSIRequest *req); void scsi_req_abort(SCSIRequest *req, int status); void scsi_req_cancel(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 1e47fb912e..762a22ec4a 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -74,7 +74,6 @@ typedef struct vscsi_req { union viosrp_iu iu; /* SCSI request tracking */ - SCSIDevice *sdev; SCSIRequest *sreq; uint32_t qtag; /* qemu tag != srp tag */ int lun; @@ -476,7 +475,6 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); vscsi_req *req = vscsi_find_req(s, sreq); - SCSIDevice *sdev; uint8_t *buf; int32_t res_in = 0, res_out = 0; int len, rc = 0; @@ -487,7 +485,6 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; } - sdev = req->sdev; if (req->sensing) { if (reason == SCSI_REASON_DONE) { @@ -495,7 +492,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); vscsi_put_req(s, req); } else { - uint8_t *buf = sdev->info->get_buf(sreq); + uint8_t *buf = scsi_req_get_buf(sreq); len = MIN(arg, SCSI_SENSE_BUF_SIZE); dprintf("VSCSI: Sense data, %d bytes:\n", len); @@ -539,7 +536,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) * to write for writes (ie, how much is to be DMA'd) */ if (arg) { - buf = sdev->info->get_buf(sreq); + buf = scsi_req_get_buf(sreq); rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg); } if (rc < 0) { @@ -646,7 +643,6 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) } return 1; } - req->sdev = sdev; req->lun = lun; req->sreq = scsi_req_new(sdev, req->qtag, lun); n = scsi_req_enqueue(req->sreq, srp->cmd.cdb); diff --git a/hw/usb-msd.c b/hw/usb-msd.c index d4c2234e81..78b57a6c3f 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -247,7 +247,7 @@ static void usb_msd_command_complete(SCSIRequest *req, int reason, uint32_t arg) } assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); s->scsi_len = arg; - s->scsi_buf = s->scsi_dev->info->get_buf(req); + s->scsi_buf = scsi_req_get_buf(req); if (p) { usb_msd_copy_data(s); if (s->usb_len == 0) { -- cgit v1.2.3-55-g7522 From c6df7102f5ebf3c9008718d044b78f1ae57aa627 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Apr 2011 12:27:30 +0200 Subject: scsi: split command_complete callback in two Signed-off-by: Paolo Bonzini Cc: Christoph Hellwig --- hw/esp.c | 62 +++++++++++++++++++--------------- hw/lsi53c895a.c | 58 ++++++++++++++++++-------------- hw/scsi-bus.c | 4 +-- hw/scsi.h | 9 ++--- hw/spapr_vscsi.c | 101 ++++++++++++++++++++++++++++++------------------------- hw/usb-msd.c | 71 +++++++++++++++++++++----------------- 6 files changed, 168 insertions(+), 137 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/esp.c b/hw/esp.c index 879c8ad45e..67f02bad56 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -395,38 +395,43 @@ static void esp_do_dma(ESPState *s) esp_dma_done(s); } -static void esp_command_complete(SCSIRequest *req, int reason, uint32_t arg) +static void esp_command_complete(SCSIRequest *req, uint32_t arg) { ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); - if (reason == SCSI_REASON_DONE) { - DPRINTF("SCSI Command complete\n"); - if (s->ti_size != 0) - DPRINTF("SCSI command completed unexpectedly\n"); - s->ti_size = 0; - s->dma_left = 0; - s->async_len = 0; - if (arg) - DPRINTF("Command failed\n"); - s->status = arg; - s->rregs[ESP_RSTAT] = STAT_ST; + DPRINTF("SCSI Command complete\n"); + if (s->ti_size != 0) { + DPRINTF("SCSI command completed unexpectedly\n"); + } + s->ti_size = 0; + s->dma_left = 0; + s->async_len = 0; + if (arg) { + DPRINTF("Command failed\n"); + } + s->status = arg; + s->rregs[ESP_RSTAT] = STAT_ST; + esp_dma_done(s); + if (s->current_req) { + scsi_req_unref(s->current_req); + s->current_req = NULL; + s->current_dev = NULL; + } +} + +static void esp_transfer_data(SCSIRequest *req, uint32_t arg) +{ + ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); + + DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); + s->async_len = arg; + s->async_buf = scsi_req_get_buf(req); + if (s->dma_left) { + esp_do_dma(s); + } else if (s->dma_counter != 0 && s->ti_size <= 0) { + /* If this was the last part of a DMA transfer then the + completion interrupt is deferred to here. */ esp_dma_done(s); - if (s->current_req) { - scsi_req_unref(s->current_req); - s->current_req = NULL; - s->current_dev = NULL; - } - } else { - DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); - s->async_len = arg; - s->async_buf = scsi_req_get_buf(req); - if (s->dma_left) { - esp_do_dma(s); - } else if (s->dma_counter != 0 && s->ti_size <= 0) { - /* If this was the last part of a DMA transfer then the - completion interrupt is deferred to here. */ - esp_dma_done(s); - } } } @@ -725,6 +730,7 @@ void esp_init(target_phys_addr_t espaddr, int it_shift, } static const struct SCSIBusOps esp_scsi_ops = { + .transfer_data = esp_transfer_data, .complete = esp_command_complete, .cancel = esp_request_cancelled }; diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 43113a17a7..c965ed40d8 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -711,32 +711,37 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) return 1; } } - /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void lsi_command_complete(SCSIRequest *req, int reason, uint32_t arg) + + /* Callback to indicate that the SCSI layer has completed a command. */ +static void lsi_command_complete(SCSIRequest *req, uint32_t arg) { LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); int out; out = (s->sstat1 & PHASE_MASK) == PHASE_DO; - if (reason == SCSI_REASON_DONE) { - DPRINTF("Command complete status=%d\n", (int)arg); - s->status = arg; - s->command_complete = 2; - if (s->waiting && s->dbc != 0) { - /* Raise phase mismatch for short transfers. */ - lsi_bad_phase(s, out, PHASE_ST); - } else { - lsi_set_phase(s, PHASE_ST); - } + DPRINTF("Command complete status=%d\n", (int)arg); + s->status = arg; + s->command_complete = 2; + if (s->waiting && s->dbc != 0) { + /* Raise phase mismatch for short transfers. */ + lsi_bad_phase(s, out, PHASE_ST); + } else { + lsi_set_phase(s, PHASE_ST); + } - if (s->current && req == s->current->req) { - scsi_req_unref(s->current->req); - qemu_free(s->current); - s->current = NULL; - } - lsi_resume_script(s); - return; + if (s->current && req == s->current->req) { + scsi_req_unref(s->current->req); + qemu_free(s->current); + s->current = NULL; } + lsi_resume_script(s); +} + + /* Callback to indicate that the SCSI layer has completed a transfer. */ +static void lsi_transfer_data(SCSIRequest *req, uint32_t arg) +{ + LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); + int out; if (s->waiting == 1 || !s->current || req->tag != s->current->tag || (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { @@ -745,16 +750,18 @@ static void lsi_command_complete(SCSIRequest *req, int reason, uint32_t arg) } } + out = (s->sstat1 & PHASE_MASK) == PHASE_DO; + /* host adapter (re)connected */ DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, arg); s->current->dma_len = arg; s->command_complete = 1; - if (!s->waiting) - return; - if (s->waiting == 1 || s->dbc == 0) { - lsi_resume_script(s); - } else { - lsi_do_dma(s, out); + if (s->waiting) { + if (s->waiting == 1 || s->dbc == 0) { + lsi_resume_script(s); + } else { + lsi_do_dma(s, out); + } } } @@ -2239,6 +2246,7 @@ static int lsi_scsi_uninit(PCIDevice *d) } static const struct SCSIBusOps lsi_scsi_ops = { + .transfer_data = lsi_transfer_data, .complete = lsi_command_complete, .cancel = lsi_request_cancelled }; diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index ae16a2d6f7..837f24e212 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -634,7 +634,7 @@ void scsi_req_continue(SCSIRequest *req) void scsi_req_data(SCSIRequest *req, int len) { trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); - req->bus->ops->complete(req, SCSI_REASON_DATA, len); + req->bus->ops->transfer_data(req, len); } void scsi_req_print(SCSIRequest *req) @@ -670,7 +670,7 @@ void scsi_req_complete(SCSIRequest *req) assert(req->status != -1); scsi_req_ref(req); scsi_req_dequeue(req); - req->bus->ops->complete(req, SCSI_REASON_DONE, req->status); + req->bus->ops->complete(req, req->status); scsi_req_unref(req); } diff --git a/hw/scsi.h b/hw/scsi.h index b56338d72a..c1dca35b86 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -9,12 +9,6 @@ #define SCSI_CMD_BUF_SIZE 16 -/* scsi-disk.c */ -enum scsi_reason { - SCSI_REASON_DONE, /* Command complete. */ - SCSI_REASON_DATA /* Transfer complete, more data required. */ -}; - typedef struct SCSIBus SCSIBus; typedef struct SCSIBusOps SCSIBusOps; typedef struct SCSIDevice SCSIDevice; @@ -84,7 +78,8 @@ struct SCSIDeviceInfo { }; struct SCSIBusOps { - void (*complete)(SCSIRequest *req, int reason, uint32_t arg); + void (*transfer_data)(SCSIRequest *req, uint32_t arg); + void (*complete)(SCSIRequest *req, uint32_t arg); void (*cancel)(SCSIRequest *req); }; diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index bae670a377..fea1f2f8b7 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -480,63 +480,34 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) } /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) +static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t arg) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); vscsi_req *req = vscsi_find_req(s, sreq); uint8_t *buf; - int32_t res_in = 0, res_out = 0; int len, rc = 0; - dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n", - reason, sreq->tag, arg, req); + dprintf("VSCSI: SCSI xfer complete tag=0x%x arg=0x%x, req=%p\n", + sreq->tag, arg, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; } if (req->sensing) { - if (reason == SCSI_REASON_DONE) { - dprintf("VSCSI: Sense done !\n"); - vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); - vscsi_put_req(s, req); - } else { - uint8_t *buf = scsi_req_get_buf(sreq); - - len = MIN(arg, SCSI_SENSE_BUF_SIZE); - dprintf("VSCSI: Sense data, %d bytes:\n", len); - dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); - dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", - buf[8], buf[9], buf[10], buf[11], - buf[12], buf[13], buf[14], buf[15]); - memcpy(req->sense, buf, len); - req->senselen = len; - scsi_req_continue(req->sreq); - } - return; - } - - if (reason == SCSI_REASON_DONE) { - dprintf("VSCSI: Command complete err=%d\n", arg); - if (arg == 0) { - /* We handle overflows, not underflows for normal commands, - * but hopefully nobody cares - */ - if (req->writing) { - res_out = req->data_len; - } else { - res_in = req->data_len; - } - vscsi_send_rsp(s, req, 0, res_in, res_out); - } else if (arg == CHECK_CONDITION) { - vscsi_send_request_sense(s, req); - return; - } else { - vscsi_send_rsp(s, req, arg, 0, 0); - } - vscsi_put_req(s, req); + uint8_t *buf = scsi_req_get_buf(sreq); + + len = MIN(arg, SCSI_SENSE_BUF_SIZE); + dprintf("VSCSI: Sense data, %d bytes:\n", len); + dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[8], buf[9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15]); + memcpy(req->sense, buf, len); + req->senselen = len; + scsi_req_continue(req->sreq); return; } @@ -559,6 +530,45 @@ static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg) scsi_req_continue(sreq); } +/* Callback to indicate that the SCSI layer has completed a transfer. */ +static void vscsi_command_complete(SCSIRequest *sreq, uint32_t arg) +{ + VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); + vscsi_req *req = vscsi_find_req(s, sreq); + int32_t res_in = 0, res_out = 0; + + dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n", + reason, sreq->tag, arg, req); + if (req == NULL) { + fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); + return; + } + + if (!req->sensing && arg == CHECK_CONDITION) { + vscsi_send_request_sense(s, req); + return; + } + + if (req->sensing) { + dprintf("VSCSI: Sense done !\n"); + arg = CHECK_CONDITION; + } else { + dprintf("VSCSI: Command complete err=%d\n", arg); + if (arg == 0) { + /* We handle overflows, not underflows for normal commands, + * but hopefully nobody cares + */ + if (req->writing) { + res_out = req->data_len; + } else { + res_in = req->data_len; + } + } + } + vscsi_send_rsp(s, req, 0, res_in, res_out); + vscsi_put_req(s, req); +} + static void vscsi_request_cancelled(SCSIRequest *sreq) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); @@ -916,6 +926,7 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) } static const struct SCSIBusOps vscsi_scsi_ops = { + .transfer_data = vscsi_transfer_data, .complete = vscsi_command_complete, .cancel = vscsi_request_cancelled }; diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 78b57a6c3f..4ebf6eb5f6 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -208,7 +208,7 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p) memcpy(p->data, &csw, len); } -static void usb_msd_command_complete(SCSIRequest *req, int reason, uint32_t arg) +static void usb_msd_transfer_data(SCSIRequest *req, uint32_t arg) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); USBPacket *p = s->packet; @@ -216,35 +216,7 @@ static void usb_msd_command_complete(SCSIRequest *req, int reason, uint32_t arg) if (req->tag != s->tag) { fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag); } - if (reason == SCSI_REASON_DONE) { - DPRINTF("Command complete %d\n", arg); - s->residue = s->data_len; - s->result = arg != 0; - if (s->packet) { - if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) { - /* A deferred packet with no write data remaining must be - the status read packet. */ - usb_msd_send_status(s, p); - s->mode = USB_MSDM_CBW; - } else { - if (s->data_len) { - s->data_len -= s->usb_len; - if (s->mode == USB_MSDM_DATAIN) - memset(s->usb_buf, 0, s->usb_len); - s->usb_len = 0; - } - if (s->data_len == 0) - s->mode = USB_MSDM_CSW; - } - s->packet = NULL; - usb_packet_complete(&s->dev, p); - } else if (s->data_len == 0) { - s->mode = USB_MSDM_CSW; - } - scsi_req_unref(req); - s->req = NULL; - return; - } + assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); s->scsi_len = arg; s->scsi_buf = scsi_req_get_buf(req); @@ -261,6 +233,44 @@ static void usb_msd_command_complete(SCSIRequest *req, int reason, uint32_t arg) } } +static void usb_msd_command_complete(SCSIRequest *req, uint32_t arg) +{ + MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); + USBPacket *p = s->packet; + + if (req->tag != s->tag) { + fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag); + } + DPRINTF("Command complete %d\n", arg); + s->residue = s->data_len; + s->result = arg != 0; + if (s->packet) { + if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) { + /* A deferred packet with no write data remaining must be + the status read packet. */ + usb_msd_send_status(s, p); + s->mode = USB_MSDM_CBW; + } else { + if (s->data_len) { + s->data_len -= s->usb_len; + if (s->mode == USB_MSDM_DATAIN) { + memset(s->usb_buf, 0, s->usb_len); + } + s->usb_len = 0; + } + if (s->data_len == 0) { + s->mode = USB_MSDM_CSW; + } + } + s->packet = NULL; + usb_packet_complete(&s->dev, p); + } else if (s->data_len == 0) { + s->mode = USB_MSDM_CSW; + } + scsi_req_unref(req); + s->req = NULL; +} + static void usb_msd_request_cancelled(SCSIRequest *req) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); @@ -494,6 +504,7 @@ static void usb_msd_password_cb(void *opaque, int err) } static const struct SCSIBusOps usb_msd_scsi_ops = { + .transfer_data = usb_msd_transfer_data, .complete = usb_msd_command_complete, .cancel = usb_msd_request_cancelled }; -- cgit v1.2.3-55-g7522 From aba1f023630146bd7150dd13e8786d1c3e5b2afb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 20 May 2011 20:18:07 +0200 Subject: scsi: rename arguments to the new callbacks Signed-off-by: Paolo Bonzini Cc: Christoph Hellwig --- hw/esp.c | 10 +++++----- hw/lsi53c895a.c | 20 ++++++++++---------- hw/spapr_vscsi.c | 31 ++++++++++++++----------------- hw/usb-msd.c | 10 +++++----- 4 files changed, 34 insertions(+), 37 deletions(-) (limited to 'hw/usb-msd.c') diff --git a/hw/esp.c b/hw/esp.c index 67f02bad56..6d3f5d239b 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -395,7 +395,7 @@ static void esp_do_dma(ESPState *s) esp_dma_done(s); } -static void esp_command_complete(SCSIRequest *req, uint32_t arg) +static void esp_command_complete(SCSIRequest *req, uint32_t status) { ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); @@ -406,10 +406,10 @@ static void esp_command_complete(SCSIRequest *req, uint32_t arg) s->ti_size = 0; s->dma_left = 0; s->async_len = 0; - if (arg) { + if (status) { DPRINTF("Command failed\n"); } - s->status = arg; + s->status = status; s->rregs[ESP_RSTAT] = STAT_ST; esp_dma_done(s); if (s->current_req) { @@ -419,12 +419,12 @@ static void esp_command_complete(SCSIRequest *req, uint32_t arg) } } -static void esp_transfer_data(SCSIRequest *req, uint32_t arg) +static void esp_transfer_data(SCSIRequest *req, uint32_t len) { ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); - s->async_len = arg; + s->async_len = len; s->async_buf = scsi_req_get_buf(req); if (s->dma_left) { esp_do_dma(s); diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index c965ed40d8..83084b6b6a 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -680,7 +680,7 @@ static void lsi_request_cancelled(SCSIRequest *req) /* 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) +static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t len) { lsi_request *p; @@ -693,7 +693,7 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) if (p->pending) { BADF("Multiple IO pending for tag %d\n", tag); } - p->pending = arg; + p->pending = len; /* Reselect if waiting for it, or if reselection triggers an IRQ and the bus is free. Since no interrupt stacking is implemented in the emulation, it @@ -707,20 +707,20 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) return 0; } else { DPRINTF("Queueing IO tag=0x%x\n", tag); - p->pending = arg; + p->pending = len; return 1; } } /* Callback to indicate that the SCSI layer has completed a command. */ -static void lsi_command_complete(SCSIRequest *req, uint32_t arg) +static void lsi_command_complete(SCSIRequest *req, uint32_t status) { LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); int out; out = (s->sstat1 & PHASE_MASK) == PHASE_DO; - DPRINTF("Command complete status=%d\n", (int)arg); - s->status = arg; + DPRINTF("Command complete status=%d\n", (int)status); + s->status = status; s->command_complete = 2; if (s->waiting && s->dbc != 0) { /* Raise phase mismatch for short transfers. */ @@ -738,14 +738,14 @@ static void lsi_command_complete(SCSIRequest *req, uint32_t arg) } /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void lsi_transfer_data(SCSIRequest *req, uint32_t arg) +static void lsi_transfer_data(SCSIRequest *req, uint32_t len) { LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); int out; if (s->waiting == 1 || !s->current || req->tag != s->current->tag || (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { - if (lsi_queue_tag(s, req->tag, arg)) { + if (lsi_queue_tag(s, req->tag, len)) { return; } } @@ -753,8 +753,8 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t arg) out = (s->sstat1 & PHASE_MASK) == PHASE_DO; /* host adapter (re)connected */ - DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, arg); - s->current->dma_len = arg; + DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len); + s->current->dma_len = len; s->command_complete = 1; if (s->waiting) { if (s->waiting == 1 || s->dbc == 0) { diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index fea1f2f8b7..1c901ef6eb 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -480,15 +480,15 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) } /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t arg) +static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); vscsi_req *req = vscsi_find_req(s, sreq); uint8_t *buf; - int len, rc = 0; + int rc = 0; - dprintf("VSCSI: SCSI xfer complete tag=0x%x arg=0x%x, req=%p\n", - sreq->tag, arg, req); + dprintf("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n", + sreq->tag, len, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; @@ -497,7 +497,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t arg) if (req->sensing) { uint8_t *buf = scsi_req_get_buf(sreq); - len = MIN(arg, SCSI_SENSE_BUF_SIZE); + len = MIN(len, SCSI_SENSE_BUF_SIZE); dprintf("VSCSI: Sense data, %d bytes:\n", len); dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], @@ -511,12 +511,9 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t arg) return; } - /* "arg" is how much we have read for reads and how much we want - * to write for writes (ie, how much is to be DMA'd) - */ - if (arg) { + if (len) { buf = scsi_req_get_buf(sreq); - rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg); + rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len); } if (rc < 0) { fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc); @@ -531,30 +528,30 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t arg) } /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void vscsi_command_complete(SCSIRequest *sreq, uint32_t arg) +static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); vscsi_req *req = vscsi_find_req(s, sreq); int32_t res_in = 0, res_out = 0; - dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n", - reason, sreq->tag, arg, req); + dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n", + reason, sreq->tag, status, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; } - if (!req->sensing && arg == CHECK_CONDITION) { + if (!req->sensing && status == CHECK_CONDITION) { vscsi_send_request_sense(s, req); return; } if (req->sensing) { dprintf("VSCSI: Sense done !\n"); - arg = CHECK_CONDITION; + status = CHECK_CONDITION; } else { - dprintf("VSCSI: Command complete err=%d\n", arg); - if (arg == 0) { + dprintf("VSCSI: Command complete err=%d\n", status); + if (status == 0) { /* We handle overflows, not underflows for normal commands, * but hopefully nobody cares */ diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 4ebf6eb5f6..6ec2255bce 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -208,7 +208,7 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p) memcpy(p->data, &csw, len); } -static void usb_msd_transfer_data(SCSIRequest *req, uint32_t arg) +static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); USBPacket *p = s->packet; @@ -218,7 +218,7 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t arg) } assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); - s->scsi_len = arg; + s->scsi_len = len; s->scsi_buf = scsi_req_get_buf(req); if (p) { usb_msd_copy_data(s); @@ -233,7 +233,7 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t arg) } } -static void usb_msd_command_complete(SCSIRequest *req, uint32_t arg) +static void usb_msd_command_complete(SCSIRequest *req, uint32_t status) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); USBPacket *p = s->packet; @@ -241,9 +241,9 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t arg) if (req->tag != s->tag) { fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag); } - DPRINTF("Command complete %d\n", arg); + DPRINTF("Command complete %d\n", status); s->residue = s->data_len; - s->result = arg != 0; + s->result = status != 0; if (s->packet) { if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) { /* A deferred packet with no write data remaining must be -- cgit v1.2.3-55-g7522