static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
                            PrdtEntry *prdt, int prdt_entries)
{
    QPCIDevice *dev;
    uint16_t bmdma_base;
    uintptr_t guest_prdt;
    size_t len;
    bool from_dev;
    uint8_t status;
    int flags;
    dev = get_pci_device(&bmdma_base);
    flags = cmd & ~0xff;
    cmd &= 0xff;
    switch (cmd) {
    case CMD_READ_DMA:
        from_dev = true;
        break;
    case CMD_WRITE_DMA:
        from_dev = false;
        break;
    default:
        g_assert_not_reached();
    /* Select device 0 */
    outb(IDE_BASE + reg_device, 0 | LBA);
    /* Stop any running transfer, clear any pending interrupt */
    outb(bmdma_base + bmreg_cmd, 0);
    outb(bmdma_base + bmreg_status, BM_STS_INTR);
    /* Setup PRDT */
    len = sizeof(*prdt) * prdt_entries;
    guest_prdt = guest_alloc(guest_malloc, len);
    memwrite(guest_prdt, prdt, len);
    outl(bmdma_base + bmreg_prdt, guest_prdt);
    /* ATA DMA command */
    outb(IDE_BASE + reg_nsectors, nb_sectors);
    outb(IDE_BASE + reg_lba_low,    sector & 0xff);
    outb(IDE_BASE + reg_lba_middle, (sector >> 8) & 0xff);
    outb(IDE_BASE + reg_lba_high,   (sector >> 16) & 0xff);
    outb(IDE_BASE + reg_command, cmd);
    /* Start DMA transfer */
    outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
    if (flags & CMDF_ABORT) {
        outb(bmdma_base + bmreg_cmd, 0);
    /* Wait for the DMA transfer to complete */
    do {
        status = inb(bmdma_base + bmreg_status);
    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
    g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR));
    /* Check IDE status code */
    assert_bit_set(inb(IDE_BASE + reg_status), DRDY);
    assert_bit_clear(inb(IDE_BASE + reg_status), BSY | DRQ);
    /* Reading the status register clears the IRQ */
    g_assert(!get_irq(IDE_PRIMARY_IRQ));
    /* Stop DMA transfer if still active */
    if (status & BM_STS_ACTIVE) {
        outb(bmdma_base + bmreg_cmd, 0);
    free_pci_device(dev);
    return status;
static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
                            PrdtEntry *prdt, int prdt_entries)
{
    QPCIDevice *dev;
    uint16_t bmdma_base;
    uintptr_t guest_prdt;
    size_t len;
    bool from_dev;
    uint8_t status;
    int flags;
    dev = get_pci_device(&bmdma_base);
    flags = cmd & ~0xff;
    cmd &= 0xff;
    switch (cmd) {
    case CMD_READ_DMA:
        from_dev = true;
        break;
    case CMD_WRITE_DMA:
        from_dev = false;
        break;
    default:
        g_assert_not_reached();
    
    outb(IDE_BASE + reg_device, 0 | LBA);
    
    outb(bmdma_base + bmreg_cmd, 0);
    outb(bmdma_base + bmreg_status, BM_STS_INTR);
    
    len = sizeof(*prdt) * prdt_entries;
    guest_prdt = guest_alloc(guest_malloc, len);
    memwrite(guest_prdt, prdt, len);
    outl(bmdma_base + bmreg_prdt, guest_prdt);
    
    outb(IDE_BASE + reg_nsectors, nb_sectors);
    outb(IDE_BASE + reg_lba_low,    sector & 0xff);
    outb(IDE_BASE + reg_lba_middle, (sector >> 8) & 0xff);
    outb(IDE_BASE + reg_lba_high,   (sector >> 16) & 0xff);
    outb(IDE_BASE + reg_command, cmd);
    
    outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
    if (flags & CMDF_ABORT) {
        outb(bmdma_base + bmreg_cmd, 0);
    
    do {
        status = inb(bmdma_base + bmreg_status);
    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
    g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR));
    
    assert_bit_set(inb(IDE_BASE + reg_status), DRDY);
    assert_bit_clear(inb(IDE_BASE + reg_status), BSY | DRQ);
    
    g_assert(!get_irq(IDE_PRIMARY_IRQ));
    
    if (status & BM_STS_ACTIVE) {
        outb(bmdma_base + bmreg_cmd, 0);
    free_pci_device(dev);
    return status;
static int FUNC_0(int VAR_0, uint64_t VAR_1, int VAR_2,
                            PrdtEntry *VAR_3, int VAR_4)
{
    QPCIDevice *dev;
    uint16_t bmdma_base;
    uintptr_t guest_prdt;
    size_t len;
    bool from_dev;
    uint8_t status;
    int VAR_5;
    dev = get_pci_device(&bmdma_base);
    VAR_5 = VAR_0 & ~0xff;
    VAR_0 &= 0xff;
    switch (VAR_0) {
    case CMD_READ_DMA:
        from_dev = true;
        break;
    case CMD_WRITE_DMA:
        from_dev = false;
        break;
    default:
        g_assert_not_reached();
    
    outb(IDE_BASE + reg_device, 0 | LBA);
    
    outb(bmdma_base + bmreg_cmd, 0);
    outb(bmdma_base + bmreg_status, BM_STS_INTR);
    
    len = sizeof(*VAR_3) * VAR_4;
    guest_prdt = guest_alloc(guest_malloc, len);
    memwrite(guest_prdt, VAR_3, len);
    outl(bmdma_base + bmreg_prdt, guest_prdt);
    
    outb(IDE_BASE + reg_nsectors, VAR_2);
    outb(IDE_BASE + reg_lba_low,    VAR_1 & 0xff);
    outb(IDE_BASE + reg_lba_middle, (VAR_1 >> 8) & 0xff);
    outb(IDE_BASE + reg_lba_high,   (VAR_1 >> 16) & 0xff);
    outb(IDE_BASE + reg_command, VAR_0);
    
    outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
    if (VAR_5 & CMDF_ABORT) {
        outb(bmdma_base + bmreg_cmd, 0);
    
    do {
        status = inb(bmdma_base + bmreg_status);
    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
    g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR));
    
    assert_bit_set(inb(IDE_BASE + reg_status), DRDY);
    assert_bit_clear(inb(IDE_BASE + reg_status), BSY | DRQ);
    
    g_assert(!get_irq(IDE_PRIMARY_IRQ));
    
    if (status & BM_STS_ACTIVE) {
        outb(bmdma_base + bmreg_cmd, 0);
    free_pci_device(dev);
    return status;
static int FUNC_0(int VAR_0, uint64_t VAR_1, int VAR_2,
PrdtEntry *VAR_3, int VAR_4)
{ QPCIDevice *dev; uint16_t bmdma_base; uintptr_t guest_prdt; size_t len; bool from_dev; uint8_t status; int VAR_5; dev = get_pci_device(&bmdma_base); VAR_5 = VAR_0 & ~0xff; VAR_0 &= 0xff; switch (VAR_0) { case CMD_READ_DMA:
from_dev = true; break; case CMD_WRITE_DMA:
from_dev = false; break; default:
g_assert_not_reached(); outb(IDE_BASE + reg_device, 0 | LBA); outb(bmdma_base + bmreg_cmd, 0); outb(bmdma_base + bmreg_status, BM_STS_INTR); len = sizeof(*VAR_3) * VAR_4; guest_prdt = guest_alloc(guest_malloc, len); memwrite(guest_prdt, VAR_3, len); outl(bmdma_base + bmreg_prdt, guest_prdt); outb(IDE_BASE + reg_nsectors, VAR_2); outb(IDE_BASE + reg_lba_low,    VAR_1 & 0xff); outb(IDE_BASE + reg_lba_middle, (VAR_1 >> 8) & 0xff); outb(IDE_BASE + reg_lba_high,   (VAR_1 >> 16) & 0xff); outb(IDE_BASE + reg_command, VAR_0); outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0)); if (VAR_5 & CMDF_ABORT) { outb(bmdma_base + bmreg_cmd, 0); do { status = inb(bmdma_base + bmreg_status); } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE); g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR)); assert_bit_set(inb(IDE_BASE + reg_status), DRDY); assert_bit_clear(inb(IDE_BASE + reg_status), BSY | DRQ); g_assert(!get_irq(IDE_PRIMARY_IRQ)); if (status & BM_STS_ACTIVE) { outb(bmdma_base + bmreg_cmd, 0); free_pci_device(dev); return status;