}
/**
- * Return the number of bytes successfully prepared.
- * -1 on error.
+ * Prepare an sglist based on available PRDs.
+ * @limit: How many bytes to prepare total.
+ *
+ * Returns the number of bytes prepared, -1 on error.
+ * IDEState.io_buffer_size will contain the number of bytes described
+ * by the PRDs, whether or not we added them to the sglist.
*/
-static int32_t bmdma_prepare_buf(IDEDMA *dma, int is_write)
+static int32_t bmdma_prepare_buf(IDEDMA *dma, int32_t limit)
{
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
IDEState *s = bmdma_active_if(bm);
/* end of table (with a fail safe of one page) */
if (bm->cur_prd_last ||
(bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) {
- return s->io_buffer_size;
+ return s->sg.size;
}
pci_dma_read(pci_dev, bm->cur_addr, &prd, 8);
bm->cur_addr += 8;
}
l = bm->cur_prd_len;
if (l > 0) {
- qemu_sglist_add(&s->sg, bm->cur_prd_addr, l);
-
- /* Note: We limit the max transfer to be 2GiB.
- * This should accommodate the largest ATA transaction
- * for LBA48 (65,536 sectors) and 32K sector sizes. */
- if (s->sg.size > INT32_MAX) {
- error_report("IDE: sglist describes more than 2GiB.");
- break;
+ uint64_t sg_len;
+
+ /* Don't add extra bytes to the SGList; consume any remaining
+ * PRDs from the guest, but ignore them. */
+ sg_len = MIN(limit - s->sg.size, bm->cur_prd_len);
+ if (sg_len) {
+ qemu_sglist_add(&s->sg, bm->cur_prd_addr, sg_len);
}
+
bm->cur_prd_addr += l;
bm->cur_prd_len -= l;
s->io_buffer_size += l;
/* Ignore writes to SSBM if it keeps the old value */
if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
if (!(val & BM_CMD_START)) {
+ /* First invoke the callbacks of all buffered requests
+ * and flag those requests as orphaned. Ideally there
+ * are no unbuffered (Scatter Gather DMA Requests or
+ * write requests) pending and we can avoid to drain. */
+ IDEBufferedRequest *req;
+ IDEState *s = idebus_active_if(bm->bus);
+ QLIST_FOREACH(req, &s->buffered_requests, list) {
+ if (!req->orphaned) {
+#ifdef DEBUG_IDE
+ printf("%s: invoking cb %p of buffered request %p with"
+ " -ECANCELED\n", __func__, req->original_cb, req);
+#endif
+ req->original_cb(req->original_opaque, -ECANCELED);
+ }
+ req->orphaned = true;
+ }
/*
* We can't cancel Scatter Gather DMA in the middle of the
* operation or a partial (not full) DMA transfer would reach
* aio operation with preadv/pwritev.
*/
if (bm->bus->dma->aiocb) {
+#ifdef DEBUG_IDE
+ printf("%s: draining all remaining requests", __func__);
+#endif
blk_drain_all();
assert(bm->bus->dma->aiocb == NULL);
}