static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)

{

    AHCICmdHdr *cmd = ad->cur_cmd;

    uint32_t opts = le32_to_cpu(cmd->opts);

    uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;

    int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;

    dma_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));

    dma_addr_t real_prdt_len = prdt_len;

    uint8_t *prdt;

    int i;

    int r = 0;

    int sum = 0;

    int off_idx = -1;

    int off_pos = -1;

    int tbl_entry_size;

    IDEBus *bus = &ad->port;

    BusState *qbus = BUS(bus);



    if (!sglist_alloc_hint) {

        DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);

        return -1;

    }



    /* map PRDT */

    if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len,

                                DMA_DIRECTION_TO_DEVICE))){

        DPRINTF(ad->port_no, "map failed\n");

        return -1;

    }



    if (prdt_len < real_prdt_len) {

        DPRINTF(ad->port_no, "mapped less than expected\n");

        r = -1;

        goto out;

    }



    /* Get entries in the PRDT, init a qemu sglist accordingly */

    if (sglist_alloc_hint > 0) {

        AHCI_SG *tbl = (AHCI_SG *)prdt;

        sum = 0;

        for (i = 0; i < sglist_alloc_hint; i++) {

            /* flags_size is zero-based */

            tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);

            if (offset <= (sum + tbl_entry_size)) {

                off_idx = i;

                off_pos = offset - sum;

                break;

            }

            sum += tbl_entry_size;

        }

        if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {

            DPRINTF(ad->port_no, "%s: Incorrect offset! "

                            "off_idx: %d, off_pos: %d\n",

                            __func__, off_idx, off_pos);

            r = -1;

            goto out;

        }



        qemu_sglist_init(sglist, qbus->parent, (sglist_alloc_hint - off_idx),

                         ad->hba->as);

        qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),

                        le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);



        for (i = off_idx + 1; i < sglist_alloc_hint; i++) {

            /* flags_size is zero-based */

            qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),

                            le32_to_cpu(tbl[i].flags_size) + 1);

        }

    }



out:

    dma_memory_unmap(ad->hba->as, prdt, prdt_len,

                     DMA_DIRECTION_TO_DEVICE, prdt_len);

    return r;

}

static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)

{

    AHCICmdHdr *cmd = ad->cur_cmd;

    uint32_t opts = le32_to_cpu(cmd->opts);

    uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;

    int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;

    dma_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));

    dma_addr_t real_prdt_len = prdt_len;

    uint8_t *prdt;

    int i;

    int r = 0;

    int sum = 0;

    int off_idx = -1;

    int off_pos = -1;

    int tbl_entry_size;

    IDEBus *bus = &ad->port;

    BusState *qbus = BUS(bus);



    if (!sglist_alloc_hint) {

        DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);

        return -1;

    }



    

    if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len,

                                DMA_DIRECTION_TO_DEVICE))){

        DPRINTF(ad->port_no, "map failed\n");

        return -1;

    }



    if (prdt_len < real_prdt_len) {

        DPRINTF(ad->port_no, "mapped less than expected\n");

        r = -1;

        goto out;

    }



    

    if (sglist_alloc_hint > 0) {

        AHCI_SG *tbl = (AHCI_SG *)prdt;

        sum = 0;

        for (i = 0; i < sglist_alloc_hint; i++) {

            

            tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);

            if (offset <= (sum + tbl_entry_size)) {

                off_idx = i;

                off_pos = offset - sum;

                break;

            }

            sum += tbl_entry_size;

        }

        if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {

            DPRINTF(ad->port_no, "%s: Incorrect offset! "

                            "off_idx: %d, off_pos: %d\n",

                            __func__, off_idx, off_pos);

            r = -1;

            goto out;

        }



        qemu_sglist_init(sglist, qbus->parent, (sglist_alloc_hint - off_idx),

                         ad->hba->as);

        qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),

                        le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);



        for (i = off_idx + 1; i < sglist_alloc_hint; i++) {

            

            qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),

                            le32_to_cpu(tbl[i].flags_size) + 1);

        }

    }



out:

    dma_memory_unmap(ad->hba->as, prdt, prdt_len,

                     DMA_DIRECTION_TO_DEVICE, prdt_len);

    return r;

}

            tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);                         le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);                             le32_to_cpu(tbl[i].flags_size) + 1);
static int FUNC_0(AHCIDevice *VAR_0, QEMUSGList *VAR_1, int VAR_2)

{

    AHCICmdHdr *cmd = VAR_0->cur_cmd;

    uint32_t opts = le32_to_cpu(cmd->opts);

    uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;

    int VAR_3 = opts >> AHCI_CMD_HDR_PRDT_LEN;

    dma_addr_t prdt_len = (VAR_3 * sizeof(AHCI_SG));

    dma_addr_t real_prdt_len = prdt_len;

    uint8_t *prdt;

    int VAR_4;

    int VAR_5 = 0;

    int VAR_6 = 0;

    int VAR_7 = -1;

    int VAR_8 = -1;

    int VAR_9;

    IDEBus *bus = &VAR_0->port;

    BusState *qbus = BUS(bus);



    if (!VAR_3) {

        DPRINTF(VAR_0->port_no, "no sg list given by guest: 0x%08x\n", opts);

        return -1;

    }



    

    if (!(prdt = dma_memory_map(VAR_0->hba->as, prdt_addr, &prdt_len,

                                DMA_DIRECTION_TO_DEVICE))){

        DPRINTF(VAR_0->port_no, "map failed\n");

        return -1;

    }



    if (prdt_len < real_prdt_len) {

        DPRINTF(VAR_0->port_no, "mapped less than expected\n");

        VAR_5 = -1;

        goto out;

    }



    

    if (VAR_3 > 0) {

        AHCI_SG *tbl = (AHCI_SG *)prdt;

        VAR_6 = 0;

        for (VAR_4 = 0; VAR_4 < VAR_3; VAR_4++) {

            

            VAR_9 = (le32_to_cpu(tbl[VAR_4].flags_size) + 1);

            if (VAR_2 <= (VAR_6 + VAR_9)) {

                VAR_7 = VAR_4;

                VAR_8 = VAR_2 - VAR_6;

                break;

            }

            VAR_6 += VAR_9;

        }

        if ((VAR_7 == -1) || (VAR_8 < 0) || (VAR_8 > VAR_9)) {

            DPRINTF(VAR_0->port_no, "%s: Incorrect VAR_2! "

                            "VAR_7: %d, VAR_8: %d\n",

                            __func__, VAR_7, VAR_8);

            VAR_5 = -1;

            goto out;

        }



        qemu_sglist_init(VAR_1, qbus->parent, (VAR_3 - VAR_7),

                         VAR_0->hba->as);

        qemu_sglist_add(VAR_1, le64_to_cpu(tbl[VAR_7].addr + VAR_8),

                        le32_to_cpu(tbl[VAR_7].flags_size) + 1 - VAR_8);



        for (VAR_4 = VAR_7 + 1; VAR_4 < VAR_3; VAR_4++) {

            

            qemu_sglist_add(VAR_1, le64_to_cpu(tbl[VAR_4].addr),

                            le32_to_cpu(tbl[VAR_4].flags_size) + 1);

        }

    }



out:

    dma_memory_unmap(VAR_0->hba->as, prdt, prdt_len,

                     DMA_DIRECTION_TO_DEVICE, prdt_len);

    return VAR_5;

}

static int FUNC_0(AHCIDevice *VAR_0, QEMUSGList *VAR_1, int VAR_2)
{ AHCICmdHdr *cmd = VAR_0->cur_cmd; uint32_t opts = le32_to_cpu(cmd->opts); uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80; int VAR_3 = opts >> AHCI_CMD_HDR_PRDT_LEN; dma_addr_t prdt_len = (VAR_3 * sizeof(AHCI_SG)); dma_addr_t real_prdt_len = prdt_len; uint8_t *prdt; int VAR_4; int VAR_5 = 0; int VAR_6 = 0; int VAR_7 = -1; int VAR_8 = -1; int VAR_9; IDEBus *bus = &VAR_0->port; BusState *qbus = BUS(bus); if (!VAR_3) { DPRINTF(VAR_0->port_no, "no sg list given by guest: 0x%08x\n", opts); return -1; } if (!(prdt = dma_memory_map(VAR_0->hba->as, prdt_addr, &prdt_len,
DMA_DIRECTION_TO_DEVICE))){ DPRINTF(VAR_0->port_no, "map failed\n"); return -1; } if (prdt_len < real_prdt_len) { DPRINTF(VAR_0->port_no, "mapped less than expected\n"); VAR_5 = -1; goto out; } if (VAR_3 > 0) { AHCI_SG *tbl = (AHCI_SG *)prdt; VAR_6 = 0; for (VAR_4 = 0; VAR_4 < VAR_3; VAR_4++) { VAR_9 = (le32_to_cpu(tbl[VAR_4].flags_size) + 1); if (VAR_2 <= (VAR_6 + VAR_9)) { VAR_7 = VAR_4; VAR_8 = VAR_2 - VAR_6; break; } VAR_6 += VAR_9; } if ((VAR_7 == -1) || (VAR_8 < 0) || (VAR_8 > VAR_9)) { DPRINTF(VAR_0->port_no, "%s: Incorrect VAR_2! "
"VAR_7: %d, VAR_8: %d\n",
__func__, VAR_7, VAR_8); VAR_5 = -1; goto out; } qemu_sglist_init(VAR_1, qbus->parent, (VAR_3 - VAR_7),
VAR_0->hba->as); qemu_sglist_add(VAR_1, le64_to_cpu(tbl[VAR_7].addr + VAR_8),
le32_to_cpu(tbl[VAR_7].flags_size) + 1 - VAR_8); for (VAR_4 = VAR_7 + 1; VAR_4 < VAR_3; VAR_4++) { qemu_sglist_add(VAR_1, le64_to_cpu(tbl[VAR_4].addr),
le32_to_cpu(tbl[VAR_4].flags_size) + 1); } } out:
dma_memory_unmap(VAR_0->hba->as, prdt, prdt_len,
DMA_DIRECTION_TO_DEVICE, prdt_len); return VAR_5; }