The floppy disk controller was incorrectly setting the FD_SR0_SEEK (Seek End) status bit during automatic track crossing in multi-track read/write operations. This caused legacy operating systems like Minix 2 to interpret successful read operations as errors, resulting in "Unrecoverable disk error" messages for blocks that crossed track boundaries.
When executing multi-sector READ/WRITE commands with the MT (multi-track) flag set, the FDC would correctly advance to the next track when needed to continue the transfer. However, it was incorrectly setting the SE (Seek End) bit in Status Register 0 (ST0) during this automatic track advancement. According to the Intel 82078 datasheet and related documentation, the SE bit (bit 5, value 0x20) in ST0 should only be set: 1. After explicit SEEK or RECALIBRATE commands 2. After READ/WRITE commands that perform an "implied seek" (when the command specifies a different cylinder/head/sector than the current position and EIS flag is not set) The SE bit should NOT be set during automatic track crossing that occurs as part of an ongoing multi-track data transfer. This automatic track advancement is part of the normal multi-track operation, not a seek. This bug prevented Minix 2 and potentially other legacy operating systems from booting. The OS floppy driver would detect the unexpected SE bit and interpret it as a read error, even though the data was transferred successfully. This particularly affected 1024-byte filesystem blocks that spanned track boundaries. Modified fdctrl_seek_to_next_sect() to remove the line that set FD_SR0_SEEK when advancing to the next track during multi-track operations. The function now: - In multi-track mode: advances tracks/heads as needed WITHOUT setting the SE bit - In non-multi-track mode: stops at end of track without seeking (also without setting SE bit, as no seek occurs) The SE bit is still correctly set by explicit SEEK and RECALIBRATE commands elsewhere in the code. Fixes: c5139bd9 (fdc: fix FD_SR0_SEEK for non-DMA transfers and multi sectors transfers) Signed-off-by: Pedro J. Ruiz <[email protected]> --- hw/block/fdc.c | 9 ++++++--- tests/qtest/fdc-test.c | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 4585640af9..21713c9c41 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -1403,14 +1403,17 @@ static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv) } else { new_head = 0; new_track++; - fdctrl->status0 |= FD_SR0_SEEK; + /* Don't set FD_SR0_SEEK for implicit track crossing during + * multi-track transfers. SEEK bit must only be set for + * explicit SEEK commands, not automatic track advancement. + */ if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) { ret = 0; } } } else { - fdctrl->status0 |= FD_SR0_SEEK; - new_track++; + /* Not in multi-track mode: stop at end of track and don't seek. */ + FLOPPY_DPRINTF("end of track, stopping transfer\n"); ret = 0; } if (ret == 1) { diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c index 1b37a8a4d2..9edfbb5a40 100644 --- a/tests/qtest/fdc-test.c +++ b/tests/qtest/fdc-test.c @@ -519,7 +519,7 @@ static void test_read_no_dma_19(void) outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08); send_seek(0); - ret = send_read_no_dma_command(19, 0x20); + ret = send_read_no_dma_command(19, 0x00); g_assert(ret == 0); } -- 2.50.1 (Apple Git-155)
