aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb/dev-storage.c30
-rw-r--r--hw/usb/trace-events1
-rw-r--r--include/hw/usb/msd.h1
3 files changed, 31 insertions, 1 deletions
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 140ef2a..e3bcffb 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -191,6 +191,23 @@ static void usb_msd_packet_complete(MSDState *s)
usb_packet_complete(&s->dev, p);
}
+static void usb_msd_fatal_error(MSDState *s)
+{
+ trace_usb_msd_fatal_error();
+
+ if (s->packet) {
+ s->packet->status = USB_RET_STALL;
+ usb_msd_packet_complete(s);
+ }
+
+ /*
+ * Guest messed up up device state with illegal requests. Go
+ * ignore any requests until the guests resets the device (and
+ * brings it into a known state that way).
+ */
+ s->needs_reset = true;
+}
+
static void usb_msd_copy_data(MSDState *s, USBPacket *p)
{
uint32_t len;
@@ -227,7 +244,11 @@ 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;
- assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
+ if ((s->mode == USB_MSDM_DATAOUT) != (req->cmd.mode == SCSI_XFER_TO_DEV)) {
+ usb_msd_fatal_error(s);
+ return;
+ }
+
s->scsi_len = len;
s->scsi_off = 0;
if (p) {
@@ -317,6 +338,8 @@ void usb_msd_handle_reset(USBDevice *dev)
memset(&s->csw, 0, sizeof(s->csw));
s->mode = USB_MSDM_CBW;
+
+ s->needs_reset = false;
}
static void usb_msd_handle_control(USBDevice *dev, USBPacket *p,
@@ -382,6 +405,11 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
SCSIDevice *scsi_dev;
uint32_t len;
+ if (s->needs_reset) {
+ p->status = USB_RET_STALL;
+ return;
+ }
+
switch (p->pid) {
case USB_TOKEN_OUT:
if (devep != 2)
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index 914ca71..b652698 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -263,6 +263,7 @@ usb_msd_packet_complete(void) ""
usb_msd_cmd_submit(unsigned lun, unsigned tag, unsigned flags, unsigned len, unsigned data_len) "lun %u, tag 0x%x, flags 0x%08x, len %d, data-len %d"
usb_msd_cmd_complete(unsigned status, unsigned tag) "status %d, tag 0x%x"
usb_msd_cmd_cancel(unsigned tag) "tag 0x%x"
+usb_msd_fatal_error(void) ""
# dev-uas.c
usb_uas_reset(int addr) "dev %d"
diff --git a/include/hw/usb/msd.h b/include/hw/usb/msd.h
index 54e9f38..f9fd862 100644
--- a/include/hw/usb/msd.h
+++ b/include/hw/usb/msd.h
@@ -40,6 +40,7 @@ struct MSDState {
bool removable;
bool commandlog;
SCSIDevice *scsi_dev;
+ bool needs_reset;
};
typedef struct MSDState MSDState;