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

                                int32_t offset)

{

    AHCICmdHdr *cmd = ad->cur_cmd;

    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++) {

            /* flags_size is zero-based */

            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,

                        prdt_tbl_entry_size(&tbl[off_idx]) - off_pos);



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

            /* flags_size is zero-based */

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

                            prdt_tbl_entry_size(&tbl[i]));

            if (sglist->size > INT32_MAX) {

                error_report("AHCI Physical Region Descriptor Table describes "

                             "more than 2 GiB.\n");

                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,

                                int32_t offset)

{

    AHCICmdHdr *cmd = ad->cur_cmd;

    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,

                        prdt_tbl_entry_size(&tbl[off_idx]) - off_pos);



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

            

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

                            prdt_tbl_entry_size(&tbl[i]));

            if (sglist->size > INT32_MAX) {

                error_report("AHCI Physical Region Descriptor Table describes "

                             "more than 2 GiB.\n");

                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;

}

                                int32_t offset)             if (offset <= (sum + tbl_entry_size)) {                         prdt_tbl_entry_size(&tbl[off_idx]) - off_pos);         for (i = off_idx + 1; i < prdtl; i++) {                             prdt_tbl_entry_size(&tbl[i]));
static int FUNC_0(AHCIDevice *VAR_0, QEMUSGList *VAR_1,

                                int32_t VAR_2)

{

    AHCICmdHdr *cmd = VAR_0->cur_cmd;

    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 VAR_3;

    int VAR_4 = 0;

    uint64_t sum = 0;

    int VAR_5 = -1;

    int64_t off_pos = -1;

    int VAR_6;

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

        goto out;

    }



    

    if (prdtl > 0) {

        AHCI_SG *tbl = (AHCI_SG *)prdt;

        sum = 0;

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

            

            VAR_6 = prdt_tbl_entry_size(&tbl[VAR_3]);

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

                VAR_5 = VAR_3;

                off_pos = VAR_2 - sum;

                break;

            }

            sum += VAR_6;

        }

        if ((VAR_5 == -1) || (off_pos < 0) || (off_pos > VAR_6)) {

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

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

                            __func__, VAR_5, off_pos);

            VAR_4 = -1;

            goto out;

        }



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

                         VAR_0->hba->as);

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

                        prdt_tbl_entry_size(&tbl[VAR_5]) - off_pos);



        for (VAR_3 = VAR_5 + 1; VAR_3 < prdtl; VAR_3++) {

            

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

                            prdt_tbl_entry_size(&tbl[VAR_3]));

            if (VAR_1->size > INT32_MAX) {

                error_report("AHCI Physical Region Descriptor Table describes "

                             "more than 2 GiB.\n");

                qemu_sglist_destroy(VAR_1);

                VAR_4 = -1;

                goto out;

            }

        }

    }



out:

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

                     DMA_DIRECTION_TO_DEVICE, prdt_len);

    return VAR_4;

}

static int FUNC_0(AHCIDevice *VAR_0, QEMUSGList *VAR_1,
int32_t VAR_2)
{ AHCICmdHdr *cmd = VAR_0->cur_cmd; 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 VAR_3; int VAR_4 = 0; uint64_t sum = 0; int VAR_5 = -1; int64_t off_pos = -1; int VAR_6; 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_4 = -1; goto out; } if (prdtl > 0) { AHCI_SG *tbl = (AHCI_SG *)prdt; sum = 0; for (VAR_3 = 0; VAR_3 < prdtl; VAR_3++) { VAR_6 = prdt_tbl_entry_size(&tbl[VAR_3]); if (VAR_2 <= (sum + VAR_6)) { VAR_5 = VAR_3; off_pos = VAR_2 - sum; break; } sum += VAR_6; } if ((VAR_5 == -1) || (off_pos < 0) || (off_pos > VAR_6)) { DPRINTF(VAR_0->port_no, "%s: Incorrect VAR_2! "
"VAR_5: %d, off_pos: %"PRId64"\n",
__func__, VAR_5, off_pos); VAR_4 = -1; goto out; } qemu_sglist_init(VAR_1, qbus->parent, (prdtl - VAR_5),
VAR_0->hba->as); qemu_sglist_add(VAR_1, le64_to_cpu(tbl[VAR_5].addr) + off_pos,
prdt_tbl_entry_size(&tbl[VAR_5]) - off_pos); for (VAR_3 = VAR_5 + 1; VAR_3 < prdtl; VAR_3++) { qemu_sglist_add(VAR_1, le64_to_cpu(tbl[VAR_3].addr),
prdt_tbl_entry_size(&tbl[VAR_3])); if (VAR_1->size > INT32_MAX) { error_report("AHCI Physical Region Descriptor Table describes "
"more than 2 GiB.\n"); qemu_sglist_destroy(VAR_1); VAR_4 = -1; goto out; } } } out:
dma_memory_unmap(VAR_0->hba->as, prdt, prdt_len,
DMA_DIRECTION_TO_DEVICE, prdt_len); return VAR_4; }