From c9b308d20b642c106048f088ccc31f2aa7cf59ba Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 30 Jan 2012 23:29:47 +0100 Subject: AHCI: Fix port reset race bdrv_aio_cancel() can trigger bdrv_aio_flush() which makes all aio that is currently in flight finish. So what we do is: port reset detect ncq in flight cancel ncq delete ncq sg list at which point we have double freed the sg list. Instead, with this patch we do: port reset detect ncq in flight cancel ncq check if we are really still in flight delete ncq sg list which makes things work and gets rid of the race. Signed-off-by: Alexander Graf Signed-off-by: Kevin Wolf --- hw/ide/ahci.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'hw/ide') diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index c87a6ca..caff7bc 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -560,6 +560,11 @@ static void ahci_reset_port(AHCIState *s, int port) ncq_tfs->aiocb = NULL; } + /* Maybe we just finished the request thanks to bdrv_aio_cancel() */ + if (!ncq_tfs->used) { + continue; + } + qemu_sglist_destroy(&ncq_tfs->sglist); ncq_tfs->used = 0; } -- cgit v1.1 From b867672884afc39b6537a8aa6aa2f20a5154bf4f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 30 Jan 2012 23:29:48 +0100 Subject: AHCI: Masking of IRQs actually masks them When masking IRQ lines, we should actually mask them out and not declare them active anymore. Once we mask them in again, they are allowed to trigger again. Signed-off-by: Alexander Graf Signed-off-by: Kevin Wolf --- hw/ide/ahci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw/ide') diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index caff7bc..f7ef114 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -146,6 +146,7 @@ static void ahci_check_irq(AHCIState *s) DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus); + s->control_regs.irqstatus = 0; for (i = 0; i < s->ports; i++) { AHCIPortRegs *pr = &s->dev[i].port_regs; if (pr->irq_stat & pr->irq_mask) { @@ -216,6 +217,7 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) break; case PORT_IRQ_STAT: pr->irq_stat &= ~val; + ahci_check_irq(s); break; case PORT_IRQ_MASK: pr->irq_mask = val & 0xfdc000ff; -- cgit v1.1