| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Driver for the SWIM3 (Super Woz Integrated Machine 3) |
|---|
| 3 | 4 | * floppy controller found on Power Macintoshes. |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Copyright (C) 1996 Paul Mackerras. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public License |
|---|
| 9 | | - * as published by the Free Software Foundation; either version |
|---|
| 10 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 11 | 7 | */ |
|---|
| 12 | 8 | |
|---|
| 13 | 9 | /* |
|---|
| .. | .. |
|---|
| 25 | 21 | #include <linux/delay.h> |
|---|
| 26 | 22 | #include <linux/fd.h> |
|---|
| 27 | 23 | #include <linux/ioctl.h> |
|---|
| 28 | | -#include <linux/blkdev.h> |
|---|
| 24 | +#include <linux/blk-mq.h> |
|---|
| 29 | 25 | #include <linux/interrupt.h> |
|---|
| 30 | 26 | #include <linux/mutex.h> |
|---|
| 31 | 27 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 206 | 202 | char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)]; |
|---|
| 207 | 203 | int index; |
|---|
| 208 | 204 | struct request *cur_req; |
|---|
| 205 | + struct blk_mq_tag_set tag_set; |
|---|
| 209 | 206 | }; |
|---|
| 210 | 207 | |
|---|
| 211 | 208 | #define swim3_err(fmt, arg...) dev_err(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg) |
|---|
| .. | .. |
|---|
| 260 | 257 | static bool swim3_end_request(struct floppy_state *fs, blk_status_t err, unsigned int nr_bytes) |
|---|
| 261 | 258 | { |
|---|
| 262 | 259 | struct request *req = fs->cur_req; |
|---|
| 263 | | - int rc; |
|---|
| 264 | 260 | |
|---|
| 265 | 261 | swim3_dbg(" end request, err=%d nr_bytes=%d, cur_req=%p\n", |
|---|
| 266 | 262 | err, nr_bytes, req); |
|---|
| 267 | 263 | |
|---|
| 268 | 264 | if (err) |
|---|
| 269 | 265 | nr_bytes = blk_rq_cur_bytes(req); |
|---|
| 270 | | - rc = __blk_end_request(req, err, nr_bytes); |
|---|
| 271 | | - if (rc) |
|---|
| 266 | + if (blk_update_request(req, err, nr_bytes)) |
|---|
| 272 | 267 | return true; |
|---|
| 268 | + __blk_mq_end_request(req, err); |
|---|
| 273 | 269 | fs->cur_req = NULL; |
|---|
| 274 | 270 | return false; |
|---|
| 275 | 271 | } |
|---|
| .. | .. |
|---|
| 309 | 305 | return (stat & DATA) == 0; |
|---|
| 310 | 306 | } |
|---|
| 311 | 307 | |
|---|
| 312 | | -static void start_request(struct floppy_state *fs) |
|---|
| 308 | +static blk_status_t swim3_queue_rq(struct blk_mq_hw_ctx *hctx, |
|---|
| 309 | + const struct blk_mq_queue_data *bd) |
|---|
| 313 | 310 | { |
|---|
| 314 | | - struct request *req; |
|---|
| 311 | + struct floppy_state *fs = hctx->queue->queuedata; |
|---|
| 312 | + struct request *req = bd->rq; |
|---|
| 315 | 313 | unsigned long x; |
|---|
| 316 | 314 | |
|---|
| 317 | | - swim3_dbg("start request, initial state=%d\n", fs->state); |
|---|
| 318 | | - |
|---|
| 319 | | - if (fs->state == idle && fs->wanted) { |
|---|
| 320 | | - fs->state = available; |
|---|
| 321 | | - wake_up(&fs->wait); |
|---|
| 322 | | - return; |
|---|
| 315 | + spin_lock_irq(&swim3_lock); |
|---|
| 316 | + if (fs->cur_req || fs->state != idle) { |
|---|
| 317 | + spin_unlock_irq(&swim3_lock); |
|---|
| 318 | + return BLK_STS_DEV_RESOURCE; |
|---|
| 323 | 319 | } |
|---|
| 324 | | - while (fs->state == idle) { |
|---|
| 325 | | - swim3_dbg("start request, idle loop, cur_req=%p\n", fs->cur_req); |
|---|
| 326 | | - if (!fs->cur_req) { |
|---|
| 327 | | - fs->cur_req = blk_fetch_request(disks[fs->index]->queue); |
|---|
| 328 | | - swim3_dbg(" fetched request %p\n", fs->cur_req); |
|---|
| 329 | | - if (!fs->cur_req) |
|---|
| 330 | | - break; |
|---|
| 331 | | - } |
|---|
| 332 | | - req = fs->cur_req; |
|---|
| 333 | | - |
|---|
| 334 | | - if (fs->mdev->media_bay && |
|---|
| 335 | | - check_media_bay(fs->mdev->media_bay) != MB_FD) { |
|---|
| 336 | | - swim3_dbg("%s", " media bay absent, dropping req\n"); |
|---|
| 337 | | - swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 338 | | - continue; |
|---|
| 339 | | - } |
|---|
| 340 | | - |
|---|
| 341 | | -#if 0 /* This is really too verbose */ |
|---|
| 342 | | - swim3_dbg("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", |
|---|
| 343 | | - req->rq_disk->disk_name, req->cmd, |
|---|
| 344 | | - (long)blk_rq_pos(req), blk_rq_sectors(req), |
|---|
| 345 | | - bio_data(req->bio)); |
|---|
| 346 | | - swim3_dbg(" current_nr_sectors=%u\n", |
|---|
| 347 | | - blk_rq_cur_sectors(req)); |
|---|
| 348 | | -#endif |
|---|
| 349 | | - |
|---|
| 350 | | - if (blk_rq_pos(req) >= fs->total_secs) { |
|---|
| 351 | | - swim3_dbg(" pos out of bounds (%ld, max is %ld)\n", |
|---|
| 352 | | - (long)blk_rq_pos(req), (long)fs->total_secs); |
|---|
| 353 | | - swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 354 | | - continue; |
|---|
| 355 | | - } |
|---|
| 356 | | - if (fs->ejected) { |
|---|
| 357 | | - swim3_dbg("%s", " disk ejected\n"); |
|---|
| 358 | | - swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 359 | | - continue; |
|---|
| 360 | | - } |
|---|
| 361 | | - |
|---|
| 362 | | - if (rq_data_dir(req) == WRITE) { |
|---|
| 363 | | - if (fs->write_prot < 0) |
|---|
| 364 | | - fs->write_prot = swim3_readbit(fs, WRITE_PROT); |
|---|
| 365 | | - if (fs->write_prot) { |
|---|
| 366 | | - swim3_dbg("%s", " try to write, disk write protected\n"); |
|---|
| 367 | | - swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 368 | | - continue; |
|---|
| 369 | | - } |
|---|
| 370 | | - } |
|---|
| 371 | | - |
|---|
| 372 | | - /* Do not remove the cast. blk_rq_pos(req) is now a |
|---|
| 373 | | - * sector_t and can be 64 bits, but it will never go |
|---|
| 374 | | - * past 32 bits for this driver anyway, so we can |
|---|
| 375 | | - * safely cast it down and not have to do a 64/32 |
|---|
| 376 | | - * division |
|---|
| 377 | | - */ |
|---|
| 378 | | - fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl; |
|---|
| 379 | | - x = ((long)blk_rq_pos(req)) % fs->secpercyl; |
|---|
| 380 | | - fs->head = x / fs->secpertrack; |
|---|
| 381 | | - fs->req_sector = x % fs->secpertrack + 1; |
|---|
| 382 | | - fs->state = do_transfer; |
|---|
| 383 | | - fs->retries = 0; |
|---|
| 384 | | - |
|---|
| 385 | | - act(fs); |
|---|
| 320 | + blk_mq_start_request(req); |
|---|
| 321 | + fs->cur_req = req; |
|---|
| 322 | + if (fs->mdev->media_bay && |
|---|
| 323 | + check_media_bay(fs->mdev->media_bay) != MB_FD) { |
|---|
| 324 | + swim3_dbg("%s", " media bay absent, dropping req\n"); |
|---|
| 325 | + swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 326 | + goto out; |
|---|
| 386 | 327 | } |
|---|
| 387 | | -} |
|---|
| 328 | + if (fs->ejected) { |
|---|
| 329 | + swim3_dbg("%s", " disk ejected\n"); |
|---|
| 330 | + swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 331 | + goto out; |
|---|
| 332 | + } |
|---|
| 333 | + if (rq_data_dir(req) == WRITE) { |
|---|
| 334 | + if (fs->write_prot < 0) |
|---|
| 335 | + fs->write_prot = swim3_readbit(fs, WRITE_PROT); |
|---|
| 336 | + if (fs->write_prot) { |
|---|
| 337 | + swim3_dbg("%s", " try to write, disk write protected\n"); |
|---|
| 338 | + swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 339 | + goto out; |
|---|
| 340 | + } |
|---|
| 341 | + } |
|---|
| 388 | 342 | |
|---|
| 389 | | -static void do_fd_request(struct request_queue * q) |
|---|
| 390 | | -{ |
|---|
| 391 | | - start_request(q->queuedata); |
|---|
| 343 | + /* |
|---|
| 344 | + * Do not remove the cast. blk_rq_pos(req) is now a sector_t and can be |
|---|
| 345 | + * 64 bits, but it will never go past 32 bits for this driver anyway, so |
|---|
| 346 | + * we can safely cast it down and not have to do a 64/32 division |
|---|
| 347 | + */ |
|---|
| 348 | + fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl; |
|---|
| 349 | + x = ((long)blk_rq_pos(req)) % fs->secpercyl; |
|---|
| 350 | + fs->head = x / fs->secpertrack; |
|---|
| 351 | + fs->req_sector = x % fs->secpertrack + 1; |
|---|
| 352 | + fs->state = do_transfer; |
|---|
| 353 | + fs->retries = 0; |
|---|
| 354 | + |
|---|
| 355 | + act(fs); |
|---|
| 356 | + |
|---|
| 357 | +out: |
|---|
| 358 | + spin_unlock_irq(&swim3_lock); |
|---|
| 359 | + return BLK_STS_OK; |
|---|
| 392 | 360 | } |
|---|
| 393 | 361 | |
|---|
| 394 | 362 | static void set_timeout(struct floppy_state *fs, int nticks, |
|---|
| .. | .. |
|---|
| 585 | 553 | if (fs->retries > 5) { |
|---|
| 586 | 554 | swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 587 | 555 | fs->state = idle; |
|---|
| 588 | | - start_request(fs); |
|---|
| 589 | 556 | } else { |
|---|
| 590 | 557 | fs->state = jogging; |
|---|
| 591 | 558 | act(fs); |
|---|
| .. | .. |
|---|
| 609 | 576 | swim3_err("%s", "Seek timeout\n"); |
|---|
| 610 | 577 | swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 611 | 578 | fs->state = idle; |
|---|
| 612 | | - start_request(fs); |
|---|
| 613 | 579 | spin_unlock_irqrestore(&swim3_lock, flags); |
|---|
| 614 | 580 | } |
|---|
| 615 | 581 | |
|---|
| .. | .. |
|---|
| 638 | 604 | swim3_err("%s", "Seek settle timeout\n"); |
|---|
| 639 | 605 | swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 640 | 606 | fs->state = idle; |
|---|
| 641 | | - start_request(fs); |
|---|
| 642 | 607 | unlock: |
|---|
| 643 | 608 | spin_unlock_irqrestore(&swim3_lock, flags); |
|---|
| 644 | 609 | } |
|---|
| .. | .. |
|---|
| 667 | 632 | (long)blk_rq_pos(fs->cur_req)); |
|---|
| 668 | 633 | swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 669 | 634 | fs->state = idle; |
|---|
| 670 | | - start_request(fs); |
|---|
| 671 | 635 | spin_unlock_irqrestore(&swim3_lock, flags); |
|---|
| 672 | 636 | } |
|---|
| 673 | 637 | |
|---|
| .. | .. |
|---|
| 704 | 668 | if (fs->retries > 5) { |
|---|
| 705 | 669 | swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 706 | 670 | fs->state = idle; |
|---|
| 707 | | - start_request(fs); |
|---|
| 708 | 671 | } else { |
|---|
| 709 | 672 | fs->state = jogging; |
|---|
| 710 | 673 | act(fs); |
|---|
| .. | .. |
|---|
| 796 | 759 | fs->state, rq_data_dir(req), intr, err); |
|---|
| 797 | 760 | swim3_end_request(fs, BLK_STS_IOERR, 0); |
|---|
| 798 | 761 | fs->state = idle; |
|---|
| 799 | | - start_request(fs); |
|---|
| 800 | 762 | break; |
|---|
| 801 | 763 | } |
|---|
| 802 | 764 | fs->retries = 0; |
|---|
| .. | .. |
|---|
| 813 | 775 | } else |
|---|
| 814 | 776 | fs->state = idle; |
|---|
| 815 | 777 | } |
|---|
| 816 | | - if (fs->state == idle) |
|---|
| 817 | | - start_request(fs); |
|---|
| 818 | 778 | break; |
|---|
| 819 | 779 | default: |
|---|
| 820 | 780 | swim3_err("Don't know what to do in state %d\n", fs->state); |
|---|
| .. | .. |
|---|
| 862 | 822 | |
|---|
| 863 | 823 | static void release_drive(struct floppy_state *fs) |
|---|
| 864 | 824 | { |
|---|
| 825 | + struct request_queue *q = disks[fs->index]->queue; |
|---|
| 865 | 826 | unsigned long flags; |
|---|
| 866 | 827 | |
|---|
| 867 | 828 | swim3_dbg("%s", "-> release drive\n"); |
|---|
| 868 | 829 | |
|---|
| 869 | 830 | spin_lock_irqsave(&swim3_lock, flags); |
|---|
| 870 | 831 | fs->state = idle; |
|---|
| 871 | | - start_request(fs); |
|---|
| 872 | 832 | spin_unlock_irqrestore(&swim3_lock, flags); |
|---|
| 833 | + |
|---|
| 834 | + blk_mq_freeze_queue(q); |
|---|
| 835 | + blk_mq_quiesce_queue(q); |
|---|
| 836 | + blk_mq_unquiesce_queue(q); |
|---|
| 837 | + blk_mq_unfreeze_queue(q); |
|---|
| 873 | 838 | } |
|---|
| 874 | 839 | |
|---|
| 875 | 840 | static int fd_eject(struct floppy_state *fs) |
|---|
| .. | .. |
|---|
| 980 | 945 | |
|---|
| 981 | 946 | if (err == 0 && (mode & FMODE_NDELAY) == 0 |
|---|
| 982 | 947 | && (mode & (FMODE_READ|FMODE_WRITE))) { |
|---|
| 983 | | - check_disk_change(bdev); |
|---|
| 948 | + if (bdev_check_media_change(bdev)) |
|---|
| 949 | + floppy_revalidate(bdev->bd_disk); |
|---|
| 984 | 950 | if (fs->ejected) |
|---|
| 985 | 951 | err = -ENXIO; |
|---|
| 986 | 952 | } |
|---|
| .. | .. |
|---|
| 1090 | 1056 | .release = floppy_release, |
|---|
| 1091 | 1057 | .ioctl = floppy_ioctl, |
|---|
| 1092 | 1058 | .check_events = floppy_check_events, |
|---|
| 1093 | | - .revalidate_disk= floppy_revalidate, |
|---|
| 1059 | +}; |
|---|
| 1060 | + |
|---|
| 1061 | +static const struct blk_mq_ops swim3_mq_ops = { |
|---|
| 1062 | + .queue_rq = swim3_queue_rq, |
|---|
| 1094 | 1063 | }; |
|---|
| 1095 | 1064 | |
|---|
| 1096 | 1065 | static void swim3_mb_event(struct macio_dev* mdev, int mb_state) |
|---|
| .. | .. |
|---|
| 1118 | 1087 | struct floppy_state *fs = &floppy_states[index]; |
|---|
| 1119 | 1088 | int rc = -EBUSY; |
|---|
| 1120 | 1089 | |
|---|
| 1121 | | - /* Do this first for message macros */ |
|---|
| 1122 | | - memset(fs, 0, sizeof(*fs)); |
|---|
| 1123 | 1090 | fs->mdev = mdev; |
|---|
| 1124 | 1091 | fs->index = index; |
|---|
| 1125 | 1092 | |
|---|
| .. | .. |
|---|
| 1182 | 1149 | swim3_err("%s", "Couldn't request interrupt\n"); |
|---|
| 1183 | 1150 | pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0); |
|---|
| 1184 | 1151 | goto out_unmap; |
|---|
| 1185 | | - return -EBUSY; |
|---|
| 1186 | 1152 | } |
|---|
| 1187 | 1153 | |
|---|
| 1188 | 1154 | timer_setup(&fs->timeout, NULL, 0); |
|---|
| .. | .. |
|---|
| 1206 | 1172 | static int swim3_attach(struct macio_dev *mdev, |
|---|
| 1207 | 1173 | const struct of_device_id *match) |
|---|
| 1208 | 1174 | { |
|---|
| 1175 | + struct floppy_state *fs; |
|---|
| 1209 | 1176 | struct gendisk *disk; |
|---|
| 1210 | | - int index, rc; |
|---|
| 1177 | + int rc; |
|---|
| 1211 | 1178 | |
|---|
| 1212 | | - index = floppy_count++; |
|---|
| 1213 | | - if (index >= MAX_FLOPPIES) |
|---|
| 1179 | + if (floppy_count >= MAX_FLOPPIES) |
|---|
| 1214 | 1180 | return -ENXIO; |
|---|
| 1215 | 1181 | |
|---|
| 1216 | | - /* Add the drive */ |
|---|
| 1217 | | - rc = swim3_add_device(mdev, index); |
|---|
| 1218 | | - if (rc) |
|---|
| 1219 | | - return rc; |
|---|
| 1220 | | - /* Now register that disk. Same comment about failure handling */ |
|---|
| 1221 | | - disk = disks[index] = alloc_disk(1); |
|---|
| 1222 | | - if (disk == NULL) |
|---|
| 1223 | | - return -ENOMEM; |
|---|
| 1224 | | - disk->queue = blk_init_queue(do_fd_request, &swim3_lock); |
|---|
| 1225 | | - if (disk->queue == NULL) { |
|---|
| 1226 | | - put_disk(disk); |
|---|
| 1227 | | - return -ENOMEM; |
|---|
| 1182 | + if (floppy_count == 0) { |
|---|
| 1183 | + rc = register_blkdev(FLOPPY_MAJOR, "fd"); |
|---|
| 1184 | + if (rc) |
|---|
| 1185 | + return rc; |
|---|
| 1186 | + } |
|---|
| 1187 | + |
|---|
| 1188 | + disk = alloc_disk(1); |
|---|
| 1189 | + if (disk == NULL) { |
|---|
| 1190 | + rc = -ENOMEM; |
|---|
| 1191 | + goto out_unregister; |
|---|
| 1192 | + } |
|---|
| 1193 | + |
|---|
| 1194 | + fs = &floppy_states[floppy_count]; |
|---|
| 1195 | + memset(fs, 0, sizeof(*fs)); |
|---|
| 1196 | + |
|---|
| 1197 | + disk->queue = blk_mq_init_sq_queue(&fs->tag_set, &swim3_mq_ops, 2, |
|---|
| 1198 | + BLK_MQ_F_SHOULD_MERGE); |
|---|
| 1199 | + if (IS_ERR(disk->queue)) { |
|---|
| 1200 | + rc = PTR_ERR(disk->queue); |
|---|
| 1201 | + disk->queue = NULL; |
|---|
| 1202 | + goto out_put_disk; |
|---|
| 1228 | 1203 | } |
|---|
| 1229 | 1204 | blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH); |
|---|
| 1230 | | - disk->queue->queuedata = &floppy_states[index]; |
|---|
| 1205 | + disk->queue->queuedata = fs; |
|---|
| 1231 | 1206 | |
|---|
| 1232 | | - if (index == 0) { |
|---|
| 1233 | | - /* If we failed, there isn't much we can do as the driver is still |
|---|
| 1234 | | - * too dumb to remove the device, just bail out |
|---|
| 1235 | | - */ |
|---|
| 1236 | | - if (register_blkdev(FLOPPY_MAJOR, "fd")) |
|---|
| 1237 | | - return 0; |
|---|
| 1238 | | - } |
|---|
| 1207 | + rc = swim3_add_device(mdev, floppy_count); |
|---|
| 1208 | + if (rc) |
|---|
| 1209 | + goto out_cleanup_queue; |
|---|
| 1239 | 1210 | |
|---|
| 1240 | 1211 | disk->major = FLOPPY_MAJOR; |
|---|
| 1241 | | - disk->first_minor = index; |
|---|
| 1212 | + disk->first_minor = floppy_count; |
|---|
| 1242 | 1213 | disk->fops = &floppy_fops; |
|---|
| 1243 | | - disk->private_data = &floppy_states[index]; |
|---|
| 1214 | + disk->private_data = fs; |
|---|
| 1215 | + disk->events = DISK_EVENT_MEDIA_CHANGE; |
|---|
| 1244 | 1216 | disk->flags |= GENHD_FL_REMOVABLE; |
|---|
| 1245 | | - sprintf(disk->disk_name, "fd%d", index); |
|---|
| 1217 | + sprintf(disk->disk_name, "fd%d", floppy_count); |
|---|
| 1246 | 1218 | set_capacity(disk, 2880); |
|---|
| 1247 | 1219 | add_disk(disk); |
|---|
| 1248 | 1220 | |
|---|
| 1221 | + disks[floppy_count++] = disk; |
|---|
| 1249 | 1222 | return 0; |
|---|
| 1223 | + |
|---|
| 1224 | +out_cleanup_queue: |
|---|
| 1225 | + blk_cleanup_queue(disk->queue); |
|---|
| 1226 | + disk->queue = NULL; |
|---|
| 1227 | + blk_mq_free_tag_set(&fs->tag_set); |
|---|
| 1228 | +out_put_disk: |
|---|
| 1229 | + put_disk(disk); |
|---|
| 1230 | +out_unregister: |
|---|
| 1231 | + if (floppy_count == 0) |
|---|
| 1232 | + unregister_blkdev(FLOPPY_MAJOR, "fd"); |
|---|
| 1233 | + return rc; |
|---|
| 1250 | 1234 | } |
|---|
| 1251 | 1235 | |
|---|
| 1252 | 1236 | static const struct of_device_id swim3_match[] = |
|---|