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

                                AHCICmdHdr *cmd, int64_t limit, int32_t offset)

{

    uint16_t opts = le16_to_cpu(cmd->opts);

    uint16_t prdtl = le16_to_cpu(cmd->prdtl);

    uint64_t cfis_addr = le64_to_cpu(cmd->tbl_addr);

    uint64_t prdt_addr = cfis_addr + 0x80;

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

    dma_addr_t real_prdt_len = prdt_len;

    uint8_t *prdt;

    int i;

    int r = 0;

    uint64_t sum = 0;

    int off_idx = -1;

    int64_t off_pos = -1;

    int tbl_entry_size;

    IDEBus *bus = &ad->port;

    BusState *qbus = BUS(bus);



    /*

     * Note: AHCI PRDT can describe up to 256GiB. SATA/ATA only support

     * transactions of up to 32MiB as of ATA8-ACS3 rev 1b, assuming a

     * 512 byte sector size. We limit the PRDT in this implementation to

     * a reasonably large 2GiB, which can accommodate the maximum transfer

     * request for sector sizes up to 32K.

     */



    if (!prdtl) {

        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 (prdtl > 0) {

        AHCI_SG *tbl = (AHCI_SG *)prdt;

        sum = 0;

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

            tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);

            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: %"PRId64"\n",

                            __func__, off_idx, off_pos);

            r = -1;

            goto out;

        }



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

                         ad->hba->as);

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

                        MIN(prdt_tbl_entry_size(&tbl[off_idx]) - off_pos,

                            limit));



        for (i = off_idx + 1; i < prdtl && sglist->size < limit; i++) {

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

                            MIN(prdt_tbl_entry_size(&tbl[i]),

                                limit - sglist->size));

            if (sglist->size > INT32_MAX) {

                error_report("AHCI Physical Region Descriptor Table describes "

                             "more than 2 GiB.");

                qemu_sglist_destroy(sglist);

                r = -1;

                goto out;

            }

        }

    }



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,

                                AHCICmdHdr *cmd, int64_t limit, int32_t offset)

{

    uint16_t opts = le16_to_cpu(cmd->opts);

    uint16_t prdtl = le16_to_cpu(cmd->prdtl);

    uint64_t cfis_addr = le64_to_cpu(cmd->tbl_addr);

    uint64_t prdt_addr = cfis_addr + 0x80;

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

    dma_addr_t real_prdt_len = prdt_len;

    uint8_t *prdt;

    int i;

    int r = 0;

    uint64_t sum = 0;

    int off_idx = -1;

    int64_t off_pos = -1;

    int tbl_entry_size;

    IDEBus *bus = &ad->port;

    BusState *qbus = BUS(bus);



    















    if (!prdtl) {

        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 (prdtl > 0) {

        AHCI_SG *tbl = (AHCI_SG *)prdt;

        sum = 0;

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

            tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);

            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: %"PRId64"\n",

                            __func__, off_idx, off_pos);

            r = -1;

            goto out;

        }



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

                         ad->hba->as);

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

                        MIN(prdt_tbl_entry_size(&tbl[off_idx]) - off_pos,

                            limit));



        for (i = off_idx + 1; i < prdtl && sglist->size < limit; i++) {

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

                            MIN(prdt_tbl_entry_size(&tbl[i]),

                                limit - sglist->size));

            if (sglist->size > INT32_MAX) {

                error_report("AHCI Physical Region Descriptor Table describes "

                             "more than 2 GiB.");

                qemu_sglist_destroy(sglist);

                r = -1;

                goto out;

            }

        }

    }



out:

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

                     DMA_DIRECTION_TO_DEVICE, prdt_len);

    return r;

}

                                AHCICmdHdr *cmd, int64_t limit, int32_t offset)             if (sglist->size > INT32_MAX) {                 error_report("AHCI Physical Region Descriptor Table describes "                              "more than 2 GiB.");                 qemu_sglist_destroy(sglist);                 r = -1;                 goto out;                 break;
static int FUNC_0(AHCIDevice *VAR_0, QEMUSGList *VAR_1,

                                AHCICmdHdr *VAR_2, int64_t VAR_3, int32_t VAR_4)

{

    uint16_t opts = le16_to_cpu(VAR_2->opts);

    uint16_t prdtl = le16_to_cpu(VAR_2->prdtl);

    uint64_t cfis_addr = le64_to_cpu(VAR_2->tbl_addr);

    uint64_t prdt_addr = cfis_addr + 0x80;

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

    dma_addr_t real_prdt_len = prdt_len;

    uint8_t *prdt;

    int VAR_5;

    int VAR_6 = 0;

    uint64_t sum = 0;

    int VAR_7 = -1;

    int64_t off_pos = -1;

    int VAR_8;

    IDEBus *bus = &VAR_0->port;

    BusState *qbus = BUS(bus);



    















    if (!prdtl) {

        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_6 = -1;

        goto out;

    }



    

    if (prdtl > 0) {

        AHCI_SG *tbl = (AHCI_SG *)prdt;

        sum = 0;

        for (VAR_5 = 0; VAR_5 < prdtl; VAR_5++) {

            VAR_8 = prdt_tbl_entry_size(&tbl[VAR_5]);

            if (VAR_4 < (sum + VAR_8)) {

                VAR_7 = VAR_5;

                off_pos = VAR_4 - sum;

                break;

            }

            sum += VAR_8;

        }

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

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

                            "VAR_7: %d, off_pos: %"PRId64"\n",

                            __func__, VAR_7, off_pos);

            VAR_6 = -1;

            goto out;

        }



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

                         VAR_0->hba->as);

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

                        MIN(prdt_tbl_entry_size(&tbl[VAR_7]) - off_pos,

                            VAR_3));



        for (VAR_5 = VAR_7 + 1; VAR_5 < prdtl && VAR_1->size < VAR_3; VAR_5++) {

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

                            MIN(prdt_tbl_entry_size(&tbl[VAR_5]),

                                VAR_3 - VAR_1->size));

            if (VAR_1->size > INT32_MAX) {

                error_report("AHCI Physical Region Descriptor Table describes "

                             "more than 2 GiB.");

                qemu_sglist_destroy(VAR_1);

                VAR_6 = -1;

                goto out;

            }

        }

    }



out:

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

                     DMA_DIRECTION_TO_DEVICE, prdt_len);

    return VAR_6;

}

static int FUNC_0(AHCIDevice *VAR_0, QEMUSGList *VAR_1,
AHCICmdHdr *VAR_2, int64_t VAR_3, int32_t VAR_4)
{ uint16_t opts = le16_to_cpu(VAR_2->opts); uint16_t prdtl = le16_to_cpu(VAR_2->prdtl); uint64_t cfis_addr = le64_to_cpu(VAR_2->tbl_addr); uint64_t prdt_addr = cfis_addr + 0x80; dma_addr_t prdt_len = (prdtl * sizeof(AHCI_SG)); dma_addr_t real_prdt_len = prdt_len; uint8_t *prdt; int VAR_5; int VAR_6 = 0; uint64_t sum = 0; int VAR_7 = -1; int64_t off_pos = -1; int VAR_8; IDEBus *bus = &VAR_0->port; BusState *qbus = BUS(bus); if (!prdtl) { 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_6 = -1; goto out; } if (prdtl > 0) { AHCI_SG *tbl = (AHCI_SG *)prdt; sum = 0; for (VAR_5 = 0; VAR_5 < prdtl; VAR_5++) { VAR_8 = prdt_tbl_entry_size(&tbl[VAR_5]); if (VAR_4 < (sum + VAR_8)) { VAR_7 = VAR_5; off_pos = VAR_4 - sum; break; } sum += VAR_8; } if ((VAR_7 == -1) || (off_pos < 0) || (off_pos > VAR_8)) { DPRINTF(VAR_0->port_no, "%s: Incorrect VAR_4! "
"VAR_7: %d, off_pos: %"PRId64"\n",
__func__, VAR_7, off_pos); VAR_6 = -1; goto out; } qemu_sglist_init(VAR_1, qbus->parent, (prdtl - VAR_7),
VAR_0->hba->as); qemu_sglist_add(VAR_1, le64_to_cpu(tbl[VAR_7].addr) + off_pos,
MIN(prdt_tbl_entry_size(&tbl[VAR_7]) - off_pos,
VAR_3)); for (VAR_5 = VAR_7 + 1; VAR_5 < prdtl && VAR_1->size < VAR_3; VAR_5++) { qemu_sglist_add(VAR_1, le64_to_cpu(tbl[VAR_5].addr),
MIN(prdt_tbl_entry_size(&tbl[VAR_5]),
VAR_3 - VAR_1->size)); if (VAR_1->size > INT32_MAX) { error_report("AHCI Physical Region Descriptor Table describes "
"more than 2 GiB."); qemu_sglist_destroy(VAR_1); VAR_6 = -1; goto out; } } } out:
dma_memory_unmap(VAR_0->hba->as, prdt, prdt_len,
DMA_DIRECTION_TO_DEVICE, prdt_len); return VAR_6; }