virtio-pci only registered reset_prepare/reset_done. The PCI error recovery core treats devices without error_detected as NO_AER_DRIVER and does not deliver pci_channel_io_perm_failure to the driver after a failed recovery. Virtio devices therefore miss the normal ERS quiesce/teardown sequence.
Register error_detected: quiesce on frozen (reset_prepare) before bus reset; on perm_failure break virtqueues and return DISCONNECT. Block-layer cleanup for virtio-blk is handled in the follow-up patch. Signed-off-by: Xixin Liu <[email protected]> --- drivers/virtio/virtio_pci_common.c | 30 +++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 164f480b18a6..e2dda946e70e 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -828,7 +828,37 @@ static void virtio_pci_reset_done(struct pci_dev *pci_dev) dev_warn(&pci_dev->dev, "Reset done failure: %d", ret); } +static pci_ers_result_t virtio_pci_error_detected(struct pci_dev *pci_dev, + pci_channel_state_t state) +{ + struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); + + /* + * PCI ERS error_detected: quiesce on frozen before bus reset; on + * permanent failure ask the virtio driver to shut down (virtio-blk + * marks the disk dead in its .shutdown handler). + */ + switch (state) { + case pci_channel_io_normal: + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + pci_info(pci_dev, "frozen error detected, quiesce device\n"); + if (virtio_device_reset_prepare(&vp_dev->vdev)) + dev_warn(&pci_dev->dev, "frozen: reset prepare failed\n"); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + dev_warn(&pci_dev->dev, + "permanent failure, disconnecting device\n"); + virtio_break_device(&vp_dev->vdev); + return PCI_ERS_RESULT_DISCONNECT; + default: + break; + } + return PCI_ERS_RESULT_NEED_RESET; +} + static const struct pci_error_handlers virtio_pci_err_handler = { + .error_detected = virtio_pci_error_detected, .reset_prepare = virtio_pci_reset_prepare, .reset_done = virtio_pci_reset_done, };

