diff options
author | Pavel Butsykin <pbutsykin@virtuozzo.com> | 2016-04-12 16:47:52 -0400 |
---|---|---|
committer | John Snow <jsnow@redhat.com> | 2016-04-12 16:47:52 -0400 |
commit | 218fd37c68e450dffe37832e82a1f0a6592e7169 (patch) | |
tree | 31b8b9dc27ca318b0bf209ecdf3e56c10758c861 /hw/ide | |
parent | d1fc684f3692d6bbe85d5ee35c2568f0bc68fa1c (diff) |
ide: don't lose pending dma state
If the migration occurs after the IDE DMA has been set up but before it
has been initiated, the state gets lost upon save/restore. Specifically,
->dma_cb callback gets cleared, so, when the guest eventually starts bus
mastering, the DMA never completes, causing the guest to time out the
operation.
OTOH all the infrastructure is already in place to restart the DMA if
the migration happens while the DMA is in progress.
So reuse that infrastructure, by setting bus->error_status based on
->dma_cmd in pre_save if ->dma_cb callback is already set but DMAING is
clear. This will indicate the need for restart and make sure ->dma_cb
is restored in ide_restart_bh(); howeover since DMAING is clear the state
upon restore will be exactly "ready for DMA" as before the save.
Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
Reviewed-by: Roman Kagan <rkagan@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: John Snow <jsnow@redhat.com>
Message-id: 1459924806-306-2-git-send-email-den@openvz.org
Signed-off-by: John Snow <jsnow@redhat.com>
Diffstat (limited to 'hw/ide')
-rw-r--r-- | hw/ide/core.c | 9 | ||||
-rw-r--r-- | hw/ide/internal.h | 15 | ||||
-rw-r--r-- | hw/ide/pci.c | 4 |
3 files changed, 20 insertions, 8 deletions
diff --git a/hw/ide/core.c b/hw/ide/core.c index 90524d5e16..58d06876dc 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -804,14 +804,7 @@ static void ide_dma_cb(void *opaque, int ret) return; } if (ret < 0) { - int op = IDE_RETRY_DMA; - - if (s->dma_cmd == IDE_DMA_READ) - op |= IDE_RETRY_READ; - else if (s->dma_cmd == IDE_DMA_TRIM) - op |= IDE_RETRY_TRIM; - - if (ide_handle_rw_error(s, -ret, op)) { + if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) { return; } } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 86bde26551..68c7d0d87e 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -513,6 +513,21 @@ struct IDEDevice { #define IDE_RETRY_TRIM 0x80 #define IDE_RETRY_HBA 0x100 +static inline uint8_t ide_dma_cmd_to_retry(uint8_t dma_cmd) +{ + switch (dma_cmd) { + case IDE_DMA_READ: + return IDE_RETRY_DMA | IDE_RETRY_READ; + case IDE_DMA_WRITE: + return IDE_RETRY_DMA; + case IDE_DMA_TRIM: + return IDE_RETRY_DMA | IDE_RETRY_TRIM; + default: + break; + } + return 0; +} + static inline IDEState *idebus_active_if(IDEBus *bus) { return bus->ifs + bus->unit; diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 92ffee7264..8d56a00b1b 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -308,6 +308,10 @@ static void ide_bmdma_pre_save(void *opaque) BMDMAState *bm = opaque; uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS; + if (!(bm->status & BM_STATUS_DMAING) && bm->dma_cb) { + bm->bus->error_status = + ide_dma_cmd_to_retry(bmdma_active_if(bm)->dma_cmd); + } bm->migration_retry_unit = bm->bus->retry_unit; bm->migration_retry_sector_num = bm->bus->retry_sector_num; bm->migration_retry_nsector = bm->bus->retry_nsector; |