void ide_dma_cb(void *opaque, int ret)
{
    IDEState *s = opaque;
    int n;
    int64_t sector_num;
    bool stay_active = false;

    if (ret < 0) {
        int op = BM_STATUS_DMA_RETRY;

        if (s->dma_cmd == IDE_DMA_READ)
            op |= BM_STATUS_RETRY_READ;
        else if (s->dma_cmd == IDE_DMA_TRIM)
            op |= BM_STATUS_RETRY_TRIM;

        if (ide_handle_rw_error(s, -ret, op)) {
            return;
        }
    }

    n = s->io_buffer_size >> 9;
    if (n > s->nsector) {
        /* The PRDs were longer than needed for this request. Shorten them so
         * we don't get a negative remainder. The Active bit must remain set
         * after the request completes. */
        n = s->nsector;
        stay_active = true;
    }

    sector_num = ide_get_sector(s);
    if (n > 0) {
        dma_buf_commit(s);
        sector_num += n;
        ide_set_sector(s, sector_num);
        s->nsector -= n;
    }

    /* end of transfer ? */
    if (s->nsector == 0) {
        s->status = READY_STAT | SEEK_STAT;
        ide_set_irq(s->bus);
        goto eot;
    }

    /* launch next transfer */
    n = s->nsector;
    s->io_buffer_index = 0;
    s->io_buffer_size = n * 512;
    if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) {
        /* The PRDs were too short. Reset the Active bit, but don't raise an
         * interrupt. */
        s->status = READY_STAT | SEEK_STAT;
        goto eot;
    }

#ifdef DEBUG_AIO
    printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, cmd_cmd=%d\n",
           sector_num, n, s->dma_cmd);
#endif

    switch (s->dma_cmd) {
    case IDE_DMA_READ:
        s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
                                           ide_dma_cb, s);
        break;
    case IDE_DMA_WRITE:
        s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
                                            ide_dma_cb, s);
        break;
    case IDE_DMA_TRIM:
        s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
                                         ide_issue_trim, ide_dma_cb, s,
                                         DMA_DIRECTION_TO_DEVICE);
        break;
    }
    return;

eot:
    if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
        bdrv_acct_done(s->bs, &s->acct);
    }
    ide_set_inactive(s);
    if (stay_active) {
        s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_DMAING);
    }
}
Unknown