diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-03-08 13:51:41 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-03-08 13:51:41 +0000 |
commit | 0436c55edf6b357ff56e2a5bf688df8636f83456 (patch) | |
tree | 31c44109513d0c7e8eca8a37279e51da7c0998ac /hw | |
parent | 138d2931979cb7ee4a54a434a54088231f6980ff (diff) | |
parent | c715343fd96bcf93263fda38d81af815fdb5a7fa (diff) | |
download | qemu-0436c55edf6b357ff56e2a5bf688df8636f83456.zip qemu-0436c55edf6b357ff56e2a5bf688df8636f83456.tar.gz qemu-0436c55edf6b357ff56e2a5bf688df8636f83456.tar.bz2 |
Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging
* fix tracing vs -daemonize (Daniel)
* detect invalid CFI configuration (Daniele)
* 32-bit PVH fix (David)
* forward SCSI passthrough host-status to the SCSI HBA (Hannes)
* detect ill-formed id in QMP object-add (Kevin)
* miscellaneous bugfixes and cleanups (Keqian, Kostiantyn, myself, Peng Liang)
* add nodelay option for chardev (myself)
* deprecate -M kernel-irqchip=off on x86 (myself)
* keep .d files (myself)
* Fix -trace file (myself)
# gpg: Signature made Sat 06 Mar 2021 10:43:12 GMT
# gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg: issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1
# Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83
* remotes/bonzini-gitlab/tags/for-upstream: (23 commits)
meson: Stop if cfi is enabled with system slirp
trace: skip qemu_set_log_filename if no "-D" option was passed
trace: fix "-trace file=..."
meson: adjust timeouts for some slower tests
build-sys: invoke ninja with -d keepdepfile
qemu-option: do not suggest using the delay option
scsi: move host_status handling into SCSI drivers
scsi: inline sg_io_sense_from_errno() into the callers.
scsi-generic: do not snoop the output of failed commands
scsi: Add mapping for generic SCSI_HOST status to sense codes
scsi: Rename linux-specific SG_ERR codes to generic SCSI_HOST error codes
qemu-config: add error propagation to qemu_config_parse
x86/pvh: extract only 4 bytes of start address for 32 bit kernels
elf_ops: correct loading of 32 bit PVH kernel
lsilogic: Use PCIDevice::exit instead of DeviceState::unrealize
accel: kvm: Add aligment assert for kvm_log_clear_one_slot
accel: kvm: Fix memory waste under mismatch page size
vl.c: do not execute trace_init_backends() before daemonizing
qom: Check for wellformed id in user_creatable_add_type()
chardev: add nodelay option
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/i386/x86.c | 6 | ||||
-rw-r--r-- | hw/intc/apic.c | 6 | ||||
-rw-r--r-- | hw/scsi/lsi53c895a.c | 4 | ||||
-rw-r--r-- | hw/scsi/scsi-bus.c | 33 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 47 | ||||
-rw-r--r-- | hw/scsi/scsi-generic.c | 25 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 46 | ||||
-rw-r--r-- | hw/scsi/vmw_pvscsi.c | 39 |
8 files changed, 188 insertions, 18 deletions
diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 6329f90..7865660 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -690,6 +690,8 @@ static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64) elf_note_data_addr = ((void *)nhdr64) + nhdr_size64 + QEMU_ALIGN_UP(nhdr_namesz, phdr_align); + + pvh_start_addr = *elf_note_data_addr; } else { struct elf32_note *nhdr32 = (struct elf32_note *)arg1; uint32_t nhdr_size32 = sizeof(struct elf32_note); @@ -699,9 +701,9 @@ static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64) elf_note_data_addr = ((void *)nhdr32) + nhdr_size32 + QEMU_ALIGN_UP(nhdr_namesz, phdr_align); - } - pvh_start_addr = *elf_note_data_addr; + pvh_start_addr = *(uint32_t *)elf_note_data_addr; + } return pvh_start_addr; } diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 3ada22f..f4f50f9 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -25,6 +25,7 @@ #include "hw/intc/i8259.h" #include "hw/pci/msi.h" #include "qemu/host-utils.h" +#include "sysemu/kvm.h" #include "trace.h" #include "hw/i386/apic-msidef.h" #include "qapi/error.h" @@ -875,6 +876,11 @@ static void apic_realize(DeviceState *dev, Error **errp) return; } + if (kvm_enabled()) { + warn_report("Userspace local APIC is deprecated for KVM."); + warn_report("Do not use kernel-irqchip except for the -M isapc machine type."); + } + memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi", APIC_SPACE_SIZE); diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index a4e58580..e2c1918 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2312,7 +2312,7 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp) scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL); } -static void lsi_scsi_unrealize(DeviceState *dev) +static void lsi_scsi_exit(PCIDevice *dev) { LSIState *s = LSI53C895A(dev); @@ -2325,11 +2325,11 @@ static void lsi_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = lsi_scsi_realize; + k->exit = lsi_scsi_exit; k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; k->device_id = PCI_DEVICE_ID_LSI_53C895A; k->class_id = PCI_CLASS_STORAGE_SCSI; k->subsystem_id = 0x1000; - dc->unrealize = lsi_scsi_unrealize; dc->reset = lsi_scsi_reset; dc->vmsd = &vmstate_lsi_scsi; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index dc4141e..2d674f9 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -692,6 +692,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, req->lun = lun; req->hba_private = hba_private; req->status = -1; + req->host_status = -1; req->ops = reqops; object_ref(OBJECT(d)); object_ref(OBJECT(qbus->parent)); @@ -1455,10 +1456,38 @@ void scsi_req_print(SCSIRequest *req) } } +void scsi_req_complete_failed(SCSIRequest *req, int host_status) +{ + SCSISense sense; + int status; + + assert(req->status == -1 && req->host_status == -1); + assert(req->ops != &reqops_unit_attention); + + if (!req->bus->info->fail) { + status = scsi_sense_from_host_status(req->host_status, &sense); + if (status == CHECK_CONDITION) { + scsi_req_build_sense(req, sense); + } + scsi_req_complete(req, status); + return; + } + + req->host_status = host_status; + scsi_req_ref(req); + scsi_req_dequeue(req); + req->bus->info->fail(req); + + /* Cancelled requests might end up being completed instead of cancelled */ + notifier_list_notify(&req->cancel_notifiers, req); + scsi_req_unref(req); +} + void scsi_req_complete(SCSIRequest *req, int status) { - assert(req->status == -1); + assert(req->status == -1 && req->host_status == -1); req->status = status; + req->host_status = SCSI_HOST_OK; assert(req->sense_len <= sizeof(req->sense)); if (status == GOOD) { @@ -1646,7 +1675,7 @@ static int put_scsi_requests(QEMUFile *f, void *pv, size_t size, QTAILQ_FOREACH(req, &s->requests, next) { assert(!req->io_canceled); - assert(req->status == -1); + assert(req->status == -1 && req->host_status == -1); assert(req->enqueued); qemu_put_sbyte(f, req->retry ? 1 : 2); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index a5a58d7..bd7103c 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -77,7 +77,6 @@ typedef struct SCSIDiskReq { struct iovec iov; QEMUIOVector qiov; BlockAcctCookie acct; - unsigned char *status; } SCSIDiskReq; #define SCSI_DISK_F_REMOVABLE 0 @@ -261,8 +260,6 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) if (ret < 0) { return scsi_handle_rw_error(r, ret, acct_failed); - } else if (r->status && *r->status) { - return scsi_handle_rw_error(r, *r->status, acct_failed); } return false; @@ -2697,8 +2694,47 @@ typedef struct SCSIBlockReq { /* CDB passed to SG_IO. */ uint8_t cdb[16]; + BlockCompletionFunc *cb; + void *cb_opaque; } SCSIBlockReq; +static void scsi_block_sgio_complete(void *opaque, int ret) +{ + SCSIBlockReq *req = (SCSIBlockReq *)opaque; + SCSIDiskReq *r = &req->req; + SCSIDevice *s = r->req.dev; + sg_io_hdr_t *io_hdr = &req->io_header; + + if (ret == 0) { + if (io_hdr->host_status != SCSI_HOST_OK) { + scsi_req_complete_failed(&r->req, io_hdr->host_status); + scsi_req_unref(&r->req); + return; + } + + if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { + ret = BUSY; + } else { + ret = io_hdr->status; + } + + if (ret > 0) { + aio_context_acquire(blk_get_aio_context(s->conf.blk)); + if (scsi_handle_rw_error(r, ret, true)) { + aio_context_release(blk_get_aio_context(s->conf.blk)); + scsi_req_unref(&r->req); + return; + } + aio_context_release(blk_get_aio_context(s->conf.blk)); + + /* Ignore error. */ + ret = 0; + } + } + + req->cb(req->cb_opaque, ret); +} + static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req, int64_t offset, QEMUIOVector *iov, int direction, @@ -2777,9 +2813,11 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req, io_header->timeout = s->qdev.io_timeout * 1000; io_header->usr_ptr = r; io_header->flags |= SG_FLAG_DIRECT_IO; + req->cb = cb; + req->cb_opaque = opaque; trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba, nb_logical_blocks, io_header->timeout); - aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque); + aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, scsi_block_sgio_complete, req); assert(aiocb != NULL); return aiocb; } @@ -2893,7 +2931,6 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) return 0; } - r->req.status = &r->io_header.status; return scsi_disk_dma_command(req, buf); } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index cf7e11c..98c30c5 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -75,6 +75,7 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) { int status; SCSISense sense; + sg_io_hdr_t *io_hdr = &r->io_header; assert(r->req.aiocb == NULL); @@ -82,15 +83,22 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) scsi_req_cancel_complete(&r->req); goto done; } - status = sg_io_sense_from_errno(-ret, &r->io_header, &sense); - if (status == CHECK_CONDITION) { - if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { - r->req.sense_len = r->io_header.sb_len_wr; - } else { + if (ret < 0) { + status = scsi_sense_from_errno(-ret, &sense); + if (status == CHECK_CONDITION) { scsi_req_build_sense(&r->req, sense); } + } else if (io_hdr->host_status != SCSI_HOST_OK) { + scsi_req_complete_failed(&r->req, io_hdr->host_status); + goto done; + } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { + status = BUSY; + } else { + status = io_hdr->status; + if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { + r->req.sense_len = io_hdr->sb_len_wr; + } } - trace_scsi_generic_command_complete_noio(r, r->req.tag, status); scsi_req_complete(&r->req, status); @@ -288,7 +296,10 @@ static void scsi_read_complete(void * opaque, int ret) } } - if (len == 0) { + if (r->io_header.host_status != SCSI_HOST_OK || + (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) || + r->io_header.status != GOOD || + len == 0) { scsi_command_complete_noio(r, 0); goto done; } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 358c0e7..6d80730 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -500,6 +500,51 @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req) virtio_scsi_complete_req(req); } +static void virtio_scsi_command_failed(SCSIRequest *r) +{ + VirtIOSCSIReq *req = r->hba_private; + + if (r->io_canceled) { + return; + } + + req->resp.cmd.status = GOOD; + switch (r->host_status) { + case SCSI_HOST_NO_LUN: + req->resp.cmd.response = VIRTIO_SCSI_S_INCORRECT_LUN; + break; + case SCSI_HOST_BUSY: + req->resp.cmd.response = VIRTIO_SCSI_S_BUSY; + break; + case SCSI_HOST_TIME_OUT: + case SCSI_HOST_ABORTED: + req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED; + break; + case SCSI_HOST_BAD_RESPONSE: + req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; + break; + case SCSI_HOST_RESET: + req->resp.cmd.response = VIRTIO_SCSI_S_RESET; + break; + case SCSI_HOST_TRANSPORT_DISRUPTED: + req->resp.cmd.response = VIRTIO_SCSI_S_TRANSPORT_FAILURE; + break; + case SCSI_HOST_TARGET_FAILURE: + req->resp.cmd.response = VIRTIO_SCSI_S_TARGET_FAILURE; + break; + case SCSI_HOST_RESERVATION_ERROR: + req->resp.cmd.response = VIRTIO_SCSI_S_NEXUS_FAILURE; + break; + case SCSI_HOST_ALLOCATION_FAILURE: + case SCSI_HOST_MEDIUM_ERROR: + case SCSI_HOST_ERROR: + default: + req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE; + break; + } + virtio_scsi_complete_cmd_req(req); +} + static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid) { VirtIOSCSIReq *req = r->hba_private; @@ -908,6 +953,7 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { .max_lun = VIRTIO_SCSI_MAX_LUN, .complete = virtio_scsi_command_complete, + .fail = virtio_scsi_command_failed, .cancel = virtio_scsi_request_cancelled, .change = virtio_scsi_change, .parse_cdb = virtio_scsi_parse_cdb, diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 0da378e..1f30cb0 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -511,6 +511,44 @@ pvscsi_write_sense(PVSCSIRequest *r, uint8_t *sense, int len) } static void +pvscsi_command_failed(SCSIRequest *req) +{ + PVSCSIRequest *pvscsi_req = req->hba_private; + PVSCSIState *s; + + if (!pvscsi_req) { + trace_pvscsi_command_complete_not_found(req->tag); + return; + } + s = pvscsi_req->dev; + + switch (req->host_status) { + case SCSI_HOST_NO_LUN: + pvscsi_req->cmp.hostStatus = BTSTAT_LUNMISMATCH; + break; + case SCSI_HOST_BUSY: + pvscsi_req->cmp.hostStatus = BTSTAT_ABORTQUEUE; + break; + case SCSI_HOST_TIME_OUT: + case SCSI_HOST_ABORTED: + pvscsi_req->cmp.hostStatus = BTSTAT_SENTRST; + break; + case SCSI_HOST_BAD_RESPONSE: + pvscsi_req->cmp.hostStatus = BTSTAT_SELTIMEO; + break; + case SCSI_HOST_RESET: + pvscsi_req->cmp.hostStatus = BTSTAT_BUSRESET; + break; + default: + pvscsi_req->cmp.hostStatus = BTSTAT_HASOFTWARE; + break; + } + pvscsi_req->cmp.scsiStatus = GOOD; + qemu_sglist_destroy(&pvscsi_req->sgl); + pvscsi_complete_request(s, pvscsi_req); +} + +static void pvscsi_command_complete(SCSIRequest *req, size_t resid) { PVSCSIRequest *pvscsi_req = req->hba_private; @@ -1103,6 +1141,7 @@ static const struct SCSIBusInfo pvscsi_scsi_info = { .get_sg_list = pvscsi_get_sg_list, .complete = pvscsi_command_complete, .cancel = pvscsi_request_cancelled, + .fail = pvscsi_command_failed, }; static void |