* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include <hw/hw.h>
-#include <hw/i386/pc.h>
-#include <hw/pci/pci.h>
-#include <hw/isa/isa.h>
-#include "sysemu/block-backend.h"
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
#include "sysemu/dma.h"
#include "qemu/error-report.h"
-#include <hw/ide/pci.h>
+#include "hw/ide/pci.h"
+#include "trace.h"
#define BMDMA_PAGE_SIZE 4096
(IDE_RETRY_DMA | IDE_RETRY_PIO | \
IDE_RETRY_READ | IDE_RETRY_FLUSH)
+static uint64_t pci_ide_cmd_read(void *opaque, hwaddr addr, unsigned size)
+{
+ IDEBus *bus = opaque;
+
+ if (addr != 2 || size != 1) {
+ return ((uint64_t)1 << (size * 8)) - 1;
+ }
+ return ide_status_read(bus, addr + 2);
+}
+
+static void pci_ide_cmd_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ IDEBus *bus = opaque;
+
+ if (addr != 2 || size != 1) {
+ return;
+ }
+ ide_cmd_write(bus, addr + 2, data);
+}
+
+const MemoryRegionOps pci_ide_cmd_le_ops = {
+ .read = pci_ide_cmd_read,
+ .write = pci_ide_cmd_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t pci_ide_data_read(void *opaque, hwaddr addr, unsigned size)
+{
+ IDEBus *bus = opaque;
+
+ if (size == 1) {
+ return ide_ioport_read(bus, addr);
+ } else if (addr == 0) {
+ if (size == 2) {
+ return ide_data_readw(bus, addr);
+ } else {
+ return ide_data_readl(bus, addr);
+ }
+ }
+ return ((uint64_t)1 << (size * 8)) - 1;
+}
+
+static void pci_ide_data_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ IDEBus *bus = opaque;
+
+ if (size == 1) {
+ ide_ioport_write(bus, addr, data);
+ } else if (addr == 0) {
+ if (size == 2) {
+ ide_data_writew(bus, addr, data);
+ } else {
+ ide_data_writel(bus, addr, data);
+ }
+ }
+}
+
+const MemoryRegionOps pci_ide_data_le_ops = {
+ .read = pci_ide_data_read,
+ .write = pci_ide_data_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
static void bmdma_start_dma(IDEDMA *dma, IDEState *s,
BlockCompletionFunc *dma_cb)
{
{
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
-#ifdef DEBUG_IDE
- printf("ide: dma_reset\n");
-#endif
+ trace_bmdma_reset();
bmdma_cancel(bm);
bm->cmd = 0;
bm->status = 0;
void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
{
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
+ trace_bmdma_cmd_writeb(val);
/* Ignore writes to SSBM if it keeps the old value */
if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
if (!(val & BM_CMD_START)) {
- /*
- * We can't cancel Scatter Gather DMA in the middle of the
- * operation or a partial (not full) DMA transfer would reach
- * the storage so we wait for completion instead (we beahve
- * like if the DMA was completed by the time the guest trying
- * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
- * set).
- *
- * In the future we'll be able to safely cancel the I/O if the
- * whole DMA operation will be submitted to disk with a single
- * aio operation with preadv/pwritev.
- */
- if (bm->bus->dma->aiocb) {
- blk_drain_all();
- assert(bm->bus->dma->aiocb == NULL);
- }
+ ide_cancel_dma_sync(idebus_active_if(bm->bus));
bm->status &= ~BM_STATUS_DMAING;
} else {
bm->cur_addr = bm->addr;
uint64_t data;
data = (bm->addr >> (addr * 8)) & mask;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, (unsigned)data);
-#endif
+ trace_bmdma_addr_read(data);
return data;
}
int shift = addr * 8;
uint32_t mask = (1ULL << (width * 8)) - 1;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, (unsigned)data);
-#endif
+ trace_bmdma_addr_write(data);
bm->addr &= ~(mask << shift);
bm->addr |= ((data & mask) << shift) & ~3;
}
return ((bm->status & abused_bits) != 0);
}
-static void ide_bmdma_pre_save(void *opaque)
+static int 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;
bm->migration_compat_status =
(bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits);
+
+ return 0;
}
/* This function accesses bm->bus->error_status which is loaded only after
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIIDEState),
.abstract = true,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
};
static void pci_ide_register_types(void)