block: ataflop: more blk-mq refactoring fixes
As it turns out, my earlier patch in commit86d46fdaa1
(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:6ec3938cff
(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>
This commit is contained in:
parent
47e9624616
commit
d28e4dff08
@ -458,10 +458,20 @@ static DEFINE_TIMER(fd_timer, check_change);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -699,12 +709,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 );
|
||||
}
|
||||
|
||||
|
||||
@ -731,8 +750,10 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
|
||||
if (type) {
|
||||
type--;
|
||||
if (type >= NUM_DISK_MINORS ||
|
||||
minor2disktype[type].drive_types > DriveType)
|
||||
minor2disktype[type].drive_types > DriveType) {
|
||||
finish_fdc();
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
q = unit[drive].disk[type]->queue;
|
||||
@ -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) {
|
||||
finish_fdc();
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -790,6 +812,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
|
||||
|
||||
wait_for_completion(&format_wait);
|
||||
|
||||
finish_fdc();
|
||||
ret = FormatError ? -EIO : 0;
|
||||
out:
|
||||
blk_mq_unquiesce_queue(q);
|
||||
@ -824,6 +847,7 @@ static void do_fd_action( int drive )
|
||||
else {
|
||||
/* all sectors finished */
|
||||
fd_end_request_cur(BLK_STS_OK);
|
||||
finish_fdc();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1227,8 +1251,8 @@ static void fd_rwsec_done1(int status)
|
||||
}
|
||||
else {
|
||||
/* all sectors finished */
|
||||
finish_fdc();
|
||||
fd_end_request_cur(BLK_STS_OK);
|
||||
finish_fdc();
|
||||
}
|
||||
return;
|
||||
|
||||
@ -1350,7 +1374,7 @@ static void fd_times_out(struct timer_list *unused)
|
||||
|
||||
static void finish_fdc( void )
|
||||
{
|
||||
if (!NeedSeek) {
|
||||
if (!NeedSeek || !stdma_is_locked_by(floppy_irq)) {
|
||||
finish_fdc_done( 0 );
|
||||
}
|
||||
else {
|
||||
@ -1385,7 +1409,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"));
|
||||
@ -1482,7 +1507,9 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
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) {
|
||||
@ -1504,6 +1531,7 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
/* drive not connected */
|
||||
printk(KERN_ERR "Unknown Device: fd%d\n", drive );
|
||||
fd_end_request_cur(BLK_STS_IOERR);
|
||||
stdma_release();
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1520,11 +1548,13 @@ static blk_status_t ataflop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
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;
|
||||
@ -1625,6 +1655,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
/* what if type > 0 here? Overwrite specified entry ? */
|
||||
if (type) {
|
||||
/* refuse to re-set a predefined type for now */
|
||||
finish_fdc();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1692,8 +1723,10 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
|
||||
/* sanity check */
|
||||
if (setprm.track != dtp->blocks/dtp->spt/2 ||
|
||||
setprm.head != 2)
|
||||
setprm.head != 2) {
|
||||
finish_fdc();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
UDT = dtp;
|
||||
set_capacity(disk, UDT->blocks);
|
||||
|
Loading…
Reference in New Issue
Block a user