| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Driver for SWIM (Sander Woz Integrated Machine) floppy controller |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 7 | 8 | * based on SWIM3 driver (c) Paul Mackerras, 1996 |
|---|
| 8 | 9 | * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath. |
|---|
| 9 | 10 | * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or |
|---|
| 11 | | - * modify it under the terms of the GNU General Public License |
|---|
| 12 | | - * as published by the Free Software Foundation; either version |
|---|
| 13 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 14 | | - * |
|---|
| 15 | 11 | * 2004-08-21 (lv) - Initial implementation |
|---|
| 16 | 12 | * 2008-10-30 (lv) - Port to 2.6 |
|---|
| 17 | 13 | */ |
|---|
| .. | .. |
|---|
| 19 | 15 | #include <linux/module.h> |
|---|
| 20 | 16 | #include <linux/fd.h> |
|---|
| 21 | 17 | #include <linux/slab.h> |
|---|
| 22 | | -#include <linux/blkdev.h> |
|---|
| 18 | +#include <linux/blk-mq.h> |
|---|
| 23 | 19 | #include <linux/mutex.h> |
|---|
| 24 | 20 | #include <linux/hdreg.h> |
|---|
| 25 | 21 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 190 | 186 | int ref_count; |
|---|
| 191 | 187 | |
|---|
| 192 | 188 | struct gendisk *disk; |
|---|
| 189 | + struct blk_mq_tag_set tag_set; |
|---|
| 193 | 190 | |
|---|
| 194 | 191 | /* parent controller */ |
|---|
| 195 | 192 | |
|---|
| .. | .. |
|---|
| 211 | 208 | struct swim_priv { |
|---|
| 212 | 209 | struct swim __iomem *base; |
|---|
| 213 | 210 | spinlock_t lock; |
|---|
| 214 | | - int fdc_queue; |
|---|
| 215 | 211 | int floppy_count; |
|---|
| 216 | 212 | struct floppy_state unit[FD_MAX_UNIT]; |
|---|
| 217 | 213 | }; |
|---|
| .. | .. |
|---|
| 331 | 327 | swim_select(base, RELAX); |
|---|
| 332 | 328 | if (swim_readbit(base, MOTOR_ON)) |
|---|
| 333 | 329 | break; |
|---|
| 334 | | - current->state = TASK_INTERRUPTIBLE; |
|---|
| 330 | + set_current_state(TASK_INTERRUPTIBLE); |
|---|
| 335 | 331 | schedule_timeout(1); |
|---|
| 336 | 332 | } |
|---|
| 337 | 333 | } else if (action == OFF) { |
|---|
| .. | .. |
|---|
| 350 | 346 | swim_select(base, RELAX); |
|---|
| 351 | 347 | if (!swim_readbit(base, DISK_IN)) |
|---|
| 352 | 348 | break; |
|---|
| 353 | | - current->state = TASK_INTERRUPTIBLE; |
|---|
| 349 | + set_current_state(TASK_INTERRUPTIBLE); |
|---|
| 354 | 350 | schedule_timeout(1); |
|---|
| 355 | 351 | } |
|---|
| 356 | 352 | swim_select(base, RELAX); |
|---|
| .. | .. |
|---|
| 374 | 370 | |
|---|
| 375 | 371 | for (wait = 0; wait < HZ; wait++) { |
|---|
| 376 | 372 | |
|---|
| 377 | | - current->state = TASK_INTERRUPTIBLE; |
|---|
| 373 | + set_current_state(TASK_INTERRUPTIBLE); |
|---|
| 378 | 374 | schedule_timeout(1); |
|---|
| 379 | 375 | |
|---|
| 380 | 376 | swim_select(base, RELAX); |
|---|
| .. | .. |
|---|
| 525 | 521 | return 0; |
|---|
| 526 | 522 | } |
|---|
| 527 | 523 | |
|---|
| 528 | | -static struct request *swim_next_request(struct swim_priv *swd) |
|---|
| 524 | +static blk_status_t swim_queue_rq(struct blk_mq_hw_ctx *hctx, |
|---|
| 525 | + const struct blk_mq_queue_data *bd) |
|---|
| 529 | 526 | { |
|---|
| 530 | | - struct request_queue *q; |
|---|
| 531 | | - struct request *rq; |
|---|
| 532 | | - int old_pos = swd->fdc_queue; |
|---|
| 527 | + struct floppy_state *fs = hctx->queue->queuedata; |
|---|
| 528 | + struct swim_priv *swd = fs->swd; |
|---|
| 529 | + struct request *req = bd->rq; |
|---|
| 530 | + blk_status_t err; |
|---|
| 531 | + |
|---|
| 532 | + if (!spin_trylock_irq(&swd->lock)) |
|---|
| 533 | + return BLK_STS_DEV_RESOURCE; |
|---|
| 534 | + |
|---|
| 535 | + blk_mq_start_request(req); |
|---|
| 536 | + |
|---|
| 537 | + if (!fs->disk_in || rq_data_dir(req) == WRITE) { |
|---|
| 538 | + err = BLK_STS_IOERR; |
|---|
| 539 | + goto out; |
|---|
| 540 | + } |
|---|
| 533 | 541 | |
|---|
| 534 | 542 | do { |
|---|
| 535 | | - q = swd->unit[swd->fdc_queue].disk->queue; |
|---|
| 536 | | - if (++swd->fdc_queue == swd->floppy_count) |
|---|
| 537 | | - swd->fdc_queue = 0; |
|---|
| 538 | | - if (q) { |
|---|
| 539 | | - rq = blk_fetch_request(q); |
|---|
| 540 | | - if (rq) |
|---|
| 541 | | - return rq; |
|---|
| 542 | | - } |
|---|
| 543 | | - } while (swd->fdc_queue != old_pos); |
|---|
| 543 | + err = floppy_read_sectors(fs, blk_rq_pos(req), |
|---|
| 544 | + blk_rq_cur_sectors(req), |
|---|
| 545 | + bio_data(req->bio)); |
|---|
| 546 | + } while (blk_update_request(req, err, blk_rq_cur_bytes(req))); |
|---|
| 547 | + __blk_mq_end_request(req, err); |
|---|
| 544 | 548 | |
|---|
| 545 | | - return NULL; |
|---|
| 546 | | -} |
|---|
| 549 | + err = BLK_STS_OK; |
|---|
| 550 | +out: |
|---|
| 551 | + spin_unlock_irq(&swd->lock); |
|---|
| 552 | + return err; |
|---|
| 547 | 553 | |
|---|
| 548 | | -static void do_fd_request(struct request_queue *q) |
|---|
| 549 | | -{ |
|---|
| 550 | | - struct swim_priv *swd = q->queuedata; |
|---|
| 551 | | - struct request *req; |
|---|
| 552 | | - struct floppy_state *fs; |
|---|
| 553 | | - |
|---|
| 554 | | - req = swim_next_request(swd); |
|---|
| 555 | | - while (req) { |
|---|
| 556 | | - blk_status_t err = BLK_STS_IOERR; |
|---|
| 557 | | - |
|---|
| 558 | | - fs = req->rq_disk->private_data; |
|---|
| 559 | | - if (blk_rq_pos(req) >= fs->total_secs) |
|---|
| 560 | | - goto done; |
|---|
| 561 | | - if (!fs->disk_in) |
|---|
| 562 | | - goto done; |
|---|
| 563 | | - if (rq_data_dir(req) == WRITE && fs->write_protected) |
|---|
| 564 | | - goto done; |
|---|
| 565 | | - |
|---|
| 566 | | - switch (rq_data_dir(req)) { |
|---|
| 567 | | - case WRITE: |
|---|
| 568 | | - /* NOT IMPLEMENTED */ |
|---|
| 569 | | - break; |
|---|
| 570 | | - case READ: |
|---|
| 571 | | - err = floppy_read_sectors(fs, blk_rq_pos(req), |
|---|
| 572 | | - blk_rq_cur_sectors(req), |
|---|
| 573 | | - bio_data(req->bio)); |
|---|
| 574 | | - break; |
|---|
| 575 | | - } |
|---|
| 576 | | - done: |
|---|
| 577 | | - if (!__blk_end_request_cur(req, err)) |
|---|
| 578 | | - req = swim_next_request(swd); |
|---|
| 579 | | - } |
|---|
| 580 | 554 | } |
|---|
| 581 | 555 | |
|---|
| 582 | 556 | static struct floppy_struct floppy_type[4] = { |
|---|
| .. | .. |
|---|
| 664 | 638 | return 0; |
|---|
| 665 | 639 | |
|---|
| 666 | 640 | if (mode & (FMODE_READ|FMODE_WRITE)) { |
|---|
| 667 | | - check_disk_change(bdev); |
|---|
| 641 | + if (bdev_check_media_change(bdev) && fs->disk_in) |
|---|
| 642 | + fs->ejected = 0; |
|---|
| 668 | 643 | if ((mode & FMODE_WRITE) && fs->write_protected) { |
|---|
| 669 | 644 | err = -EROFS; |
|---|
| 670 | 645 | goto out; |
|---|
| .. | .. |
|---|
| 761 | 736 | return fs->ejected ? DISK_EVENT_MEDIA_CHANGE : 0; |
|---|
| 762 | 737 | } |
|---|
| 763 | 738 | |
|---|
| 764 | | -static int floppy_revalidate(struct gendisk *disk) |
|---|
| 765 | | -{ |
|---|
| 766 | | - struct floppy_state *fs = disk->private_data; |
|---|
| 767 | | - struct swim __iomem *base = fs->swd->base; |
|---|
| 768 | | - |
|---|
| 769 | | - swim_drive(base, fs->location); |
|---|
| 770 | | - |
|---|
| 771 | | - if (fs->ejected) |
|---|
| 772 | | - setup_medium(fs); |
|---|
| 773 | | - |
|---|
| 774 | | - if (!fs->disk_in) |
|---|
| 775 | | - swim_motor(base, OFF); |
|---|
| 776 | | - else |
|---|
| 777 | | - fs->ejected = 0; |
|---|
| 778 | | - |
|---|
| 779 | | - return !fs->disk_in; |
|---|
| 780 | | -} |
|---|
| 781 | | - |
|---|
| 782 | 739 | static const struct block_device_operations floppy_fops = { |
|---|
| 783 | 740 | .owner = THIS_MODULE, |
|---|
| 784 | 741 | .open = floppy_unlocked_open, |
|---|
| .. | .. |
|---|
| 786 | 743 | .ioctl = floppy_ioctl, |
|---|
| 787 | 744 | .getgeo = floppy_getgeo, |
|---|
| 788 | 745 | .check_events = floppy_check_events, |
|---|
| 789 | | - .revalidate_disk = floppy_revalidate, |
|---|
| 790 | 746 | }; |
|---|
| 791 | 747 | |
|---|
| 792 | 748 | static struct kobject *floppy_find(dev_t dev, int *part, void *data) |
|---|
| .. | .. |
|---|
| 823 | 779 | return 0; |
|---|
| 824 | 780 | } |
|---|
| 825 | 781 | |
|---|
| 782 | +static const struct blk_mq_ops swim_mq_ops = { |
|---|
| 783 | + .queue_rq = swim_queue_rq, |
|---|
| 784 | +}; |
|---|
| 785 | + |
|---|
| 826 | 786 | static int swim_floppy_init(struct swim_priv *swd) |
|---|
| 827 | 787 | { |
|---|
| 828 | 788 | int err; |
|---|
| .. | .. |
|---|
| 852 | 812 | spin_lock_init(&swd->lock); |
|---|
| 853 | 813 | |
|---|
| 854 | 814 | for (drive = 0; drive < swd->floppy_count; drive++) { |
|---|
| 815 | + struct request_queue *q; |
|---|
| 816 | + |
|---|
| 855 | 817 | swd->unit[drive].disk = alloc_disk(1); |
|---|
| 856 | 818 | if (swd->unit[drive].disk == NULL) { |
|---|
| 857 | 819 | err = -ENOMEM; |
|---|
| 858 | 820 | goto exit_put_disks; |
|---|
| 859 | 821 | } |
|---|
| 860 | | - swd->unit[drive].disk->queue = blk_init_queue(do_fd_request, |
|---|
| 861 | | - &swd->lock); |
|---|
| 862 | | - if (!swd->unit[drive].disk->queue) { |
|---|
| 863 | | - err = -ENOMEM; |
|---|
| 822 | + |
|---|
| 823 | + q = blk_mq_init_sq_queue(&swd->unit[drive].tag_set, &swim_mq_ops, |
|---|
| 824 | + 2, BLK_MQ_F_SHOULD_MERGE); |
|---|
| 825 | + if (IS_ERR(q)) { |
|---|
| 826 | + err = PTR_ERR(q); |
|---|
| 864 | 827 | goto exit_put_disks; |
|---|
| 865 | 828 | } |
|---|
| 829 | + |
|---|
| 830 | + swd->unit[drive].disk->queue = q; |
|---|
| 866 | 831 | blk_queue_bounce_limit(swd->unit[drive].disk->queue, |
|---|
| 867 | 832 | BLK_BOUNCE_HIGH); |
|---|
| 868 | | - swd->unit[drive].disk->queue->queuedata = swd; |
|---|
| 833 | + swd->unit[drive].disk->queue->queuedata = &swd->unit[drive]; |
|---|
| 869 | 834 | swd->unit[drive].swd = swd; |
|---|
| 870 | 835 | } |
|---|
| 871 | 836 | |
|---|
| .. | .. |
|---|
| 875 | 840 | swd->unit[drive].disk->first_minor = drive; |
|---|
| 876 | 841 | sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive); |
|---|
| 877 | 842 | swd->unit[drive].disk->fops = &floppy_fops; |
|---|
| 843 | + swd->unit[drive].disk->events = DISK_EVENT_MEDIA_CHANGE; |
|---|
| 878 | 844 | swd->unit[drive].disk->private_data = &swd->unit[drive]; |
|---|
| 879 | 845 | set_capacity(swd->unit[drive].disk, 2880); |
|---|
| 880 | 846 | add_disk(swd->unit[drive].disk); |
|---|
| .. | .. |
|---|
| 895 | 861 | blk_cleanup_queue(disk->queue); |
|---|
| 896 | 862 | disk->queue = NULL; |
|---|
| 897 | 863 | } |
|---|
| 864 | + blk_mq_free_tag_set(&swd->unit[drive].tag_set); |
|---|
| 898 | 865 | put_disk(disk); |
|---|
| 899 | 866 | } |
|---|
| 900 | 867 | } while (drive--); |
|---|
| .. | .. |
|---|
| 970 | 937 | for (drive = 0; drive < swd->floppy_count; drive++) { |
|---|
| 971 | 938 | del_gendisk(swd->unit[drive].disk); |
|---|
| 972 | 939 | blk_cleanup_queue(swd->unit[drive].disk->queue); |
|---|
| 940 | + blk_mq_free_tag_set(&swd->unit[drive].tag_set); |
|---|
| 973 | 941 | put_disk(swd->unit[drive].disk); |
|---|
| 974 | 942 | } |
|---|
| 975 | 943 | |
|---|