diff options
Diffstat (limited to 'hw/scsi')
-rw-r--r-- | hw/scsi/esp-pci.c | 3 | ||||
-rw-r--r-- | hw/scsi/esp.c | 11 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi-dataplane.c | 9 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 17 |
4 files changed, 36 insertions, 4 deletions
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index 82795e6..00b7297 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -268,6 +268,9 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len, /* update status registers */ pci->dma_regs[DMA_WBC] -= len; pci->dma_regs[DMA_WAC] += len; + if (pci->dma_regs[DMA_WBC] == 0) { + pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE; + } } static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len) diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 5ab44d8..272d13d 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -364,7 +364,7 @@ void esp_hard_reset(ESPState *s) { memset(s->rregs, 0, ESP_REGS); memset(s->wregs, 0, ESP_REGS); - s->rregs[ESP_TCHI] = s->chip_id; + s->tchi_written = 0; s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; @@ -422,6 +422,11 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr) esp_lower_irq(s); return old_val; + case ESP_TCHI: + /* Return the unique id if the value has never been written */ + if (!s->tchi_written) { + return s->chip_id; + } default: break; } @@ -432,9 +437,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) { trace_esp_mem_writeb(saddr, s->wregs[saddr], val); switch (saddr) { + case ESP_TCHI: + s->tchi_written = true; + /* fall through */ case ESP_TCLO: case ESP_TCMID: - case ESP_TCHI: s->rregs[ESP_RSTAT] &= ~STAT_TC; break; case ESP_FIFO: diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 9651e6f..03a1e8c 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -92,9 +92,14 @@ VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) { + VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent); + vring_push(&req->vring->vring, &req->elem, req->qsgl.size + req->resp_iov.size); - event_notifier_set(&req->vring->guest_notifier); + + if (vring_should_notify(vdev, &req->vring->vring)) { + event_notifier_set(&req->vring->guest_notifier); + } } static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier) @@ -230,7 +235,7 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s) if (!s->event_vring) { goto fail_vrings; } - s->cmd_vrings = g_malloc0(sizeof(VirtIOSCSIVring) * vs->conf.num_queues); + s->cmd_vrings = g_new(VirtIOSCSIVring *, vs->conf.num_queues); for (i = 0; i < vs->conf.num_queues; i++) { s->cmd_vrings[i] = virtio_scsi_vring_init(s, vs->cmd_vqs[i], diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index fdcacfd..ef48550 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -118,6 +118,7 @@ static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov, static int virtio_scsi_parse_req(VirtIOSCSIReq *req, unsigned req_size, unsigned resp_size) { + VirtIODevice *vdev = (VirtIODevice *) req->dev; size_t in_size, out_size; if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, @@ -130,8 +131,24 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req, resp_size) < resp_size) { return -EINVAL; } + req->resp_size = resp_size; + /* Old BIOSes left some padding by mistake after the req_size/resp_size. + * As a workaround, always consider the first buffer as the virtio-scsi + * request/response, making the payload start at the second element + * of the iovec. + * + * The actual length of the response header, stored in req->resp_size, + * does not change. + * + * TODO: always disable this workaround for virtio 1.0 devices. + */ + if ((vdev->guest_features & VIRTIO_F_ANY_LAYOUT) == 0) { + req_size = req->elem.out_sg[0].iov_len; + resp_size = req->elem.in_sg[0].iov_len; + } + out_size = qemu_sgl_concat(req, req->elem.out_sg, &req->elem.out_addr[0], req->elem.out_num, req_size); |