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

    if (ret == -ECANCELED) {
        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)) {
            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) {
        assert(s->io_buffer_size == s->sg.size);
        dma_buf_commit(s, s->io_buffer_size);
        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)) < 512) {
        /* The PRDs were too short. Reset the Active bit, but don't raise an
         * interrupt. */
        s->status = READY_STAT | SEEK_STAT;
        dma_buf_commit(s, 0);
        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

    if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
        !ide_sect_range_ok(s, sector_num, n)) {
        ide_dma_error(s);
        return;
    }

    switch (s->dma_cmd) {
    case IDE_DMA_READ:
        s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, sector_num,
                                          ide_dma_cb, s);
        break;
    case IDE_DMA_WRITE:
        s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, sector_num,
                                           ide_dma_cb, s);
        break;
    case IDE_DMA_TRIM:
        s->bus->dma->aiocb = dma_blk_io(s->blk, &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) {
        block_acct_done(blk_get_stats(s->blk), &s->acct);
    }
    ide_set_inactive(s, stay_active);
}
void ide_dma_cb(void *opaque, int ret)
{
    IDEState *s = opaque;
    int n;
    int64_t sector_num;
    bool stay_active = false;

    if (ret == -ECANCELED) {
        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)) {
            return;
        }
    }

    n = s->io_buffer_size >> 9;
    if (n > s->nsector) {
         
        n = s->nsector;
        stay_active = true;
    }

    sector_num = ide_get_sector(s);
    if (n > 0) {
        assert(s->io_buffer_size == s->sg.size);
        dma_buf_commit(s, s->io_buffer_size);
        sector_num += n;
        ide_set_sector(s, sector_num);
        s->nsector -= n;
    }

     
    if (s->nsector == 0) {
        s->status = READY_STAT | SEEK_STAT;
        ide_set_irq(s->bus);
        goto eot;
    }

     
    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)) < 512) {
         
        s->status = READY_STAT | SEEK_STAT;
        dma_buf_commit(s, 0);
        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

    if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
        !ide_sect_range_ok(s, sector_num, n)) {
        ide_dma_error(s);
        return;
    }

    switch (s->dma_cmd) {
    case IDE_DMA_READ:
        s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, sector_num,
                                          ide_dma_cb, s);
        break;
    case IDE_DMA_WRITE:
        s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, sector_num,
                                           ide_dma_cb, s);
        break;
    case IDE_DMA_TRIM:
        s->bus->dma->aiocb = dma_blk_io(s->blk, &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) {
        block_acct_done(blk_get_stats(s->blk), &s->acct);
    }
    ide_set_inactive(s, stay_active);
}