.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/amiga/amiflop.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
61 | 62 | #include <linux/delay.h> |
---|
62 | 63 | #include <linux/init.h> |
---|
63 | 64 | #include <linux/mutex.h> |
---|
64 | | -#include <linux/amifdreg.h> |
---|
65 | | -#include <linux/amifd.h> |
---|
66 | 65 | #include <linux/fs.h> |
---|
67 | | -#include <linux/blkdev.h> |
---|
| 66 | +#include <linux/blk-mq.h> |
---|
68 | 67 | #include <linux/elevator.h> |
---|
69 | 68 | #include <linux/interrupt.h> |
---|
70 | 69 | #include <linux/platform_device.h> |
---|
.. | .. |
---|
85 | 84 | /* |
---|
86 | 85 | * Defines |
---|
87 | 86 | */ |
---|
| 87 | + |
---|
| 88 | +/* |
---|
| 89 | + * CIAAPRA bits (read only) |
---|
| 90 | + */ |
---|
| 91 | + |
---|
| 92 | +#define DSKRDY (0x1<<5) /* disk ready when low */ |
---|
| 93 | +#define DSKTRACK0 (0x1<<4) /* head at track zero when low */ |
---|
| 94 | +#define DSKPROT (0x1<<3) /* disk protected when low */ |
---|
| 95 | +#define DSKCHANGE (0x1<<2) /* low when disk removed */ |
---|
| 96 | + |
---|
| 97 | +/* |
---|
| 98 | + * CIAAPRB bits (read/write) |
---|
| 99 | + */ |
---|
| 100 | + |
---|
| 101 | +#define DSKMOTOR (0x1<<7) /* motor on when low */ |
---|
| 102 | +#define DSKSEL3 (0x1<<6) /* select drive 3 when low */ |
---|
| 103 | +#define DSKSEL2 (0x1<<5) /* select drive 2 when low */ |
---|
| 104 | +#define DSKSEL1 (0x1<<4) /* select drive 1 when low */ |
---|
| 105 | +#define DSKSEL0 (0x1<<3) /* select drive 0 when low */ |
---|
| 106 | +#define DSKSIDE (0x1<<2) /* side selection: 0 = upper, 1 = lower */ |
---|
| 107 | +#define DSKDIREC (0x1<<1) /* step direction: 0=in, 1=out (to trk 0) */ |
---|
| 108 | +#define DSKSTEP (0x1) /* pulse low to step head 1 track */ |
---|
| 109 | + |
---|
| 110 | +/* |
---|
| 111 | + * DSKBYTR bits (read only) |
---|
| 112 | + */ |
---|
| 113 | + |
---|
| 114 | +#define DSKBYT (1<<15) /* register contains valid byte when set */ |
---|
| 115 | +#define DMAON (1<<14) /* disk DMA enabled */ |
---|
| 116 | +#define DISKWRITE (1<<13) /* disk write bit in DSKLEN enabled */ |
---|
| 117 | +#define WORDEQUAL (1<<12) /* DSKSYNC register match when true */ |
---|
| 118 | +/* bits 7-0 are data */ |
---|
| 119 | + |
---|
| 120 | +/* |
---|
| 121 | + * ADKCON/ADKCONR bits |
---|
| 122 | + */ |
---|
| 123 | + |
---|
| 124 | +#ifndef SETCLR |
---|
| 125 | +#define ADK_SETCLR (1<<15) /* control bit */ |
---|
| 126 | +#endif |
---|
| 127 | +#define ADK_PRECOMP1 (1<<14) /* precompensation selection */ |
---|
| 128 | +#define ADK_PRECOMP0 (1<<13) /* 00=none, 01=140ns, 10=280ns, 11=500ns */ |
---|
| 129 | +#define ADK_MFMPREC (1<<12) /* 0=GCR precomp., 1=MFM precomp. */ |
---|
| 130 | +#define ADK_WORDSYNC (1<<10) /* enable DSKSYNC auto DMA */ |
---|
| 131 | +#define ADK_MSBSYNC (1<<9) /* when 1, enable sync on MSbit (for GCR) */ |
---|
| 132 | +#define ADK_FAST (1<<8) /* bit cell: 0=2us (GCR), 1=1us (MFM) */ |
---|
| 133 | + |
---|
| 134 | +/* |
---|
| 135 | + * DSKLEN bits |
---|
| 136 | + */ |
---|
| 137 | + |
---|
| 138 | +#define DSKLEN_DMAEN (1<<15) |
---|
| 139 | +#define DSKLEN_WRITE (1<<14) |
---|
| 140 | + |
---|
| 141 | +/* |
---|
| 142 | + * INTENA/INTREQ bits |
---|
| 143 | + */ |
---|
| 144 | + |
---|
| 145 | +#define DSKINDEX (0x1<<4) /* DSKINDEX bit */ |
---|
| 146 | + |
---|
| 147 | +/* |
---|
| 148 | + * Misc |
---|
| 149 | + */ |
---|
| 150 | + |
---|
| 151 | +#define MFM_SYNC 0x4489 /* standard MFM sync value */ |
---|
| 152 | + |
---|
| 153 | +/* Values for FD_COMMAND */ |
---|
| 154 | +#define FD_RECALIBRATE 0x07 /* move to track 0 */ |
---|
| 155 | +#define FD_SEEK 0x0F /* seek track */ |
---|
| 156 | +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ |
---|
| 157 | +#define FD_WRITE 0xC5 /* write with MT, MFM */ |
---|
| 158 | +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ |
---|
| 159 | +#define FD_SPECIFY 0x03 /* specify HUT etc */ |
---|
| 160 | +#define FD_FORMAT 0x4D /* format one track */ |
---|
| 161 | +#define FD_VERSION 0x10 /* get version code */ |
---|
| 162 | +#define FD_CONFIGURE 0x13 /* configure FIFO operation */ |
---|
| 163 | +#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */ |
---|
| 164 | + |
---|
| 165 | +#define FD_MAX_UNITS 4 /* Max. Number of drives */ |
---|
| 166 | +#define FLOPPY_MAX_SECTORS 22 /* Max. Number of sectors per track */ |
---|
| 167 | + |
---|
| 168 | +struct fd_data_type { |
---|
| 169 | + char *name; /* description of data type */ |
---|
| 170 | + int sects; /* sectors per track */ |
---|
| 171 | + int (*read_fkt)(int); /* read whole track */ |
---|
| 172 | + void (*write_fkt)(int); /* write whole track */ |
---|
| 173 | +}; |
---|
| 174 | + |
---|
| 175 | +struct fd_drive_type { |
---|
| 176 | + unsigned long code; /* code returned from drive */ |
---|
| 177 | + char *name; /* description of drive */ |
---|
| 178 | + unsigned int tracks; /* number of tracks */ |
---|
| 179 | + unsigned int heads; /* number of heads */ |
---|
| 180 | + unsigned int read_size; /* raw read size for one track */ |
---|
| 181 | + unsigned int write_size; /* raw write size for one track */ |
---|
| 182 | + unsigned int sect_mult; /* sectors and gap multiplier (HD = 2) */ |
---|
| 183 | + unsigned int precomp1; /* start track for precomp 1 */ |
---|
| 184 | + unsigned int precomp2; /* start track for precomp 2 */ |
---|
| 185 | + unsigned int step_delay; /* time (in ms) for delay after step */ |
---|
| 186 | + unsigned int settle_time; /* time to settle after dir change */ |
---|
| 187 | + unsigned int side_time; /* time needed to change sides */ |
---|
| 188 | +}; |
---|
| 189 | + |
---|
| 190 | +struct amiga_floppy_struct { |
---|
| 191 | + struct fd_drive_type *type; /* type of floppy for this unit */ |
---|
| 192 | + struct fd_data_type *dtype; /* type of floppy for this unit */ |
---|
| 193 | + int track; /* current track (-1 == unknown) */ |
---|
| 194 | + unsigned char *trackbuf; /* current track (kmaloc()'d */ |
---|
| 195 | + |
---|
| 196 | + int blocks; /* total # blocks on disk */ |
---|
| 197 | + |
---|
| 198 | + int changed; /* true when not known */ |
---|
| 199 | + int disk; /* disk in drive (-1 == unknown) */ |
---|
| 200 | + int motor; /* true when motor is at speed */ |
---|
| 201 | + int busy; /* true when drive is active */ |
---|
| 202 | + int dirty; /* true when trackbuf is not on disk */ |
---|
| 203 | + int status; /* current error code for unit */ |
---|
| 204 | + struct gendisk *gendisk; |
---|
| 205 | + struct blk_mq_tag_set tag_set; |
---|
| 206 | +}; |
---|
88 | 207 | |
---|
89 | 208 | /* |
---|
90 | 209 | * Error codes |
---|
.. | .. |
---|
164 | 283 | static int writepending; |
---|
165 | 284 | static int writefromint; |
---|
166 | 285 | static char *raw_buf; |
---|
167 | | -static int fdc_queue; |
---|
168 | 286 | |
---|
169 | 287 | static DEFINE_SPINLOCK(amiflop_lock); |
---|
170 | 288 | |
---|
.. | .. |
---|
1337 | 1455 | return -1; |
---|
1338 | 1456 | } |
---|
1339 | 1457 | |
---|
1340 | | -/* |
---|
1341 | | - * Round-robin between our available drives, doing one request from each |
---|
1342 | | - */ |
---|
1343 | | -static struct request *set_next_request(void) |
---|
| 1458 | +static blk_status_t amiflop_rw_cur_segment(struct amiga_floppy_struct *floppy, |
---|
| 1459 | + struct request *rq) |
---|
1344 | 1460 | { |
---|
1345 | | - struct request_queue *q; |
---|
1346 | | - int cnt = FD_MAX_UNITS; |
---|
1347 | | - struct request *rq = NULL; |
---|
1348 | | - |
---|
1349 | | - /* Find next queue we can dispatch from */ |
---|
1350 | | - fdc_queue = fdc_queue + 1; |
---|
1351 | | - if (fdc_queue == FD_MAX_UNITS) |
---|
1352 | | - fdc_queue = 0; |
---|
1353 | | - |
---|
1354 | | - for(cnt = FD_MAX_UNITS; cnt > 0; cnt--) { |
---|
1355 | | - |
---|
1356 | | - if (unit[fdc_queue].type->code == FD_NODRIVE) { |
---|
1357 | | - if (++fdc_queue == FD_MAX_UNITS) |
---|
1358 | | - fdc_queue = 0; |
---|
1359 | | - continue; |
---|
1360 | | - } |
---|
1361 | | - |
---|
1362 | | - q = unit[fdc_queue].gendisk->queue; |
---|
1363 | | - if (q) { |
---|
1364 | | - rq = blk_fetch_request(q); |
---|
1365 | | - if (rq) |
---|
1366 | | - break; |
---|
1367 | | - } |
---|
1368 | | - |
---|
1369 | | - if (++fdc_queue == FD_MAX_UNITS) |
---|
1370 | | - fdc_queue = 0; |
---|
1371 | | - } |
---|
1372 | | - |
---|
1373 | | - return rq; |
---|
1374 | | -} |
---|
1375 | | - |
---|
1376 | | -static void redo_fd_request(void) |
---|
1377 | | -{ |
---|
1378 | | - struct request *rq; |
---|
| 1461 | + int drive = floppy - unit; |
---|
1379 | 1462 | unsigned int cnt, block, track, sector; |
---|
1380 | | - int drive; |
---|
1381 | | - struct amiga_floppy_struct *floppy; |
---|
1382 | 1463 | char *data; |
---|
1383 | | - unsigned long flags; |
---|
1384 | | - blk_status_t err; |
---|
1385 | 1464 | |
---|
1386 | | -next_req: |
---|
1387 | | - rq = set_next_request(); |
---|
1388 | | - if (!rq) { |
---|
1389 | | - /* Nothing left to do */ |
---|
1390 | | - return; |
---|
1391 | | - } |
---|
1392 | | - |
---|
1393 | | - floppy = rq->rq_disk->private_data; |
---|
1394 | | - drive = floppy - unit; |
---|
1395 | | - |
---|
1396 | | -next_segment: |
---|
1397 | | - /* Here someone could investigate to be more efficient */ |
---|
1398 | | - for (cnt = 0, err = BLK_STS_OK; cnt < blk_rq_cur_sectors(rq); cnt++) { |
---|
| 1465 | + for (cnt = 0; cnt < blk_rq_cur_sectors(rq); cnt++) { |
---|
1399 | 1466 | #ifdef DEBUG |
---|
1400 | 1467 | printk("fd: sector %ld + %d requested for %s\n", |
---|
1401 | 1468 | blk_rq_pos(rq), cnt, |
---|
1402 | 1469 | (rq_data_dir(rq) == READ) ? "read" : "write"); |
---|
1403 | 1470 | #endif |
---|
1404 | 1471 | block = blk_rq_pos(rq) + cnt; |
---|
1405 | | - if ((int)block > floppy->blocks) { |
---|
1406 | | - err = BLK_STS_IOERR; |
---|
1407 | | - break; |
---|
1408 | | - } |
---|
1409 | | - |
---|
1410 | 1472 | track = block / (floppy->dtype->sects * floppy->type->sect_mult); |
---|
1411 | 1473 | sector = block % (floppy->dtype->sects * floppy->type->sect_mult); |
---|
1412 | 1474 | data = bio_data(rq->bio) + 512 * cnt; |
---|
.. | .. |
---|
1415 | 1477 | "0x%08lx\n", track, sector, data); |
---|
1416 | 1478 | #endif |
---|
1417 | 1479 | |
---|
1418 | | - if (get_track(drive, track) == -1) { |
---|
1419 | | - err = BLK_STS_IOERR; |
---|
1420 | | - break; |
---|
1421 | | - } |
---|
| 1480 | + if (get_track(drive, track) == -1) |
---|
| 1481 | + return BLK_STS_IOERR; |
---|
1422 | 1482 | |
---|
1423 | 1483 | if (rq_data_dir(rq) == READ) { |
---|
1424 | 1484 | memcpy(data, floppy->trackbuf + sector * 512, 512); |
---|
.. | .. |
---|
1426 | 1486 | memcpy(floppy->trackbuf + sector * 512, data, 512); |
---|
1427 | 1487 | |
---|
1428 | 1488 | /* keep the drive spinning while writes are scheduled */ |
---|
1429 | | - if (!fd_motor_on(drive)) { |
---|
1430 | | - err = BLK_STS_IOERR; |
---|
1431 | | - break; |
---|
1432 | | - } |
---|
| 1489 | + if (!fd_motor_on(drive)) |
---|
| 1490 | + return BLK_STS_IOERR; |
---|
1433 | 1491 | /* |
---|
1434 | 1492 | * setup a callback to write the track buffer |
---|
1435 | 1493 | * after a short (1 tick) delay. |
---|
1436 | 1494 | */ |
---|
1437 | | - local_irq_save(flags); |
---|
1438 | | - |
---|
1439 | 1495 | floppy->dirty = 1; |
---|
1440 | 1496 | /* reset the timer */ |
---|
1441 | 1497 | mod_timer (flush_track_timer + drive, jiffies + 1); |
---|
1442 | | - local_irq_restore(flags); |
---|
1443 | 1498 | } |
---|
1444 | 1499 | } |
---|
1445 | 1500 | |
---|
1446 | | - if (__blk_end_request_cur(rq, err)) |
---|
1447 | | - goto next_segment; |
---|
1448 | | - goto next_req; |
---|
| 1501 | + return BLK_STS_OK; |
---|
1449 | 1502 | } |
---|
1450 | 1503 | |
---|
1451 | | -static void do_fd_request(struct request_queue * q) |
---|
| 1504 | +static blk_status_t amiflop_queue_rq(struct blk_mq_hw_ctx *hctx, |
---|
| 1505 | + const struct blk_mq_queue_data *bd) |
---|
1452 | 1506 | { |
---|
1453 | | - redo_fd_request(); |
---|
| 1507 | + struct request *rq = bd->rq; |
---|
| 1508 | + struct amiga_floppy_struct *floppy = rq->rq_disk->private_data; |
---|
| 1509 | + blk_status_t err; |
---|
| 1510 | + |
---|
| 1511 | + if (!spin_trylock_irq(&amiflop_lock)) |
---|
| 1512 | + return BLK_STS_DEV_RESOURCE; |
---|
| 1513 | + |
---|
| 1514 | + blk_mq_start_request(rq); |
---|
| 1515 | + |
---|
| 1516 | + do { |
---|
| 1517 | + err = amiflop_rw_cur_segment(floppy, rq); |
---|
| 1518 | + } while (blk_update_request(rq, err, blk_rq_cur_bytes(rq))); |
---|
| 1519 | + blk_mq_end_request(rq, err); |
---|
| 1520 | + |
---|
| 1521 | + spin_unlock_irq(&amiflop_lock); |
---|
| 1522 | + return BLK_STS_OK; |
---|
1454 | 1523 | } |
---|
1455 | 1524 | |
---|
1456 | 1525 | static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) |
---|
.. | .. |
---|
1533 | 1602 | return p->type->read_size; |
---|
1534 | 1603 | #endif |
---|
1535 | 1604 | default: |
---|
1536 | | - printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.", |
---|
1537 | | - cmd, drive); |
---|
1538 | 1605 | return -ENOSYS; |
---|
1539 | 1606 | } |
---|
1540 | 1607 | return 0; |
---|
.. | .. |
---|
1603 | 1670 | } |
---|
1604 | 1671 | |
---|
1605 | 1672 | if (mode & (FMODE_READ|FMODE_WRITE)) { |
---|
1606 | | - check_disk_change(bdev); |
---|
| 1673 | + bdev_check_media_change(bdev); |
---|
1607 | 1674 | if (mode & FMODE_WRITE) { |
---|
1608 | 1675 | int wrprot; |
---|
1609 | 1676 | |
---|
.. | .. |
---|
1701 | 1768 | .check_events = amiga_check_events, |
---|
1702 | 1769 | }; |
---|
1703 | 1770 | |
---|
| 1771 | +static const struct blk_mq_ops amiflop_mq_ops = { |
---|
| 1772 | + .queue_rq = amiflop_queue_rq, |
---|
| 1773 | +}; |
---|
| 1774 | + |
---|
1704 | 1775 | static struct gendisk *fd_alloc_disk(int drive) |
---|
1705 | 1776 | { |
---|
1706 | 1777 | struct gendisk *disk; |
---|
.. | .. |
---|
1709 | 1780 | if (!disk) |
---|
1710 | 1781 | goto out; |
---|
1711 | 1782 | |
---|
1712 | | - disk->queue = blk_init_queue(do_fd_request, &amiflop_lock); |
---|
| 1783 | + disk->queue = blk_mq_init_sq_queue(&unit[drive].tag_set, &amiflop_mq_ops, |
---|
| 1784 | + 2, BLK_MQ_F_SHOULD_MERGE); |
---|
1713 | 1785 | if (IS_ERR(disk->queue)) { |
---|
1714 | 1786 | disk->queue = NULL; |
---|
1715 | 1787 | goto out_put_disk; |
---|
.. | .. |
---|
1724 | 1796 | out_cleanup_queue: |
---|
1725 | 1797 | blk_cleanup_queue(disk->queue); |
---|
1726 | 1798 | disk->queue = NULL; |
---|
| 1799 | + blk_mq_free_tag_set(&unit[drive].tag_set); |
---|
1727 | 1800 | out_put_disk: |
---|
1728 | 1801 | put_disk(disk); |
---|
1729 | 1802 | out: |
---|
.. | .. |
---|
1757 | 1830 | disk->major = FLOPPY_MAJOR; |
---|
1758 | 1831 | disk->first_minor = drive; |
---|
1759 | 1832 | disk->fops = &floppy_fops; |
---|
| 1833 | + disk->events = DISK_EVENT_MEDIA_CHANGE; |
---|
1760 | 1834 | sprintf(disk->disk_name, "fd%d", drive); |
---|
1761 | 1835 | disk->private_data = &unit[drive]; |
---|
1762 | 1836 | set_capacity(disk, 880*2); |
---|