Commit d28e4dff authored by Michael Schmitz's avatar Michael Schmitz Committed by Jens Axboe

block: ataflop: more blk-mq refactoring fixes

As it turns out, my earlier patch in commit 86d46fda (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: default avatarMichael Schmitz <schmitzmic@gmail.com>
Fixes: 6ec3938c (ataflop: convert to blk-mq)
CC: linux-block@vger.kernel.org
Link: https://lore.kernel.org/r/20211024002013.9332-1-schmitzmic@gmail.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 47e96246
...@@ -458,10 +458,20 @@ static DEFINE_TIMER(fd_timer, check_change); ...@@ -458,10 +458,20 @@ static DEFINE_TIMER(fd_timer, check_change);
static void fd_end_request_cur(blk_status_t err) 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, if (!blk_update_request(fd_request, err,
blk_rq_cur_bytes(fd_request))) { blk_rq_cur_bytes(fd_request))) {
DPRINT(("calling __blk_mq_end_request()\n"));
__blk_mq_end_request(fd_request, err); __blk_mq_end_request(fd_request, err);
fd_request = NULL; 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;
} }
} }
...@@ -699,12 +709,21 @@ static void fd_error( void ) ...@@ -699,12 +709,21 @@ static void fd_error( void )
if (fd_request->error_count >= MAX_ERRORS) { if (fd_request->error_count >= MAX_ERRORS) {
printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive ); printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
fd_end_request_cur(BLK_STS_IOERR); fd_end_request_cur(BLK_STS_IOERR);
finish_fdc();
return;
} }
else if (fd_request->error_count == RECALIBRATE_ERRORS) { else if (fd_request->error_count == RECALIBRATE_ERRORS) {
printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive ); printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );
if (SelectedDrive != -1) if (SelectedDrive != -1)
SUD.track = -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 );
} }
...@@ -731,8 +750,10 @@ static int do_format(int drive, int type, struct atari_format_descr *desc) ...@@ -731,8 +750,10 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
if (type) { if (type) {
type--; type--;
if (type >= NUM_DISK_MINORS || if (type >= NUM_DISK_MINORS ||
minor2disktype[type].drive_types > DriveType) minor2disktype[type].drive_types > DriveType) {
finish_fdc();
return -EINVAL; return -EINVAL;
}
} }
q = unit[drive].disk[type]->queue; q = unit[drive].disk[type]->queue;
...@@ -750,6 +771,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc) ...@@ -750,6 +771,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
} }
if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) { if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {
finish_fdc();
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
...@@ -790,6 +812,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc) ...@@ -790,6 +812,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
wait_for_completion(&format_wait); wait_for_completion(&format_wait);
finish_fdc();
ret = FormatError ? -EIO : 0; ret = FormatError ? -EIO : 0;
out: out:
blk_mq_unquiesce_queue(q); blk_mq_unquiesce_queue(q);
...@@ -824,6 +847,7 @@ static void do_fd_action( int drive ) ...@@ -824,6 +847,7 @@ static void do_fd_action( int drive )
else { else {
/* all sectors finished */ /* all sectors finished */
fd_end_request_cur(BLK_STS_OK); fd_end_request_cur(BLK_STS_OK);
finish_fdc();
return; return;
} }
} }
...@@ -1227,8 +1251,8 @@ static void fd_rwsec_done1(int status) ...@@ -1227,8 +1251,8 @@ static void fd_rwsec_done1(int status)
} }
else { else {
/* all sectors finished */ /* all sectors finished */
finish_fdc();
fd_end_request_cur(BLK_STS_OK); fd_end_request_cur(BLK_STS_OK);
finish_fdc();
} }
return; return;
...@@ -1350,7 +1374,7 @@ static void fd_times_out(struct timer_list *unused) ...@@ -1350,7 +1374,7 @@ static void fd_times_out(struct timer_list *unused)
static void finish_fdc( void ) static void finish_fdc( void )
{ {
if (!NeedSeek) { if (!NeedSeek || !stdma_is_locked_by(floppy_irq)) {
finish_fdc_done( 0 ); finish_fdc_done( 0 );
} }
else { else {
...@@ -1385,7 +1409,8 @@ static void finish_fdc_done( int dummy ) ...@@ -1385,7 +1409,8 @@ static void finish_fdc_done( int dummy )
start_motor_off_timer(); start_motor_off_timer();
local_irq_save(flags); local_irq_save(flags);
stdma_release(); if (stdma_is_locked_by(floppy_irq))
stdma_release();
local_irq_restore(flags); local_irq_restore(flags);
DPRINT(("finish_fdc() finished\n")); DPRINT(("finish_fdc() finished\n"));
...@@ -1482,7 +1507,9 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx, ...@@ -1482,7 +1507,9 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
int drive = floppy - unit; int drive = floppy - unit;
int type = floppy->type; 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); spin_lock_irq(&ataflop_lock);
if (fd_request) { if (fd_request) {
...@@ -1504,6 +1531,7 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx, ...@@ -1504,6 +1531,7 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
/* drive not connected */ /* drive not connected */
printk(KERN_ERR "Unknown Device: fd%d\n", drive ); printk(KERN_ERR "Unknown Device: fd%d\n", drive );
fd_end_request_cur(BLK_STS_IOERR); fd_end_request_cur(BLK_STS_IOERR);
stdma_release();
goto out; goto out;
} }
...@@ -1520,11 +1548,13 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx, ...@@ -1520,11 +1548,13 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
if (--type >= NUM_DISK_MINORS) { if (--type >= NUM_DISK_MINORS) {
printk(KERN_WARNING "fd%d: invalid disk format", drive ); printk(KERN_WARNING "fd%d: invalid disk format", drive );
fd_end_request_cur(BLK_STS_IOERR); fd_end_request_cur(BLK_STS_IOERR);
stdma_release();
goto out; goto out;
} }
if (minor2disktype[type].drive_types > DriveType) { if (minor2disktype[type].drive_types > DriveType) {
printk(KERN_WARNING "fd%d: unsupported disk format", drive ); printk(KERN_WARNING "fd%d: unsupported disk format", drive );
fd_end_request_cur(BLK_STS_IOERR); fd_end_request_cur(BLK_STS_IOERR);
stdma_release();
goto out; goto out;
} }
type = minor2disktype[type].index; type = minor2disktype[type].index;
...@@ -1625,6 +1655,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -1625,6 +1655,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
/* what if type > 0 here? Overwrite specified entry ? */ /* what if type > 0 here? Overwrite specified entry ? */
if (type) { if (type) {
/* refuse to re-set a predefined type for now */ /* refuse to re-set a predefined type for now */
finish_fdc();
return -EINVAL; return -EINVAL;
} }
...@@ -1692,8 +1723,10 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -1692,8 +1723,10 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
/* sanity check */ /* sanity check */
if (setprm.track != dtp->blocks/dtp->spt/2 || if (setprm.track != dtp->blocks/dtp->spt/2 ||
setprm.head != 2) setprm.head != 2) {
finish_fdc();
return -EINVAL; return -EINVAL;
}
UDT = dtp; UDT = dtp;
set_capacity(disk, UDT->blocks); set_capacity(disk, UDT->blocks);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment