blob: 6d4a2e14799a6e6607733081876bc73b95dc049b [file] [log] [blame]
Thomas Gleixner09c434b2019-05-19 13:08:20 +01001// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/drivers/block/floppy.c
4 *
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 * Copyright (C) 1993, 1994 Alain Knaff
7 * Copyright (C) 1998 Alan Cox
8 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07009
Linus Torvalds1da177e2005-04-16 15:20:36 -070010/*
11 * 02.12.91 - Changed to static variables to indicate need for reset
12 * and recalibrate. This makes some things easier (output_byte reset
13 * checking etc), and means less interrupt jumping in case of errors,
14 * so the code is hopefully easier to understand.
15 */
16
17/*
18 * This file is certainly a mess. I've tried my best to get it working,
19 * but I don't like programming floppies, and I have only one anyway.
20 * Urgel. I should check for more errors, and do more graceful error
21 * recovery. Seems there are problems with several drives. I've tried to
22 * correct them. No promises.
23 */
24
25/*
26 * As with hd.c, all routines within this file can (and will) be called
27 * by interrupts, so extreme caution is needed. A hardware interrupt
28 * handler may not sleep, or a kernel panic will happen. Thus I cannot
29 * call "floppy-on" directly, but have to set a special timer interrupt
30 * etc.
31 */
32
33/*
34 * 28.02.92 - made track-buffering routines, based on the routines written
35 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
36 */
37
38/*
39 * Automatic floppy-detection and formatting written by Werner Almesberger
40 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
41 * the floppy-change signal detection.
42 */
43
44/*
45 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
46 * FDC data overrun bug, added some preliminary stuff for vertical
47 * recording support.
48 *
49 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
50 *
51 * TODO: Errors are still not counted properly.
52 */
53
54/* 1992/9/20
55 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
56 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
57 * Christoph H. Hochst\"atter.
58 * I have fixed the shift values to the ones I always use. Maybe a new
59 * ioctl() should be created to be able to modify them.
60 * There is a bug in the driver that makes it impossible to format a
61 * floppy as the first thing after bootup.
62 */
63
64/*
65 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
66 * this helped the floppy driver as well. Much cleaner, and still seems to
67 * work.
68 */
69
70/* 1994/6/24 --bbroad-- added the floppy table entries and made
71 * minor modifications to allow 2.88 floppies to be run.
72 */
73
74/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
75 * disk types.
76 */
77
78/*
79 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
80 * format bug fixes, but unfortunately some new bugs too...
81 */
82
83/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
84 * errors to allow safe writing by specialized programs.
85 */
86
87/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
88 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
89 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
90 * drives are "upside-down").
91 */
92
93/*
94 * 1995/8/26 -- Andreas Busse -- added Mips support.
95 */
96
97/*
98 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
99 * features to asm/floppy.h.
100 */
101
102/*
James Nelsonb88b0982005-11-08 16:52:12 +0100103 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
104 */
105
106/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
108 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
109 * use of '0' for NULL.
110 */
111
112/*
113 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
114 * failures.
115 */
116
117/*
118 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
119 */
120
121/*
122 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
123 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
124 * being used to store jiffies, which are unsigned longs).
125 */
126
127/*
128 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
129 * - get rid of check_region
130 * - s/suser/capable/
131 */
132
133/*
134 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
135 * floppy controller (lingering task on list after module is gone... boom.)
136 */
137
138/*
139 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
140 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
141 * requires many non-obvious changes in arch dependent code.
142 */
143
144/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
145 * Better audit of register_blkdev.
146 */
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148#undef FLOPPY_SILENT_DCL_CLEAR
149
150#define REALLY_SLOW_IO
151
152#define DEBUGT 2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Joe Perches891eda82010-03-10 15:21:05 -0800154#define DPRINT(format, args...) \
155 pr_info("floppy%d: " format, current_drive, ##args)
156
157#define DCL_DEBUG /* debug disk change line */
Joe Perches87f530d2010-03-10 15:20:54 -0800158#ifdef DCL_DEBUG
159#define debug_dcl(test, fmt, args...) \
160 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
161#else
162#define debug_dcl(test, fmt, args...) \
163 do { if (0) DPRINT(fmt, ##args); } while (0)
164#endif
165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166/* do print messages for unexpected interrupts */
167static int print_unex = 1;
168#include <linux/module.h>
169#include <linux/sched.h>
170#include <linux/fs.h>
171#include <linux/kernel.h>
172#include <linux/timer.h>
173#include <linux/workqueue.h>
174#define FDPATCHES
175#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#include <linux/fd.h>
177#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178#include <linux/errno.h>
179#include <linux/slab.h>
180#include <linux/mm.h>
181#include <linux/bio.h>
182#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800183#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#include <linux/fcntl.h>
185#include <linux/delay.h>
186#include <linux/mc146818rtc.h> /* CMOS defines */
187#include <linux/ioport.h>
188#include <linux/interrupt.h>
189#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100190#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700191#include <linux/mod_devicetable.h>
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800192#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800193#include <linux/io.h>
194#include <linux/uaccess.h>
Andi Kleen0cc15d032012-07-02 17:27:04 -0700195#include <linux/async.h>
Al Viro229b53c2017-06-27 15:47:56 -0400196#include <linux/compat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198/*
199 * PS/2 floppies have much slower step rates than regular floppies.
200 * It's been recommended that take about 1/4 of the default speed
201 * in some more extreme cases.
202 */
Arnd Bergmann2a48fc02010-06-02 14:28:52 +0200203static DEFINE_MUTEX(floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static int slow_floppy;
205
206#include <asm/dma.h>
207#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209static int FLOPPY_IRQ = 6;
210static int FLOPPY_DMA = 2;
211static int can_use_virtual_dma = 2;
212/* =======
213 * can use virtual DMA:
214 * 0 = use of virtual DMA disallowed by config
215 * 1 = use of virtual DMA prescribed by config
216 * 2 = no virtual DMA preference configured. By default try hard DMA,
217 * but fall back on virtual DMA when not enough memory available
218 */
219
220static int use_virtual_dma;
221/* =======
222 * use virtual DMA
223 * 0 using hard DMA
224 * 1 using virtual DMA
225 * This variable is set to virtual when a DMA mem problem arises, and
226 * reset back in floppy_grab_irq_and_dma.
227 * It is not safe to reset it in other circumstances, because the floppy
228 * driver may have several buffers in use at once, and we do currently not
229 * record each buffers capabilities
230 */
231
232static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100235irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238#define K_64 0x10000 /* 64KB */
239
240/* the following is the mask of allowed drives. By default units 2 and
241 * 3 of both floppy controllers are disabled, because switching on the
242 * motor of these drives causes system hangs on some PCI computers. drive
243 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
244 * a drive is allowed.
245 *
246 * NOTE: This must come before we include the arch floppy header because
247 * some ports reference this variable from there. -DaveM
248 */
249
250static int allowed_drive_mask = 0x33;
251
252#include <asm/floppy.h>
253
254static int irqdma_allocated;
255
Omar Sandovala9f38e12018-10-15 09:21:34 -0600256#include <linux/blk-mq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257#include <linux/blkpg.h>
258#include <linux/cdrom.h> /* for the compatibility eject ioctl */
259#include <linux/completion.h>
260
Omar Sandovala9f38e12018-10-15 09:21:34 -0600261static LIST_HEAD(floppy_reqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262static struct request *current_req;
Jens Axboe48821182010-09-22 09:32:36 +0200263static int set_next_request(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265#ifndef fd_get_dma_residue
266#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
267#endif
268
269/* Dma Memory related stuff */
270
271#ifndef fd_dma_mem_free
272#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
273#endif
274
275#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800276#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277#endif
278
Christoph Hellwigacfef4f2017-07-13 16:12:05 +0200279#ifndef fd_cacheflush
280#define fd_cacheflush(addr, size) /* nothing... */
281#endif
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283static inline void fallback_on_nodma_alloc(char **addr, size_t l)
284{
285#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
286 if (*addr)
287 return; /* we have the memory */
288 if (can_use_virtual_dma != 2)
289 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800290 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 *addr = (char *)nodma_mem_alloc(l);
292#else
293 return;
294#endif
295}
296
297/* End dma memory related stuff */
298
299static unsigned long fake_change;
Joe Perches29f1c782010-03-10 15:21:00 -0800300static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Joe Perches48c8cee2010-03-10 15:20:45 -0800302#define ITYPE(x) (((x) >> 2) & 0x1f)
303#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
304#define UNIT(x) ((x) & 0x03) /* drive on fdc */
305#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700306 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Joe Perches48c8cee2010-03-10 15:20:45 -0800309#define DRWE (&write_errors[current_drive])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Joe Perches48c8cee2010-03-10 15:20:45 -0800311#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
312#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800315#define COMMAND (raw_cmd->cmd[0])
316#define DR_SELECT (raw_cmd->cmd[1])
317#define TRACK (raw_cmd->cmd[2])
318#define HEAD (raw_cmd->cmd[3])
319#define SECTOR (raw_cmd->cmd[4])
320#define SIZECODE (raw_cmd->cmd[5])
321#define SECT_PER_TRACK (raw_cmd->cmd[6])
322#define GAP (raw_cmd->cmd[7])
323#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324#define NR_RW 9
325
326/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800327#define F_SIZECODE (raw_cmd->cmd[2])
328#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
329#define F_GAP (raw_cmd->cmd[4])
330#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331#define NR_F 6
332
333/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800334 * Maximum disk size (in kilobytes).
335 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 * [Now it is rather a minimum]
337 */
338#define MAX_DISK_SIZE 4 /* 3984 */
339
340/*
341 * globals used by 'result()'
342 */
343#define MAX_REPLIES 16
344static unsigned char reply_buffer[MAX_REPLIES];
Joe Perches891eda82010-03-10 15:21:05 -0800345static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800346#define ST0 (reply_buffer[0])
347#define ST1 (reply_buffer[1])
348#define ST2 (reply_buffer[2])
349#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
350#define R_TRACK (reply_buffer[3])
351#define R_HEAD (reply_buffer[4])
352#define R_SECTOR (reply_buffer[5])
353#define R_SIZECODE (reply_buffer[6])
354
355#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357/*
358 * this struct defines the different floppy drive types.
359 */
360static struct {
361 struct floppy_drive_params params;
362 const char *name; /* name printed while booting */
363} default_drive_params[] = {
364/* NOTE: the time values in jiffies should be in msec!
365 CMOS drive type
366 | Maximum data rate supported by drive type
367 | | Head load time, msec
368 | | | Head unload time, msec (not used)
369 | | | | Step rate interval, usec
370 | | | | | Time needed for spinup time (jiffies)
371 | | | | | | Timeout for spinning down (jiffies)
372 | | | | | | | Spindown offset (where disk stops)
373 | | | | | | | | Select delay
374 | | | | | | | | | RPS
375 | | | | | | | | | | Max number of tracks
376 | | | | | | | | | | | Interrupt timeout
377 | | | | | | | | | | | | Max nonintlv. sectors
378 | | | | | | | | | | | | | -Max Errors- flags */
379{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
380 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
381
382{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
383 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
384
385{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
386 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
387
388{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
389 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
390
391{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
392 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
393
394{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
395 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
396
397{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
398 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
399/* | --autodetected formats--- | | |
400 * read_track | | Name printed when booting
401 * | Native format
402 * Frequency of disk change checks */
403};
404
405static struct floppy_drive_params drive_params[N_DRIVE];
406static struct floppy_drive_struct drive_state[N_DRIVE];
407static struct floppy_write_errors write_errors[N_DRIVE];
408static struct timer_list motor_off_timer[N_DRIVE];
409static struct gendisk *disks[N_DRIVE];
Omar Sandovala9f38e12018-10-15 09:21:34 -0600410static struct blk_mq_tag_set tag_sets[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800412static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
414
415/*
416 * This struct defines the different floppy types.
417 *
418 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
419 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
420 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
421 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
422 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
423 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
424 * side 0 is on physical side 0 (but with the misnamed sector IDs).
425 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700426 * 'options'.
427 *
428 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
429 * The LSB (bit 2) is flipped. For most disks, the first sector
430 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
431 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
432 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
433 *
434 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 */
436/*
437 Size
438 | Sectors per track
439 | | Head
440 | | | Tracks
441 | | | | Stretch
442 | | | | | Gap 1 size
443 | | | | | | Data rate, | 0x40 for perp
444 | | | | | | | Spec1 (stepping rate, head unload
445 | | | | | | | | /fmt gap (gap2) */
446static struct floppy_struct floppy_type[32] = {
447 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
448 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
449 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
450 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
451 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
452 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
453 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
454 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
455 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
456 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
457
458 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
459 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
460 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
461 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
462 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
463 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
464 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
465 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
466 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
467 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
468
469 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
470 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
471 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
472 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
473 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
474 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
475 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
476 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
477 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
481 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
482};
483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484#define SECTSIZE (_FD_SECTSIZE(*floppy))
485
486/* Auto-detection: Disk type used until the next media change occurs. */
487static struct floppy_struct *current_type[N_DRIVE];
488
489/*
490 * User-provided type information. current_type points to
491 * the respective entry of this array.
492 */
493static struct floppy_struct user_params[N_DRIVE];
494
495static sector_t floppy_sizes[256];
496
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200497static char floppy_device_name[] = "floppy";
498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499/*
500 * The driver is trying to determine the correct media format
501 * while probing is set. rw_interrupt() clears it after a
502 * successful access.
503 */
504static int probing;
505
506/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800507#define FD_COMMAND_NONE -1
508#define FD_COMMAND_ERROR 2
509#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
511static volatile int command_status = FD_COMMAND_NONE;
512static unsigned long fdc_busy;
513static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
514static DECLARE_WAIT_QUEUE_HEAD(command_done);
515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516/* Errors during formatting are counted here. */
517static int format_errors;
518
519/* Format request descriptor. */
520static struct format_descr format_req;
521
522/*
523 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
524 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
525 * H is head unload time (1=16ms, 2=32ms, etc)
526 */
527
528/*
529 * Track buffer
530 * Because these are written to by the DMA controller, they must
531 * not contain a 64k byte boundary crossing, or data will be
532 * corrupted/lost.
533 */
534static char *floppy_track_buffer;
535static int max_buffer_sectors;
536
537static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700538typedef void (*done_f)(int);
Stephen Hemminger3b06c212010-07-20 20:09:00 -0600539static const struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800540 void (*interrupt)(void);
541 /* this is called after the interrupt of the
542 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700543 void (*redo)(void); /* this is called to retry the operation */
544 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 done_f done; /* this is called to say if the operation has
546 * succeeded/failed */
547} *cont;
548
549static void floppy_ready(void);
550static void floppy_start(void);
551static void process_fd_request(void);
552static void recalibrate_floppy(void);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200553static void floppy_shutdown(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800555static int floppy_request_regions(int);
556static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557static int floppy_grab_irq_and_dma(void);
558static void floppy_release_irq_and_dma(void);
559
560/*
561 * The "reset" variable should be tested whenever an interrupt is scheduled,
562 * after the commands have been sent. This is to ensure that the driver doesn't
563 * get wedged when the interrupt doesn't come because of a failed command.
564 * reset doesn't need to be tested before sending commands, because
565 * output_byte is automatically disabled when reset is set.
566 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567static void reset_fdc(void);
568
569/*
570 * These are global variables, as that's the easiest way to give
571 * information to interrupts. They are the data used for the current
572 * request.
573 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800574#define NO_TRACK -1
575#define NEED_1_RECAL -2
576#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200578static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580/* buffer related variables */
581static int buffer_track = -1;
582static int buffer_drive = -1;
583static int buffer_min = -1;
584static int buffer_max = -1;
585
586/* fdc related variables, should end up in a struct */
587static struct floppy_fdc_state fdc_state[N_FDC];
588static int fdc; /* current fdc */
589
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200590static struct workqueue_struct *floppy_wq;
591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592static struct floppy_struct *_floppy = floppy_type;
593static unsigned char current_drive;
594static long current_count_sectors;
595static unsigned char fsector_t; /* sector in track */
596static unsigned char in_sector_offset; /* offset within physical sector,
597 * expressed in units of 512 bytes */
598
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100599static inline bool drive_no_geom(int drive)
600{
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100601 return !current_type[drive] && !ITYPE(drive_state[drive].fd_device);
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100602}
603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604#ifndef fd_eject
605static inline int fd_eject(int drive)
606{
607 return -EINVAL;
608}
609#endif
610
611/*
612 * Debugging
613 * =========
614 */
615#ifdef DEBUGT
616static long unsigned debugtimer;
617
618static inline void set_debugt(void)
619{
620 debugtimer = jiffies;
621}
622
Joe Perchesded28632010-03-10 15:21:09 -0800623static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Willy Tarreau031faab2020-02-24 22:23:48 +0100625 if (drive_params[current_drive].flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800626 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627}
628#else
629static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800630static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631#endif /* DEBUGT */
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200634static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635static const char *timeout_message;
636
Joe Perches275176b2010-03-10 15:21:06 -0800637static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
639 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800640 if (test_bit(0, &fdc_busy) && command_status < 2 &&
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200641 !delayed_work_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800642 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Joe Perches48c8cee2010-03-10 15:20:45 -0800646static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648#define OLOGSIZE 20
649
Joe Perches48c8cee2010-03-10 15:20:45 -0800650static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651static unsigned long interruptjiffies;
652static unsigned long resultjiffies;
653static int resultsize;
654static unsigned long lastredo;
655
656static struct output_log {
657 unsigned char data;
658 unsigned char status;
659 unsigned long jiffies;
660} output_log[OLOGSIZE];
661
662static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664#define current_reqD -1
665#define MAXTIMEOUT -2
666
Joe Perches73507e62010-03-10 15:21:03 -0800667static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200669 unsigned long delay;
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (drive == current_reqD)
672 drive = current_drive;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200673
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700674 if (drive < 0 || drive >= N_DRIVE) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200675 delay = 20UL * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 drive = 0;
677 } else
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100678 delay = drive_params[drive].timeout;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200679
Tejun Heoe7c2f962012-08-21 13:18:24 -0700680 mod_delayed_work(floppy_wq, &fd_timeout, delay);
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100681 if (drive_params[drive].flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800682 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 timeout_message = message;
684}
685
Joe Perches73507e62010-03-10 15:21:03 -0800686static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
688 unsigned long flags;
689
690 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800691 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 spin_unlock_irqrestore(&floppy_lock, flags);
693}
694
Joe Perches48c8cee2010-03-10 15:20:45 -0800695#define INFBOUND(a, b) (a) = max_t(int, a, b)
696#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698/*
699 * Bottom half floppy driver.
700 * ==========================
701 *
702 * This part of the file contains the code talking directly to the hardware,
703 * and also the main service loop (seek-configure-spinup-command)
704 */
705
706/*
707 * disk change.
708 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
709 * and the last_checked date.
710 *
711 * last_checked is the date of the last check which showed 'no disk change'
712 * FD_DISK_CHANGE is set under two conditions:
713 * 1. The floppy has been changed after some i/o to that floppy already
714 * took place.
715 * 2. No floppy disk is in the drive. This is done in order to ensure that
716 * requests are quickly flushed in case there is no disk in the drive. It
717 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
718 * the drive.
719 *
720 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
721 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
722 * each seek. If a disk is present, the disk change line should also be
723 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
724 * change line is set, this means either that no disk is in the drive, or
725 * that it has been removed since the last seek.
726 *
727 * This means that we really have a third possibility too:
728 * The floppy has been changed after the last seek.
729 */
730
731static int disk_change(int drive)
732{
733 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700734
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100735 if (time_before(jiffies, drive_state[drive].select_date + drive_params[drive].select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 DPRINT("WARNING disk change called early\n");
Willy Tarreaude6048b2020-02-24 22:23:43 +0100737 if (!(fdc_state[fdc].dor & (0x10 << UNIT(drive))) ||
738 (fdc_state[fdc].dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 DPRINT("probing disk change on unselected drive\n");
740 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
Willy Tarreaude6048b2020-02-24 22:23:43 +0100741 (unsigned int)fdc_state[fdc].dor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100744 debug_dcl(drive_params[drive].flags,
Joe Perches87f530d2010-03-10 15:20:54 -0800745 "checking disk change line for drive %d\n", drive);
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100746 debug_dcl(drive_params[drive].flags, "jiffies=%lu\n", jiffies);
747 debug_dcl(drive_params[drive].flags, "disk change line=%x\n",
748 fd_inb(FD_DIR) & 0x80);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100749 debug_dcl(drive_params[drive].flags, "flags=%lx\n",
750 drive_state[drive].flags);
Joe Perches87f530d2010-03-10 15:20:54 -0800751
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100752 if (drive_params[drive].flags & FD_BROKEN_DCL)
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100753 return test_bit(FD_DISK_CHANGED_BIT,
754 &drive_state[drive].flags);
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100755 if ((fd_inb(FD_DIR) ^ drive_params[drive].flags) & 0x80) {
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100756 set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
Joe Perchese0298532010-03-10 15:20:55 -0800757 /* verify write protection */
758
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100759 if (drive_state[drive].maxblock) /* mark it changed */
760 set_bit(FD_DISK_CHANGED_BIT,
761 &drive_state[drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763 /* invalidate its geometry */
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100764 if (drive_state[drive].keep_data >= 0) {
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100765 if ((drive_params[drive].flags & FTD_MSG) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800767 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 current_type[drive] = NULL;
769 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
770 }
771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return 1;
773 } else {
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100774 drive_state[drive].last_checked = jiffies;
775 clear_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
777 return 0;
778}
779
780static inline int is_selected(int dor, int unit)
781{
782 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
783}
784
Joe Perches57584c52010-03-10 15:21:00 -0800785static bool is_ready_state(int status)
786{
787 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
788 return state == STATUS_READY;
789}
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791static int set_dor(int fdc, char mask, char data)
792{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700793 unsigned char unit;
794 unsigned char drive;
795 unsigned char newdor;
796 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Willy Tarreaude6048b2020-02-24 22:23:43 +0100798 if (fdc_state[fdc].address == -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 return -1;
800
Willy Tarreaude6048b2020-02-24 22:23:43 +0100801 olddor = fdc_state[fdc].dor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 newdor = (olddor & mask) | data;
803 if (newdor != olddor) {
804 unit = olddor & 0x3;
805 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
806 drive = REVDRIVE(fdc, unit);
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100807 debug_dcl(drive_params[drive].flags,
Joe Perches87f530d2010-03-10 15:20:54 -0800808 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 disk_change(drive);
810 }
Willy Tarreaude6048b2020-02-24 22:23:43 +0100811 fdc_state[fdc].dor = newdor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 fd_outb(newdor, FD_DOR);
813
814 unit = newdor & 0x3;
815 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
816 drive = REVDRIVE(fdc, unit);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100817 drive_state[drive].select_date = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 return olddor;
821}
822
823static void twaddle(void)
824{
Willy Tarreau031faab2020-02-24 22:23:48 +0100825 if (drive_params[current_drive].select_delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 return;
Willy Tarreaude6048b2020-02-24 22:23:43 +0100827 fd_outb(fdc_state[fdc].dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
828 fd_outb(fdc_state[fdc].dor, FD_DOR);
Willy Tarreau3bd7f872020-02-24 22:23:49 +0100829 drive_state[current_drive].select_date = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830}
831
Joe Perches57584c52010-03-10 15:21:00 -0800832/*
833 * Reset all driver information about the current fdc.
834 * This is needed after a reset, and after a raw command.
835 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836static void reset_fdc_info(int mode)
837{
838 int drive;
839
Willy Tarreaude6048b2020-02-24 22:23:43 +0100840 fdc_state[fdc].spec1 = fdc_state[fdc].spec2 = -1;
841 fdc_state[fdc].need_configure = 1;
842 fdc_state[fdc].perp_mode = 1;
843 fdc_state[fdc].rawcmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 for (drive = 0; drive < N_DRIVE; drive++)
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100845 if (FDC(drive) == fdc && (mode || drive_state[drive].track != NEED_1_RECAL))
846 drive_state[drive].track = NEED_2_RECAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847}
848
849/* selects the fdc and drive, and enables the fdc's input/dma. */
850static void set_fdc(int drive)
851{
Linus Torvalds2e90ca62020-02-21 12:43:35 -0800852 unsigned int new_fdc = fdc;
853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 if (drive >= 0 && drive < N_DRIVE) {
Linus Torvalds2e90ca62020-02-21 12:43:35 -0800855 new_fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 current_drive = drive;
857 }
Linus Torvalds2e90ca62020-02-21 12:43:35 -0800858 if (new_fdc >= N_FDC) {
Joe Perchesb46df352010-03-10 15:20:46 -0800859 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 return;
861 }
Linus Torvalds2e90ca62020-02-21 12:43:35 -0800862 fdc = new_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 set_dor(fdc, ~0, 8);
864#if N_FDC > 1
865 set_dor(1 - fdc, ~8, 0);
866#endif
Willy Tarreaude6048b2020-02-24 22:23:43 +0100867 if (fdc_state[fdc].rawcmd == 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 reset_fdc_info(1);
869 if (fd_inb(FD_STATUS) != STATUS_READY)
Willy Tarreaude6048b2020-02-24 22:23:43 +0100870 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871}
872
873/* locks the driver */
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +0100874static int lock_fdc(int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200876 if (WARN(atomic_read(&usage_count) == 0,
877 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200880 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
881 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 command_status = FD_COMMAND_NONE;
884
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200885 reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 set_fdc(drive);
887 return 0;
888}
889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200891static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 if (!test_bit(0, &fdc_busy))
894 DPRINT("FDC access conflict!\n");
895
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200896 raw_cmd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 command_status = FD_COMMAND_NONE;
Tejun Heo136b5722012-08-21 13:18:24 -0700898 cancel_delayed_work(&fd_timeout);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200899 do_floppy = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 cont = NULL;
901 clear_bit(0, &fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 wake_up(&fdc_wait);
903}
904
905/* switches the motor off after a given timeout */
Kees Cookb1bf4212017-10-04 17:49:29 -0700906static void motor_off_callback(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
Kees Cookb1bf4212017-10-04 17:49:29 -0700908 unsigned long nr = t - motor_off_timer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 unsigned char mask = ~(0x10 << UNIT(nr));
910
Kees Cookb1bf4212017-10-04 17:49:29 -0700911 if (WARN_ON_ONCE(nr >= N_DRIVE))
912 return;
913
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 set_dor(FDC(nr), mask, 0);
915}
916
917/* schedules motor off */
918static void floppy_off(unsigned int drive)
919{
920 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700921 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Willy Tarreaude6048b2020-02-24 22:23:43 +0100923 if (!(fdc_state[fdc].dor & (0x10 << UNIT(drive))))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 return;
925
926 del_timer(motor_off_timer + drive);
927
928 /* make spindle stop in a position which minimizes spinup time
929 * next time */
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100930 if (drive_params[drive].rps) {
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100931 delta = jiffies - drive_state[drive].first_read_date + HZ -
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100932 drive_params[drive].spindown_offset;
933 delta = ((delta * drive_params[drive].rps) % HZ) / drive_params[drive].rps;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 motor_off_timer[drive].expires =
Willy Tarreau1ce9ae92020-02-24 22:23:45 +0100935 jiffies + drive_params[drive].spindown - delta;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 }
937 add_timer(motor_off_timer + drive);
938}
939
940/*
941 * cycle through all N_DRIVE floppy drives, for disk change testing.
942 * stopping at current drive. This is done before any long operation, to
943 * be sure to have up to date disk change information.
944 */
945static void scandrives(void)
946{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700947 int i;
948 int drive;
949 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
Willy Tarreau031faab2020-02-24 22:23:48 +0100951 if (drive_params[current_drive].select_delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 return;
953
954 saved_drive = current_drive;
955 for (i = 0; i < N_DRIVE; i++) {
956 drive = (saved_drive + i + 1) % N_DRIVE;
Willy Tarreau8d9d34e22020-02-24 22:23:46 +0100957 if (drive_state[drive].fd_ref == 0 || drive_params[drive].select_delay != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 continue; /* skip closed drives */
959 set_fdc(drive);
960 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
961 (0x10 << UNIT(drive))))
962 /* switch the motor off again, if it was off to
963 * begin with */
964 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
965 }
966 set_fdc(saved_drive);
967}
968
969static void empty(void)
970{
971}
972
Tejun Heo75ddb382014-03-07 10:24:48 -0500973static void (*floppy_work_fn)(void);
974
975static void floppy_work_workfn(struct work_struct *work)
976{
977 floppy_work_fn();
978}
979
980static DECLARE_WORK(floppy_work, floppy_work_workfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Joe Perches48c8cee2010-03-10 15:20:45 -0800982static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200984 WARN_ON(work_pending(&floppy_work));
985
Tejun Heo75ddb382014-03-07 10:24:48 -0500986 floppy_work_fn = handler;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200987 queue_work(floppy_wq, &floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988}
989
Tejun Heo75ddb382014-03-07 10:24:48 -0500990static void (*fd_timer_fn)(void) = NULL;
991
992static void fd_timer_workfn(struct work_struct *work)
993{
994 fd_timer_fn();
995}
996
997static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
999static void cancel_activity(void)
1000{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 do_floppy = NULL;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001002 cancel_delayed_work_sync(&fd_timer);
1003 cancel_work_sync(&floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004}
1005
1006/* this function makes sure that the disk stays in the drive during the
1007 * transfer */
Tejun Heo75ddb382014-03-07 10:24:48 -05001008static void fd_watchdog(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{
Willy Tarreau031faab2020-02-24 22:23:48 +01001010 debug_dcl(drive_params[current_drive].flags,
1011 "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013 if (disk_change(current_drive)) {
1014 DPRINT("disk removed during i/o\n");
1015 cancel_activity();
1016 cont->done(0);
1017 reset_fdc();
1018 } else {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001019 cancel_delayed_work(&fd_timer);
Tejun Heo75ddb382014-03-07 10:24:48 -05001020 fd_timer_fn = fd_watchdog;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001021 queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
1023}
1024
1025static void main_command_interrupt(void)
1026{
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001027 cancel_delayed_work(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 cont->interrupt();
1029}
1030
1031/* waits for a delay (spinup or select) to pass */
Tejun Heo75ddb382014-03-07 10:24:48 -05001032static int fd_wait_for_completion(unsigned long expires,
1033 void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034{
Willy Tarreaude6048b2020-02-24 22:23:43 +01001035 if (fdc_state[fdc].reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 reset_fdc(); /* do the reset during sleep to win time
1037 * if we don't need to sleep, it's a good
1038 * occasion anyways */
1039 return 1;
1040 }
1041
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001042 if (time_before(jiffies, expires)) {
1043 cancel_delayed_work(&fd_timer);
Tejun Heo75ddb382014-03-07 10:24:48 -05001044 fd_timer_fn = function;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001045 queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return 1;
1047 }
1048 return 0;
1049}
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051static void setup_DMA(void)
1052{
1053 unsigned long f;
1054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 if (raw_cmd->length == 0) {
1056 int i;
1057
Joe Perchesb46df352010-03-10 15:20:46 -08001058 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001060 pr_cont("%x,", raw_cmd->cmd[i]);
1061 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 cont->done(0);
Willy Tarreaude6048b2020-02-24 22:23:43 +01001063 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return;
1065 }
1066 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001067 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 cont->done(0);
Willy Tarreaude6048b2020-02-24 22:23:43 +01001069 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 return;
1071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 f = claim_dma_lock();
1073 fd_disable_dma();
1074#ifdef fd_dma_setup
1075 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1076 (raw_cmd->flags & FD_RAW_READ) ?
Willy Tarreaude6048b2020-02-24 22:23:43 +01001077 DMA_MODE_READ : DMA_MODE_WRITE, fdc_state[fdc].address) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 release_dma_lock(f);
1079 cont->done(0);
Willy Tarreaude6048b2020-02-24 22:23:43 +01001080 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 return;
1082 }
1083 release_dma_lock(f);
1084#else
1085 fd_clear_dma_ff();
1086 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1087 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1088 DMA_MODE_READ : DMA_MODE_WRITE);
1089 fd_set_dma_addr(raw_cmd->kernel_data);
1090 fd_set_dma_count(raw_cmd->length);
Willy Tarreaude6048b2020-02-24 22:23:43 +01001091 virtual_dma_port = fdc_state[fdc].address;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 fd_enable_dma();
1093 release_dma_lock(f);
1094#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
1097static void show_floppy(void);
1098
1099/* waits until the fdc becomes ready */
1100static int wait_til_ready(void)
1101{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001102 int status;
1103 int counter;
1104
Willy Tarreaude6048b2020-02-24 22:23:43 +01001105 if (fdc_state[fdc].reset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 return -1;
1107 for (counter = 0; counter < 10000; counter++) {
1108 status = fd_inb(FD_STATUS);
1109 if (status & STATUS_READY)
1110 return status;
1111 }
Joe Perches29f1c782010-03-10 15:21:00 -08001112 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1114 show_floppy();
1115 }
Willy Tarreaude6048b2020-02-24 22:23:43 +01001116 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 return -1;
1118}
1119
1120/* sends a command byte to the fdc */
1121static int output_byte(char byte)
1122{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001123 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001125 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001127
1128 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 output_log[output_log_pos].data = byte;
1131 output_log[output_log_pos].status = status;
1132 output_log[output_log_pos].jiffies = jiffies;
1133 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 return 0;
1135 }
Willy Tarreaude6048b2020-02-24 22:23:43 +01001136 fdc_state[fdc].reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001137 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1139 byte, fdc, status);
1140 show_floppy();
1141 }
1142 return -1;
1143}
1144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145/* gets the response from the fdc */
1146static int result(void)
1147{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001148 int i;
1149 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001152 status = wait_til_ready();
1153 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 break;
1155 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1156 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 resultjiffies = jiffies;
1158 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 return i;
1160 }
1161 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1162 reply_buffer[i] = fd_inb(FD_DATA);
1163 else
1164 break;
1165 }
Joe Perches29f1c782010-03-10 15:21:00 -08001166 if (initialized) {
1167 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1168 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 show_floppy();
1170 }
Willy Tarreaude6048b2020-02-24 22:23:43 +01001171 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return -1;
1173}
1174
1175#define MORE_OUTPUT -2
1176/* does the fdc need more output? */
1177static int need_more_output(void)
1178{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001179 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001180
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001181 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001183
1184 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001186
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 return result();
1188}
1189
1190/* Set perpendicular mode as required, based on data rate, if supported.
1191 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1192 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001193static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
1195 unsigned char perp_mode;
1196
1197 if (raw_cmd->rate & 0x40) {
1198 switch (raw_cmd->rate & 3) {
1199 case 0:
1200 perp_mode = 2;
1201 break;
1202 case 3:
1203 perp_mode = 3;
1204 break;
1205 default:
1206 DPRINT("Invalid data rate for perpendicular mode!\n");
1207 cont->done(0);
Willy Tarreaude6048b2020-02-24 22:23:43 +01001208 fdc_state[fdc].reset = 1;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001209 /*
1210 * convenient way to return to
1211 * redo without too much hassle
1212 * (deep stack et al.)
1213 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 return;
1215 }
1216 } else
1217 perp_mode = 0;
1218
Willy Tarreaude6048b2020-02-24 22:23:43 +01001219 if (fdc_state[fdc].perp_mode == perp_mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 return;
Willy Tarreaude6048b2020-02-24 22:23:43 +01001221 if (fdc_state[fdc].version >= FDC_82077_ORIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 output_byte(FD_PERPENDICULAR);
1223 output_byte(perp_mode);
Willy Tarreaude6048b2020-02-24 22:23:43 +01001224 fdc_state[fdc].perp_mode = perp_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 } else if (perp_mode) {
1226 DPRINT("perpendicular mode not supported by this FDC.\n");
1227 }
1228} /* perpendicular_mode */
1229
1230static int fifo_depth = 0xa;
1231static int no_fifo;
1232
1233static int fdc_configure(void)
1234{
1235 /* Turn on FIFO */
1236 output_byte(FD_CONFIGURE);
1237 if (need_more_output() != MORE_OUTPUT)
1238 return 0;
1239 output_byte(0);
1240 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1241 output_byte(0); /* pre-compensation from track
1242 0 upwards */
1243 return 1;
1244}
1245
1246#define NOMINAL_DTR 500
1247
1248/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1249 * head load time, and DMA disable flag to values needed by floppy.
1250 *
1251 * The value "dtr" is the data transfer rate in Kbps. It is needed
1252 * to account for the data rate-based scaling done by the 82072 and 82077
1253 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1254 * 8272a).
1255 *
1256 * Note that changing the data transfer rate has a (probably deleterious)
1257 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1258 * fdc_specify is called again after each data transfer rate
1259 * change.
1260 *
1261 * srt: 1000 to 16000 in microseconds
1262 * hut: 16 to 240 milliseconds
1263 * hlt: 2 to 254 milliseconds
1264 *
1265 * These values are rounded up to the next highest available delay time.
1266 */
1267static void fdc_specify(void)
1268{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001269 unsigned char spec1;
1270 unsigned char spec2;
1271 unsigned long srt;
1272 unsigned long hlt;
1273 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 unsigned long dtr = NOMINAL_DTR;
1275 unsigned long scale_dtr = NOMINAL_DTR;
1276 int hlt_max_code = 0x7f;
1277 int hut_max_code = 0xf;
1278
Willy Tarreaude6048b2020-02-24 22:23:43 +01001279 if (fdc_state[fdc].need_configure && fdc_state[fdc].version >= FDC_82072A) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 fdc_configure();
Willy Tarreaude6048b2020-02-24 22:23:43 +01001281 fdc_state[fdc].need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 }
1283
1284 switch (raw_cmd->rate & 0x03) {
1285 case 3:
1286 dtr = 1000;
1287 break;
1288 case 1:
1289 dtr = 300;
Willy Tarreaude6048b2020-02-24 22:23:43 +01001290 if (fdc_state[fdc].version >= FDC_82078) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 /* chose the default rate table, not the one
1292 * where 1 = 2 Mbps */
1293 output_byte(FD_DRIVESPEC);
1294 if (need_more_output() == MORE_OUTPUT) {
1295 output_byte(UNIT(current_drive));
1296 output_byte(0xc0);
1297 }
1298 }
1299 break;
1300 case 2:
1301 dtr = 250;
1302 break;
1303 }
1304
Willy Tarreaude6048b2020-02-24 22:23:43 +01001305 if (fdc_state[fdc].version >= FDC_82072) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 scale_dtr = dtr;
1307 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1308 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1309 }
1310
1311 /* Convert step rate from microseconds to milliseconds and 4 bits */
Willy Tarreau031faab2020-02-24 22:23:48 +01001312 srt = 16 - DIV_ROUND_UP(drive_params[current_drive].srt * scale_dtr / 1000,
1313 NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001314 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001316
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 SUPBOUND(srt, 0xf);
1318 INFBOUND(srt, 0);
1319
Willy Tarreau031faab2020-02-24 22:23:48 +01001320 hlt = DIV_ROUND_UP(drive_params[current_drive].hlt * scale_dtr / 2,
1321 NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (hlt < 0x01)
1323 hlt = 0x01;
1324 else if (hlt > 0x7f)
1325 hlt = hlt_max_code;
1326
Willy Tarreau031faab2020-02-24 22:23:48 +01001327 hut = DIV_ROUND_UP(drive_params[current_drive].hut * scale_dtr / 16,
1328 NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 if (hut < 0x1)
1330 hut = 0x1;
1331 else if (hut > 0xf)
1332 hut = hut_max_code;
1333
1334 spec1 = (srt << 4) | hut;
1335 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1336
1337 /* If these parameters did not change, just return with success */
Willy Tarreaude6048b2020-02-24 22:23:43 +01001338 if (fdc_state[fdc].spec1 != spec1 || fdc_state[fdc].spec2 != spec2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 /* Go ahead and set spec1 and spec2 */
1340 output_byte(FD_SPECIFY);
Willy Tarreaude6048b2020-02-24 22:23:43 +01001341 output_byte(fdc_state[fdc].spec1 = spec1);
1342 output_byte(fdc_state[fdc].spec2 = spec2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 }
1344} /* fdc_specify */
1345
1346/* Set the FDC's data transfer rate on behalf of the specified drive.
1347 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1348 * of the specify command (i.e. using the fdc_specify function).
1349 */
1350static int fdc_dtr(void)
1351{
1352 /* If data rate not already set to desired value, set it. */
Willy Tarreaude6048b2020-02-24 22:23:43 +01001353 if ((raw_cmd->rate & 3) == fdc_state[fdc].dtr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 return 0;
1355
1356 /* Set dtr */
1357 fd_outb(raw_cmd->rate & 3, FD_DCR);
1358
1359 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1360 * need a stabilization period of several milliseconds to be
1361 * enforced after data rate changes before R/W operations.
1362 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1363 */
Willy Tarreaude6048b2020-02-24 22:23:43 +01001364 fdc_state[fdc].dtr = raw_cmd->rate & 3;
Tejun Heo75ddb382014-03-07 10:24:48 -05001365 return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366} /* fdc_dtr */
1367
1368static void tell_sector(void)
1369{
Joe Perchesb46df352010-03-10 15:20:46 -08001370 pr_cont(": track %d, head %d, sector %d, size %d",
1371 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372} /* tell_sector */
1373
Joe Perchesb46df352010-03-10 15:20:46 -08001374static void print_errors(void)
1375{
1376 DPRINT("");
1377 if (ST0 & ST0_ECE) {
1378 pr_cont("Recalibrate failed!");
1379 } else if (ST2 & ST2_CRC) {
1380 pr_cont("data CRC error");
1381 tell_sector();
1382 } else if (ST1 & ST1_CRC) {
1383 pr_cont("CRC error");
1384 tell_sector();
1385 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1386 (ST2 & ST2_MAM)) {
1387 if (!probing) {
1388 pr_cont("sector not found");
1389 tell_sector();
1390 } else
1391 pr_cont("probe failed...");
1392 } else if (ST2 & ST2_WC) { /* seek error */
1393 pr_cont("wrong cylinder");
1394 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1395 pr_cont("bad cylinder");
1396 } else {
1397 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1398 ST0, ST1, ST2);
1399 tell_sector();
1400 }
1401 pr_cont("\n");
1402}
1403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404/*
1405 * OK, this error interpreting routine is called after a
1406 * DMA read/write has succeeded
1407 * or failed, so we check the results, and copy any buffers.
1408 * hhb: Added better error reporting.
1409 * ak: Made this into a separate routine.
1410 */
1411static int interpret_errors(void)
1412{
1413 char bad;
1414
1415 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001416 DPRINT("-- FDC reply error\n");
Willy Tarreaude6048b2020-02-24 22:23:43 +01001417 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 return 1;
1419 }
1420
1421 /* check IC to find cause of interrupt */
1422 switch (ST0 & ST0_INTR) {
1423 case 0x40: /* error occurred during command execution */
1424 if (ST1 & ST1_EOC)
1425 return 0; /* occurs with pseudo-DMA */
1426 bad = 1;
1427 if (ST1 & ST1_WP) {
1428 DPRINT("Drive is write protected\n");
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001429 clear_bit(FD_DISK_WRITABLE_BIT,
1430 &drive_state[current_drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 cont->done(0);
1432 bad = 2;
1433 } else if (ST1 & ST1_ND) {
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001434 set_bit(FD_NEED_TWADDLE_BIT,
1435 &drive_state[current_drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 } else if (ST1 & ST1_OR) {
Willy Tarreau031faab2020-02-24 22:23:48 +01001437 if (drive_params[current_drive].flags & FTD_MSG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 DPRINT("Over/Underrun - retrying\n");
1439 bad = 0;
Willy Tarreau031faab2020-02-24 22:23:48 +01001440 } else if (*errors >= drive_params[current_drive].max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001441 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 }
1443 if (ST2 & ST2_WC || ST2 & ST2_BC)
1444 /* wrong cylinder => recal */
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001445 drive_state[current_drive].track = NEED_2_RECAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 return bad;
1447 case 0x80: /* invalid command given */
1448 DPRINT("Invalid FDC command given!\n");
1449 cont->done(0);
1450 return 2;
1451 case 0xc0:
1452 DPRINT("Abnormal termination caused by polling\n");
1453 cont->error();
1454 return 2;
1455 default: /* (0) Normal command termination */
1456 return 0;
1457 }
1458}
1459
1460/*
1461 * This routine is called when everything should be correctly set up
1462 * for the transfer (i.e. floppy motor is on, the correct floppy is
1463 * selected, and the head is sitting on the right track).
1464 */
1465static void setup_rw_floppy(void)
1466{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001467 int i;
1468 int r;
1469 int flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 unsigned long ready_date;
Tejun Heo75ddb382014-03-07 10:24:48 -05001471 void (*function)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
1473 flags = raw_cmd->flags;
1474 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1475 flags |= FD_RAW_INTR;
1476
1477 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001478 ready_date = drive_state[current_drive].spinup_date + drive_params[current_drive].spinup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 /* If spinup will take a long time, rerun scandrives
1480 * again just before spinup completion. Beware that
1481 * after scandrives, we must again wait for selection.
1482 */
Willy Tarreau031faab2020-02-24 22:23:48 +01001483 if (time_after(ready_date, jiffies + drive_params[current_drive].select_delay)) {
1484 ready_date -= drive_params[current_drive].select_delay;
Tejun Heo75ddb382014-03-07 10:24:48 -05001485 function = floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 } else
Tejun Heo75ddb382014-03-07 10:24:48 -05001487 function = setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
1489 /* wait until the floppy is spinning fast enough */
1490 if (fd_wait_for_completion(ready_date, function))
1491 return;
1492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1494 setup_DMA();
1495
1496 if (flags & FD_RAW_INTR)
1497 do_floppy = main_command_interrupt;
1498
1499 r = 0;
1500 for (i = 0; i < raw_cmd->cmd_count; i++)
1501 r |= output_byte(raw_cmd->cmd[i]);
1502
Joe Perchesded28632010-03-10 15:21:09 -08001503 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 if (r) {
1506 cont->error();
1507 reset_fdc();
1508 return;
1509 }
1510
1511 if (!(flags & FD_RAW_INTR)) {
1512 inr = result();
1513 cont->interrupt();
1514 } else if (flags & FD_RAW_NEED_DISK)
Tejun Heo75ddb382014-03-07 10:24:48 -05001515 fd_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516}
1517
1518static int blind_seek;
1519
1520/*
1521 * This is the routine called after every seek (or recalibrate) interrupt
1522 * from the floppy controller.
1523 */
1524static void seek_interrupt(void)
1525{
Joe Perchesded28632010-03-10 15:21:09 -08001526 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1528 DPRINT("seek failed\n");
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001529 drive_state[current_drive].track = NEED_2_RECAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 cont->error();
1531 cont->redo();
1532 return;
1533 }
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001534 if (drive_state[current_drive].track >= 0 && drive_state[current_drive].track != ST1 && !blind_seek) {
Willy Tarreau031faab2020-02-24 22:23:48 +01001535 debug_dcl(drive_params[current_drive].flags,
Joe Perches87f530d2010-03-10 15:20:54 -08001536 "clearing NEWCHANGE flag because of effective seek\n");
Willy Tarreau031faab2020-02-24 22:23:48 +01001537 debug_dcl(drive_params[current_drive].flags, "jiffies=%lu\n",
1538 jiffies);
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001539 clear_bit(FD_DISK_NEWCHANGE_BIT,
1540 &drive_state[current_drive].flags);
Joe Perchese0298532010-03-10 15:20:55 -08001541 /* effective seek */
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001542 drive_state[current_drive].select_date = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 }
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001544 drive_state[current_drive].track = ST1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 floppy_ready();
1546}
1547
1548static void check_wp(void)
1549{
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001550 if (test_bit(FD_VERIFY_BIT, &drive_state[current_drive].flags)) {
Joe Perchese0298532010-03-10 15:20:55 -08001551 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 output_byte(FD_GETSTATUS);
1553 output_byte(UNIT(current_drive));
1554 if (result() != 1) {
Willy Tarreaude6048b2020-02-24 22:23:43 +01001555 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 return;
1557 }
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001558 clear_bit(FD_VERIFY_BIT, &drive_state[current_drive].flags);
1559 clear_bit(FD_NEED_TWADDLE_BIT,
1560 &drive_state[current_drive].flags);
Willy Tarreau031faab2020-02-24 22:23:48 +01001561 debug_dcl(drive_params[current_drive].flags,
Joe Perches87f530d2010-03-10 15:20:54 -08001562 "checking whether disk is write protected\n");
Willy Tarreau031faab2020-02-24 22:23:48 +01001563 debug_dcl(drive_params[current_drive].flags, "wp=%x\n",
1564 ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 if (!(ST3 & 0x40))
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001566 set_bit(FD_DISK_WRITABLE_BIT,
1567 &drive_state[current_drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 else
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001569 clear_bit(FD_DISK_WRITABLE_BIT,
1570 &drive_state[current_drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 }
1572}
1573
1574static void seek_floppy(void)
1575{
1576 int track;
1577
1578 blind_seek = 0;
1579
Willy Tarreau031faab2020-02-24 22:23:48 +01001580 debug_dcl(drive_params[current_drive].flags,
1581 "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001583 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1585 /* the media changed flag should be cleared after the seek.
1586 * If it isn't, this means that there is really no disk in
1587 * the drive.
1588 */
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001589 set_bit(FD_DISK_CHANGED_BIT,
1590 &drive_state[current_drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 cont->done(0);
1592 cont->redo();
1593 return;
1594 }
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001595 if (drive_state[current_drive].track <= NEED_1_RECAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 recalibrate_floppy();
1597 return;
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001598 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001600 (drive_state[current_drive].track <= NO_TRACK || drive_state[current_drive].track == raw_cmd->track)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 /* we seek to clear the media-changed condition. Does anybody
1602 * know a more elegant way, which works on all drives? */
1603 if (raw_cmd->track)
1604 track = raw_cmd->track - 1;
1605 else {
Willy Tarreau031faab2020-02-24 22:23:48 +01001606 if (drive_params[current_drive].flags & FD_SILENT_DCL_CLEAR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1608 blind_seek = 1;
1609 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1610 }
1611 track = 1;
1612 }
1613 } else {
1614 check_wp();
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001615 if (raw_cmd->track != drive_state[current_drive].track &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1617 track = raw_cmd->track;
1618 else {
1619 setup_rw_floppy();
1620 return;
1621 }
1622 }
1623
1624 do_floppy = seek_interrupt;
1625 output_byte(FD_SEEK);
1626 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001627 if (output_byte(track) < 0) {
1628 reset_fdc();
1629 return;
1630 }
Joe Perchesded28632010-03-10 15:21:09 -08001631 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632}
1633
1634static void recal_interrupt(void)
1635{
Joe Perchesded28632010-03-10 15:21:09 -08001636 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 if (inr != 2)
Willy Tarreaude6048b2020-02-24 22:23:43 +01001638 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 else if (ST0 & ST0_ECE) {
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001640 switch (drive_state[current_drive].track) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001642 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 /* after a second recalibrate, we still haven't
1644 * reached track 0. Probably no drive. Raise an
1645 * error, as failing immediately might upset
1646 * computers possessed by the Devil :-) */
1647 cont->error();
1648 cont->redo();
1649 return;
1650 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001651 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 /* If we already did a recalibrate,
1653 * and we are not at track 0, this
1654 * means we have moved. (The only way
1655 * not to move at recalibration is to
1656 * be already at track 0.) Clear the
1657 * new change flag */
Willy Tarreau031faab2020-02-24 22:23:48 +01001658 debug_dcl(drive_params[current_drive].flags,
Joe Perches87f530d2010-03-10 15:20:54 -08001659 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001661 clear_bit(FD_DISK_NEWCHANGE_BIT,
1662 &drive_state[current_drive].flags);
1663 drive_state[current_drive].select_date = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 /* fall through */
1665 default:
Joe Perchesded28632010-03-10 15:21:09 -08001666 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 /* Recalibrate moves the head by at
1668 * most 80 steps. If after one
1669 * recalibrate we don't have reached
1670 * track 0, this might mean that we
1671 * started beyond track 80. Try
1672 * again. */
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001673 drive_state[current_drive].track = NEED_1_RECAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 break;
1675 }
1676 } else
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001677 drive_state[current_drive].track = ST1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 floppy_ready();
1679}
1680
1681static void print_result(char *message, int inr)
1682{
1683 int i;
1684
1685 DPRINT("%s ", message);
1686 if (inr >= 0)
1687 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001688 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1689 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690}
1691
1692/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001693irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 int do_print;
1696 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001697 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 lasthandler = handler;
1700 interruptjiffies = jiffies;
1701
1702 f = claim_dma_lock();
1703 fd_disable_dma();
1704 release_dma_lock(f);
1705
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 do_floppy = NULL;
Willy Tarreaude6048b2020-02-24 22:23:43 +01001707 if (fdc >= N_FDC || fdc_state[fdc].address == -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001709 pr_info("DOR0=%x\n", fdc_state[0].dor);
1710 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Sakari Ailusd75f7732019-03-25 21:32:28 +02001711 pr_info("handler=%ps\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001712 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 return IRQ_NONE;
1714 }
1715
Willy Tarreaude6048b2020-02-24 22:23:43 +01001716 fdc_state[fdc].reset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 /* We have to clear the reset flag here, because apparently on boxes
1718 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
Willy Tarreaude6048b2020-02-24 22:23:43 +01001719 * emit SENSEI's to clear the interrupt line. And fdc_state[fdc].reset
1720 * blocks the emission of the SENSEI's.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 * It is OK to emit floppy commands because we are in an interrupt
1722 * handler here, and thus we have to fear no interference of other
1723 * activity.
1724 */
1725
Joe Perches29f1c782010-03-10 15:21:00 -08001726 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 inr = result();
1729 if (do_print)
1730 print_result("unexpected interrupt", inr);
1731 if (inr == 0) {
1732 int max_sensei = 4;
1733 do {
1734 output_byte(FD_SENSEI);
1735 inr = result();
1736 if (do_print)
1737 print_result("sensei", inr);
1738 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001739 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1740 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 }
1742 if (!handler) {
Willy Tarreaude6048b2020-02-24 22:23:43 +01001743 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 return IRQ_NONE;
1745 }
1746 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001747 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
1749 /* FIXME! Was it really for us? */
1750 return IRQ_HANDLED;
1751}
1752
1753static void recalibrate_floppy(void)
1754{
Joe Perchesded28632010-03-10 15:21:09 -08001755 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 do_floppy = recal_interrupt;
1757 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001758 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001759 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760}
1761
1762/*
1763 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1764 */
1765static void reset_interrupt(void)
1766{
Joe Perchesded28632010-03-10 15:21:09 -08001767 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 result(); /* get the status ready for set_fdc */
Willy Tarreaude6048b2020-02-24 22:23:43 +01001769 if (fdc_state[fdc].reset) {
Sakari Ailusd75f7732019-03-25 21:32:28 +02001770 pr_info("reset set in interrupt, calling %ps\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 cont->error(); /* a reset just after a reset. BAD! */
1772 }
1773 cont->redo();
1774}
1775
1776/*
1777 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1778 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1779 */
1780static void reset_fdc(void)
1781{
1782 unsigned long flags;
1783
1784 do_floppy = reset_interrupt;
Willy Tarreaude6048b2020-02-24 22:23:43 +01001785 fdc_state[fdc].reset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 reset_fdc_info(0);
1787
1788 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1789 /* Irrelevant for systems with true DMA (i386). */
1790
1791 flags = claim_dma_lock();
1792 fd_disable_dma();
1793 release_dma_lock(flags);
1794
Willy Tarreaude6048b2020-02-24 22:23:43 +01001795 if (fdc_state[fdc].version >= FDC_82072A)
1796 fd_outb(0x80 | (fdc_state[fdc].dtr & 3), FD_STATUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 else {
Willy Tarreaude6048b2020-02-24 22:23:43 +01001798 fd_outb(fdc_state[fdc].dor & ~0x04, FD_DOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 udelay(FD_RESET_DELAY);
Willy Tarreaude6048b2020-02-24 22:23:43 +01001800 fd_outb(fdc_state[fdc].dor, FD_DOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 }
1802}
1803
1804static void show_floppy(void)
1805{
1806 int i;
1807
Joe Perchesb46df352010-03-10 15:20:46 -08001808 pr_info("\n");
1809 pr_info("floppy driver state\n");
1810 pr_info("-------------------\n");
Sakari Ailusd75f7732019-03-25 21:32:28 +02001811 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%ps\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001812 jiffies, interruptjiffies, jiffies - interruptjiffies,
1813 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
Joe Perchesb46df352010-03-10 15:20:46 -08001815 pr_info("timeout_message=%s\n", timeout_message);
1816 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001818 pr_info("%2x %2x %lu\n",
1819 output_log[(i + output_log_pos) % OLOGSIZE].data,
1820 output_log[(i + output_log_pos) % OLOGSIZE].status,
1821 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1822 pr_info("last result at %lu\n", resultjiffies);
1823 pr_info("last redo_fd_request at %lu\n", lastredo);
1824 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1825 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
Joe Perchesb46df352010-03-10 15:20:46 -08001827 pr_info("status=%x\n", fd_inb(FD_STATUS));
1828 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 if (do_floppy)
Sakari Ailusd75f7732019-03-25 21:32:28 +02001830 pr_info("do_floppy=%ps\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001831 if (work_pending(&floppy_work))
Sakari Ailusd75f7732019-03-25 21:32:28 +02001832 pr_info("floppy_work.func=%ps\n", floppy_work.func);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001833 if (delayed_work_pending(&fd_timer))
1834 pr_info("delayed work.function=%p expires=%ld\n",
1835 fd_timer.work.func,
1836 fd_timer.timer.expires - jiffies);
1837 if (delayed_work_pending(&fd_timeout))
1838 pr_info("timer_function=%p expires=%ld\n",
1839 fd_timeout.work.func,
1840 fd_timeout.timer.expires - jiffies);
1841
Joe Perchesb46df352010-03-10 15:20:46 -08001842 pr_info("cont=%p\n", cont);
1843 pr_info("current_req=%p\n", current_req);
1844 pr_info("command_status=%d\n", command_status);
1845 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846}
1847
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001848static void floppy_shutdown(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849{
1850 unsigned long flags;
1851
Joe Perches29f1c782010-03-10 15:21:00 -08001852 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 show_floppy();
1854 cancel_activity();
1855
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 flags = claim_dma_lock();
1857 fd_disable_dma();
1858 release_dma_lock(flags);
1859
1860 /* avoid dma going to a random drive after shutdown */
1861
Joe Perches29f1c782010-03-10 15:21:00 -08001862 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 DPRINT("floppy timeout called\n");
Willy Tarreaude6048b2020-02-24 22:23:43 +01001864 fdc_state[fdc].reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 if (cont) {
1866 cont->done(0);
1867 cont->redo(); /* this will recall reset when needed */
1868 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001869 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 process_fd_request();
1871 }
Joe Perches275176b2010-03-10 15:21:06 -08001872 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873}
1874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001876static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001878 int mask;
1879 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
1881 mask = 0xfc;
1882 data = UNIT(current_drive);
1883 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
Willy Tarreaude6048b2020-02-24 22:23:43 +01001884 if (!(fdc_state[fdc].dor & (0x10 << UNIT(current_drive)))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 set_debugt();
1886 /* no read since this drive is running */
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001887 drive_state[current_drive].first_read_date = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 /* note motor start time if motor is not yet running */
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001889 drive_state[current_drive].spinup_date = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 data |= (0x10 << UNIT(current_drive));
1891 }
Willy Tarreaude6048b2020-02-24 22:23:43 +01001892 } else if (fdc_state[fdc].dor & (0x10 << UNIT(current_drive)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 mask &= ~(0x10 << UNIT(current_drive));
1894
1895 /* starts motor and selects floppy */
1896 del_timer(motor_off_timer + current_drive);
1897 set_dor(fdc, mask, data);
1898
1899 /* wait_for_completion also schedules reset if needed. */
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001900 return fd_wait_for_completion(drive_state[current_drive].select_date + drive_params[current_drive].select_delay,
Tejun Heo75ddb382014-03-07 10:24:48 -05001901 function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902}
1903
1904static void floppy_ready(void)
1905{
Willy Tarreaude6048b2020-02-24 22:23:43 +01001906 if (fdc_state[fdc].reset) {
Joe Perches045f9832010-03-10 15:20:47 -08001907 reset_fdc();
1908 return;
1909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 if (start_motor(floppy_ready))
1911 return;
1912 if (fdc_dtr())
1913 return;
1914
Willy Tarreau031faab2020-02-24 22:23:48 +01001915 debug_dcl(drive_params[current_drive].flags,
1916 "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
Willy Tarreau031faab2020-02-24 22:23:48 +01001918 disk_change(current_drive) && !drive_params[current_drive].select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001919 twaddle(); /* this clears the dcl on certain
1920 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922#ifdef fd_chose_dma_mode
1923 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1924 unsigned long flags = claim_dma_lock();
1925 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1926 release_dma_lock(flags);
1927 }
1928#endif
1929
1930 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1931 perpendicular_mode();
1932 fdc_specify(); /* must be done here because of hut, hlt ... */
1933 seek_floppy();
1934 } else {
1935 if ((raw_cmd->flags & FD_RAW_READ) ||
1936 (raw_cmd->flags & FD_RAW_WRITE))
1937 fdc_specify();
1938 setup_rw_floppy();
1939 }
1940}
1941
1942static void floppy_start(void)
1943{
Joe Perches73507e62010-03-10 15:21:03 -08001944 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
1946 scandrives();
Willy Tarreau031faab2020-02-24 22:23:48 +01001947 debug_dcl(drive_params[current_drive].flags,
1948 "setting NEWCHANGE in floppy_start\n");
Willy Tarreau3bd7f872020-02-24 22:23:49 +01001949 set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 floppy_ready();
1951}
1952
1953/*
1954 * ========================================================================
1955 * here ends the bottom half. Exported routines are:
1956 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1957 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1958 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1959 * and set_dor.
1960 * ========================================================================
1961 */
1962/*
1963 * General purpose continuations.
1964 * ==============================
1965 */
1966
1967static void do_wakeup(void)
1968{
Joe Perches73507e62010-03-10 15:21:03 -08001969 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 cont = NULL;
1971 command_status += 2;
1972 wake_up(&command_done);
1973}
1974
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001975static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 .interrupt = empty,
1977 .redo = do_wakeup,
1978 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001979 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980};
1981
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001982static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 .interrupt = empty,
1984 .redo = process_fd_request,
1985 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001986 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987};
1988
Joe Perches74f63f42010-03-10 15:20:58 -08001989static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990{
1991 int ret;
1992
1993 schedule_bh(handler);
1994
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001995 if (interruptible)
1996 wait_event_interruptible(command_done, command_status >= 2);
1997 else
1998 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
2000 if (command_status < 2) {
2001 cancel_activity();
2002 cont = &intr_cont;
2003 reset_fdc();
2004 return -EINTR;
2005 }
2006
Willy Tarreaude6048b2020-02-24 22:23:43 +01002007 if (fdc_state[fdc].reset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 command_status = FD_COMMAND_ERROR;
2009 if (command_status == FD_COMMAND_OKAY)
2010 ret = 0;
2011 else
2012 ret = -EIO;
2013 command_status = FD_COMMAND_NONE;
2014 return ret;
2015}
2016
2017static void generic_done(int result)
2018{
2019 command_status = result;
2020 cont = &wakeup_cont;
2021}
2022
2023static void generic_success(void)
2024{
2025 cont->done(1);
2026}
2027
2028static void generic_failure(void)
2029{
2030 cont->done(0);
2031}
2032
2033static void success_and_wakeup(void)
2034{
2035 generic_success();
2036 cont->redo();
2037}
2038
2039/*
2040 * formatting and rw support.
2041 * ==========================
2042 */
2043
2044static int next_valid_format(void)
2045{
2046 int probed_format;
2047
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002048 probed_format = drive_state[current_drive].probed_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 while (1) {
Willy Tarreau031faab2020-02-24 22:23:48 +01002050 if (probed_format >= 8 || !drive_params[current_drive].autodetect[probed_format]) {
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002051 drive_state[current_drive].probed_format = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 return 1;
2053 }
Willy Tarreau031faab2020-02-24 22:23:48 +01002054 if (floppy_type[drive_params[current_drive].autodetect[probed_format]].sect) {
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002055 drive_state[current_drive].probed_format = probed_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 return 0;
2057 }
2058 probed_format++;
2059 }
2060}
2061
2062static void bad_flp_intr(void)
2063{
2064 int err_count;
2065
2066 if (probing) {
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002067 drive_state[current_drive].probed_format++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 if (!next_valid_format())
2069 return;
2070 }
2071 err_count = ++(*errors);
2072 INFBOUND(DRWE->badness, err_count);
Willy Tarreau031faab2020-02-24 22:23:48 +01002073 if (err_count > drive_params[current_drive].max_errors.abort)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 cont->done(0);
Willy Tarreau031faab2020-02-24 22:23:48 +01002075 if (err_count > drive_params[current_drive].max_errors.reset)
Willy Tarreaude6048b2020-02-24 22:23:43 +01002076 fdc_state[fdc].reset = 1;
Willy Tarreau031faab2020-02-24 22:23:48 +01002077 else if (err_count > drive_params[current_drive].max_errors.recal)
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002078 drive_state[current_drive].track = NEED_2_RECAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079}
2080
2081static void set_floppy(int drive)
2082{
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01002083 int type = ITYPE(drive_state[drive].fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002084
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 if (type)
2086 _floppy = floppy_type + type;
2087 else
2088 _floppy = current_type[drive];
2089}
2090
2091/*
2092 * formatting support.
2093 * ===================
2094 */
2095static void format_interrupt(void)
2096{
2097 switch (interpret_errors()) {
2098 case 1:
2099 cont->error();
2100 case 2:
2101 break;
2102 case 0:
2103 cont->done(1);
2104 }
2105 cont->redo();
2106}
2107
Joe Perches48c8cee2010-03-10 15:20:45 -08002108#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111static void setup_format_params(int track)
2112{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002113 int n;
2114 int il;
2115 int count;
2116 int head_shift;
2117 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 struct fparm {
2119 unsigned char track, head, sect, size;
2120 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
2122 raw_cmd = &default_raw_cmd;
2123 raw_cmd->track = track;
2124
Joe Perches48c8cee2010-03-10 15:20:45 -08002125 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2126 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 raw_cmd->rate = _floppy->rate & 0x43;
2128 raw_cmd->cmd_count = NR_F;
2129 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2130 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2131 F_SIZECODE = FD_SIZECODE(_floppy);
2132 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2133 F_GAP = _floppy->fmt_gap;
2134 F_FILL = FD_FILL_BYTE;
2135
2136 raw_cmd->kernel_data = floppy_track_buffer;
2137 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2138
Denis Efremovf3554ae2019-07-12 21:55:20 +03002139 if (!F_SECT_PER_TRACK)
2140 return;
2141
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 /* allow for about 30ms for data transport per track */
2143 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2144
2145 /* a ``cylinder'' is two tracks plus a little stepping time */
2146 track_shift = 2 * head_shift + 3;
2147
2148 /* position of logical sector 1 on this track */
2149 n = (track_shift * format_req.track + head_shift * format_req.head)
2150 % F_SECT_PER_TRACK;
2151
2152 /* determine interleave */
2153 il = 1;
2154 if (_floppy->fmt_gap < 0x22)
2155 il++;
2156
2157 /* initialize field */
2158 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2159 here[count].track = format_req.track;
2160 here[count].head = format_req.head;
2161 here[count].sect = 0;
2162 here[count].size = F_SIZECODE;
2163 }
2164 /* place logical sectors */
2165 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2166 here[n].sect = count;
2167 n = (n + il) % F_SECT_PER_TRACK;
2168 if (here[n].sect) { /* sector busy, find next free sector */
2169 ++n;
2170 if (n >= F_SECT_PER_TRACK) {
2171 n -= F_SECT_PER_TRACK;
2172 while (here[n].sect)
2173 ++n;
2174 }
2175 }
2176 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002177 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002179 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 }
2181}
2182
2183static void redo_format(void)
2184{
2185 buffer_track = -1;
2186 setup_format_params(format_req.track << STRETCH(_floppy));
2187 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002188 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189}
2190
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002191static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 .interrupt = format_interrupt,
2193 .redo = redo_format,
2194 .error = bad_flp_intr,
2195 .done = generic_done
2196};
2197
2198static int do_format(int drive, struct format_descr *tmp_format_req)
2199{
2200 int ret;
2201
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01002202 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08002203 return -EINTR;
2204
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 set_floppy(drive);
2206 if (!_floppy ||
Willy Tarreau031faab2020-02-24 22:23:48 +01002207 _floppy->track > drive_params[current_drive].tracks ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 tmp_format_req->track >= _floppy->track ||
2209 tmp_format_req->head >= _floppy->head ||
2210 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2211 !_floppy->fmt_gap) {
2212 process_fd_request();
2213 return -EINVAL;
2214 }
2215 format_req = *tmp_format_req;
2216 format_errors = 0;
2217 cont = &format_cont;
2218 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002219 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002220 if (ret == -EINTR)
2221 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 process_fd_request();
2223 return ret;
2224}
2225
2226/*
2227 * Buffer read/write and support
2228 * =============================
2229 */
2230
Christoph Hellwig2a842ac2017-06-03 09:38:04 +02002231static void floppy_end_request(struct request *req, blk_status_t error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232{
2233 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002234 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
2236 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002237 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002238 nr_sectors = blk_rq_cur_sectors(req);
Omar Sandovala9f38e12018-10-15 09:21:34 -06002239 if (blk_update_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 return;
Omar Sandovala9f38e12018-10-15 09:21:34 -06002241 __blk_mq_end_request(req, error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
2243 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002244 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 current_req = NULL;
2246}
2247
2248/* new request_done. Can handle physical sectors which are smaller than a
2249 * logical buffer */
2250static void request_done(int uptodate)
2251{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 struct request *req = current_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002254 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255
2256 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002257 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2258 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259
2260 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002261 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 return;
2263 }
2264
2265 if (uptodate) {
2266 /* maintain values for invalidation on geometry
2267 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002268 block = current_count_sectors + blk_rq_pos(req);
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002269 INFBOUND(drive_state[current_drive].maxblock, block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 if (block > _floppy->sect)
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002271 drive_state[current_drive].maxtrack = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002273 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 } else {
2275 if (rq_data_dir(req) == WRITE) {
2276 /* record write error information */
2277 DRWE->write_errors++;
2278 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002279 DRWE->first_error_sector = blk_rq_pos(req);
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002280 DRWE->first_error_generation = drive_state[current_drive].generation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002282 DRWE->last_error_sector = blk_rq_pos(req);
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002283 DRWE->last_error_generation = drive_state[current_drive].generation;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 }
Christoph Hellwig2a842ac2017-06-03 09:38:04 +02002285 floppy_end_request(req, BLK_STS_IOERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 }
2287}
2288
2289/* Interrupt handler evaluating the result of the r/w operation */
2290static void rw_interrupt(void)
2291{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002292 int eoc;
2293 int ssize;
2294 int heads;
2295 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297 if (R_HEAD >= 2) {
2298 /* some Toshiba floppy controllers occasionnally seem to
2299 * return bogus interrupts after read/write operations, which
2300 * can be recognized by a bad head number (>= 2) */
2301 return;
2302 }
2303
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002304 if (!drive_state[current_drive].first_read_date)
2305 drive_state[current_drive].first_read_date = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002308 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
2310 if (ST1 & ST1_EOC)
2311 eoc = 1;
2312 else
2313 eoc = 0;
2314
2315 if (COMMAND & 0x80)
2316 heads = 2;
2317 else
2318 heads = 1;
2319
2320 nr_sectors = (((R_TRACK - TRACK) * heads +
2321 R_HEAD - HEAD) * SECT_PER_TRACK +
2322 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2323
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002325 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 DPRINT("long rw: %x instead of %lx\n",
2327 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002328 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2329 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2330 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2331 pr_info("heads=%d eoc=%d\n", heads, eoc);
2332 pr_info("spt=%d st=%d ss=%d\n",
2333 SECT_PER_TRACK, fsector_t, ssize);
2334 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
2337 nr_sectors -= in_sector_offset;
2338 INFBOUND(nr_sectors, 0);
2339 SUPBOUND(current_count_sectors, nr_sectors);
2340
2341 switch (interpret_errors()) {
2342 case 2:
2343 cont->redo();
2344 return;
2345 case 1:
2346 if (!current_count_sectors) {
2347 cont->error();
2348 cont->redo();
2349 return;
2350 }
2351 break;
2352 case 0:
2353 if (!current_count_sectors) {
2354 cont->redo();
2355 return;
2356 }
2357 current_type[current_drive] = _floppy;
2358 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2359 break;
2360 }
2361
2362 if (probing) {
Willy Tarreau031faab2020-02-24 22:23:48 +01002363 if (drive_params[current_drive].flags & FTD_MSG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 DPRINT("Auto-detected floppy type %s in fd%d\n",
2365 _floppy->name, current_drive);
2366 current_type[current_drive] = _floppy;
2367 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2368 probing = 0;
2369 }
2370
2371 if (CT(COMMAND) != FD_READ ||
Jens Axboeb4f42e22014-04-10 09:46:28 -06002372 raw_cmd->kernel_data == bio_data(current_req->bio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 /* transfer directly from buffer */
2374 cont->done(1);
2375 } else if (CT(COMMAND) == FD_READ) {
2376 buffer_track = raw_cmd->track;
2377 buffer_drive = current_drive;
2378 INFBOUND(buffer_max, nr_sectors + fsector_t);
2379 }
2380 cont->redo();
2381}
2382
2383/* Compute maximal contiguous buffer size. */
2384static int buffer_chain_size(void)
2385{
Kent Overstreet79886132013-11-23 17:19:00 -08002386 struct bio_vec bv;
NeilBrown5705f702007-09-25 12:35:59 +02002387 int size;
2388 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 char *base;
2390
2391 base = bio_data(current_req->bio);
2392 size = 0;
2393
NeilBrown5705f702007-09-25 12:35:59 +02002394 rq_for_each_segment(bv, current_req, iter) {
Kent Overstreet79886132013-11-23 17:19:00 -08002395 if (page_address(bv.bv_page) + bv.bv_offset != base + size)
NeilBrown5705f702007-09-25 12:35:59 +02002396 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
Kent Overstreet79886132013-11-23 17:19:00 -08002398 size += bv.bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 }
2400
2401 return size >> 9;
2402}
2403
2404/* Compute the maximal transfer size */
2405static int transfer_size(int ssize, int max_sector, int max_size)
2406{
2407 SUPBOUND(max_sector, fsector_t + max_size);
2408
2409 /* alignment */
2410 max_sector -= (max_sector % _floppy->sect) % ssize;
2411
2412 /* transfer size, beginning not aligned */
2413 current_count_sectors = max_sector - fsector_t;
2414
2415 return max_sector;
2416}
2417
2418/*
2419 * Move data from/to the track buffer to/from the buffer cache.
2420 */
2421static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2422{
2423 int remaining; /* number of transferred 512-byte sectors */
Kent Overstreet79886132013-11-23 17:19:00 -08002424 struct bio_vec bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002425 char *buffer;
2426 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002427 int size;
2428 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
2430 max_sector = transfer_size(ssize,
2431 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002432 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002435 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002437 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
2439 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002440 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002442 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2443 pr_info("remaining=%d\n", remaining >> 9);
2444 pr_info("current_req->nr_sectors=%u\n",
2445 blk_rq_sectors(current_req));
2446 pr_info("current_req->current_nr_sectors=%u\n",
2447 blk_rq_cur_sectors(current_req));
2448 pr_info("max_sector=%d\n", max_sector);
2449 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
2452 buffer_max = max(max_sector, buffer_max);
2453
2454 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2455
Tejun Heo1011c1b2009-05-07 22:24:45 +09002456 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
NeilBrown5705f702007-09-25 12:35:59 +02002458 rq_for_each_segment(bv, current_req, iter) {
2459 if (!remaining)
2460 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
Kent Overstreet79886132013-11-23 17:19:00 -08002462 size = bv.bv_len;
NeilBrown5705f702007-09-25 12:35:59 +02002463 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464
Kent Overstreet79886132013-11-23 17:19:00 -08002465 buffer = page_address(bv.bv_page) + bv.bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002466 if (dma_buffer + size >
2467 floppy_track_buffer + (max_buffer_sectors << 10) ||
2468 dma_buffer < floppy_track_buffer) {
2469 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002470 (int)((floppy_track_buffer - dma_buffer) >> 9));
2471 pr_info("fsector_t=%d buffer_min=%d\n",
2472 fsector_t, buffer_min);
2473 pr_info("current_count_sectors=%ld\n",
2474 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002476 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002477 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002478 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002479 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 }
NeilBrown5705f702007-09-25 12:35:59 +02002481 if (((unsigned long)buffer) % 512)
2482 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002483
NeilBrown5705f702007-09-25 12:35:59 +02002484 if (CT(COMMAND) == FD_READ)
2485 memcpy(buffer, dma_buffer, size);
2486 else
2487 memcpy(dma_buffer, buffer, size);
2488
2489 remaining -= size;
2490 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 if (remaining) {
2493 if (remaining > 0)
2494 max_sector -= remaining >> 9;
2495 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497}
2498
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499/* work around a bug in pseudo DMA
2500 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2501 * sending data. Hence we need a different way to signal the
2502 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2503 * does not work with MT, hence we can only transfer one head at
2504 * a time
2505 */
2506static void virtualdmabug_workaround(void)
2507{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002508 int hard_sectors;
2509 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 if (CT(COMMAND) == FD_WRITE) {
2512 COMMAND &= ~0x80; /* switch off multiple track mode */
2513
2514 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2515 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002517 pr_info("too many sectors %d > %d\n",
2518 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 return;
2520 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002521 SECT_PER_TRACK = end_sector;
2522 /* make sure SECT_PER_TRACK
2523 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 }
2525}
2526
2527/*
2528 * Formulate a read/write request.
2529 * this routine decides where to load the data (directly to buffer, or to
2530 * tmp floppy area), how much data to load (the size of the buffer, the whole
2531 * track, or a single sector)
2532 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2533 * allocation on the fly, it should be done here. No other part should need
2534 * modification.
2535 */
2536
2537static int make_raw_rw_request(void)
2538{
2539 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002540 int max_sector;
2541 int max_size;
2542 int tracksize;
2543 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002545 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
2548 set_fdc((long)current_req->rq_disk->private_data);
2549
2550 raw_cmd = &default_raw_cmd;
Fengguang Wu2fb2ca62012-07-28 19:45:59 +08002551 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 raw_cmd->cmd_count = NR_RW;
2553 if (rq_data_dir(current_req) == READ) {
2554 raw_cmd->flags |= FD_RAW_READ;
2555 COMMAND = FM_MODE(_floppy, FD_READ);
2556 } else if (rq_data_dir(current_req) == WRITE) {
2557 raw_cmd->flags |= FD_RAW_WRITE;
2558 COMMAND = FM_MODE(_floppy, FD_WRITE);
2559 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002560 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 return 0;
2562 }
2563
2564 max_sector = _floppy->sect * _floppy->head;
2565
Tejun Heo83096eb2009-05-07 22:24:39 +09002566 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2567 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002569 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 current_count_sectors = 1;
2571 return 1;
2572 } else
2573 return 0;
2574 }
2575 HEAD = fsector_t / _floppy->sect;
2576
Keith Wansbrough9e491842008-09-22 14:57:17 -07002577 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002578 test_bit(FD_NEED_TWADDLE_BIT, &drive_state[current_drive].flags)) &&
Joe Perchese0298532010-03-10 15:20:55 -08002579 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 max_sector = _floppy->sect;
2581
2582 /* 2M disks have phantom sectors on the first track */
2583 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2584 max_sector = 2 * _floppy->sect / 3;
2585 if (fsector_t >= max_sector) {
2586 current_count_sectors =
2587 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002588 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 return 1;
2590 }
2591 SIZECODE = 2;
2592 } else
2593 SIZECODE = FD_SIZECODE(_floppy);
2594 raw_cmd->rate = _floppy->rate & 0x43;
2595 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2596 raw_cmd->rate = 1;
2597
2598 if (SIZECODE)
2599 SIZECODE2 = 0xff;
2600 else
2601 SIZECODE2 = 0x80;
2602 raw_cmd->track = TRACK << STRETCH(_floppy);
2603 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2604 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002605 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2607 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002608 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
2610 /* tracksize describes the size which can be filled up with sectors
2611 * of size ssize.
2612 */
2613 tracksize = _floppy->sect - _floppy->sect % ssize;
2614 if (tracksize < _floppy->sect) {
2615 SECT_PER_TRACK++;
2616 if (tracksize <= fsector_t % _floppy->sect)
2617 SECTOR--;
2618
2619 /* if we are beyond tracksize, fill up using smaller sectors */
2620 while (tracksize <= fsector_t % _floppy->sect) {
2621 while (tracksize + ssize > _floppy->sect) {
2622 SIZECODE--;
2623 ssize >>= 1;
2624 }
2625 SECTOR++;
2626 SECT_PER_TRACK++;
2627 tracksize += ssize;
2628 }
2629 max_sector = HEAD * _floppy->sect + tracksize;
2630 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2631 max_sector = _floppy->sect;
2632 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2633 /* for virtual DMA bug workaround */
2634 max_sector = _floppy->sect;
2635 }
2636
2637 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2638 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002639 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 if ((raw_cmd->track == buffer_track) &&
2641 (current_drive == buffer_drive) &&
2642 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2643 /* data already in track buffer */
2644 if (CT(COMMAND) == FD_READ) {
2645 copy_buffer(1, max_sector, buffer_max);
2646 return 1;
2647 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002648 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002650 unsigned int sectors;
2651
2652 sectors = fsector_t + blk_rq_sectors(current_req);
2653 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 max_size = ssize + ssize;
2655 else
2656 max_size = ssize;
2657 }
2658 raw_cmd->flags &= ~FD_RAW_WRITE;
2659 raw_cmd->flags |= FD_RAW_READ;
2660 COMMAND = FM_MODE(_floppy, FD_READ);
Jens Axboeb4f42e22014-04-10 09:46:28 -06002661 } else if ((unsigned long)bio_data(current_req->bio) < MAX_DMA_ADDRESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 unsigned long dma_limit;
2663 int direct, indirect;
2664
2665 indirect =
2666 transfer_size(ssize, max_sector,
2667 max_buffer_sectors * 2) - fsector_t;
2668
2669 /*
2670 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2671 * on a 64 bit machine!
2672 */
2673 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002674 dma_limit = (MAX_DMA_ADDRESS -
Jens Axboeb4f42e22014-04-10 09:46:28 -06002675 ((unsigned long)bio_data(current_req->bio))) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002676 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 /* 64 kb boundaries */
Jens Axboeb4f42e22014-04-10 09:46:28 -06002679 if (CROSS_64KB(bio_data(current_req->bio), max_size << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 max_size = (K_64 -
Jens Axboeb4f42e22014-04-10 09:46:28 -06002681 ((unsigned long)bio_data(current_req->bio)) %
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 K_64) >> 9;
2683 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2684 /*
2685 * We try to read tracks, but if we get too many errors, we
2686 * go back to reading just one sector at a time.
2687 *
2688 * This means we should be able to read a sector even if there
2689 * are other bad sectors on this track.
2690 */
2691 if (!direct ||
2692 (indirect * 2 > direct * 3 &&
Willy Tarreau031faab2020-02-24 22:23:48 +01002693 *errors < drive_params[current_drive].max_errors.read_track &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002694 ((!probing ||
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002695 (drive_params[current_drive].read_track & (1 << drive_state[current_drive].probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002696 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 } else {
Jens Axboeb4f42e22014-04-10 09:46:28 -06002698 raw_cmd->kernel_data = bio_data(current_req->bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 raw_cmd->length = current_count_sectors << 9;
2700 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002701 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002702 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 indirect, direct, fsector_t);
2704 return 0;
2705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 virtualdmabug_workaround();
2707 return 2;
2708 }
2709 }
2710
2711 if (CT(COMMAND) == FD_READ)
2712 max_size = max_sector; /* unbounded */
2713
2714 /* claim buffer track if needed */
2715 if (buffer_track != raw_cmd->track || /* bad track */
2716 buffer_drive != current_drive || /* bad drive */
2717 fsector_t > buffer_max ||
2718 fsector_t < buffer_min ||
2719 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002720 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002722 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2723 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 buffer_track = -1;
2725 buffer_drive = current_drive;
2726 buffer_max = buffer_min = aligned_sector_t;
2727 }
2728 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002729 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730
2731 if (CT(COMMAND) == FD_WRITE) {
2732 /* copy write buffer to track buffer.
2733 * if we get here, we know that the write
2734 * is either aligned or the data already in the buffer
2735 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 if (in_sector_offset && buffer_track == -1)
2737 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 buffer_track = raw_cmd->track;
2739 buffer_drive = current_drive;
2740 copy_buffer(ssize, max_sector,
2741 2 * max_buffer_sectors + buffer_min);
2742 } else
2743 transfer_size(ssize, max_sector,
2744 2 * max_buffer_sectors + buffer_min -
2745 aligned_sector_t);
2746
2747 /* round up current_count_sectors to get dma xfer size */
2748 raw_cmd->length = in_sector_offset + current_count_sectors;
2749 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2750 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 if ((raw_cmd->length < current_count_sectors << 9) ||
Jens Axboeb4f42e22014-04-10 09:46:28 -06002752 (raw_cmd->kernel_data != bio_data(current_req->bio) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 CT(COMMAND) == FD_WRITE &&
2754 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2755 aligned_sector_t < buffer_min)) ||
2756 raw_cmd->length % (128 << SIZECODE) ||
2757 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2758 DPRINT("fractionary current count b=%lx s=%lx\n",
2759 raw_cmd->length, current_count_sectors);
Jens Axboeb4f42e22014-04-10 09:46:28 -06002760 if (raw_cmd->kernel_data != bio_data(current_req->bio))
Joe Perchesb46df352010-03-10 15:20:46 -08002761 pr_info("addr=%d, length=%ld\n",
2762 (int)((raw_cmd->kernel_data -
2763 floppy_track_buffer) >> 9),
2764 current_count_sectors);
2765 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2766 fsector_t, aligned_sector_t, max_sector, max_size);
2767 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2768 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2769 COMMAND, SECTOR, HEAD, TRACK);
2770 pr_info("buffer drive=%d\n", buffer_drive);
2771 pr_info("buffer track=%d\n", buffer_track);
2772 pr_info("buffer_min=%d\n", buffer_min);
2773 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return 0;
2775 }
2776
Jens Axboeb4f42e22014-04-10 09:46:28 -06002777 if (raw_cmd->kernel_data != bio_data(current_req->bio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 if (raw_cmd->kernel_data < floppy_track_buffer ||
2779 current_count_sectors < 0 ||
2780 raw_cmd->length < 0 ||
2781 raw_cmd->kernel_data + raw_cmd->length >
2782 floppy_track_buffer + (max_buffer_sectors << 10)) {
2783 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002784 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2785 fsector_t, buffer_min, raw_cmd->length >> 9);
2786 pr_info("current_count_sectors=%ld\n",
2787 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002789 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002791 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 return 0;
2793 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002794 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002795 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 DPRINT("buffer overrun in direct transfer\n");
2797 return 0;
2798 } else if (raw_cmd->length < current_count_sectors << 9) {
2799 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002800 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2801 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 }
2803 if (raw_cmd->length == 0) {
2804 DPRINT("zero dma transfer attempted from make_raw_request\n");
2805 return 0;
2806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808 virtualdmabug_workaround();
2809 return 2;
2810}
2811
Jens Axboe48821182010-09-22 09:32:36 +02002812static int set_next_request(void)
2813{
Omar Sandovala9f38e12018-10-15 09:21:34 -06002814 current_req = list_first_entry_or_null(&floppy_reqs, struct request,
2815 queuelist);
2816 if (current_req) {
2817 current_req->error_count = 0;
2818 list_del_init(&current_req->queuelist);
2819 }
Jens Axboe48821182010-09-22 09:32:36 +02002820 return current_req != NULL;
2821}
2822
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823static void redo_fd_request(void)
2824{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 int drive;
2826 int tmp;
2827
2828 lastredo = jiffies;
2829 if (current_drive < N_DRIVE)
2830 floppy_off(current_drive);
2831
Joe Perches0da31322010-03-10 15:21:03 -08002832do_request:
2833 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002834 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
Jens Axboe48821182010-09-22 09:32:36 +02002836 spin_lock_irq(&floppy_lock);
2837 pending = set_next_request();
2838 spin_unlock_irq(&floppy_lock);
Jens Axboe48821182010-09-22 09:32:36 +02002839 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002840 do_floppy = NULL;
2841 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 }
Joe Perches0da31322010-03-10 15:21:03 -08002845 drive = (long)current_req->rq_disk->private_data;
2846 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002847 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002848
2849 set_floppy(drive);
2850 raw_cmd = &default_raw_cmd;
2851 raw_cmd->flags = 0;
2852 if (start_motor(redo_fd_request))
2853 return;
2854
2855 disk_change(current_drive);
2856 if (test_bit(current_drive, &fake_change) ||
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002857 test_bit(FD_DISK_CHANGED_BIT, &drive_state[current_drive].flags)) {
Joe Perches0da31322010-03-10 15:21:03 -08002858 DPRINT("disk absent or changed during operation\n");
2859 request_done(0);
2860 goto do_request;
2861 }
2862 if (!_floppy) { /* Autodetection */
2863 if (!probing) {
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002864 drive_state[current_drive].probed_format = 0;
Joe Perches0da31322010-03-10 15:21:03 -08002865 if (next_valid_format()) {
2866 DPRINT("no autodetectable formats\n");
2867 _floppy = NULL;
2868 request_done(0);
2869 goto do_request;
2870 }
2871 }
2872 probing = 1;
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002873 _floppy = floppy_type + drive_params[current_drive].autodetect[drive_state[current_drive].probed_format];
Joe Perches0da31322010-03-10 15:21:03 -08002874 } else
2875 probing = 0;
Christoph Hellwig45908792017-04-20 16:03:12 +02002876 errors = &(current_req->error_count);
Joe Perches0da31322010-03-10 15:21:03 -08002877 tmp = make_raw_rw_request();
2878 if (tmp < 2) {
2879 request_done(tmp);
2880 goto do_request;
2881 }
2882
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002883 if (test_bit(FD_NEED_TWADDLE_BIT, &drive_state[current_drive].flags))
Joe Perches0da31322010-03-10 15:21:03 -08002884 twaddle();
2885 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002886 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002887 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888}
2889
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002890static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 .interrupt = rw_interrupt,
2892 .redo = redo_fd_request,
2893 .error = bad_flp_intr,
2894 .done = request_done
2895};
2896
2897static void process_fd_request(void)
2898{
2899 cont = &rw_cont;
2900 schedule_bh(redo_fd_request);
2901}
2902
Omar Sandovala9f38e12018-10-15 09:21:34 -06002903static blk_status_t floppy_queue_rq(struct blk_mq_hw_ctx *hctx,
2904 const struct blk_mq_queue_data *bd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905{
Omar Sandovala9f38e12018-10-15 09:21:34 -06002906 blk_mq_start_request(bd->rq);
2907
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002908 if (WARN(max_buffer_sectors == 0,
2909 "VFS: %s called on non-open device\n", __func__))
Omar Sandovala9f38e12018-10-15 09:21:34 -06002910 return BLK_STS_IOERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002912 if (WARN(atomic_read(&usage_count) == 0,
Christoph Hellwigaebf5262017-01-31 16:57:31 +01002913 "warning: usage count=0, current_req=%p sect=%ld flags=%llx\n",
2914 current_req, (long)blk_rq_pos(current_req),
Jens Axboe59533162013-05-23 12:25:08 +02002915 (unsigned long long) current_req->cmd_flags))
Omar Sandovala9f38e12018-10-15 09:21:34 -06002916 return BLK_STS_IOERR;
2917
2918 spin_lock_irq(&floppy_lock);
2919 list_add_tail(&bd->rq->queuelist, &floppy_reqs);
2920 spin_unlock_irq(&floppy_lock);
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002921
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002922 if (test_and_set_bit(0, &fdc_busy)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 /* fdc busy, this new request will be treated when the
2924 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002925 is_alive(__func__, "old request running");
Omar Sandovala9f38e12018-10-15 09:21:34 -06002926 return BLK_STS_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 }
Omar Sandovala9f38e12018-10-15 09:21:34 -06002928
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002929 command_status = FD_COMMAND_NONE;
2930 __reschedule_timeout(MAXTIMEOUT, "fd_request");
2931 set_fdc(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002933 is_alive(__func__, "");
Omar Sandovala9f38e12018-10-15 09:21:34 -06002934 return BLK_STS_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935}
2936
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002937static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 .interrupt = success_and_wakeup,
2939 .redo = floppy_ready,
2940 .error = generic_failure,
2941 .done = generic_done
2942};
2943
Joe Perches74f63f42010-03-10 15:20:58 -08002944static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 /* no auto-sense, just clear dcl */
2947 raw_cmd = &default_raw_cmd;
2948 raw_cmd->flags = flag;
2949 raw_cmd->track = 0;
2950 raw_cmd->cmd_count = 0;
2951 cont = &poll_cont;
Willy Tarreau031faab2020-02-24 22:23:48 +01002952 debug_dcl(drive_params[current_drive].flags,
2953 "setting NEWCHANGE in poll_drive\n");
Willy Tarreau3bd7f872020-02-24 22:23:49 +01002954 set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags);
Joe Perches55eee802010-03-10 15:20:57 -08002955
2956 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957}
2958
2959/*
2960 * User triggered reset
2961 * ====================
2962 */
2963
2964static void reset_intr(void)
2965{
Joe Perchesb46df352010-03-10 15:20:46 -08002966 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967}
2968
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002969static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 .interrupt = reset_intr,
2971 .redo = success_and_wakeup,
2972 .error = generic_failure,
2973 .done = generic_done
2974};
2975
Joe Perches74f63f42010-03-10 15:20:58 -08002976static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977{
2978 int ret;
2979
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01002980 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08002981 return -EINTR;
2982
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 if (arg == FD_RESET_ALWAYS)
Willy Tarreaude6048b2020-02-24 22:23:43 +01002984 fdc_state[fdc].reset = 1;
2985 if (fdc_state[fdc].reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002987 ret = wait_til_done(reset_fdc, interruptible);
2988 if (ret == -EINTR)
2989 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 }
2991 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002992 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993}
2994
2995/*
2996 * Misc Ioctl's and support
2997 * ========================
2998 */
2999static inline int fd_copyout(void __user *param, const void *address,
3000 unsigned long size)
3001{
3002 return copy_to_user(param, address, size) ? -EFAULT : 0;
3003}
3004
Joe Perches48c8cee2010-03-10 15:20:45 -08003005static inline int fd_copyin(void __user *param, void *address,
3006 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007{
3008 return copy_from_user(address, param, size) ? -EFAULT : 0;
3009}
3010
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003011static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012{
3013 struct floppy_struct *floppy;
3014
3015 if (type)
3016 floppy = floppy_type + type;
3017 else {
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003018 if (drive_params[drive].native_format)
3019 floppy = floppy_type + drive_params[drive].native_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 else
3021 return "(null)";
3022 }
3023 if (floppy->name)
3024 return floppy->name;
3025 else
3026 return "(null)";
3027}
3028
3029/* raw commands */
3030static void raw_cmd_done(int flag)
3031{
3032 int i;
3033
3034 if (!flag) {
3035 raw_cmd->flags |= FD_RAW_FAILURE;
3036 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3037 } else {
3038 raw_cmd->reply_count = inr;
3039 if (raw_cmd->reply_count > MAX_REPLIES)
3040 raw_cmd->reply_count = 0;
3041 for (i = 0; i < raw_cmd->reply_count; i++)
3042 raw_cmd->reply[i] = reply_buffer[i];
3043
3044 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3045 unsigned long flags;
3046 flags = claim_dma_lock();
3047 raw_cmd->length = fd_get_dma_residue();
3048 release_dma_lock(flags);
3049 }
3050
3051 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3052 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3053 raw_cmd->flags |= FD_RAW_FAILURE;
3054
3055 if (disk_change(current_drive))
3056 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3057 else
3058 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3059 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
Kees Cookb1bf4212017-10-04 17:49:29 -07003060 motor_off_callback(&motor_off_timer[current_drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
3062 if (raw_cmd->next &&
3063 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3064 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3065 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3066 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3067 raw_cmd = raw_cmd->next;
3068 return;
3069 }
3070 }
3071 generic_done(flag);
3072}
3073
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003074static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 .interrupt = success_and_wakeup,
3076 .redo = floppy_start,
3077 .error = generic_failure,
3078 .done = raw_cmd_done
3079};
3080
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003081static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 struct floppy_raw_cmd *ptr)
3083{
3084 int ret;
3085
3086 while (ptr) {
Matthew Daley2145e152014-04-28 19:05:21 +12003087 struct floppy_raw_cmd cmd = *ptr;
3088 cmd.next = NULL;
3089 cmd.kernel_data = NULL;
3090 ret = copy_to_user(param, &cmd, sizeof(cmd));
Joe Perches86b12b42010-03-10 15:20:56 -08003091 if (ret)
3092 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 param += sizeof(struct floppy_raw_cmd);
3094 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003095 if (ptr->length >= 0 &&
3096 ptr->length <= ptr->buffer_length) {
3097 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003098 ret = fd_copyout(ptr->data, ptr->kernel_data,
3099 length);
3100 if (ret)
3101 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003102 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 }
3104 ptr = ptr->next;
3105 }
Joe Perches7f252712010-03-10 15:21:08 -08003106
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 return 0;
3108}
3109
3110static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3111{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003112 struct floppy_raw_cmd *next;
3113 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
3115 this = *ptr;
3116 *ptr = NULL;
3117 while (this) {
3118 if (this->buffer_length) {
3119 fd_dma_mem_free((unsigned long)this->kernel_data,
3120 this->buffer_length);
3121 this->buffer_length = 0;
3122 }
3123 next = this->next;
3124 kfree(this);
3125 this = next;
3126 }
3127}
3128
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003129static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 struct floppy_raw_cmd **rcmd)
3131{
3132 struct floppy_raw_cmd *ptr;
3133 int ret;
3134 int i;
3135
3136 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003137
3138loop:
Vlastimil Babka1661f2e2017-01-04 11:19:31 +01003139 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_KERNEL);
Joe Perches7f252712010-03-10 15:21:08 -08003140 if (!ptr)
3141 return -ENOMEM;
3142 *rcmd = ptr;
3143 ret = copy_from_user(ptr, param, sizeof(*ptr));
Joe Perches7f252712010-03-10 15:21:08 -08003144 ptr->next = NULL;
3145 ptr->buffer_length = 0;
Matthew Daleyef87dbe2014-04-28 19:05:20 +12003146 ptr->kernel_data = NULL;
3147 if (ret)
3148 return -EFAULT;
Joe Perches7f252712010-03-10 15:21:08 -08003149 param += sizeof(struct floppy_raw_cmd);
3150 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 /* the command may now also take up the space
3152 * initially intended for the reply & the
3153 * reply count. Needed for long 82078 commands
3154 * such as RESTORE, which takes ... 17 command
3155 * bytes. Murphy's law #137: When you reserve
3156 * 16 bytes for a structure, you'll one day
3157 * discover that you really need 17...
3158 */
Joe Perches7f252712010-03-10 15:21:08 -08003159 return -EINVAL;
3160
3161 for (i = 0; i < 16; i++)
3162 ptr->reply[i] = 0;
3163 ptr->resultcode = 0;
Joe Perches7f252712010-03-10 15:21:08 -08003164
3165 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3166 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003168 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3169 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3170 if (!ptr->kernel_data)
3171 return -ENOMEM;
3172 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 }
Joe Perches7f252712010-03-10 15:21:08 -08003174 if (ptr->flags & FD_RAW_WRITE) {
3175 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3176 if (ret)
3177 return ret;
3178 }
3179
3180 if (ptr->flags & FD_RAW_MORE) {
3181 rcmd = &(ptr->next);
3182 ptr->rate &= 0x43;
3183 goto loop;
3184 }
3185
3186 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187}
3188
3189static int raw_cmd_ioctl(int cmd, void __user *param)
3190{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003192 int drive;
3193 int ret2;
3194 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
Willy Tarreaude6048b2020-02-24 22:23:43 +01003196 if (fdc_state[fdc].rawcmd <= 1)
3197 fdc_state[fdc].rawcmd = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 for (drive = 0; drive < N_DRIVE; drive++) {
3199 if (FDC(drive) != fdc)
3200 continue;
3201 if (drive == current_drive) {
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003202 if (drive_state[drive].fd_ref > 1) {
Willy Tarreaude6048b2020-02-24 22:23:43 +01003203 fdc_state[fdc].rawcmd = 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 break;
3205 }
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003206 } else if (drive_state[drive].fd_ref) {
Willy Tarreaude6048b2020-02-24 22:23:43 +01003207 fdc_state[fdc].rawcmd = 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 break;
3209 }
3210 }
3211
Willy Tarreaude6048b2020-02-24 22:23:43 +01003212 if (fdc_state[fdc].reset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 return -EIO;
3214
3215 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3216 if (ret) {
3217 raw_cmd_free(&my_raw_cmd);
3218 return ret;
3219 }
3220
3221 raw_cmd = my_raw_cmd;
3222 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003223 ret = wait_til_done(floppy_start, true);
Willy Tarreau031faab2020-02-24 22:23:48 +01003224 debug_dcl(drive_params[current_drive].flags,
3225 "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226
Willy Tarreaude6048b2020-02-24 22:23:43 +01003227 if (ret != -EINTR && fdc_state[fdc].reset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 ret = -EIO;
3229
Willy Tarreau3bd7f872020-02-24 22:23:49 +01003230 drive_state[current_drive].track = NO_TRACK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
3232 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3233 if (!ret)
3234 ret = ret2;
3235 raw_cmd_free(&my_raw_cmd);
3236 return ret;
3237}
3238
3239static int invalidate_drive(struct block_device *bdev)
3240{
3241 /* invalidate the buffer track to force a reread */
3242 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3243 process_fd_request();
3244 check_disk_change(bdev);
3245 return 0;
3246}
3247
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003248static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 int drive, int type, struct block_device *bdev)
3250{
3251 int cnt;
3252
3253 /* sanity checking for parameters. */
Denis Efremovda994662019-07-12 21:55:23 +03003254 if ((int)g->sect <= 0 ||
3255 (int)g->head <= 0 ||
3256 /* check for overflow in max_sector */
3257 (int)(g->sect * g->head) <= 0 ||
Denis Efremovf3554ae2019-07-12 21:55:20 +03003258 /* check for zero in F_SECT_PER_TRACK */
3259 (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003260 g->track <= 0 || g->track > drive_params[drive].tracks >> STRETCH(g) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003262 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 return -EINVAL;
3264 if (type) {
3265 if (!capable(CAP_SYS_ADMIN))
3266 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003267 mutex_lock(&open_lock);
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003268 if (lock_fdc(drive)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003269 mutex_unlock(&open_lock);
3270 return -EINTR;
3271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 floppy_type[type] = *g;
3273 floppy_type[type].name = "user format";
3274 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3275 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3276 floppy_type[type].size + 1;
3277 process_fd_request();
3278 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3279 struct block_device *bdev = opened_bdev[cnt];
3280 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3281 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003282 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003284 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 } else {
3286 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003287
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003288 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003289 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003290 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 /* notice a disk change immediately, else
3292 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003293 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003294 return -EINTR;
3295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 oldStretch = g->stretch;
3297 user_params[drive] = *g;
3298 if (buffer_drive == drive)
3299 SUPBOUND(buffer_max, user_params[drive].sect);
3300 current_type[drive] = &user_params[drive];
3301 floppy_sizes[drive] = user_params[drive].size;
3302 if (cmd == FDDEFPRM)
Willy Tarreau3bd7f872020-02-24 22:23:49 +01003303 drive_state[current_drive].keep_data = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 else
Willy Tarreau3bd7f872020-02-24 22:23:49 +01003305 drive_state[current_drive].keep_data = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 /* invalidation. Invalidate only when needed, i.e.
3307 * when there are already sectors in the buffer cache
3308 * whose number will change. This is useful, because
3309 * mtools often changes the geometry of the disk after
3310 * looking at the boot block */
Willy Tarreau3bd7f872020-02-24 22:23:49 +01003311 if (drive_state[current_drive].maxblock > user_params[drive].sect ||
3312 drive_state[current_drive].maxtrack ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003314 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 invalidate_drive(bdev);
3316 else
3317 process_fd_request();
3318 }
3319 return 0;
3320}
3321
3322/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003323static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 FDCLRPRM,
3325 FDSETPRM,
3326 FDDEFPRM,
3327 FDGETPRM,
3328 FDMSGON,
3329 FDMSGOFF,
3330 FDFMTBEG,
3331 FDFMTTRK,
3332 FDFMTEND,
3333 FDSETEMSGTRESH,
3334 FDFLUSH,
3335 FDSETMAXERRS,
3336 FDGETMAXERRS,
3337 FDGETDRVTYP,
3338 FDSETDRVPRM,
3339 FDGETDRVPRM,
3340 FDGETDRVSTAT,
3341 FDPOLLDRVSTAT,
3342 FDRESET,
3343 FDGETFDCSTAT,
3344 FDWERRORCLR,
3345 FDWERRORGET,
3346 FDRAWCMD,
3347 FDEJECT,
3348 FDTWADDLE
3349};
3350
Stephen Hemminger21af5442010-06-15 13:21:11 +02003351static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352{
3353 int i;
3354
3355 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3356 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3357 *size = _IOC_SIZE(*cmd);
3358 *cmd = ioctl_table[i];
3359 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003360 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 return -EFAULT;
3362 }
3363 return 0;
3364 }
3365 }
3366 return -EINVAL;
3367}
3368
3369static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3370{
3371 if (type)
3372 *g = &floppy_type[type];
3373 else {
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003374 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003375 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003376 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003377 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 process_fd_request();
3379 *g = current_type[drive];
3380 }
3381 if (!*g)
3382 return -ENODEV;
3383 return 0;
3384}
3385
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003386static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3387{
3388 int drive = (long)bdev->bd_disk->private_data;
3389 int type = ITYPE(drive_state[drive].fd_device);
3390 struct floppy_struct *g;
3391 int ret;
3392
3393 ret = get_floppy_geometry(drive, type, &g);
3394 if (ret)
3395 return ret;
3396
3397 geo->heads = g->head;
3398 geo->sectors = g->sect;
3399 geo->cylinders = g->track;
3400 return 0;
3401}
3402
Denis Efremov9b046092019-07-12 21:55:22 +03003403static bool valid_floppy_drive_params(const short autodetect[8],
3404 int native_format)
Denis Efremov5635f892019-07-12 21:55:21 +03003405{
3406 size_t floppy_type_size = ARRAY_SIZE(floppy_type);
3407 size_t i = 0;
3408
3409 for (i = 0; i < 8; ++i) {
3410 if (autodetect[i] < 0 ||
3411 autodetect[i] >= floppy_type_size)
3412 return false;
3413 }
3414
Denis Efremov9b046092019-07-12 21:55:22 +03003415 if (native_format < 0 || native_format >= floppy_type_size)
3416 return false;
3417
Denis Efremov5635f892019-07-12 21:55:21 +03003418 return true;
3419}
3420
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003421static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 unsigned long param)
3423{
Al Viroa4af9b42008-03-02 09:27:55 -05003424 int drive = (long)bdev->bd_disk->private_data;
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003425 int type = ITYPE(drive_state[drive].fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07003426 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 int ret;
3428 int size;
3429 union inparam {
3430 struct floppy_struct g; /* geometry */
3431 struct format_descr f;
3432 struct floppy_max_errors max_errors;
3433 struct floppy_drive_params dp;
3434 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003435 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436
3437 /* convert compatibility eject ioctls into floppy eject ioctl.
3438 * We do this in order to provide a means to eject floppy disks before
3439 * installing the new fdutils package */
3440 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003441 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 DPRINT("obsolete eject ioctl\n");
3443 DPRINT("please use floppycontrol --eject\n");
3444 cmd = FDEJECT;
3445 }
3446
Joe Perchesa81ee542010-03-10 15:20:46 -08003447 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 return -EINVAL;
3449
Joe Perchesa81ee542010-03-10 15:20:46 -08003450 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003451 ret = normalize_ioctl(&cmd, &size);
3452 if (ret)
3453 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003454
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003456 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3458 return -EPERM;
3459
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003460 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3461 return -EINVAL;
3462
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003464 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003465 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3466 ret = fd_copyin((void __user *)param, &inparam, size);
3467 if (ret)
3468 return ret;
3469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470
Joe Perchesda273652010-03-10 15:20:52 -08003471 switch (cmd) {
3472 case FDEJECT:
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003473 if (drive_state[drive].fd_ref != 1)
Joe Perchesda273652010-03-10 15:20:52 -08003474 /* somebody else has this drive open */
3475 return -EBUSY;
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003476 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003477 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478
Joe Perchesda273652010-03-10 15:20:52 -08003479 /* do the actual eject. Fails on
3480 * non-Sparc architectures */
3481 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003483 set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
3484 set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
Joe Perchesda273652010-03-10 15:20:52 -08003485 process_fd_request();
3486 return ret;
3487 case FDCLRPRM:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003488 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003489 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003490 current_type[drive] = NULL;
3491 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003492 drive_state[drive].keep_data = 0;
Joe Perchesda273652010-03-10 15:20:52 -08003493 return invalidate_drive(bdev);
3494 case FDSETPRM:
3495 case FDDEFPRM:
3496 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3497 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003498 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003499 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003500 if (ret)
3501 return ret;
Andy Whitcroft65eea8e2018-09-20 09:09:48 -06003502 memcpy(&inparam.g, outparam,
3503 offsetof(struct floppy_struct, name));
3504 outparam = &inparam.g;
Joe Perchesda273652010-03-10 15:20:52 -08003505 break;
3506 case FDMSGON:
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003507 drive_params[drive].flags |= FTD_MSG;
Joe Perchesda273652010-03-10 15:20:52 -08003508 return 0;
3509 case FDMSGOFF:
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003510 drive_params[drive].flags &= ~FTD_MSG;
Joe Perchesda273652010-03-10 15:20:52 -08003511 return 0;
3512 case FDFMTBEG:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003513 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003514 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003515 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003516 return -EINTR;
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003517 ret = drive_state[drive].flags;
Joe Perchesda273652010-03-10 15:20:52 -08003518 process_fd_request();
3519 if (ret & FD_VERIFY)
3520 return -ENODEV;
3521 if (!(ret & FD_DISK_WRITABLE))
3522 return -EROFS;
3523 return 0;
3524 case FDFMTTRK:
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003525 if (drive_state[drive].fd_ref != 1)
Joe Perchesda273652010-03-10 15:20:52 -08003526 return -EBUSY;
3527 return do_format(drive, &inparam.f);
3528 case FDFMTEND:
3529 case FDFLUSH:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003530 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003531 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003532 return invalidate_drive(bdev);
3533 case FDSETEMSGTRESH:
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003534 drive_params[drive].max_errors.reporting = (unsigned short)(param & 0x0f);
Joe Perchesda273652010-03-10 15:20:52 -08003535 return 0;
3536 case FDGETMAXERRS:
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003537 outparam = &drive_params[drive].max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003538 break;
3539 case FDSETMAXERRS:
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003540 drive_params[drive].max_errors = inparam.max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003541 break;
3542 case FDGETDRVTYP:
3543 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003544 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003545 break;
3546 case FDSETDRVPRM:
Denis Efremov9b046092019-07-12 21:55:22 +03003547 if (!valid_floppy_drive_params(inparam.dp.autodetect,
3548 inparam.dp.native_format))
Denis Efremov5635f892019-07-12 21:55:21 +03003549 return -EINVAL;
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003550 drive_params[drive] = inparam.dp;
Joe Perchesda273652010-03-10 15:20:52 -08003551 break;
3552 case FDGETDRVPRM:
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003553 outparam = &drive_params[drive];
Joe Perchesda273652010-03-10 15:20:52 -08003554 break;
3555 case FDPOLLDRVSTAT:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003556 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003557 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003558 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003559 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003560 process_fd_request();
3561 /* fall through */
3562 case FDGETDRVSTAT:
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003563 outparam = &drive_state[drive];
Joe Perchesda273652010-03-10 15:20:52 -08003564 break;
3565 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003566 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003567 case FDGETFDCSTAT:
Willy Tarreauf9d322b2020-02-24 22:23:44 +01003568 outparam = &fdc_state[FDC(drive)];
Joe Perchesda273652010-03-10 15:20:52 -08003569 break;
3570 case FDWERRORCLR:
Willy Tarreau121e2972020-02-24 22:23:47 +01003571 memset(&write_errors[drive], 0, sizeof(write_errors[drive]));
Joe Perchesda273652010-03-10 15:20:52 -08003572 return 0;
3573 case FDWERRORGET:
Willy Tarreau121e2972020-02-24 22:23:47 +01003574 outparam = &write_errors[drive];
Joe Perchesda273652010-03-10 15:20:52 -08003575 break;
3576 case FDRAWCMD:
3577 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 return -EINVAL;
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003579 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003580 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003581 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003582 i = raw_cmd_ioctl(cmd, (void __user *)param);
3583 if (i == -EINTR)
3584 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003585 process_fd_request();
3586 return i;
3587 case FDTWADDLE:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003588 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003589 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003590 twaddle();
3591 process_fd_request();
3592 return 0;
3593 default:
3594 return -EINVAL;
3595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 if (_IOC_DIR(cmd) & _IOC_READ)
3598 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003599
3600 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601}
3602
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003603static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3604 unsigned int cmd, unsigned long param)
3605{
3606 int ret;
3607
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003608 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003609 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003610 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003611
3612 return ret;
3613}
3614
Al Viro229b53c2017-06-27 15:47:56 -04003615#ifdef CONFIG_COMPAT
3616
3617struct compat_floppy_drive_params {
3618 char cmos;
3619 compat_ulong_t max_dtr;
3620 compat_ulong_t hlt;
3621 compat_ulong_t hut;
3622 compat_ulong_t srt;
3623 compat_ulong_t spinup;
3624 compat_ulong_t spindown;
3625 unsigned char spindown_offset;
3626 unsigned char select_delay;
3627 unsigned char rps;
3628 unsigned char tracks;
3629 compat_ulong_t timeout;
3630 unsigned char interleave_sect;
3631 struct floppy_max_errors max_errors;
3632 char flags;
3633 char read_track;
3634 short autodetect[8];
3635 compat_int_t checkfreq;
3636 compat_int_t native_format;
3637};
3638
3639struct compat_floppy_drive_struct {
3640 signed char flags;
3641 compat_ulong_t spinup_date;
3642 compat_ulong_t select_date;
3643 compat_ulong_t first_read_date;
3644 short probed_format;
3645 short track;
3646 short maxblock;
3647 short maxtrack;
3648 compat_int_t generation;
3649 compat_int_t keep_data;
3650 compat_int_t fd_ref;
3651 compat_int_t fd_device;
3652 compat_int_t last_checked;
3653 compat_caddr_t dmabuf;
3654 compat_int_t bufblocks;
3655};
3656
3657struct compat_floppy_fdc_state {
3658 compat_int_t spec1;
3659 compat_int_t spec2;
3660 compat_int_t dtr;
3661 unsigned char version;
3662 unsigned char dor;
3663 compat_ulong_t address;
3664 unsigned int rawcmd:2;
3665 unsigned int reset:1;
3666 unsigned int need_configure:1;
3667 unsigned int perp_mode:2;
3668 unsigned int has_fifo:1;
3669 unsigned int driver_version;
3670 unsigned char track[4];
3671};
3672
3673struct compat_floppy_write_errors {
3674 unsigned int write_errors;
3675 compat_ulong_t first_error_sector;
3676 compat_int_t first_error_generation;
3677 compat_ulong_t last_error_sector;
3678 compat_int_t last_error_generation;
3679 compat_uint_t badness;
3680};
3681
3682#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
3683#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
3684#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
3685#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
3686#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
3687#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
3688#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
3689#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
3690
3691static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3692 struct compat_floppy_struct __user *arg)
3693{
3694 struct floppy_struct v;
3695 int drive, type;
3696 int err;
3697
3698 BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
3699 offsetof(struct compat_floppy_struct, name));
3700
3701 if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
3702 return -EPERM;
3703
3704 memset(&v, 0, sizeof(struct floppy_struct));
3705 if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
3706 return -EFAULT;
3707
3708 mutex_lock(&floppy_mutex);
3709 drive = (long)bdev->bd_disk->private_data;
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003710 type = ITYPE(drive_state[drive].fd_device);
Al Viro229b53c2017-06-27 15:47:56 -04003711 err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
3712 &v, drive, type, bdev);
3713 mutex_unlock(&floppy_mutex);
3714 return err;
3715}
3716
3717static int compat_get_prm(int drive,
3718 struct compat_floppy_struct __user *arg)
3719{
3720 struct compat_floppy_struct v;
3721 struct floppy_struct *p;
3722 int err;
3723
3724 memset(&v, 0, sizeof(v));
3725 mutex_lock(&floppy_mutex);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003726 err = get_floppy_geometry(drive, ITYPE(drive_state[drive].fd_device),
3727 &p);
Al Viro229b53c2017-06-27 15:47:56 -04003728 if (err) {
3729 mutex_unlock(&floppy_mutex);
3730 return err;
3731 }
3732 memcpy(&v, p, offsetof(struct floppy_struct, name));
3733 mutex_unlock(&floppy_mutex);
3734 if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
3735 return -EFAULT;
3736 return 0;
3737}
3738
3739static int compat_setdrvprm(int drive,
3740 struct compat_floppy_drive_params __user *arg)
3741{
3742 struct compat_floppy_drive_params v;
3743
3744 if (!capable(CAP_SYS_ADMIN))
3745 return -EPERM;
3746 if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
3747 return -EFAULT;
Denis Efremov9b046092019-07-12 21:55:22 +03003748 if (!valid_floppy_drive_params(v.autodetect, v.native_format))
Denis Efremov5635f892019-07-12 21:55:21 +03003749 return -EINVAL;
Al Viro229b53c2017-06-27 15:47:56 -04003750 mutex_lock(&floppy_mutex);
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003751 drive_params[drive].cmos = v.cmos;
3752 drive_params[drive].max_dtr = v.max_dtr;
3753 drive_params[drive].hlt = v.hlt;
3754 drive_params[drive].hut = v.hut;
3755 drive_params[drive].srt = v.srt;
3756 drive_params[drive].spinup = v.spinup;
3757 drive_params[drive].spindown = v.spindown;
3758 drive_params[drive].spindown_offset = v.spindown_offset;
3759 drive_params[drive].select_delay = v.select_delay;
3760 drive_params[drive].rps = v.rps;
3761 drive_params[drive].tracks = v.tracks;
3762 drive_params[drive].timeout = v.timeout;
3763 drive_params[drive].interleave_sect = v.interleave_sect;
3764 drive_params[drive].max_errors = v.max_errors;
3765 drive_params[drive].flags = v.flags;
3766 drive_params[drive].read_track = v.read_track;
3767 memcpy(drive_params[drive].autodetect, v.autodetect,
3768 sizeof(v.autodetect));
3769 drive_params[drive].checkfreq = v.checkfreq;
3770 drive_params[drive].native_format = v.native_format;
Al Viro229b53c2017-06-27 15:47:56 -04003771 mutex_unlock(&floppy_mutex);
3772 return 0;
3773}
3774
3775static int compat_getdrvprm(int drive,
3776 struct compat_floppy_drive_params __user *arg)
3777{
3778 struct compat_floppy_drive_params v;
3779
3780 memset(&v, 0, sizeof(struct compat_floppy_drive_params));
3781 mutex_lock(&floppy_mutex);
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003782 v.cmos = drive_params[drive].cmos;
3783 v.max_dtr = drive_params[drive].max_dtr;
3784 v.hlt = drive_params[drive].hlt;
3785 v.hut = drive_params[drive].hut;
3786 v.srt = drive_params[drive].srt;
3787 v.spinup = drive_params[drive].spinup;
3788 v.spindown = drive_params[drive].spindown;
3789 v.spindown_offset = drive_params[drive].spindown_offset;
3790 v.select_delay = drive_params[drive].select_delay;
3791 v.rps = drive_params[drive].rps;
3792 v.tracks = drive_params[drive].tracks;
3793 v.timeout = drive_params[drive].timeout;
3794 v.interleave_sect = drive_params[drive].interleave_sect;
3795 v.max_errors = drive_params[drive].max_errors;
3796 v.flags = drive_params[drive].flags;
3797 v.read_track = drive_params[drive].read_track;
3798 memcpy(v.autodetect, drive_params[drive].autodetect,
3799 sizeof(v.autodetect));
3800 v.checkfreq = drive_params[drive].checkfreq;
3801 v.native_format = drive_params[drive].native_format;
Al Viro229b53c2017-06-27 15:47:56 -04003802 mutex_unlock(&floppy_mutex);
3803
Jann Horn52f6f9d2019-03-26 23:03:48 +01003804 if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
Al Viro229b53c2017-06-27 15:47:56 -04003805 return -EFAULT;
3806 return 0;
3807}
3808
3809static int compat_getdrvstat(int drive, bool poll,
3810 struct compat_floppy_drive_struct __user *arg)
3811{
3812 struct compat_floppy_drive_struct v;
3813
3814 memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
3815 mutex_lock(&floppy_mutex);
3816
3817 if (poll) {
3818 if (lock_fdc(drive))
3819 goto Eintr;
3820 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
3821 goto Eintr;
3822 process_fd_request();
3823 }
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01003824 v.spinup_date = drive_state[drive].spinup_date;
3825 v.select_date = drive_state[drive].select_date;
3826 v.first_read_date = drive_state[drive].first_read_date;
3827 v.probed_format = drive_state[drive].probed_format;
3828 v.track = drive_state[drive].track;
3829 v.maxblock = drive_state[drive].maxblock;
3830 v.maxtrack = drive_state[drive].maxtrack;
3831 v.generation = drive_state[drive].generation;
3832 v.keep_data = drive_state[drive].keep_data;
3833 v.fd_ref = drive_state[drive].fd_ref;
3834 v.fd_device = drive_state[drive].fd_device;
3835 v.last_checked = drive_state[drive].last_checked;
3836 v.dmabuf = (uintptr_t) drive_state[drive].dmabuf;
3837 v.bufblocks = drive_state[drive].bufblocks;
Al Viro229b53c2017-06-27 15:47:56 -04003838 mutex_unlock(&floppy_mutex);
3839
Jann Horn52f6f9d2019-03-26 23:03:48 +01003840 if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
Al Viro229b53c2017-06-27 15:47:56 -04003841 return -EFAULT;
3842 return 0;
3843Eintr:
3844 mutex_unlock(&floppy_mutex);
3845 return -EINTR;
3846}
3847
3848static int compat_getfdcstat(int drive,
3849 struct compat_floppy_fdc_state __user *arg)
3850{
3851 struct compat_floppy_fdc_state v32;
3852 struct floppy_fdc_state v;
3853
3854 mutex_lock(&floppy_mutex);
Willy Tarreauf9d322b2020-02-24 22:23:44 +01003855 v = fdc_state[FDC(drive)];
Al Viro229b53c2017-06-27 15:47:56 -04003856 mutex_unlock(&floppy_mutex);
3857
3858 memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
3859 v32.spec1 = v.spec1;
3860 v32.spec2 = v.spec2;
3861 v32.dtr = v.dtr;
3862 v32.version = v.version;
3863 v32.dor = v.dor;
3864 v32.address = v.address;
3865 v32.rawcmd = v.rawcmd;
3866 v32.reset = v.reset;
3867 v32.need_configure = v.need_configure;
3868 v32.perp_mode = v.perp_mode;
3869 v32.has_fifo = v.has_fifo;
3870 v32.driver_version = v.driver_version;
3871 memcpy(v32.track, v.track, 4);
3872 if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
3873 return -EFAULT;
3874 return 0;
3875}
3876
3877static int compat_werrorget(int drive,
3878 struct compat_floppy_write_errors __user *arg)
3879{
3880 struct compat_floppy_write_errors v32;
3881 struct floppy_write_errors v;
3882
3883 memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
3884 mutex_lock(&floppy_mutex);
Willy Tarreau121e2972020-02-24 22:23:47 +01003885 v = write_errors[drive];
Al Viro229b53c2017-06-27 15:47:56 -04003886 mutex_unlock(&floppy_mutex);
3887 v32.write_errors = v.write_errors;
3888 v32.first_error_sector = v.first_error_sector;
3889 v32.first_error_generation = v.first_error_generation;
3890 v32.last_error_sector = v.last_error_sector;
3891 v32.last_error_generation = v.last_error_generation;
3892 v32.badness = v.badness;
3893 if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
3894 return -EFAULT;
3895 return 0;
3896}
3897
3898static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3899 unsigned long param)
3900{
3901 int drive = (long)bdev->bd_disk->private_data;
3902 switch (cmd) {
Arnd Bergmann9452b1a2019-11-28 15:48:10 +01003903 case CDROMEJECT: /* CD-ROM eject */
3904 case 0x6470: /* SunOS floppy eject */
3905
Al Viro229b53c2017-06-27 15:47:56 -04003906 case FDMSGON:
3907 case FDMSGOFF:
3908 case FDSETEMSGTRESH:
3909 case FDFLUSH:
3910 case FDWERRORCLR:
3911 case FDEJECT:
3912 case FDCLRPRM:
3913 case FDFMTBEG:
3914 case FDRESET:
3915 case FDTWADDLE:
3916 return fd_ioctl(bdev, mode, cmd, param);
3917 case FDSETMAXERRS:
3918 case FDGETMAXERRS:
3919 case FDGETDRVTYP:
3920 case FDFMTEND:
3921 case FDFMTTRK:
3922 case FDRAWCMD:
3923 return fd_ioctl(bdev, mode, cmd,
3924 (unsigned long)compat_ptr(param));
3925 case FDSETPRM32:
3926 case FDDEFPRM32:
3927 return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
3928 case FDGETPRM32:
3929 return compat_get_prm(drive, compat_ptr(param));
3930 case FDSETDRVPRM32:
3931 return compat_setdrvprm(drive, compat_ptr(param));
3932 case FDGETDRVPRM32:
3933 return compat_getdrvprm(drive, compat_ptr(param));
3934 case FDPOLLDRVSTAT32:
3935 return compat_getdrvstat(drive, true, compat_ptr(param));
3936 case FDGETDRVSTAT32:
3937 return compat_getdrvstat(drive, false, compat_ptr(param));
3938 case FDGETFDCSTAT32:
3939 return compat_getfdcstat(drive, compat_ptr(param));
3940 case FDWERRORGET32:
3941 return compat_werrorget(drive, compat_ptr(param));
3942 }
3943 return -EINVAL;
3944}
3945#endif
3946
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947static void __init config_types(void)
3948{
Joe Perchesb46df352010-03-10 15:20:46 -08003949 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 int drive;
3951
3952 /* read drive info out of physical CMOS */
3953 drive = 0;
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003954 if (!drive_params[drive].cmos)
3955 drive_params[drive].cmos = FLOPPY0_TYPE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 drive = 1;
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003957 if (!drive_params[drive].cmos)
3958 drive_params[drive].cmos = FLOPPY1_TYPE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959
Jesper Juhl06f748c2007-10-16 23:30:57 -07003960 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961
3962 for (drive = 0; drive < N_DRIVE; drive++) {
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003963 unsigned int type = drive_params[drive].cmos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 struct floppy_drive_params *params;
3965 const char *name = NULL;
Rasmus Villemoesbcf42992015-12-01 15:54:01 +01003966 char temparea[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967
Tobias Klauser945f3902006-01-08 01:05:11 -08003968 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 params = &default_drive_params[type].params;
3970 if (type) {
3971 name = default_drive_params[type].name;
3972 allowed_drive_mask |= 1 << drive;
3973 } else
3974 allowed_drive_mask &= ~(1 << drive);
3975 } else {
3976 params = &default_drive_params[0].params;
Rasmus Villemoesbcf42992015-12-01 15:54:01 +01003977 snprintf(temparea, sizeof(temparea),
3978 "unknown type %d (usb?)", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 name = temparea;
3980 }
3981 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003982 const char *prepend;
3983 if (!has_drive) {
3984 prepend = "";
3985 has_drive = true;
3986 pr_info("Floppy drive(s):");
3987 } else {
3988 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 }
Joe Perchesb46df352010-03-10 15:20:46 -08003990
3991 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 }
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01003993 drive_params[drive] = *params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 }
Joe Perchesb46df352010-03-10 15:20:46 -08003995
3996 if (has_drive)
3997 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998}
3999
Al Virodb2a1442013-05-05 21:52:57 -04004000static void floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001{
Al Viroa4af9b42008-03-02 09:27:55 -05004002 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004004 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004005 mutex_lock(&open_lock);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004006 if (!drive_state[drive].fd_ref--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 DPRINT("floppy_release with fd_ref == 0");
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004008 drive_state[drive].fd_ref = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 }
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004010 if (!drive_state[drive].fd_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004012 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004013 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014}
4015
4016/*
4017 * floppy_open check for aliasing (/dev/fd0 can be the same as
4018 * /dev/PS0 etc), and disallows simultaneous access to the same
4019 * drive with different device numbers.
4020 */
Al Viroa4af9b42008-03-02 09:27:55 -05004021static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022{
Al Viroa4af9b42008-03-02 09:27:55 -05004023 int drive = (long)bdev->bd_disk->private_data;
4024 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 int try;
4026 int res = -EBUSY;
4027 char *tmp;
4028
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004029 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004030 mutex_lock(&open_lock);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004031 old_dev = drive_state[drive].fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05004032 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 goto out2;
4034
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004035 if (!drive_state[drive].fd_ref && (drive_params[drive].flags & FD_BROKEN_DCL)) {
4036 set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
4037 set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 }
4039
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004040 drive_state[drive].fd_ref++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041
Al Viroa4af9b42008-03-02 09:27:55 -05004042 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
4044 res = -ENXIO;
4045
4046 if (!floppy_track_buffer) {
4047 /* if opening an ED drive, reserve a big buffer,
4048 * else reserve a small one */
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01004049 if ((drive_params[drive].cmos == 6) || (drive_params[drive].cmos == 5))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 try = 64; /* Only 48 actually useful */
4051 else
4052 try = 32; /* Only 24 actually useful */
4053
4054 tmp = (char *)fd_dma_mem_alloc(1024 * try);
4055 if (!tmp && !floppy_track_buffer) {
4056 try >>= 1; /* buffer only one side */
4057 INFBOUND(try, 16);
4058 tmp = (char *)fd_dma_mem_alloc(1024 * try);
4059 }
Joe Perchesa81ee542010-03-10 15:20:46 -08004060 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 if (!tmp && !floppy_track_buffer) {
4063 DPRINT("Unable to allocate DMA memory\n");
4064 goto out;
4065 }
4066 if (floppy_track_buffer) {
4067 if (tmp)
4068 fd_dma_mem_free((unsigned long)tmp, try * 1024);
4069 } else {
4070 buffer_min = buffer_max = -1;
4071 floppy_track_buffer = tmp;
4072 max_buffer_sectors = try;
4073 }
4074 }
4075
Al Viroa4af9b42008-03-02 09:27:55 -05004076 new_dev = MINOR(bdev->bd_dev);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004077 drive_state[drive].fd_device = new_dev;
Al Viroa4af9b42008-03-02 09:27:55 -05004078 set_capacity(disks[drive], floppy_sizes[new_dev]);
4079 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 if (buffer_drive == drive)
4081 buffer_track = -1;
4082 }
4083
Willy Tarreauf9d322b2020-02-24 22:23:44 +01004084 if (fdc_state[FDC(drive)].rawcmd == 1)
4085 fdc_state[FDC(drive)].rawcmd = 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
Jens Axboef2791e72016-08-25 08:56:51 -06004087 if (!(mode & FMODE_NDELAY)) {
4088 if (mode & (FMODE_READ|FMODE_WRITE)) {
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004089 drive_state[drive].last_checked = 0;
4090 clear_bit(FD_OPEN_SHOULD_FAIL_BIT,
4091 &drive_state[drive].flags);
Jens Axboef2791e72016-08-25 08:56:51 -06004092 check_disk_change(bdev);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004093 if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags))
Jens Axboef2791e72016-08-25 08:56:51 -06004094 goto out;
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004095 if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &drive_state[drive].flags))
Jens Axboef2791e72016-08-25 08:56:51 -06004096 goto out;
4097 }
4098 res = -EROFS;
4099 if ((mode & FMODE_WRITE) &&
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004100 !test_bit(FD_DISK_WRITABLE_BIT, &drive_state[drive].flags))
Jens Axboef2791e72016-08-25 08:56:51 -06004101 goto out;
4102 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004103 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004104 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 return 0;
4106out:
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004107 drive_state[drive].fd_ref--;
Jiri Kosinabfa10b82012-05-18 13:50:28 +02004108
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004109 if (!drive_state[drive].fd_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004112 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004113 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 return res;
4115}
4116
4117/*
4118 * Check if the disk has been changed or if a change has been faked.
4119 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004120static unsigned int floppy_check_events(struct gendisk *disk,
4121 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122{
4123 int drive = (long)disk->private_data;
4124
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004125 if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
4126 test_bit(FD_VERIFY_BIT, &drive_state[drive].flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004127 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004129 if (time_after(jiffies, drive_state[drive].last_checked + drive_params[drive].checkfreq)) {
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01004130 if (lock_fdc(drive))
Yufen Yu96d7cb92019-01-29 16:34:04 +08004131 return 0;
Joe Perches74f63f42010-03-10 15:20:58 -08004132 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 }
4135
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004136 if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
4137 test_bit(FD_VERIFY_BIT, &drive_state[drive].flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004139 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004140 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 return 0;
4142}
4143
4144/*
4145 * This implements "read block 0" for floppy_revalidate().
4146 * Needed for format autodetection, checking whether there is
4147 * a disk in the drive, and whether that disk is writable.
4148 */
4149
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004150struct rb0_cbdata {
4151 int drive;
4152 struct completion complete;
4153};
4154
Christoph Hellwig4246a0b2015-07-20 15:29:37 +02004155static void floppy_rb0_cb(struct bio *bio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156{
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004157 struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
4158 int drive = cbdata->drive;
4159
Christoph Hellwig4e4cbee2017-06-03 09:38:06 +02004160 if (bio->bi_status) {
Christoph Hellwig4246a0b2015-07-20 15:29:37 +02004161 pr_info("floppy: error %d while reading block 0\n",
Christoph Hellwig4e4cbee2017-06-03 09:38:06 +02004162 bio->bi_status);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004163 set_bit(FD_OPEN_SHOULD_FAIL_BIT, &drive_state[drive].flags);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004164 }
4165 complete(&cbdata->complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166}
4167
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004168static int __floppy_read_block_0(struct block_device *bdev, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169{
4170 struct bio bio;
4171 struct bio_vec bio_vec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 struct page *page;
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004173 struct rb0_cbdata cbdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 size_t size;
4175
4176 page = alloc_page(GFP_NOIO);
4177 if (!page) {
4178 process_fd_request();
4179 return -ENOMEM;
4180 }
4181
4182 size = bdev->bd_block_size;
4183 if (!size)
4184 size = 1024;
4185
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004186 cbdata.drive = drive;
4187
Ming Lei3a83f462016-11-22 08:57:21 -07004188 bio_init(&bio, &bio_vec, 1);
Christoph Hellwig74d46992017-08-23 19:10:32 +02004189 bio_set_dev(&bio, bdev);
Ming Lei2c73a602016-11-11 20:05:31 +08004190 bio_add_page(&bio, page, size, 0);
4191
Kent Overstreet4f024f32013-10-11 15:44:27 -07004192 bio.bi_iter.bi_sector = 0;
Jiri Kosina6314a102014-05-28 11:55:23 +02004193 bio.bi_flags |= (1 << BIO_QUIET);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004194 bio.bi_private = &cbdata;
4195 bio.bi_end_io = floppy_rb0_cb;
Mike Christie95fe6c12016-06-05 14:31:48 -05004196 bio_set_op_attrs(&bio, REQ_OP_READ, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197
Jens Axboede7b75d2018-11-09 15:58:40 -07004198 init_completion(&cbdata.complete);
4199
Mike Christie4e49ea42016-06-05 14:31:41 -05004200 submit_bio(&bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 process_fd_request();
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004202
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004203 wait_for_completion(&cbdata.complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204
4205 __free_page(page);
4206
4207 return 0;
4208}
4209
4210/* revalidate the floppy disk, i.e. trigger format autodetection by reading
4211 * the bootblock (block 0). "Autodetection" is also needed to check whether
4212 * there is a disk in the drive at all... Thus we also do it for fixed
4213 * geometry formats */
4214static int floppy_revalidate(struct gendisk *disk)
4215{
4216 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 int cf;
4218 int res = 0;
4219
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004220 if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
4221 test_bit(FD_VERIFY_BIT, &drive_state[drive].flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004222 test_bit(drive, &fake_change) ||
4223 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02004224 if (WARN(atomic_read(&usage_count) == 0,
4225 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02004227
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01004228 res = lock_fdc(drive);
4229 if (res)
4230 return res;
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004231 cf = (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
4232 test_bit(FD_VERIFY_BIT, &drive_state[drive].flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004233 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 process_fd_request(); /*already done by another thread */
4235 return 0;
4236 }
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004237 drive_state[drive].maxblock = 0;
4238 drive_state[drive].maxtrack = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 if (buffer_drive == drive)
4240 buffer_track = -1;
4241 clear_bit(drive, &fake_change);
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004242 clear_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 if (cf)
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004244 drive_state[drive].generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004245 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 /* auto-sensing */
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004247 res = __floppy_read_block_0(opened_bdev[drive], drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 } else {
4249 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08004250 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 process_fd_request();
4252 }
4253 }
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004254 set_capacity(disk, floppy_sizes[drive_state[drive].fd_device]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 return res;
4256}
4257
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07004258static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07004259 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05004260 .open = floppy_open,
4261 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02004262 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07004263 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004264 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07004265 .revalidate_disk = floppy_revalidate,
Al Viro229b53c2017-06-27 15:47:56 -04004266#ifdef CONFIG_COMPAT
4267 .compat_ioctl = fd_compat_ioctl,
4268#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271/*
4272 * Floppy Driver initialization
4273 * =============================
4274 */
4275
4276/* Determine the floppy disk controller type */
4277/* This routine was written by David C. Niemi */
4278static char __init get_fdc_version(void)
4279{
4280 int r;
4281
4282 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
Willy Tarreaude6048b2020-02-24 22:23:43 +01004283 if (fdc_state[fdc].reset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004285 r = result();
4286 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 return FDC_NONE; /* No FDC present ??? */
4288 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004289 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
4291 }
4292 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08004293 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
4294 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 return FDC_UNKNOWN;
4296 }
4297
4298 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08004299 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 return FDC_82072; /* 82072 doesn't know CONFIGURE */
4301 }
4302
4303 output_byte(FD_PERPENDICULAR);
4304 if (need_more_output() == MORE_OUTPUT) {
4305 output_byte(0);
4306 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08004307 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 return FDC_82072A; /* 82072A as found on Sparcs. */
4309 }
4310
4311 output_byte(FD_UNLOCK);
4312 r = result();
4313 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004314 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004315 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 * LOCK/UNLOCK */
4317 }
4318 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004319 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
4320 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 return FDC_UNKNOWN;
4322 }
4323 output_byte(FD_PARTID);
4324 r = result();
4325 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08004326 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
4327 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 return FDC_UNKNOWN;
4329 }
4330 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08004331 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 return FDC_82077; /* Revised 82077AA passes all the tests */
4333 }
4334 switch (reply_buffer[0] >> 5) {
4335 case 0x0:
4336 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08004337 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 return FDC_82078;
4339 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004340 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 return FDC_82078;
4342 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004343 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 return FDC_S82078B;
4345 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004346 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 return FDC_87306;
4348 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004349 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4350 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 return FDC_82078_UNKN;
4352 }
4353} /* get_fdc_version */
4354
4355/* lilo configuration */
4356
4357static void __init floppy_set_flags(int *ints, int param, int param2)
4358{
4359 int i;
4360
4361 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4362 if (param)
4363 default_drive_params[i].params.flags |= param2;
4364 else
4365 default_drive_params[i].params.flags &= ~param2;
4366 }
4367 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4368}
4369
4370static void __init daring(int *ints, int param, int param2)
4371{
4372 int i;
4373
4374 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4375 if (param) {
4376 default_drive_params[i].params.select_delay = 0;
4377 default_drive_params[i].params.flags |=
4378 FD_SILENT_DCL_CLEAR;
4379 } else {
4380 default_drive_params[i].params.select_delay =
4381 2 * HZ / 100;
4382 default_drive_params[i].params.flags &=
4383 ~FD_SILENT_DCL_CLEAR;
4384 }
4385 }
4386 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4387}
4388
4389static void __init set_cmos(int *ints, int dummy, int dummy2)
4390{
4391 int current_drive = 0;
4392
4393 if (ints[0] != 2) {
4394 DPRINT("wrong number of parameters for CMOS\n");
4395 return;
4396 }
4397 current_drive = ints[1];
4398 if (current_drive < 0 || current_drive >= 8) {
4399 DPRINT("bad drive for set_cmos\n");
4400 return;
4401 }
4402#if N_FDC > 1
4403 if (current_drive >= 4 && !FDC2)
4404 FDC2 = 0x370;
4405#endif
Willy Tarreau031faab2020-02-24 22:23:48 +01004406 drive_params[current_drive].cmos = ints[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 DPRINT("setting CMOS code to %d\n", ints[2]);
4408}
4409
4410static struct param_table {
4411 const char *name;
4412 void (*fn) (int *ints, int param, int param2);
4413 int *var;
4414 int def_param;
4415 int param2;
4416} config_params[] __initdata = {
4417 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4418 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4419 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4420 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4421 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4422 {"daring", daring, NULL, 1, 0},
4423#if N_FDC > 1
4424 {"two_fdc", NULL, &FDC2, 0x370, 0},
4425 {"one_fdc", NULL, &FDC2, 0, 0},
4426#endif
4427 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4428 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4429 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4430 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4431 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4432 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4433 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4434 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4435 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4436 {"nofifo", NULL, &no_fifo, 0x20, 0},
4437 {"usefifo", NULL, &no_fifo, 0, 0},
4438 {"cmos", set_cmos, NULL, 0, 0},
4439 {"slow", NULL, &slow_floppy, 1, 0},
4440 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4441 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4442 {"L40SX", NULL, &print_unex, 0, 0}
4443
4444 EXTRA_FLOPPY_PARAMS
4445};
4446
4447static int __init floppy_setup(char *str)
4448{
4449 int i;
4450 int param;
4451 int ints[11];
4452
4453 str = get_options(str, ARRAY_SIZE(ints), ints);
4454 if (str) {
4455 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4456 if (strcmp(str, config_params[i].name) == 0) {
4457 if (ints[0])
4458 param = ints[1];
4459 else
4460 param = config_params[i].def_param;
4461 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004462 config_params[i].fn(ints, param,
4463 config_params[i].
4464 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 if (config_params[i].var) {
4466 DPRINT("%s=%d\n", str, param);
4467 *config_params[i].var = param;
4468 }
4469 return 1;
4470 }
4471 }
4472 }
4473 if (str) {
4474 DPRINT("unknown floppy option [%s]\n", str);
4475
4476 DPRINT("allowed options are:");
4477 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004478 pr_cont(" %s", config_params[i].name);
4479 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 } else
4481 DPRINT("botched floppy option\n");
Mauro Carvalho Chehabe7751612019-06-18 11:47:10 -03004482 DPRINT("Read Documentation/admin-guide/blockdev/floppy.rst\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 return 0;
4484}
4485
4486static int have_no_fdc = -ENODEV;
4487
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004488static ssize_t floppy_cmos_show(struct device *dev,
4489 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004490{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004491 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004492 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004493
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004494 drive = p->id;
Willy Tarreau1ce9ae92020-02-24 22:23:45 +01004495 return sprintf(buf, "%X\n", drive_params[drive].cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004496}
Joe Perches48c8cee2010-03-10 15:20:45 -08004497
Joe Perches5657a812018-05-24 13:38:59 -06004498static DEVICE_ATTR(cmos, 0444, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004499
Takashi Iwaib7f120b2015-02-02 17:08:45 +01004500static struct attribute *floppy_dev_attrs[] = {
4501 &dev_attr_cmos.attr,
4502 NULL
4503};
4504
4505ATTRIBUTE_GROUPS(floppy_dev);
4506
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507static void floppy_device_release(struct device *dev)
4508{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509}
4510
Frans Popc90cd332009-07-25 22:24:54 +02004511static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004512{
4513 int fdc;
4514
4515 for (fdc = 0; fdc < N_FDC; fdc++)
Willy Tarreaude6048b2020-02-24 22:23:43 +01004516 if (fdc_state[fdc].address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004517 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004518
4519 return 0;
4520}
4521
Alexey Dobriyan47145212009-12-14 18:00:08 -08004522static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004523 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004524 .restore = floppy_resume,
4525};
4526
4527static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004528 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004529 .name = "floppy",
4530 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004531 },
4532};
4533
Omar Sandovala9f38e12018-10-15 09:21:34 -06004534static const struct blk_mq_ops floppy_mq_ops = {
4535 .queue_rq = floppy_queue_rq,
4536};
4537
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004538static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004540static bool floppy_available(int drive)
4541{
4542 if (!(allowed_drive_mask & (1 << drive)))
4543 return false;
4544 if (fdc_state[FDC(drive)].version == FDC_NONE)
4545 return false;
4546 return true;
4547}
4548
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4550{
4551 int drive = (*part & 3) | ((*part & 0x80) >> 5);
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004552 if (drive >= N_DRIVE || !floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004554 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 return NULL;
4556 *part = 0;
Jan Kara3079c222018-02-26 13:01:38 +01004557 return get_disk_and_module(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558}
4559
Andi Kleen0cc15d032012-07-02 17:27:04 -07004560static int __init do_floppy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561{
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004562 int i, unit, drive, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563
Stephen Hemminger285203c2010-06-15 13:21:11 +02004564 set_debugt();
4565 interruptjiffies = resultjiffies = jiffies;
4566
Kumar Gala68e1ee62008-09-22 14:41:31 -07004567#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004568 if (check_legacy_ioport(FDC1))
4569 return -ENODEV;
4570#endif
4571
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 raw_cmd = NULL;
4573
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004574 floppy_wq = alloc_ordered_workqueue("floppy", 0);
4575 if (!floppy_wq)
4576 return -ENOMEM;
4577
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004578 for (drive = 0; drive < N_DRIVE; drive++) {
4579 disks[drive] = alloc_disk(1);
4580 if (!disks[drive]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 err = -ENOMEM;
4582 goto out_put_disk;
4583 }
4584
Omar Sandovala9f38e12018-10-15 09:21:34 -06004585 disks[drive]->queue = blk_mq_init_sq_queue(&tag_sets[drive],
4586 &floppy_mq_ops, 2,
4587 BLK_MQ_F_SHOULD_MERGE);
4588 if (IS_ERR(disks[drive]->queue)) {
4589 err = PTR_ERR(disks[drive]->queue);
4590 disks[drive]->queue = NULL;
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004591 goto out_put_disk;
Jens Axboe48821182010-09-22 09:32:36 +02004592 }
4593
Christoph Hellwig8fc45042017-06-19 09:26:26 +02004594 blk_queue_bounce_limit(disks[drive]->queue, BLK_BOUNCE_HIGH);
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004595 blk_queue_max_hw_sectors(disks[drive]->queue, 64);
4596 disks[drive]->major = FLOPPY_MAJOR;
4597 disks[drive]->first_minor = TOMINOR(drive);
4598 disks[drive]->fops = &floppy_fops;
Martin Wilck773008f2019-03-27 14:51:04 +01004599 disks[drive]->events = DISK_EVENT_MEDIA_CHANGE;
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004600 sprintf(disks[drive]->disk_name, "fd%d", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601
Kees Cookb1bf4212017-10-04 17:49:29 -07004602 timer_setup(&motor_off_timer[drive], motor_off_callback, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 }
4604
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 err = register_blkdev(FLOPPY_MAJOR, "fd");
4606 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004607 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004609 err = platform_driver_register(&floppy_driver);
4610 if (err)
4611 goto out_unreg_blkdev;
4612
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4614 floppy_find, NULL, NULL);
4615
4616 for (i = 0; i < 256; i++)
4617 if (ITYPE(i))
4618 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4619 else
4620 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4621
Joe Perches73507e62010-03-10 15:21:03 -08004622 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 config_types();
4624
4625 for (i = 0; i < N_FDC; i++) {
4626 fdc = i;
Willy Tarreaude6048b2020-02-24 22:23:43 +01004627 memset(&fdc_state[fdc], 0, sizeof(*fdc_state));
4628 fdc_state[fdc].dtr = -1;
4629 fdc_state[fdc].dor = 0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004631 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632#ifdef __mc68000__
4633 if (MACH_IS_SUN3X)
4634#endif
Willy Tarreaude6048b2020-02-24 22:23:43 +01004635 fdc_state[fdc].version = FDC_82072A;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636#endif
4637 }
4638
4639 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 fdc_state[0].address = FDC1;
4641 if (fdc_state[0].address == -1) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004642 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 err = -ENODEV;
4644 goto out_unreg_region;
4645 }
4646#if N_FDC > 1
4647 fdc_state[1].address = FDC2;
4648#endif
4649
4650 fdc = 0; /* reset fdc in case of unexpected interrupt */
4651 err = floppy_grab_irq_and_dma();
4652 if (err) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004653 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 err = -EBUSY;
4655 goto out_unreg_region;
4656 }
4657
4658 /* initialise drive state */
4659 for (drive = 0; drive < N_DRIVE; drive++) {
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004660 memset(&drive_state[drive], 0, sizeof(drive_state[drive]));
Willy Tarreau121e2972020-02-24 22:23:47 +01004661 memset(&write_errors[drive], 0, sizeof(write_errors[drive]));
Willy Tarreau8d9d34e22020-02-24 22:23:46 +01004662 set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[drive].flags);
4663 set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
4664 set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
4665 drive_state[drive].fd_device = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 floppy_track_buffer = NULL;
4667 max_buffer_sectors = 0;
4668 }
4669 /*
4670 * Small 10 msec delay to let through any interrupt that
4671 * initialization might have triggered, to not
4672 * confuse detection:
4673 */
4674 msleep(10);
4675
4676 for (i = 0; i < N_FDC; i++) {
4677 fdc = i;
Willy Tarreaude6048b2020-02-24 22:23:43 +01004678 fdc_state[fdc].driver_version = FD_DRIVER_VERSION;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 for (unit = 0; unit < 4; unit++)
Willy Tarreaude6048b2020-02-24 22:23:43 +01004680 fdc_state[fdc].track[unit] = 0;
4681 if (fdc_state[fdc].address == -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 continue;
Willy Tarreaude6048b2020-02-24 22:23:43 +01004683 fdc_state[fdc].rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004684 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004686 floppy_release_regions(fdc);
Willy Tarreaude6048b2020-02-24 22:23:43 +01004687 fdc_state[fdc].address = -1;
4688 fdc_state[fdc].version = FDC_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 continue;
4690 }
4691 /* Try to determine the floppy controller type */
Willy Tarreaude6048b2020-02-24 22:23:43 +01004692 fdc_state[fdc].version = get_fdc_version();
4693 if (fdc_state[fdc].version == FDC_NONE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004695 floppy_release_regions(fdc);
Willy Tarreaude6048b2020-02-24 22:23:43 +01004696 fdc_state[fdc].address = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 continue;
4698 }
Willy Tarreaude6048b2020-02-24 22:23:43 +01004699 if (can_use_virtual_dma == 2 && fdc_state[fdc].version < FDC_82072A)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700 can_use_virtual_dma = 0;
4701
4702 have_no_fdc = 0;
4703 /* Not all FDCs seem to be able to handle the version command
4704 * properly, so force a reset for the standard FDC clones,
4705 * to avoid interrupt garbage.
4706 */
Joe Perches74f63f42010-03-10 15:20:58 -08004707 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 }
4709 fdc = 0;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004710 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004712 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 if (have_no_fdc) {
4714 DPRINT("no floppy controllers found\n");
4715 err = have_no_fdc;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004716 goto out_release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 }
4718
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 for (drive = 0; drive < N_DRIVE; drive++) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004720 if (!floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004722
4723 floppy_device[drive].name = floppy_device_name;
4724 floppy_device[drive].id = drive;
4725 floppy_device[drive].dev.release = floppy_device_release;
Takashi Iwaib7f120b2015-02-02 17:08:45 +01004726 floppy_device[drive].dev.groups = floppy_dev_groups;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004727
4728 err = platform_device_register(&floppy_device[drive]);
4729 if (err)
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004730 goto out_remove_drives;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004731
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 /* to be cleaned up... */
4733 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reineckefef912b2018-09-28 08:17:19 +02004735 device_add_disk(&floppy_device[drive].dev, disks[drive], NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 }
4737
4738 return 0;
4739
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004740out_remove_drives:
4741 while (drive--) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004742 if (floppy_available(drive)) {
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004743 del_gendisk(disks[drive]);
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004744 platform_device_unregister(&floppy_device[drive]);
4745 }
4746 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004747out_release_dma:
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004748 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 floppy_release_irq_and_dma();
4750out_unreg_region:
4751 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004752 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753out_unreg_blkdev:
4754 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755out_put_disk:
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004756 destroy_workqueue(floppy_wq);
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004757 for (drive = 0; drive < N_DRIVE; drive++) {
4758 if (!disks[drive])
4759 break;
4760 if (disks[drive]->queue) {
4761 del_timer_sync(&motor_off_timer[drive]);
4762 blk_cleanup_queue(disks[drive]->queue);
4763 disks[drive]->queue = NULL;
Omar Sandovala9f38e12018-10-15 09:21:34 -06004764 blk_mq_free_tag_set(&tag_sets[drive]);
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004765 }
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004766 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 }
4768 return err;
4769}
4770
Andi Kleen0cc15d032012-07-02 17:27:04 -07004771#ifndef MODULE
4772static __init void floppy_async_init(void *data, async_cookie_t cookie)
4773{
4774 do_floppy_init();
4775}
4776#endif
4777
4778static int __init floppy_init(void)
4779{
4780#ifdef MODULE
4781 return do_floppy_init();
4782#else
4783 /* Don't hold up the bootup by the floppy initialization */
4784 async_schedule(floppy_async_init, NULL);
4785 return 0;
4786#endif
4787}
4788
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004789static const struct io_region {
4790 int offset;
4791 int size;
4792} io_regions[] = {
4793 { 2, 1 },
4794 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4795 { 4, 2 },
4796 /* address + 6 is reserved, and may be taken by IDE.
4797 * Unfortunately, Adaptec doesn't know this :-(, */
4798 { 7, 1 },
4799};
4800
4801static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4802{
4803 while (p != io_regions) {
4804 p--;
Willy Tarreaude6048b2020-02-24 22:23:43 +01004805 release_region(fdc_state[fdc].address + p->offset, p->size);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004806 }
4807}
4808
4809#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4810
4811static int floppy_request_regions(int fdc)
4812{
4813 const struct io_region *p;
4814
4815 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Willy Tarreaude6048b2020-02-24 22:23:43 +01004816 if (!request_region(fdc_state[fdc].address + p->offset,
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004817 p->size, "floppy")) {
4818 DPRINT("Floppy io-port 0x%04lx in use\n",
Willy Tarreaude6048b2020-02-24 22:23:43 +01004819 fdc_state[fdc].address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004820 floppy_release_allocated_regions(fdc, p);
4821 return -EBUSY;
4822 }
4823 }
4824 return 0;
4825}
4826
4827static void floppy_release_regions(int fdc)
4828{
4829 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4830}
4831
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832static int floppy_grab_irq_and_dma(void)
4833{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004834 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004836
4837 /*
4838 * We might have scheduled a free_irq(), wait it to
4839 * drain first:
4840 */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004841 flush_workqueue(floppy_wq);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004842
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 if (fd_request_irq()) {
4844 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4845 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004846 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 return -1;
4848 }
4849 if (fd_request_dma()) {
4850 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4851 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004852 if (can_use_virtual_dma & 2)
4853 use_virtual_dma = can_use_virtual_dma = 1;
4854 if (!(can_use_virtual_dma & 1)) {
4855 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004856 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004857 return -1;
4858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 }
4860
4861 for (fdc = 0; fdc < N_FDC; fdc++) {
Willy Tarreaude6048b2020-02-24 22:23:43 +01004862 if (fdc_state[fdc].address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004863 if (floppy_request_regions(fdc))
4864 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 }
4866 }
4867 for (fdc = 0; fdc < N_FDC; fdc++) {
Willy Tarreaude6048b2020-02-24 22:23:43 +01004868 if (fdc_state[fdc].address != -1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 reset_fdc_info(1);
Willy Tarreaude6048b2020-02-24 22:23:43 +01004870 fd_outb(fdc_state[fdc].dor, FD_DOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 }
4872 }
4873 fdc = 0;
4874 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4875
4876 for (fdc = 0; fdc < N_FDC; fdc++)
Willy Tarreaude6048b2020-02-24 22:23:43 +01004877 if (fdc_state[fdc].address != -1)
4878 fd_outb(fdc_state[fdc].dor, FD_DOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004880 * The driver will try and free resources and relies on us
4881 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 */
4883 fdc = 0;
4884 irqdma_allocated = 1;
4885 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004886cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 fd_free_irq();
4888 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004889 while (--fdc >= 0)
4890 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004891 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 return -1;
4893}
4894
4895static void floppy_release_irq_and_dma(void)
4896{
4897 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898#ifndef __sparc__
4899 int drive;
4900#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 long tmpsize;
4902 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004904 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004906
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 if (irqdma_allocated) {
4908 fd_disable_dma();
4909 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004910 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 irqdma_allocated = 0;
4912 }
4913 set_dor(0, ~0, 8);
4914#if N_FDC > 1
4915 set_dor(1, ~8, 0);
4916#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917
4918 if (floppy_track_buffer && max_buffer_sectors) {
4919 tmpsize = max_buffer_sectors * 1024;
4920 tmpaddr = (unsigned long)floppy_track_buffer;
4921 floppy_track_buffer = NULL;
4922 max_buffer_sectors = 0;
4923 buffer_min = buffer_max = -1;
4924 fd_dma_mem_free(tmpaddr, tmpsize);
4925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926#ifndef __sparc__
4927 for (drive = 0; drive < N_FDC * 4; drive++)
4928 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004929 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930#endif
4931
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004932 if (delayed_work_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004933 pr_info("floppy timer still active:%s\n", timeout_message);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004934 if (delayed_work_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004935 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004936 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004937 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 old_fdc = fdc;
4939 for (fdc = 0; fdc < N_FDC; fdc++)
Willy Tarreaude6048b2020-02-24 22:23:43 +01004940 if (fdc_state[fdc].address != -1)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004941 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 fdc = old_fdc;
4943}
4944
4945#ifdef MODULE
4946
4947static char *floppy;
4948
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949static void __init parse_floppy_cfg_string(char *cfg)
4950{
4951 char *ptr;
4952
4953 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004954 ptr = cfg;
4955 while (*cfg && *cfg != ' ' && *cfg != '\t')
4956 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 if (*cfg) {
4958 *cfg = '\0';
4959 cfg++;
4960 }
4961 if (*ptr)
4962 floppy_setup(ptr);
4963 }
4964}
4965
Jon Schindler7afea3b2008-04-29 00:59:21 -07004966static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967{
4968 if (floppy)
4969 parse_floppy_cfg_string(floppy);
4970 return floppy_init();
4971}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004972module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973
Jon Schindler7afea3b2008-04-29 00:59:21 -07004974static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975{
4976 int drive;
4977
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4979 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004980 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004982 destroy_workqueue(floppy_wq);
4983
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 for (drive = 0; drive < N_DRIVE; drive++) {
4985 del_timer_sync(&motor_off_timer[drive]);
4986
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004987 if (floppy_available(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004989 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 }
Jens Axboe48821182010-09-22 09:32:36 +02004991 blk_cleanup_queue(disks[drive]->queue);
Omar Sandovala9f38e12018-10-15 09:21:34 -06004992 blk_mq_free_tag_set(&tag_sets[drive]);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004993
4994 /*
4995 * These disks have not called add_disk(). Don't put down
4996 * queue reference in put_disk().
4997 */
4998 if (!(allowed_drive_mask & (1 << drive)) ||
4999 fdc_state[FDC(drive)].version == FDC_NONE)
5000 disks[drive]->queue = NULL;
5001
Vivek Goyald017bf62010-11-06 08:16:05 -04005002 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004
Jiri Kosina070ad7e2012-05-18 13:50:25 +02005005 cancel_delayed_work_sync(&fd_timeout);
5006 cancel_delayed_work_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007
Stephen Hemminger575cfc62010-06-15 13:21:11 +02005008 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 floppy_release_irq_and_dma();
5010
5011 /* eject disk, if any */
5012 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013}
Joe Perches48c8cee2010-03-10 15:20:45 -08005014
Jon Schindler7afea3b2008-04-29 00:59:21 -07005015module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016
5017module_param(floppy, charp, 0);
5018module_param(FLOPPY_IRQ, int, 0);
5019module_param(FLOPPY_DMA, int, 0);
5020MODULE_AUTHOR("Alain L. Knaff");
5021MODULE_SUPPORTED_DEVICE("fd");
5022MODULE_LICENSE("GPL");
5023
Scott James Remnant83f9ef42009-04-02 16:56:47 -07005024/* This doesn't actually get used other than for module information */
5025static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08005026 {"PNP0700", 0},
5027 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07005028};
Joe Perches48c8cee2010-03-10 15:20:45 -08005029
Scott James Remnant83f9ef42009-04-02 16:56:47 -07005030MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
5031
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032#else
5033
5034__setup("floppy=", floppy_setup);
5035module_init(floppy_init)
5036#endif
5037
5038MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);