Suppress use of CMD23 for multi-block SD transfers on SDHOST controller
The SDHOST controller is used for the SD slot on WiFi-capable Pi models prior to the Raspberry Pi 4, and for any SD card HATs on generation-4 Raspberry Pis.
With certain SD cards, certain patterns of reads and writes would occasionally cause a transfer (always a write transfer) to time out. This wasn't reproducible 100% of the time, and replaying only the failing write transfer - however many times - wouldn't trigger the failure. Changing the screen mode could also affect the reproducibility - meaning it was very timing sensitive.
Under observation with a logic analyser, it was clearer what was happening. The controller is gating the SDCLK signal so that it only transitions while activity is occurring on the other lines of the SD bus (this is a fairly common practice, performed for the sake of reducing power consumption but at the cost of breaking compatibility with IO cards). But in the problem cases, SDCLK is stopped before the transfer has completed. Specifically, it looks as though the card is stuck signalling "busy" on DAT0 - a condition intended to allow the card to hold off further activity from the host while it performs flash programming. But in the absence of any further SDCLK transitions, the card appears unable to ever signal it is no longer busy. Eventually the software timeout in SDIODriver triggers and it retries the operation, but as far as the card is concerned, it's seeing a new write operation start before the old one finishes, which isn't supposed to happen, and how it handles the situation is undefined. Data corruption under such circumstances is quite possible.
The workaround relies on the fact that the (e)MMC and SD standards support two different types of multi-block data transfer operations: open-ended (which is terminated by a CMD12) and pre-defined (which is preceded by a CMD23 to specify the number of blocks). (e)MMC cards (except the earliest ones that don't support multi-block transfers at all) support both CMD12 and CMD23. Early SD cards only support CMD12 - only once you reach UHS-I cards capable of SDR104 bus speeds does the standard specify that they must support CMD23. Nevertheless, you'd normally want to use CMD23 wherever possible so as to give the on-card controller the best chance to manage its flash programming strategy. But it stands to reason that the SDHOST controller must be snooping the argument to CMD23 in order to know when to gate SDCLK. And indeed, when we only use CMD12, the transfers always appear to run to completion.
For reference, the Linux driver also disables CMD23, although it only does so for write operations. I tried a similar strategy but still observed frozen transfer operations, so I'm using CMD12 for both reads and writes.
See also RiscOS/Sources/HWSupport/SD/SDIODriver!8 (merged) and RiscOS/Sources/FileSys/SDFS/SDFS!4 (merged)