--- /dev/null
+From d28e4dff085c5a87025c9a0a85fb798bd8e9ca17 Mon Sep 17 00:00:00 2001
+From: Michael Schmitz <schmitzmic@gmail.com>
+Date: Sun, 24 Oct 2021 13:20:13 +1300
+Subject: block: ataflop: more blk-mq refactoring fixes
+
+From: Michael Schmitz <schmitzmic@gmail.com>
+
+commit d28e4dff085c5a87025c9a0a85fb798bd8e9ca17 upstream.
+
+As it turns out, my earlier patch in commit 86d46fdaa12a (block:
+ataflop: fix breakage introduced at blk-mq refactoring) was
+incomplete. This patch fixes any remaining issues found during
+more testing and code review.
+
+Requests exceeding 4 k are handled in 4k segments but
+__blk_mq_end_request() is never called on these (still
+sectors outstanding on the request). With redo_fd_request()
+removed, there is no provision to kick off processing of the
+next segment, causing requests exceeding 4k to hang. (By
+setting /sys/block/fd0/queue/max_sectors_k <= 4 as workaround,
+this behaviour can be avoided).
+
+Instead of reintroducing redo_fd_request(), requeue the remainder
+of the request by calling blk_mq_requeue_request() on incomplete
+requests (i.e. when blk_update_request() still returns true), and
+rely on the block layer to queue the residual as new request.
+
+Both error handling and formatting needs to release the
+ST-DMA lock, so call finish_fdc() on these (this was previously
+handled by redo_fd_request()). finish_fdc() may be called
+legitimately without the ST-DMA lock held - make sure we only
+release the lock if we actually held it. In a similar way,
+early exit due to errors in ataflop_queue_rq() must release
+the lock.
+
+After minor errors, fd_error sets up to recalibrate the drive
+but never re-runs the current operation (another task handled by
+redo_fd_request() before). Call do_fd_action() to get the next
+steps (seek, retry read/write) underway.
+
+Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
+Fixes: 6ec3938cff95f (ataflop: convert to blk-mq)
+CC: linux-block@vger.kernel.org
+Link: https://lore.kernel.org/r/20211024002013.9332-1-schmitzmic@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+[MSch: v5.10 backport merge conflict fix]
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/block/ataflop.c | 42 +++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 37 insertions(+), 5 deletions(-)
+
+--- a/drivers/block/ataflop.c
++++ b/drivers/block/ataflop.c
+@@ -456,10 +456,20 @@ static DEFINE_TIMER(fd_timer, check_chan
+
+ static void fd_end_request_cur(blk_status_t err)
+ {
++ DPRINT(("fd_end_request_cur(), bytes %d of %d\n",
++ blk_rq_cur_bytes(fd_request),
++ blk_rq_bytes(fd_request)));
++
+ if (!blk_update_request(fd_request, err,
+ blk_rq_cur_bytes(fd_request))) {
++ DPRINT(("calling __blk_mq_end_request()\n"));
+ __blk_mq_end_request(fd_request, err);
+ fd_request = NULL;
++ } else {
++ /* requeue rest of request */
++ DPRINT(("calling blk_mq_requeue_request()\n"));
++ blk_mq_requeue_request(fd_request, true);
++ fd_request = NULL;
+ }
+ }
+
+@@ -697,12 +707,21 @@ static void fd_error( void )
+ if (fd_request->error_count >= MAX_ERRORS) {
+ printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
+ fd_end_request_cur(BLK_STS_IOERR);
++ finish_fdc();
++ return;
+ }
+ else if (fd_request->error_count == RECALIBRATE_ERRORS) {
+ printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );
+ if (SelectedDrive != -1)
+ SUD.track = -1;
+ }
++ /* need to re-run request to recalibrate */
++ atari_disable_irq( IRQ_MFP_FDC );
++
++ setup_req_params( SelectedDrive );
++ do_fd_action( SelectedDrive );
++
++ atari_enable_irq( IRQ_MFP_FDC );
+ }
+
+
+@@ -737,6 +756,7 @@ static int do_format(int drive, int type
+ if (type) {
+ if (--type >= NUM_DISK_MINORS ||
+ minor2disktype[type].drive_types > DriveType) {
++ finish_fdc();
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -745,6 +765,7 @@ static int do_format(int drive, int type
+ }
+
+ if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
++ finish_fdc();
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -785,6 +806,7 @@ static int do_format(int drive, int type
+
+ wait_for_completion(&format_wait);
+
++ finish_fdc();
+ ret = FormatError ? -EIO : 0;
+ out:
+ blk_mq_unquiesce_queue(q);
+@@ -819,6 +841,7 @@ static void do_fd_action( int drive )
+ else {
+ /* all sectors finished */
+ fd_end_request_cur(BLK_STS_OK);
++ finish_fdc();
+ return;
+ }
+ }
+@@ -1222,8 +1245,8 @@ static void fd_rwsec_done1(int status)
+ }
+ else {
+ /* all sectors finished */
+- finish_fdc();
+ fd_end_request_cur(BLK_STS_OK);
++ finish_fdc();
+ }
+ return;
+
+@@ -1345,7 +1368,7 @@ static void fd_times_out(struct timer_li
+
+ static void finish_fdc( void )
+ {
+- if (!NeedSeek) {
++ if (!NeedSeek || !stdma_is_locked_by(floppy_irq)) {
+ finish_fdc_done( 0 );
+ }
+ else {
+@@ -1380,7 +1403,8 @@ static void finish_fdc_done( int dummy )
+ start_motor_off_timer();
+
+ local_irq_save(flags);
+- stdma_release();
++ if (stdma_is_locked_by(floppy_irq))
++ stdma_release();
+ local_irq_restore(flags);
+
+ DPRINT(("finish_fdc() finished\n"));
+@@ -1477,7 +1501,9 @@ static blk_status_t ataflop_queue_rq(str
+ int drive = floppy - unit;
+ int type = floppy->type;
+
+- DPRINT(("Queue request: drive %d type %d last %d\n", drive, type, bd->last));
++ DPRINT(("Queue request: drive %d type %d sectors %d of %d last %d\n",
++ drive, type, blk_rq_cur_sectors(bd->rq),
++ blk_rq_sectors(bd->rq), bd->last));
+
+ spin_lock_irq(&ataflop_lock);
+ if (fd_request) {
+@@ -1499,6 +1525,7 @@ static blk_status_t ataflop_queue_rq(str
+ /* drive not connected */
+ printk(KERN_ERR "Unknown Device: fd%d\n", drive );
+ fd_end_request_cur(BLK_STS_IOERR);
++ stdma_release();
+ goto out;
+ }
+
+@@ -1515,11 +1542,13 @@ static blk_status_t ataflop_queue_rq(str
+ if (--type >= NUM_DISK_MINORS) {
+ printk(KERN_WARNING "fd%d: invalid disk format", drive );
+ fd_end_request_cur(BLK_STS_IOERR);
++ stdma_release();
+ goto out;
+ }
+ if (minor2disktype[type].drive_types > DriveType) {
+ printk(KERN_WARNING "fd%d: unsupported disk format", drive );
+ fd_end_request_cur(BLK_STS_IOERR);
++ stdma_release();
+ goto out;
+ }
+ type = minor2disktype[type].index;
+@@ -1620,6 +1649,7 @@ static int fd_locked_ioctl(struct block_
+ /* what if type > 0 here? Overwrite specified entry ? */
+ if (type) {
+ /* refuse to re-set a predefined type for now */
++ finish_fdc();
+ return -EINVAL;
+ }
+
+@@ -1687,8 +1717,10 @@ static int fd_locked_ioctl(struct block_
+
+ /* sanity check */
+ if (setprm.track != dtp->blocks/dtp->spt/2 ||
+- setprm.head != 2)
++ setprm.head != 2) {
++ finish_fdc();
+ return -EINVAL;
++ }
+
+ UDT = dtp;
+ set_capacity(floppy->disk, UDT->blocks);