From 8cc5583abe6419e7faaebc9fbd109f34f4c850f2 Mon Sep 17 00:00:00 2001 From: Venu Busireddy Date: Thu, 6 Oct 2022 14:49:46 -0500 Subject: virtio-scsi: Send "REPORTED LUNS CHANGED" sense data upon disk hotplug events Section 5.6.6.3 of VirtIO specification states, "Events will also be reported via sense codes..." However, no sense data is sent when VIRTIO_SCSI_EVT_RESET_RESCAN or VIRTIO_SCSI_EVT_RESET_REMOVED events are reported (when disk hotplug/hotunplug events occur). SCSI layer on Solaris depends on this sense data, and hence does not handle disk hotplug/hotunplug events. When the disk inventory changes, use the bus unit attention mechanism to return a CHECK_CONDITION status with sense data of 0x06/0x3F/0x0E (sense code REPORTED_LUNS_CHANGED). The first device on the bus to execute a command successfully will report and consume the unit attention status. Signed-off-by: Venu Busireddy Message-Id: <20221006194946.24134-1-venu.busireddy@oracle.com> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 18 ++++++++++++++++++ hw/scsi/virtio-scsi.c | 2 ++ 2 files changed, 20 insertions(+) (limited to 'hw') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 4403717..ceceafb 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1616,6 +1616,24 @@ static int scsi_ua_precedence(SCSISense sense) return (sense.asc << 8) | sense.ascq; } +void scsi_bus_set_ua(SCSIBus *bus, SCSISense sense) +{ + int prec1, prec2; + if (sense.key != UNIT_ATTENTION) { + return; + } + + /* + * Override a pre-existing unit attention condition, except for a more + * important reset condition. + */ + prec1 = scsi_ua_precedence(bus->unit_attention); + prec2 = scsi_ua_precedence(sense); + if (prec2 < prec1) { + bus->unit_attention = sense; + } +} + void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense) { int prec1, prec2; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 41f2a56..cf2721a 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -956,6 +956,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN); + scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED)); virtio_scsi_release(s); } } @@ -973,6 +974,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED); + scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED)); virtio_scsi_release(s); } -- cgit v1.1 From 4a5fc890b1d3609f7b22d2094d094e80c24bcf40 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 13 Oct 2022 17:06:22 +0100 Subject: scsi: Use device_cold_reset() and bus_cold_reset() In the SCSI subsystem we currently use the legacy functions qdev_reset_all() and qbus_reset_all(). These perform a recursive reset, starting from either a qbus or a qdev. However they do not permit any of the devices in the tree to use three-phase reset, because device reset goes through the device_legacy_reset() function that only calls the single DeviceClass::reset method. Switch to using the device_cold_reset() and bus_cold_reset() functions. These also perform a recursive reset, where first the children are reset and then finally the parent, but they use the new (...in 2020...) Resettable mechanism, which supports both the old style single-reset method and also the new 3-phase reset handling. Since no devices attached to SCSI buses currently try to use 3-phase reset, this should be a no-behaviour-change commit which just reduces the use of a deprecated API. Commit created with: sed -i -e 's/qdev_reset_all/device_cold_reset/g;s/qbus_reset_all/bus_cold_reset/g' hw/scsi/*.c Signed-off-by: Peter Maydell Message-Id: <20221013160623.1296109-2-peter.maydell@linaro.org> Signed-off-by: Paolo Bonzini --- hw/scsi/esp.c | 2 +- hw/scsi/lsi53c895a.c | 4 ++-- hw/scsi/megasas.c | 2 +- hw/scsi/mptsas.c | 8 ++++---- hw/scsi/spapr_vscsi.c | 2 +- hw/scsi/virtio-scsi.c | 6 +++--- hw/scsi/vmw_pvscsi.c | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'hw') diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 2ff18ce..e5b281e 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -941,7 +941,7 @@ static void esp_soft_reset(ESPState *s) static void esp_bus_reset(ESPState *s) { - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); } static void parent_esp_reset(ESPState *s, int irq, int level) diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 05a43ec..5097964 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -1868,7 +1868,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) } if (val & LSI_SCNTL1_RST) { if (!(s->sstat0 & LSI_SSTAT0_RST)) { - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->sstat0 |= LSI_SSTAT0_RST; lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); } @@ -1926,7 +1926,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) lsi_execute_script(s); } if (val & LSI_ISTAT0_SRST) { - qdev_reset_all(DEVICE(s)); + device_cold_reset(DEVICE(s)); } break; case 0x16: /* MBOX0 */ diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 7082456..9cbbb16 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -1484,7 +1484,7 @@ static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd) MegasasCmd *tmp_cmd = &s->frames[i]; if (tmp_cmd->req && tmp_cmd->req->dev->id == target_id) { SCSIDevice *d = tmp_cmd->req->dev; - qdev_reset_all(&d->qdev); + device_cold_reset(&d->qdev); } } return MFI_STAT_OK; diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index a90c254..c485da7 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -522,7 +522,7 @@ reply_maybe_async: reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN; goto out; } - qdev_reset_all(&sdev->qdev); + device_cold_reset(&sdev->qdev); break; case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: @@ -538,13 +538,13 @@ reply_maybe_async: QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { sdev = SCSI_DEVICE(kid->child); if (sdev->channel == 0 && sdev->id == req->TargetID) { - qdev_reset_all(kid->child); + device_cold_reset(kid->child); } } break; case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); break; default: @@ -807,7 +807,7 @@ static void mptsas_soft_reset(MPTSASState *s) s->intr_mask = MPI_HIM_DIM | MPI_HIM_RIM; mptsas_update_interrupt(s); - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->intr_status = 0; s->intr_mask = save_mask; diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 0a8cbf5..5bbbef6 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -865,7 +865,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req) break; } - qdev_reset_all(&d->qdev); + device_cold_reset(&d->qdev); break; case SRP_TSK_ABORT_TASK_SET: diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index cf2721a..6f6e2e3 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -365,7 +365,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) goto incorrect_lun; } s->resetting++; - qdev_reset_all(&d->qdev); + device_cold_reset(&d->qdev); s->resetting--; break; @@ -417,7 +417,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) { SCSIDevice *d1 = SCSI_DEVICE(kid->child); if (d1->channel == 0 && d1->id == target) { - qdev_reset_all(&d1->qdev); + device_cold_reset(&d1->qdev); } } rcu_read_unlock(); @@ -831,7 +831,7 @@ static void virtio_scsi_reset(VirtIODevice *vdev) assert(!s->dataplane_started); s->resetting++; - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->resetting--; vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE; diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 91e2f85..3ea2c8c 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -445,7 +445,7 @@ static void pvscsi_reset_adapter(PVSCSIState *s) { s->resetting++; - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->resetting--; pvscsi_process_completion_queue(s); assert(QTAILQ_EMPTY(&s->pending_queue)); @@ -894,7 +894,7 @@ pvscsi_on_cmd_reset_bus(PVSCSIState *s) trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_RESET_BUS"); s->resetting++; - qbus_reset_all(BUS(&s->bus)); + bus_cold_reset(BUS(&s->bus)); s->resetting--; return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; } -- cgit v1.1 From 8b5335e381e7fd7554a65c6d591875ade1cea062 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 13 Oct 2022 17:06:23 +0100 Subject: hw/scsi/vmw_pvscsi.c: Use device_cold_reset() to reset SCSI devices Currently the vwm_pvscsi controller resets individual SCSI devices with the device_legacy_reset() function. The only difference between this and device_cold_reset() is that device_legacy_reset() resets the device but not any child qbuses it might have. In this case, no SCSI device has a child qbus, so the functions have the same behaviour. Switch to device_cold_reset() to move away from using the deprecated function, and bring this SCSI controller in to line with what all the others do. Signed-off-by: Peter Maydell Message-Id: <20221013160623.1296109-3-peter.maydell@linaro.org> Signed-off-by: Paolo Bonzini --- hw/scsi/vmw_pvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 3ea2c8c..fa76696 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -880,7 +880,7 @@ pvscsi_on_cmd_reset_device(PVSCSIState *s) if (sdev != NULL) { s->resetting++; - device_legacy_reset(&sdev->qdev); + device_cold_reset(&sdev->qdev); s->resetting--; return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; } -- cgit v1.1 From ec19444a53ef221954128e36e1387592a2273dc2 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Fri, 30 Sep 2022 17:52:03 +0200 Subject: hyperv: fix SynIC SINT assertion failure on guest reset Resetting a guest that has Hyper-V VMBus support enabled triggers a QEMU assertion failure: hw/hyperv/hyperv.c:131: synic_reset: Assertion `QLIST_EMPTY(&synic->sint_routes)' failed. This happens both on normal guest reboot or when using "system_reset" HMP command. The failing assertion was introduced by commit 64ddecc88bcf ("hyperv: SControl is optional to enable SynIc") to catch dangling SINT routes on SynIC reset. The root cause of this problem is that the SynIC itself is reset before devices using SINT routes have chance to clean up these routes. Since there seems to be no existing mechanism to force reset callbacks (or methods) to be executed in specific order let's use a similar method that is already used to reset another interrupt controller (APIC) after devices have been reset - by invoking the SynIC reset from the machine reset handler via a new x86_cpu_after_reset() function co-located with the existing x86_cpu_reset() in target/i386/cpu.c. Opportunistically move the APIC reset handler there, too. Fixes: 64ddecc88bcf ("hyperv: SControl is optional to enable SynIc") # exposed the bug Signed-off-by: Maciej S. Szmigiero Message-Id: Signed-off-by: Paolo Bonzini --- hw/i386/microvm.c | 4 +--- hw/i386/pc.c | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 7fe8cce..52f9aa9 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -485,9 +485,7 @@ static void microvm_machine_reset(MachineState *machine) CPU_FOREACH(cs) { cpu = X86_CPU(cs); - if (cpu->apic_state) { - device_legacy_reset(cpu->apic_state); - } + x86_cpu_after_reset(cpu); } } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 566accf..768982a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -92,6 +92,7 @@ #include "hw/virtio/virtio-mem-pci.h" #include "hw/mem/memory-device.h" #include "sysemu/replay.h" +#include "target/i386/cpu.h" #include "qapi/qmp/qerror.h" #include "e820_memory_layout.h" #include "fw_cfg.h" @@ -1859,9 +1860,7 @@ static void pc_machine_reset(MachineState *machine) CPU_FOREACH(cs) { cpu = X86_CPU(cs); - if (cpu->apic_state) { - device_legacy_reset(cpu->apic_state); - } + x86_cpu_after_reset(cpu); } } -- cgit v1.1