hc
2024-05-14 bedbef8ad3e75a304af6361af235302bcc61d06b
kernel/drivers/block/amiflop.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * linux/amiga/amiflop.c
34 *
....@@ -61,10 +62,8 @@
6162 #include <linux/delay.h>
6263 #include <linux/init.h>
6364 #include <linux/mutex.h>
64
-#include <linux/amifdreg.h>
65
-#include <linux/amifd.h>
6665 #include <linux/fs.h>
67
-#include <linux/blkdev.h>
66
+#include <linux/blk-mq.h>
6867 #include <linux/elevator.h>
6968 #include <linux/interrupt.h>
7069 #include <linux/platform_device.h>
....@@ -85,6 +84,126 @@
8584 /*
8685 * Defines
8786 */
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
+};
88207
89208 /*
90209 * Error codes
....@@ -164,7 +283,6 @@
164283 static int writepending;
165284 static int writefromint;
166285 static char *raw_buf;
167
-static int fdc_queue;
168286
169287 static DEFINE_SPINLOCK(amiflop_lock);
170288
....@@ -1337,76 +1455,20 @@
13371455 return -1;
13381456 }
13391457
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)
13441460 {
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;
13791462 unsigned int cnt, block, track, sector;
1380
- int drive;
1381
- struct amiga_floppy_struct *floppy;
13821463 char *data;
1383
- unsigned long flags;
1384
- blk_status_t err;
13851464
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++) {
13991466 #ifdef DEBUG
14001467 printk("fd: sector %ld + %d requested for %s\n",
14011468 blk_rq_pos(rq), cnt,
14021469 (rq_data_dir(rq) == READ) ? "read" : "write");
14031470 #endif
14041471 block = blk_rq_pos(rq) + cnt;
1405
- if ((int)block > floppy->blocks) {
1406
- err = BLK_STS_IOERR;
1407
- break;
1408
- }
1409
-
14101472 track = block / (floppy->dtype->sects * floppy->type->sect_mult);
14111473 sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
14121474 data = bio_data(rq->bio) + 512 * cnt;
....@@ -1415,10 +1477,8 @@
14151477 "0x%08lx\n", track, sector, data);
14161478 #endif
14171479
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;
14221482
14231483 if (rq_data_dir(rq) == READ) {
14241484 memcpy(data, floppy->trackbuf + sector * 512, 512);
....@@ -1426,31 +1486,40 @@
14261486 memcpy(floppy->trackbuf + sector * 512, data, 512);
14271487
14281488 /* 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;
14331491 /*
14341492 * setup a callback to write the track buffer
14351493 * after a short (1 tick) delay.
14361494 */
1437
- local_irq_save(flags);
1438
-
14391495 floppy->dirty = 1;
14401496 /* reset the timer */
14411497 mod_timer (flush_track_timer + drive, jiffies + 1);
1442
- local_irq_restore(flags);
14431498 }
14441499 }
14451500
1446
- if (__blk_end_request_cur(rq, err))
1447
- goto next_segment;
1448
- goto next_req;
1501
+ return BLK_STS_OK;
14491502 }
14501503
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)
14521506 {
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;
14541523 }
14551524
14561525 static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
....@@ -1533,8 +1602,6 @@
15331602 return p->type->read_size;
15341603 #endif
15351604 default:
1536
- printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.",
1537
- cmd, drive);
15381605 return -ENOSYS;
15391606 }
15401607 return 0;
....@@ -1603,7 +1670,7 @@
16031670 }
16041671
16051672 if (mode & (FMODE_READ|FMODE_WRITE)) {
1606
- check_disk_change(bdev);
1673
+ bdev_check_media_change(bdev);
16071674 if (mode & FMODE_WRITE) {
16081675 int wrprot;
16091676
....@@ -1701,6 +1768,10 @@
17011768 .check_events = amiga_check_events,
17021769 };
17031770
1771
+static const struct blk_mq_ops amiflop_mq_ops = {
1772
+ .queue_rq = amiflop_queue_rq,
1773
+};
1774
+
17041775 static struct gendisk *fd_alloc_disk(int drive)
17051776 {
17061777 struct gendisk *disk;
....@@ -1709,7 +1780,8 @@
17091780 if (!disk)
17101781 goto out;
17111782
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);
17131785 if (IS_ERR(disk->queue)) {
17141786 disk->queue = NULL;
17151787 goto out_put_disk;
....@@ -1724,6 +1796,7 @@
17241796 out_cleanup_queue:
17251797 blk_cleanup_queue(disk->queue);
17261798 disk->queue = NULL;
1799
+ blk_mq_free_tag_set(&unit[drive].tag_set);
17271800 out_put_disk:
17281801 put_disk(disk);
17291802 out:
....@@ -1757,6 +1830,7 @@
17571830 disk->major = FLOPPY_MAJOR;
17581831 disk->first_minor = drive;
17591832 disk->fops = &floppy_fops;
1833
+ disk->events = DISK_EVENT_MEDIA_CHANGE;
17601834 sprintf(disk->disk_name, "fd%d", drive);
17611835 disk->private_data = &unit[drive];
17621836 set_capacity(disk, 880*2);