On Sun, Sep 06, 2015 at 11:24:10AM +0200, Peter Lieven wrote: > > Taking a step back, what are the semantics of writing !(val & > > BM_CMD_START)? Is the device guaranteed to cancel/complete requests > > during the register write? > > I have to check that. John, do you have an idea? > > Stefan, or do you have a better approach for getting rid of the bdrv_drain_all > in this piece of code?
What's needed is an asynchronous approach that honors the semantics of the Start/Stop bit. >From "Programming Interface for Bus Master IDE Controller", Revision 1.0: "Start/Stop Bus Master: Writing a '1' to this bit enables bus master operation of the controller. Bus master operation begins when this bit is detected changing from a zero to a one. The controller will transfer data between the IDE device and memory only when this bit is set. Master operation can be halted by writing a '0' to this bit. All state information is lost when a '0' is written; Master mode operation cannot be stopped and then resumed. If this bit is reset while bus master operation is still active (i.e., the Bus Master IDE Active bit of the Bus Master IDE Status register for that IDE channel is set) and the drive has not yet finished its data transfer (The Interupt bit in the Bus Master IDE Status register for that IDE channel is not set), the bus master command is said to be aborted and data transfered from the drive may be discarded before being written to system memory. This bit is intended to be reset after the data transfer is completed, as indicated by either the Bus Master IDE Active bit or the Interrupt bit of the Bus Master IDE Status register for that IDE channel being set, or both." bdrv_aio_cancel() can be used to nudge the request to cancel. The completion function is still called at some later point - and it could take an arbitrary amount of time before the request finishes. >From the IDE emulation perspective, there are two requirements: 1. After the Start bit has been cleared, no IDE state changes should occur due to the pending request. No interrupts should be raised and no registers should change when the request completes (success/error/cancelled). Also, the guest should be able to set the bit again and submit a new request. 2. No guest memory should be touched by a running request after the bit is cleared. QEMU needs to go through bounce buffers in all cases instead of doing zero copy (mapping the PRDT). Using bounce buffers should be doable but you need to check the IDE code paths (PIO, DMA, and ATAPI) reachable from hw/ide/pci.c. There's also a denial-of-service scenario where the guest repeatedly submits an I/O requests and then clears the Start/Stop bit. That would cause QEMU to build up many pending I/O requests and bounce buffers. That needs to be handled, for example by punishing the guest by failing news I/O if there are more than 16 cancelled requests pending. I'm interested in other ideas, but I think the solution space for synchronous approaches that implement the semantics correctly is small. I can think of a few other approaches that are easier to implement, perform better, etc but they aren't correct. Stefan