blob: 9fb9b312ab6bfea7980a67e7712a56905a8bea10 [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 DP (&drive_params[current_drive])
310#define DRS (&drive_state[current_drive])
311#define DRWE (&write_errors[current_drive])
312#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Joe Perches48c8cee2010-03-10 15:20:45 -0800314#define UDP (&drive_params[drive])
315#define UDRS (&drive_state[drive])
316#define UDRWE (&write_errors[drive])
317#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Joe Perches48c8cee2010-03-10 15:20:45 -0800319#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
320#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800323#define COMMAND (raw_cmd->cmd[0])
324#define DR_SELECT (raw_cmd->cmd[1])
325#define TRACK (raw_cmd->cmd[2])
326#define HEAD (raw_cmd->cmd[3])
327#define SECTOR (raw_cmd->cmd[4])
328#define SIZECODE (raw_cmd->cmd[5])
329#define SECT_PER_TRACK (raw_cmd->cmd[6])
330#define GAP (raw_cmd->cmd[7])
331#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332#define NR_RW 9
333
334/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800335#define F_SIZECODE (raw_cmd->cmd[2])
336#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
337#define F_GAP (raw_cmd->cmd[4])
338#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339#define NR_F 6
340
341/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800342 * Maximum disk size (in kilobytes).
343 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 * [Now it is rather a minimum]
345 */
346#define MAX_DISK_SIZE 4 /* 3984 */
347
348/*
349 * globals used by 'result()'
350 */
351#define MAX_REPLIES 16
352static unsigned char reply_buffer[MAX_REPLIES];
Joe Perches891eda82010-03-10 15:21:05 -0800353static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800354#define ST0 (reply_buffer[0])
355#define ST1 (reply_buffer[1])
356#define ST2 (reply_buffer[2])
357#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
358#define R_TRACK (reply_buffer[3])
359#define R_HEAD (reply_buffer[4])
360#define R_SECTOR (reply_buffer[5])
361#define R_SIZECODE (reply_buffer[6])
362
363#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365/*
366 * this struct defines the different floppy drive types.
367 */
368static struct {
369 struct floppy_drive_params params;
370 const char *name; /* name printed while booting */
371} default_drive_params[] = {
372/* NOTE: the time values in jiffies should be in msec!
373 CMOS drive type
374 | Maximum data rate supported by drive type
375 | | Head load time, msec
376 | | | Head unload time, msec (not used)
377 | | | | Step rate interval, usec
378 | | | | | Time needed for spinup time (jiffies)
379 | | | | | | Timeout for spinning down (jiffies)
380 | | | | | | | Spindown offset (where disk stops)
381 | | | | | | | | Select delay
382 | | | | | | | | | RPS
383 | | | | | | | | | | Max number of tracks
384 | | | | | | | | | | | Interrupt timeout
385 | | | | | | | | | | | | Max nonintlv. sectors
386 | | | | | | | | | | | | | -Max Errors- flags */
387{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
388 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
389
390{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
391 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
392
393{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
394 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
395
396{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
397 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
398
399{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
400 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
401
402{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
403 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
404
405{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
406 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
407/* | --autodetected formats--- | | |
408 * read_track | | Name printed when booting
409 * | Native format
410 * Frequency of disk change checks */
411};
412
413static struct floppy_drive_params drive_params[N_DRIVE];
414static struct floppy_drive_struct drive_state[N_DRIVE];
415static struct floppy_write_errors write_errors[N_DRIVE];
416static struct timer_list motor_off_timer[N_DRIVE];
417static struct gendisk *disks[N_DRIVE];
Omar Sandovala9f38e12018-10-15 09:21:34 -0600418static struct blk_mq_tag_set tag_sets[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800420static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
422
423/*
424 * This struct defines the different floppy types.
425 *
426 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
427 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
428 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
429 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
430 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
431 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
432 * side 0 is on physical side 0 (but with the misnamed sector IDs).
433 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700434 * 'options'.
435 *
436 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
437 * The LSB (bit 2) is flipped. For most disks, the first sector
438 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
439 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
440 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
441 *
442 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 */
444/*
445 Size
446 | Sectors per track
447 | | Head
448 | | | Tracks
449 | | | | Stretch
450 | | | | | Gap 1 size
451 | | | | | | Data rate, | 0x40 for perp
452 | | | | | | | Spec1 (stepping rate, head unload
453 | | | | | | | | /fmt gap (gap2) */
454static struct floppy_struct floppy_type[32] = {
455 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
456 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
457 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
458 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
459 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
460 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
461 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
462 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
463 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
464 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
465
466 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
467 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
468 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
469 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
470 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
471 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
472 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
473 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
474 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
475 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
476
477 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
478 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
479 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
480 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
481 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
482 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
483 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
484 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
485 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
489 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
490};
491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492#define SECTSIZE (_FD_SECTSIZE(*floppy))
493
494/* Auto-detection: Disk type used until the next media change occurs. */
495static struct floppy_struct *current_type[N_DRIVE];
496
497/*
498 * User-provided type information. current_type points to
499 * the respective entry of this array.
500 */
501static struct floppy_struct user_params[N_DRIVE];
502
503static sector_t floppy_sizes[256];
504
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200505static char floppy_device_name[] = "floppy";
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507/*
508 * The driver is trying to determine the correct media format
509 * while probing is set. rw_interrupt() clears it after a
510 * successful access.
511 */
512static int probing;
513
514/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800515#define FD_COMMAND_NONE -1
516#define FD_COMMAND_ERROR 2
517#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519static volatile int command_status = FD_COMMAND_NONE;
520static unsigned long fdc_busy;
521static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
522static DECLARE_WAIT_QUEUE_HEAD(command_done);
523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524/* Errors during formatting are counted here. */
525static int format_errors;
526
527/* Format request descriptor. */
528static struct format_descr format_req;
529
530/*
531 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
532 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
533 * H is head unload time (1=16ms, 2=32ms, etc)
534 */
535
536/*
537 * Track buffer
538 * Because these are written to by the DMA controller, they must
539 * not contain a 64k byte boundary crossing, or data will be
540 * corrupted/lost.
541 */
542static char *floppy_track_buffer;
543static int max_buffer_sectors;
544
545static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700546typedef void (*done_f)(int);
Stephen Hemminger3b06c212010-07-20 20:09:00 -0600547static const struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800548 void (*interrupt)(void);
549 /* this is called after the interrupt of the
550 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700551 void (*redo)(void); /* this is called to retry the operation */
552 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 done_f done; /* this is called to say if the operation has
554 * succeeded/failed */
555} *cont;
556
557static void floppy_ready(void);
558static void floppy_start(void);
559static void process_fd_request(void);
560static void recalibrate_floppy(void);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200561static void floppy_shutdown(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800563static int floppy_request_regions(int);
564static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565static int floppy_grab_irq_and_dma(void);
566static void floppy_release_irq_and_dma(void);
567
568/*
569 * The "reset" variable should be tested whenever an interrupt is scheduled,
570 * after the commands have been sent. This is to ensure that the driver doesn't
571 * get wedged when the interrupt doesn't come because of a failed command.
572 * reset doesn't need to be tested before sending commands, because
573 * output_byte is automatically disabled when reset is set.
574 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575static void reset_fdc(void);
576
577/*
578 * These are global variables, as that's the easiest way to give
579 * information to interrupts. They are the data used for the current
580 * request.
581 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800582#define NO_TRACK -1
583#define NEED_1_RECAL -2
584#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200586static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588/* buffer related variables */
589static int buffer_track = -1;
590static int buffer_drive = -1;
591static int buffer_min = -1;
592static int buffer_max = -1;
593
594/* fdc related variables, should end up in a struct */
595static struct floppy_fdc_state fdc_state[N_FDC];
596static int fdc; /* current fdc */
597
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200598static struct workqueue_struct *floppy_wq;
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600static struct floppy_struct *_floppy = floppy_type;
601static unsigned char current_drive;
602static long current_count_sectors;
603static unsigned char fsector_t; /* sector in track */
604static unsigned char in_sector_offset; /* offset within physical sector,
605 * expressed in units of 512 bytes */
606
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100607static inline bool drive_no_geom(int drive)
608{
609 return !current_type[drive] && !ITYPE(UDRS->fd_device);
610}
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612#ifndef fd_eject
613static inline int fd_eject(int drive)
614{
615 return -EINVAL;
616}
617#endif
618
619/*
620 * Debugging
621 * =========
622 */
623#ifdef DEBUGT
624static long unsigned debugtimer;
625
626static inline void set_debugt(void)
627{
628 debugtimer = jiffies;
629}
630
Joe Perchesded28632010-03-10 15:21:09 -0800631static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
633 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800634 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635}
636#else
637static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800638static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639#endif /* DEBUGT */
640
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200642static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643static const char *timeout_message;
644
Joe Perches275176b2010-03-10 15:21:06 -0800645static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
647 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800648 if (test_bit(0, &fdc_busy) && command_status < 2 &&
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200649 !delayed_work_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800650 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
652}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Joe Perches48c8cee2010-03-10 15:20:45 -0800654static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656#define OLOGSIZE 20
657
Joe Perches48c8cee2010-03-10 15:20:45 -0800658static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659static unsigned long interruptjiffies;
660static unsigned long resultjiffies;
661static int resultsize;
662static unsigned long lastredo;
663
664static struct output_log {
665 unsigned char data;
666 unsigned char status;
667 unsigned long jiffies;
668} output_log[OLOGSIZE];
669
670static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672#define current_reqD -1
673#define MAXTIMEOUT -2
674
Joe Perches73507e62010-03-10 15:21:03 -0800675static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200677 unsigned long delay;
678
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (drive == current_reqD)
680 drive = current_drive;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200681
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700682 if (drive < 0 || drive >= N_DRIVE) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200683 delay = 20UL * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 drive = 0;
685 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200686 delay = UDP->timeout;
687
Tejun Heoe7c2f962012-08-21 13:18:24 -0700688 mod_delayed_work(floppy_wq, &fd_timeout, delay);
Joe Perchesa81ee542010-03-10 15:20:46 -0800689 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800690 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 timeout_message = message;
692}
693
Joe Perches73507e62010-03-10 15:21:03 -0800694static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
696 unsigned long flags;
697
698 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800699 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 spin_unlock_irqrestore(&floppy_lock, flags);
701}
702
Joe Perches48c8cee2010-03-10 15:20:45 -0800703#define INFBOUND(a, b) (a) = max_t(int, a, b)
704#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706/*
707 * Bottom half floppy driver.
708 * ==========================
709 *
710 * This part of the file contains the code talking directly to the hardware,
711 * and also the main service loop (seek-configure-spinup-command)
712 */
713
714/*
715 * disk change.
716 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
717 * and the last_checked date.
718 *
719 * last_checked is the date of the last check which showed 'no disk change'
720 * FD_DISK_CHANGE is set under two conditions:
721 * 1. The floppy has been changed after some i/o to that floppy already
722 * took place.
723 * 2. No floppy disk is in the drive. This is done in order to ensure that
724 * requests are quickly flushed in case there is no disk in the drive. It
725 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
726 * the drive.
727 *
728 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
729 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
730 * each seek. If a disk is present, the disk change line should also be
731 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
732 * change line is set, this means either that no disk is in the drive, or
733 * that it has been removed since the last seek.
734 *
735 * This means that we really have a third possibility too:
736 * The floppy has been changed after the last seek.
737 */
738
739static int disk_change(int drive)
740{
741 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700742
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800743 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 DPRINT("WARNING disk change called early\n");
745 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
746 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
747 DPRINT("probing disk change on unselected drive\n");
748 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
749 (unsigned int)FDCS->dor);
750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Joe Perches87f530d2010-03-10 15:20:54 -0800752 debug_dcl(UDP->flags,
753 "checking disk change line for drive %d\n", drive);
754 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
755 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
756 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
757
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800759 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800761 set_bit(FD_VERIFY_BIT, &UDRS->flags);
762 /* verify write protection */
763
764 if (UDRS->maxblock) /* mark it changed */
765 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 /* invalidate its geometry */
768 if (UDRS->keep_data >= 0) {
769 if ((UDP->flags & FTD_MSG) &&
770 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800771 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 current_type[drive] = NULL;
773 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
774 }
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return 1;
777 } else {
778 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800779 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
781 return 0;
782}
783
784static inline int is_selected(int dor, int unit)
785{
786 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
787}
788
Joe Perches57584c52010-03-10 15:21:00 -0800789static bool is_ready_state(int status)
790{
791 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
792 return state == STATUS_READY;
793}
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795static int set_dor(int fdc, char mask, char data)
796{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700797 unsigned char unit;
798 unsigned char drive;
799 unsigned char newdor;
800 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 if (FDCS->address == -1)
803 return -1;
804
805 olddor = FDCS->dor;
806 newdor = (olddor & mask) | data;
807 if (newdor != olddor) {
808 unit = olddor & 0x3;
809 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
810 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800811 debug_dcl(UDP->flags,
812 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 disk_change(drive);
814 }
815 FDCS->dor = newdor;
816 fd_outb(newdor, FD_DOR);
817
818 unit = newdor & 0x3;
819 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
820 drive = REVDRIVE(fdc, unit);
821 UDRS->select_date = jiffies;
822 }
823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return olddor;
825}
826
827static void twaddle(void)
828{
829 if (DP->select_delay)
830 return;
831 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
832 fd_outb(FDCS->dor, FD_DOR);
833 DRS->select_date = jiffies;
834}
835
Joe Perches57584c52010-03-10 15:21:00 -0800836/*
837 * Reset all driver information about the current fdc.
838 * This is needed after a reset, and after a raw command.
839 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840static void reset_fdc_info(int mode)
841{
842 int drive;
843
844 FDCS->spec1 = FDCS->spec2 = -1;
845 FDCS->need_configure = 1;
846 FDCS->perp_mode = 1;
847 FDCS->rawcmd = 0;
848 for (drive = 0; drive < N_DRIVE; drive++)
849 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
850 UDRS->track = NEED_2_RECAL;
851}
852
853/* selects the fdc and drive, and enables the fdc's input/dma. */
854static void set_fdc(int drive)
855{
856 if (drive >= 0 && drive < N_DRIVE) {
857 fdc = FDC(drive);
858 current_drive = drive;
859 }
860 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800861 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 return;
863 }
864 set_dor(fdc, ~0, 8);
865#if N_FDC > 1
866 set_dor(1 - fdc, ~8, 0);
867#endif
868 if (FDCS->rawcmd == 2)
869 reset_fdc_info(1);
870 if (fd_inb(FD_STATUS) != STATUS_READY)
871 FDCS->reset = 1;
872}
873
874/* locks the driver */
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +0100875static int lock_fdc(int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200877 if (WARN(atomic_read(&usage_count) == 0,
878 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200881 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
882 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 command_status = FD_COMMAND_NONE;
885
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200886 reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 set_fdc(drive);
888 return 0;
889}
890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200892static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 if (!test_bit(0, &fdc_busy))
895 DPRINT("FDC access conflict!\n");
896
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200897 raw_cmd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 command_status = FD_COMMAND_NONE;
Tejun Heo136b5722012-08-21 13:18:24 -0700899 cancel_delayed_work(&fd_timeout);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200900 do_floppy = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 cont = NULL;
902 clear_bit(0, &fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 wake_up(&fdc_wait);
904}
905
906/* switches the motor off after a given timeout */
Kees Cookb1bf4212017-10-04 17:49:29 -0700907static void motor_off_callback(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908{
Kees Cookb1bf4212017-10-04 17:49:29 -0700909 unsigned long nr = t - motor_off_timer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 unsigned char mask = ~(0x10 << UNIT(nr));
911
Kees Cookb1bf4212017-10-04 17:49:29 -0700912 if (WARN_ON_ONCE(nr >= N_DRIVE))
913 return;
914
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 set_dor(FDC(nr), mask, 0);
916}
917
918/* schedules motor off */
919static void floppy_off(unsigned int drive)
920{
921 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700922 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 if (!(FDCS->dor & (0x10 << UNIT(drive))))
925 return;
926
927 del_timer(motor_off_timer + drive);
928
929 /* make spindle stop in a position which minimizes spinup time
930 * next time */
931 if (UDP->rps) {
932 delta = jiffies - UDRS->first_read_date + HZ -
933 UDP->spindown_offset;
934 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
935 motor_off_timer[drive].expires =
936 jiffies + UDP->spindown - delta;
937 }
938 add_timer(motor_off_timer + drive);
939}
940
941/*
942 * cycle through all N_DRIVE floppy drives, for disk change testing.
943 * stopping at current drive. This is done before any long operation, to
944 * be sure to have up to date disk change information.
945 */
946static void scandrives(void)
947{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700948 int i;
949 int drive;
950 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 if (DP->select_delay)
953 return;
954
955 saved_drive = current_drive;
956 for (i = 0; i < N_DRIVE; i++) {
957 drive = (saved_drive + i + 1) % N_DRIVE;
958 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
959 continue; /* skip closed drives */
960 set_fdc(drive);
961 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
962 (0x10 << UNIT(drive))))
963 /* switch the motor off again, if it was off to
964 * begin with */
965 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
966 }
967 set_fdc(saved_drive);
968}
969
970static void empty(void)
971{
972}
973
Tejun Heo75ddb382014-03-07 10:24:48 -0500974static void (*floppy_work_fn)(void);
975
976static void floppy_work_workfn(struct work_struct *work)
977{
978 floppy_work_fn();
979}
980
981static DECLARE_WORK(floppy_work, floppy_work_workfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Joe Perches48c8cee2010-03-10 15:20:45 -0800983static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200985 WARN_ON(work_pending(&floppy_work));
986
Tejun Heo75ddb382014-03-07 10:24:48 -0500987 floppy_work_fn = handler;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200988 queue_work(floppy_wq, &floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989}
990
Tejun Heo75ddb382014-03-07 10:24:48 -0500991static void (*fd_timer_fn)(void) = NULL;
992
993static void fd_timer_workfn(struct work_struct *work)
994{
995 fd_timer_fn();
996}
997
998static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000static void cancel_activity(void)
1001{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 do_floppy = NULL;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001003 cancel_delayed_work_sync(&fd_timer);
1004 cancel_work_sync(&floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005}
1006
1007/* this function makes sure that the disk stays in the drive during the
1008 * transfer */
Tejun Heo75ddb382014-03-07 10:24:48 -05001009static void fd_watchdog(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010{
Joe Perches87f530d2010-03-10 15:20:54 -08001011 debug_dcl(DP->flags, "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{
1035 if (FDCS->reset) {
1036 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);
1063 FDCS->reset = 1;
1064 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);
1069 FDCS->reset = 1;
1070 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) ?
1077 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1078 release_dma_lock(f);
1079 cont->done(0);
1080 FDCS->reset = 1;
1081 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);
1091 virtual_dma_port = FDCS->address;
1092 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 if (FDCS->reset)
1106 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 }
1116 FDCS->reset = 1;
1117 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 }
1136 FDCS->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 }
1171 FDCS->reset = 1;
1172 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);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001208 FDCS->reset = 1;
1209 /*
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
1219 if (FDCS->perp_mode == perp_mode)
1220 return;
1221 if (FDCS->version >= FDC_82077_ORIG) {
1222 output_byte(FD_PERPENDICULAR);
1223 output_byte(perp_mode);
1224 FDCS->perp_mode = perp_mode;
1225 } 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
1279 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1280 fdc_configure();
1281 FDCS->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;
1290 if (FDCS->version >= FDC_82078) {
1291 /* 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
1305 if (FDCS->version >= FDC_82072) {
1306 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 */
Julia Lawall061837b2008-09-22 14:57:16 -07001312 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001313 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 SUPBOUND(srt, 0xf);
1317 INFBOUND(srt, 0);
1318
Julia Lawall061837b2008-09-22 14:57:16 -07001319 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 if (hlt < 0x01)
1321 hlt = 0x01;
1322 else if (hlt > 0x7f)
1323 hlt = hlt_max_code;
1324
Julia Lawall061837b2008-09-22 14:57:16 -07001325 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 if (hut < 0x1)
1327 hut = 0x1;
1328 else if (hut > 0xf)
1329 hut = hut_max_code;
1330
1331 spec1 = (srt << 4) | hut;
1332 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1333
1334 /* If these parameters did not change, just return with success */
1335 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1336 /* Go ahead and set spec1 and spec2 */
1337 output_byte(FD_SPECIFY);
1338 output_byte(FDCS->spec1 = spec1);
1339 output_byte(FDCS->spec2 = spec2);
1340 }
1341} /* fdc_specify */
1342
1343/* Set the FDC's data transfer rate on behalf of the specified drive.
1344 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1345 * of the specify command (i.e. using the fdc_specify function).
1346 */
1347static int fdc_dtr(void)
1348{
1349 /* If data rate not already set to desired value, set it. */
1350 if ((raw_cmd->rate & 3) == FDCS->dtr)
1351 return 0;
1352
1353 /* Set dtr */
1354 fd_outb(raw_cmd->rate & 3, FD_DCR);
1355
1356 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1357 * need a stabilization period of several milliseconds to be
1358 * enforced after data rate changes before R/W operations.
1359 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1360 */
1361 FDCS->dtr = raw_cmd->rate & 3;
Tejun Heo75ddb382014-03-07 10:24:48 -05001362 return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363} /* fdc_dtr */
1364
1365static void tell_sector(void)
1366{
Joe Perchesb46df352010-03-10 15:20:46 -08001367 pr_cont(": track %d, head %d, sector %d, size %d",
1368 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369} /* tell_sector */
1370
Joe Perchesb46df352010-03-10 15:20:46 -08001371static void print_errors(void)
1372{
1373 DPRINT("");
1374 if (ST0 & ST0_ECE) {
1375 pr_cont("Recalibrate failed!");
1376 } else if (ST2 & ST2_CRC) {
1377 pr_cont("data CRC error");
1378 tell_sector();
1379 } else if (ST1 & ST1_CRC) {
1380 pr_cont("CRC error");
1381 tell_sector();
1382 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1383 (ST2 & ST2_MAM)) {
1384 if (!probing) {
1385 pr_cont("sector not found");
1386 tell_sector();
1387 } else
1388 pr_cont("probe failed...");
1389 } else if (ST2 & ST2_WC) { /* seek error */
1390 pr_cont("wrong cylinder");
1391 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1392 pr_cont("bad cylinder");
1393 } else {
1394 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1395 ST0, ST1, ST2);
1396 tell_sector();
1397 }
1398 pr_cont("\n");
1399}
1400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401/*
1402 * OK, this error interpreting routine is called after a
1403 * DMA read/write has succeeded
1404 * or failed, so we check the results, and copy any buffers.
1405 * hhb: Added better error reporting.
1406 * ak: Made this into a separate routine.
1407 */
1408static int interpret_errors(void)
1409{
1410 char bad;
1411
1412 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001413 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 FDCS->reset = 1;
1415 return 1;
1416 }
1417
1418 /* check IC to find cause of interrupt */
1419 switch (ST0 & ST0_INTR) {
1420 case 0x40: /* error occurred during command execution */
1421 if (ST1 & ST1_EOC)
1422 return 0; /* occurs with pseudo-DMA */
1423 bad = 1;
1424 if (ST1 & ST1_WP) {
1425 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001426 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 cont->done(0);
1428 bad = 2;
1429 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001430 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 } else if (ST1 & ST1_OR) {
1432 if (DP->flags & FTD_MSG)
1433 DPRINT("Over/Underrun - retrying\n");
1434 bad = 0;
1435 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001436 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 }
1438 if (ST2 & ST2_WC || ST2 & ST2_BC)
1439 /* wrong cylinder => recal */
1440 DRS->track = NEED_2_RECAL;
1441 return bad;
1442 case 0x80: /* invalid command given */
1443 DPRINT("Invalid FDC command given!\n");
1444 cont->done(0);
1445 return 2;
1446 case 0xc0:
1447 DPRINT("Abnormal termination caused by polling\n");
1448 cont->error();
1449 return 2;
1450 default: /* (0) Normal command termination */
1451 return 0;
1452 }
1453}
1454
1455/*
1456 * This routine is called when everything should be correctly set up
1457 * for the transfer (i.e. floppy motor is on, the correct floppy is
1458 * selected, and the head is sitting on the right track).
1459 */
1460static void setup_rw_floppy(void)
1461{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001462 int i;
1463 int r;
1464 int flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 unsigned long ready_date;
Tejun Heo75ddb382014-03-07 10:24:48 -05001466 void (*function)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
1468 flags = raw_cmd->flags;
1469 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1470 flags |= FD_RAW_INTR;
1471
1472 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1473 ready_date = DRS->spinup_date + DP->spinup;
1474 /* If spinup will take a long time, rerun scandrives
1475 * again just before spinup completion. Beware that
1476 * after scandrives, we must again wait for selection.
1477 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001478 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 ready_date -= DP->select_delay;
Tejun Heo75ddb382014-03-07 10:24:48 -05001480 function = floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 } else
Tejun Heo75ddb382014-03-07 10:24:48 -05001482 function = setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
1484 /* wait until the floppy is spinning fast enough */
1485 if (fd_wait_for_completion(ready_date, function))
1486 return;
1487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1489 setup_DMA();
1490
1491 if (flags & FD_RAW_INTR)
1492 do_floppy = main_command_interrupt;
1493
1494 r = 0;
1495 for (i = 0; i < raw_cmd->cmd_count; i++)
1496 r |= output_byte(raw_cmd->cmd[i]);
1497
Joe Perchesded28632010-03-10 15:21:09 -08001498 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
1500 if (r) {
1501 cont->error();
1502 reset_fdc();
1503 return;
1504 }
1505
1506 if (!(flags & FD_RAW_INTR)) {
1507 inr = result();
1508 cont->interrupt();
1509 } else if (flags & FD_RAW_NEED_DISK)
Tejun Heo75ddb382014-03-07 10:24:48 -05001510 fd_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511}
1512
1513static int blind_seek;
1514
1515/*
1516 * This is the routine called after every seek (or recalibrate) interrupt
1517 * from the floppy controller.
1518 */
1519static void seek_interrupt(void)
1520{
Joe Perchesded28632010-03-10 15:21:09 -08001521 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1523 DPRINT("seek failed\n");
1524 DRS->track = NEED_2_RECAL;
1525 cont->error();
1526 cont->redo();
1527 return;
1528 }
1529 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001530 debug_dcl(DP->flags,
1531 "clearing NEWCHANGE flag because of effective seek\n");
1532 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001533 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1534 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 DRS->select_date = jiffies;
1536 }
1537 DRS->track = ST1;
1538 floppy_ready();
1539}
1540
1541static void check_wp(void)
1542{
Joe Perchese0298532010-03-10 15:20:55 -08001543 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1544 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 output_byte(FD_GETSTATUS);
1546 output_byte(UNIT(current_drive));
1547 if (result() != 1) {
1548 FDCS->reset = 1;
1549 return;
1550 }
Joe Perchese0298532010-03-10 15:20:55 -08001551 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1552 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001553 debug_dcl(DP->flags,
1554 "checking whether disk is write protected\n");
1555 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001557 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 else
Joe Perchese0298532010-03-10 15:20:55 -08001559 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 }
1561}
1562
1563static void seek_floppy(void)
1564{
1565 int track;
1566
1567 blind_seek = 0;
1568
Joe Perchesded28632010-03-10 15:21:09 -08001569 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
Joe Perchese0298532010-03-10 15:20:55 -08001571 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1573 /* the media changed flag should be cleared after the seek.
1574 * If it isn't, this means that there is really no disk in
1575 * the drive.
1576 */
Joe Perchese0298532010-03-10 15:20:55 -08001577 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 cont->done(0);
1579 cont->redo();
1580 return;
1581 }
1582 if (DRS->track <= NEED_1_RECAL) {
1583 recalibrate_floppy();
1584 return;
Joe Perchese0298532010-03-10 15:20:55 -08001585 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1587 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1588 /* we seek to clear the media-changed condition. Does anybody
1589 * know a more elegant way, which works on all drives? */
1590 if (raw_cmd->track)
1591 track = raw_cmd->track - 1;
1592 else {
1593 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1594 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1595 blind_seek = 1;
1596 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1597 }
1598 track = 1;
1599 }
1600 } else {
1601 check_wp();
1602 if (raw_cmd->track != DRS->track &&
1603 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1604 track = raw_cmd->track;
1605 else {
1606 setup_rw_floppy();
1607 return;
1608 }
1609 }
1610
1611 do_floppy = seek_interrupt;
1612 output_byte(FD_SEEK);
1613 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001614 if (output_byte(track) < 0) {
1615 reset_fdc();
1616 return;
1617 }
Joe Perchesded28632010-03-10 15:21:09 -08001618 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619}
1620
1621static void recal_interrupt(void)
1622{
Joe Perchesded28632010-03-10 15:21:09 -08001623 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 if (inr != 2)
1625 FDCS->reset = 1;
1626 else if (ST0 & ST0_ECE) {
1627 switch (DRS->track) {
1628 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001629 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 /* after a second recalibrate, we still haven't
1631 * reached track 0. Probably no drive. Raise an
1632 * error, as failing immediately might upset
1633 * computers possessed by the Devil :-) */
1634 cont->error();
1635 cont->redo();
1636 return;
1637 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001638 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 /* If we already did a recalibrate,
1640 * and we are not at track 0, this
1641 * means we have moved. (The only way
1642 * not to move at recalibration is to
1643 * be already at track 0.) Clear the
1644 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001645 debug_dcl(DP->flags,
1646 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Joe Perchese0298532010-03-10 15:20:55 -08001648 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 DRS->select_date = jiffies;
1650 /* fall through */
1651 default:
Joe Perchesded28632010-03-10 15:21:09 -08001652 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 /* Recalibrate moves the head by at
1654 * most 80 steps. If after one
1655 * recalibrate we don't have reached
1656 * track 0, this might mean that we
1657 * started beyond track 80. Try
1658 * again. */
1659 DRS->track = NEED_1_RECAL;
1660 break;
1661 }
1662 } else
1663 DRS->track = ST1;
1664 floppy_ready();
1665}
1666
1667static void print_result(char *message, int inr)
1668{
1669 int i;
1670
1671 DPRINT("%s ", message);
1672 if (inr >= 0)
1673 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001674 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1675 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676}
1677
1678/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001679irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 int do_print;
1682 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001683 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
1685 lasthandler = handler;
1686 interruptjiffies = jiffies;
1687
1688 f = claim_dma_lock();
1689 fd_disable_dma();
1690 release_dma_lock(f);
1691
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 do_floppy = NULL;
1693 if (fdc >= N_FDC || FDCS->address == -1) {
1694 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001695 pr_info("DOR0=%x\n", fdc_state[0].dor);
1696 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Sakari Ailusd75f7732019-03-25 21:32:28 +02001697 pr_info("handler=%ps\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001698 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 return IRQ_NONE;
1700 }
1701
1702 FDCS->reset = 0;
1703 /* We have to clear the reset flag here, because apparently on boxes
1704 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1705 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1706 * emission of the SENSEI's.
1707 * It is OK to emit floppy commands because we are in an interrupt
1708 * handler here, and thus we have to fear no interference of other
1709 * activity.
1710 */
1711
Joe Perches29f1c782010-03-10 15:21:00 -08001712 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
1714 inr = result();
1715 if (do_print)
1716 print_result("unexpected interrupt", inr);
1717 if (inr == 0) {
1718 int max_sensei = 4;
1719 do {
1720 output_byte(FD_SENSEI);
1721 inr = result();
1722 if (do_print)
1723 print_result("sensei", inr);
1724 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001725 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1726 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 }
1728 if (!handler) {
1729 FDCS->reset = 1;
1730 return IRQ_NONE;
1731 }
1732 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001733 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
1735 /* FIXME! Was it really for us? */
1736 return IRQ_HANDLED;
1737}
1738
1739static void recalibrate_floppy(void)
1740{
Joe Perchesded28632010-03-10 15:21:09 -08001741 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 do_floppy = recal_interrupt;
1743 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001744 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001745 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746}
1747
1748/*
1749 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1750 */
1751static void reset_interrupt(void)
1752{
Joe Perchesded28632010-03-10 15:21:09 -08001753 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 result(); /* get the status ready for set_fdc */
1755 if (FDCS->reset) {
Sakari Ailusd75f7732019-03-25 21:32:28 +02001756 pr_info("reset set in interrupt, calling %ps\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 cont->error(); /* a reset just after a reset. BAD! */
1758 }
1759 cont->redo();
1760}
1761
1762/*
1763 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1764 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1765 */
1766static void reset_fdc(void)
1767{
1768 unsigned long flags;
1769
1770 do_floppy = reset_interrupt;
1771 FDCS->reset = 0;
1772 reset_fdc_info(0);
1773
1774 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1775 /* Irrelevant for systems with true DMA (i386). */
1776
1777 flags = claim_dma_lock();
1778 fd_disable_dma();
1779 release_dma_lock(flags);
1780
1781 if (FDCS->version >= FDC_82072A)
1782 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1783 else {
1784 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1785 udelay(FD_RESET_DELAY);
1786 fd_outb(FDCS->dor, FD_DOR);
1787 }
1788}
1789
1790static void show_floppy(void)
1791{
1792 int i;
1793
Joe Perchesb46df352010-03-10 15:20:46 -08001794 pr_info("\n");
1795 pr_info("floppy driver state\n");
1796 pr_info("-------------------\n");
Sakari Ailusd75f7732019-03-25 21:32:28 +02001797 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%ps\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001798 jiffies, interruptjiffies, jiffies - interruptjiffies,
1799 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Joe Perchesb46df352010-03-10 15:20:46 -08001801 pr_info("timeout_message=%s\n", timeout_message);
1802 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001804 pr_info("%2x %2x %lu\n",
1805 output_log[(i + output_log_pos) % OLOGSIZE].data,
1806 output_log[(i + output_log_pos) % OLOGSIZE].status,
1807 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1808 pr_info("last result at %lu\n", resultjiffies);
1809 pr_info("last redo_fd_request at %lu\n", lastredo);
1810 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1811 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Joe Perchesb46df352010-03-10 15:20:46 -08001813 pr_info("status=%x\n", fd_inb(FD_STATUS));
1814 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 if (do_floppy)
Sakari Ailusd75f7732019-03-25 21:32:28 +02001816 pr_info("do_floppy=%ps\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001817 if (work_pending(&floppy_work))
Sakari Ailusd75f7732019-03-25 21:32:28 +02001818 pr_info("floppy_work.func=%ps\n", floppy_work.func);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001819 if (delayed_work_pending(&fd_timer))
1820 pr_info("delayed work.function=%p expires=%ld\n",
1821 fd_timer.work.func,
1822 fd_timer.timer.expires - jiffies);
1823 if (delayed_work_pending(&fd_timeout))
1824 pr_info("timer_function=%p expires=%ld\n",
1825 fd_timeout.work.func,
1826 fd_timeout.timer.expires - jiffies);
1827
Joe Perchesb46df352010-03-10 15:20:46 -08001828 pr_info("cont=%p\n", cont);
1829 pr_info("current_req=%p\n", current_req);
1830 pr_info("command_status=%d\n", command_status);
1831 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832}
1833
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001834static void floppy_shutdown(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835{
1836 unsigned long flags;
1837
Joe Perches29f1c782010-03-10 15:21:00 -08001838 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 show_floppy();
1840 cancel_activity();
1841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 flags = claim_dma_lock();
1843 fd_disable_dma();
1844 release_dma_lock(flags);
1845
1846 /* avoid dma going to a random drive after shutdown */
1847
Joe Perches29f1c782010-03-10 15:21:00 -08001848 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 DPRINT("floppy timeout called\n");
1850 FDCS->reset = 1;
1851 if (cont) {
1852 cont->done(0);
1853 cont->redo(); /* this will recall reset when needed */
1854 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001855 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 process_fd_request();
1857 }
Joe Perches275176b2010-03-10 15:21:06 -08001858 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859}
1860
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001862static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001864 int mask;
1865 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
1867 mask = 0xfc;
1868 data = UNIT(current_drive);
1869 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1870 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1871 set_debugt();
1872 /* no read since this drive is running */
1873 DRS->first_read_date = 0;
1874 /* note motor start time if motor is not yet running */
1875 DRS->spinup_date = jiffies;
1876 data |= (0x10 << UNIT(current_drive));
1877 }
1878 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1879 mask &= ~(0x10 << UNIT(current_drive));
1880
1881 /* starts motor and selects floppy */
1882 del_timer(motor_off_timer + current_drive);
1883 set_dor(fdc, mask, data);
1884
1885 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001886 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
Tejun Heo75ddb382014-03-07 10:24:48 -05001887 function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888}
1889
1890static void floppy_ready(void)
1891{
Joe Perches045f9832010-03-10 15:20:47 -08001892 if (FDCS->reset) {
1893 reset_fdc();
1894 return;
1895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 if (start_motor(floppy_ready))
1897 return;
1898 if (fdc_dtr())
1899 return;
1900
Joe Perches87f530d2010-03-10 15:20:54 -08001901 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1903 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001904 twaddle(); /* this clears the dcl on certain
1905 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
1907#ifdef fd_chose_dma_mode
1908 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1909 unsigned long flags = claim_dma_lock();
1910 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1911 release_dma_lock(flags);
1912 }
1913#endif
1914
1915 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1916 perpendicular_mode();
1917 fdc_specify(); /* must be done here because of hut, hlt ... */
1918 seek_floppy();
1919 } else {
1920 if ((raw_cmd->flags & FD_RAW_READ) ||
1921 (raw_cmd->flags & FD_RAW_WRITE))
1922 fdc_specify();
1923 setup_rw_floppy();
1924 }
1925}
1926
1927static void floppy_start(void)
1928{
Joe Perches73507e62010-03-10 15:21:03 -08001929 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001932 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001933 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 floppy_ready();
1935}
1936
1937/*
1938 * ========================================================================
1939 * here ends the bottom half. Exported routines are:
1940 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1941 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1942 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1943 * and set_dor.
1944 * ========================================================================
1945 */
1946/*
1947 * General purpose continuations.
1948 * ==============================
1949 */
1950
1951static void do_wakeup(void)
1952{
Joe Perches73507e62010-03-10 15:21:03 -08001953 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 cont = NULL;
1955 command_status += 2;
1956 wake_up(&command_done);
1957}
1958
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001959static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 .interrupt = empty,
1961 .redo = do_wakeup,
1962 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001963 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964};
1965
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001966static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 .interrupt = empty,
1968 .redo = process_fd_request,
1969 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001970 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971};
1972
Joe Perches74f63f42010-03-10 15:20:58 -08001973static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974{
1975 int ret;
1976
1977 schedule_bh(handler);
1978
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001979 if (interruptible)
1980 wait_event_interruptible(command_done, command_status >= 2);
1981 else
1982 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
1984 if (command_status < 2) {
1985 cancel_activity();
1986 cont = &intr_cont;
1987 reset_fdc();
1988 return -EINTR;
1989 }
1990
1991 if (FDCS->reset)
1992 command_status = FD_COMMAND_ERROR;
1993 if (command_status == FD_COMMAND_OKAY)
1994 ret = 0;
1995 else
1996 ret = -EIO;
1997 command_status = FD_COMMAND_NONE;
1998 return ret;
1999}
2000
2001static void generic_done(int result)
2002{
2003 command_status = result;
2004 cont = &wakeup_cont;
2005}
2006
2007static void generic_success(void)
2008{
2009 cont->done(1);
2010}
2011
2012static void generic_failure(void)
2013{
2014 cont->done(0);
2015}
2016
2017static void success_and_wakeup(void)
2018{
2019 generic_success();
2020 cont->redo();
2021}
2022
2023/*
2024 * formatting and rw support.
2025 * ==========================
2026 */
2027
2028static int next_valid_format(void)
2029{
2030 int probed_format;
2031
2032 probed_format = DRS->probed_format;
2033 while (1) {
2034 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2035 DRS->probed_format = 0;
2036 return 1;
2037 }
2038 if (floppy_type[DP->autodetect[probed_format]].sect) {
2039 DRS->probed_format = probed_format;
2040 return 0;
2041 }
2042 probed_format++;
2043 }
2044}
2045
2046static void bad_flp_intr(void)
2047{
2048 int err_count;
2049
2050 if (probing) {
2051 DRS->probed_format++;
2052 if (!next_valid_format())
2053 return;
2054 }
2055 err_count = ++(*errors);
2056 INFBOUND(DRWE->badness, err_count);
2057 if (err_count > DP->max_errors.abort)
2058 cont->done(0);
2059 if (err_count > DP->max_errors.reset)
2060 FDCS->reset = 1;
2061 else if (err_count > DP->max_errors.recal)
2062 DRS->track = NEED_2_RECAL;
2063}
2064
2065static void set_floppy(int drive)
2066{
2067 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002068
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 if (type)
2070 _floppy = floppy_type + type;
2071 else
2072 _floppy = current_type[drive];
2073}
2074
2075/*
2076 * formatting support.
2077 * ===================
2078 */
2079static void format_interrupt(void)
2080{
2081 switch (interpret_errors()) {
2082 case 1:
2083 cont->error();
2084 case 2:
2085 break;
2086 case 0:
2087 cont->done(1);
2088 }
2089 cont->redo();
2090}
2091
Joe Perches48c8cee2010-03-10 15:20:45 -08002092#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002094
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095static void setup_format_params(int track)
2096{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002097 int n;
2098 int il;
2099 int count;
2100 int head_shift;
2101 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 struct fparm {
2103 unsigned char track, head, sect, size;
2104 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
2106 raw_cmd = &default_raw_cmd;
2107 raw_cmd->track = track;
2108
Joe Perches48c8cee2010-03-10 15:20:45 -08002109 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2110 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 raw_cmd->rate = _floppy->rate & 0x43;
2112 raw_cmd->cmd_count = NR_F;
2113 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2114 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2115 F_SIZECODE = FD_SIZECODE(_floppy);
2116 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2117 F_GAP = _floppy->fmt_gap;
2118 F_FILL = FD_FILL_BYTE;
2119
2120 raw_cmd->kernel_data = floppy_track_buffer;
2121 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2122
2123 /* allow for about 30ms for data transport per track */
2124 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2125
2126 /* a ``cylinder'' is two tracks plus a little stepping time */
2127 track_shift = 2 * head_shift + 3;
2128
2129 /* position of logical sector 1 on this track */
2130 n = (track_shift * format_req.track + head_shift * format_req.head)
2131 % F_SECT_PER_TRACK;
2132
2133 /* determine interleave */
2134 il = 1;
2135 if (_floppy->fmt_gap < 0x22)
2136 il++;
2137
2138 /* initialize field */
2139 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2140 here[count].track = format_req.track;
2141 here[count].head = format_req.head;
2142 here[count].sect = 0;
2143 here[count].size = F_SIZECODE;
2144 }
2145 /* place logical sectors */
2146 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2147 here[n].sect = count;
2148 n = (n + il) % F_SECT_PER_TRACK;
2149 if (here[n].sect) { /* sector busy, find next free sector */
2150 ++n;
2151 if (n >= F_SECT_PER_TRACK) {
2152 n -= F_SECT_PER_TRACK;
2153 while (here[n].sect)
2154 ++n;
2155 }
2156 }
2157 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002158 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002160 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 }
2162}
2163
2164static void redo_format(void)
2165{
2166 buffer_track = -1;
2167 setup_format_params(format_req.track << STRETCH(_floppy));
2168 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002169 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170}
2171
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002172static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 .interrupt = format_interrupt,
2174 .redo = redo_format,
2175 .error = bad_flp_intr,
2176 .done = generic_done
2177};
2178
2179static int do_format(int drive, struct format_descr *tmp_format_req)
2180{
2181 int ret;
2182
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01002183 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08002184 return -EINTR;
2185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 set_floppy(drive);
2187 if (!_floppy ||
2188 _floppy->track > DP->tracks ||
2189 tmp_format_req->track >= _floppy->track ||
2190 tmp_format_req->head >= _floppy->head ||
2191 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2192 !_floppy->fmt_gap) {
2193 process_fd_request();
2194 return -EINVAL;
2195 }
2196 format_req = *tmp_format_req;
2197 format_errors = 0;
2198 cont = &format_cont;
2199 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002200 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002201 if (ret == -EINTR)
2202 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 process_fd_request();
2204 return ret;
2205}
2206
2207/*
2208 * Buffer read/write and support
2209 * =============================
2210 */
2211
Christoph Hellwig2a842ac2017-06-03 09:38:04 +02002212static void floppy_end_request(struct request *req, blk_status_t error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213{
2214 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002215 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
2217 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002218 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002219 nr_sectors = blk_rq_cur_sectors(req);
Omar Sandovala9f38e12018-10-15 09:21:34 -06002220 if (blk_update_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 return;
Omar Sandovala9f38e12018-10-15 09:21:34 -06002222 __blk_mq_end_request(req, error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002225 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 current_req = NULL;
2227}
2228
2229/* new request_done. Can handle physical sectors which are smaller than a
2230 * logical buffer */
2231static void request_done(int uptodate)
2232{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 struct request *req = current_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002235 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
2237 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002238 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2239 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
2241 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002242 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 return;
2244 }
2245
2246 if (uptodate) {
2247 /* maintain values for invalidation on geometry
2248 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002249 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 INFBOUND(DRS->maxblock, block);
2251 if (block > _floppy->sect)
2252 DRS->maxtrack = 1;
2253
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002254 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 } else {
2256 if (rq_data_dir(req) == WRITE) {
2257 /* record write error information */
2258 DRWE->write_errors++;
2259 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002260 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 DRWE->first_error_generation = DRS->generation;
2262 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002263 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 DRWE->last_error_generation = DRS->generation;
2265 }
Christoph Hellwig2a842ac2017-06-03 09:38:04 +02002266 floppy_end_request(req, BLK_STS_IOERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 }
2268}
2269
2270/* Interrupt handler evaluating the result of the r/w operation */
2271static void rw_interrupt(void)
2272{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002273 int eoc;
2274 int ssize;
2275 int heads;
2276 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277
2278 if (R_HEAD >= 2) {
2279 /* some Toshiba floppy controllers occasionnally seem to
2280 * return bogus interrupts after read/write operations, which
2281 * can be recognized by a bad head number (>= 2) */
2282 return;
2283 }
2284
2285 if (!DRS->first_read_date)
2286 DRS->first_read_date = jiffies;
2287
2288 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002289 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
2291 if (ST1 & ST1_EOC)
2292 eoc = 1;
2293 else
2294 eoc = 0;
2295
2296 if (COMMAND & 0x80)
2297 heads = 2;
2298 else
2299 heads = 1;
2300
2301 nr_sectors = (((R_TRACK - TRACK) * heads +
2302 R_HEAD - HEAD) * SECT_PER_TRACK +
2303 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2304
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002306 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 DPRINT("long rw: %x instead of %lx\n",
2308 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002309 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2310 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2311 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2312 pr_info("heads=%d eoc=%d\n", heads, eoc);
2313 pr_info("spt=%d st=%d ss=%d\n",
2314 SECT_PER_TRACK, fsector_t, ssize);
2315 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
2318 nr_sectors -= in_sector_offset;
2319 INFBOUND(nr_sectors, 0);
2320 SUPBOUND(current_count_sectors, nr_sectors);
2321
2322 switch (interpret_errors()) {
2323 case 2:
2324 cont->redo();
2325 return;
2326 case 1:
2327 if (!current_count_sectors) {
2328 cont->error();
2329 cont->redo();
2330 return;
2331 }
2332 break;
2333 case 0:
2334 if (!current_count_sectors) {
2335 cont->redo();
2336 return;
2337 }
2338 current_type[current_drive] = _floppy;
2339 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2340 break;
2341 }
2342
2343 if (probing) {
2344 if (DP->flags & FTD_MSG)
2345 DPRINT("Auto-detected floppy type %s in fd%d\n",
2346 _floppy->name, current_drive);
2347 current_type[current_drive] = _floppy;
2348 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2349 probing = 0;
2350 }
2351
2352 if (CT(COMMAND) != FD_READ ||
Jens Axboeb4f42e22014-04-10 09:46:28 -06002353 raw_cmd->kernel_data == bio_data(current_req->bio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 /* transfer directly from buffer */
2355 cont->done(1);
2356 } else if (CT(COMMAND) == FD_READ) {
2357 buffer_track = raw_cmd->track;
2358 buffer_drive = current_drive;
2359 INFBOUND(buffer_max, nr_sectors + fsector_t);
2360 }
2361 cont->redo();
2362}
2363
2364/* Compute maximal contiguous buffer size. */
2365static int buffer_chain_size(void)
2366{
Kent Overstreet79886132013-11-23 17:19:00 -08002367 struct bio_vec bv;
NeilBrown5705f702007-09-25 12:35:59 +02002368 int size;
2369 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 char *base;
2371
2372 base = bio_data(current_req->bio);
2373 size = 0;
2374
NeilBrown5705f702007-09-25 12:35:59 +02002375 rq_for_each_segment(bv, current_req, iter) {
Kent Overstreet79886132013-11-23 17:19:00 -08002376 if (page_address(bv.bv_page) + bv.bv_offset != base + size)
NeilBrown5705f702007-09-25 12:35:59 +02002377 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Kent Overstreet79886132013-11-23 17:19:00 -08002379 size += bv.bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 }
2381
2382 return size >> 9;
2383}
2384
2385/* Compute the maximal transfer size */
2386static int transfer_size(int ssize, int max_sector, int max_size)
2387{
2388 SUPBOUND(max_sector, fsector_t + max_size);
2389
2390 /* alignment */
2391 max_sector -= (max_sector % _floppy->sect) % ssize;
2392
2393 /* transfer size, beginning not aligned */
2394 current_count_sectors = max_sector - fsector_t;
2395
2396 return max_sector;
2397}
2398
2399/*
2400 * Move data from/to the track buffer to/from the buffer cache.
2401 */
2402static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2403{
2404 int remaining; /* number of transferred 512-byte sectors */
Kent Overstreet79886132013-11-23 17:19:00 -08002405 struct bio_vec bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002406 char *buffer;
2407 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002408 int size;
2409 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
2411 max_sector = transfer_size(ssize,
2412 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002413 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
2415 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002416 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002418 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002421 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002423 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2424 pr_info("remaining=%d\n", remaining >> 9);
2425 pr_info("current_req->nr_sectors=%u\n",
2426 blk_rq_sectors(current_req));
2427 pr_info("current_req->current_nr_sectors=%u\n",
2428 blk_rq_cur_sectors(current_req));
2429 pr_info("max_sector=%d\n", max_sector);
2430 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
2433 buffer_max = max(max_sector, buffer_max);
2434
2435 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2436
Tejun Heo1011c1b2009-05-07 22:24:45 +09002437 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
NeilBrown5705f702007-09-25 12:35:59 +02002439 rq_for_each_segment(bv, current_req, iter) {
2440 if (!remaining)
2441 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
Kent Overstreet79886132013-11-23 17:19:00 -08002443 size = bv.bv_len;
NeilBrown5705f702007-09-25 12:35:59 +02002444 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
Kent Overstreet79886132013-11-23 17:19:00 -08002446 buffer = page_address(bv.bv_page) + bv.bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002447 if (dma_buffer + size >
2448 floppy_track_buffer + (max_buffer_sectors << 10) ||
2449 dma_buffer < floppy_track_buffer) {
2450 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002451 (int)((floppy_track_buffer - dma_buffer) >> 9));
2452 pr_info("fsector_t=%d buffer_min=%d\n",
2453 fsector_t, buffer_min);
2454 pr_info("current_count_sectors=%ld\n",
2455 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002457 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002458 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002459 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002460 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 }
NeilBrown5705f702007-09-25 12:35:59 +02002462 if (((unsigned long)buffer) % 512)
2463 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002464
NeilBrown5705f702007-09-25 12:35:59 +02002465 if (CT(COMMAND) == FD_READ)
2466 memcpy(buffer, dma_buffer, size);
2467 else
2468 memcpy(dma_buffer, buffer, size);
2469
2470 remaining -= size;
2471 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 if (remaining) {
2474 if (remaining > 0)
2475 max_sector -= remaining >> 9;
2476 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478}
2479
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480/* work around a bug in pseudo DMA
2481 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2482 * sending data. Hence we need a different way to signal the
2483 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2484 * does not work with MT, hence we can only transfer one head at
2485 * a time
2486 */
2487static void virtualdmabug_workaround(void)
2488{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002489 int hard_sectors;
2490 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492 if (CT(COMMAND) == FD_WRITE) {
2493 COMMAND &= ~0x80; /* switch off multiple track mode */
2494
2495 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2496 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002498 pr_info("too many sectors %d > %d\n",
2499 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 return;
2501 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002502 SECT_PER_TRACK = end_sector;
2503 /* make sure SECT_PER_TRACK
2504 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 }
2506}
2507
2508/*
2509 * Formulate a read/write request.
2510 * this routine decides where to load the data (directly to buffer, or to
2511 * tmp floppy area), how much data to load (the size of the buffer, the whole
2512 * track, or a single sector)
2513 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2514 * allocation on the fly, it should be done here. No other part should need
2515 * modification.
2516 */
2517
2518static int make_raw_rw_request(void)
2519{
2520 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002521 int max_sector;
2522 int max_size;
2523 int tracksize;
2524 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002526 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
2529 set_fdc((long)current_req->rq_disk->private_data);
2530
2531 raw_cmd = &default_raw_cmd;
Fengguang Wu2fb2ca62012-07-28 19:45:59 +08002532 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 raw_cmd->cmd_count = NR_RW;
2534 if (rq_data_dir(current_req) == READ) {
2535 raw_cmd->flags |= FD_RAW_READ;
2536 COMMAND = FM_MODE(_floppy, FD_READ);
2537 } else if (rq_data_dir(current_req) == WRITE) {
2538 raw_cmd->flags |= FD_RAW_WRITE;
2539 COMMAND = FM_MODE(_floppy, FD_WRITE);
2540 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002541 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 return 0;
2543 }
2544
2545 max_sector = _floppy->sect * _floppy->head;
2546
Tejun Heo83096eb2009-05-07 22:24:39 +09002547 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2548 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002550 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 current_count_sectors = 1;
2552 return 1;
2553 } else
2554 return 0;
2555 }
2556 HEAD = fsector_t / _floppy->sect;
2557
Keith Wansbrough9e491842008-09-22 14:57:17 -07002558 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002559 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2560 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 max_sector = _floppy->sect;
2562
2563 /* 2M disks have phantom sectors on the first track */
2564 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2565 max_sector = 2 * _floppy->sect / 3;
2566 if (fsector_t >= max_sector) {
2567 current_count_sectors =
2568 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002569 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 return 1;
2571 }
2572 SIZECODE = 2;
2573 } else
2574 SIZECODE = FD_SIZECODE(_floppy);
2575 raw_cmd->rate = _floppy->rate & 0x43;
2576 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2577 raw_cmd->rate = 1;
2578
2579 if (SIZECODE)
2580 SIZECODE2 = 0xff;
2581 else
2582 SIZECODE2 = 0x80;
2583 raw_cmd->track = TRACK << STRETCH(_floppy);
2584 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2585 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002586 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2588 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002589 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
2591 /* tracksize describes the size which can be filled up with sectors
2592 * of size ssize.
2593 */
2594 tracksize = _floppy->sect - _floppy->sect % ssize;
2595 if (tracksize < _floppy->sect) {
2596 SECT_PER_TRACK++;
2597 if (tracksize <= fsector_t % _floppy->sect)
2598 SECTOR--;
2599
2600 /* if we are beyond tracksize, fill up using smaller sectors */
2601 while (tracksize <= fsector_t % _floppy->sect) {
2602 while (tracksize + ssize > _floppy->sect) {
2603 SIZECODE--;
2604 ssize >>= 1;
2605 }
2606 SECTOR++;
2607 SECT_PER_TRACK++;
2608 tracksize += ssize;
2609 }
2610 max_sector = HEAD * _floppy->sect + tracksize;
2611 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2612 max_sector = _floppy->sect;
2613 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2614 /* for virtual DMA bug workaround */
2615 max_sector = _floppy->sect;
2616 }
2617
2618 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2619 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002620 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 if ((raw_cmd->track == buffer_track) &&
2622 (current_drive == buffer_drive) &&
2623 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2624 /* data already in track buffer */
2625 if (CT(COMMAND) == FD_READ) {
2626 copy_buffer(1, max_sector, buffer_max);
2627 return 1;
2628 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002629 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002631 unsigned int sectors;
2632
2633 sectors = fsector_t + blk_rq_sectors(current_req);
2634 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 max_size = ssize + ssize;
2636 else
2637 max_size = ssize;
2638 }
2639 raw_cmd->flags &= ~FD_RAW_WRITE;
2640 raw_cmd->flags |= FD_RAW_READ;
2641 COMMAND = FM_MODE(_floppy, FD_READ);
Jens Axboeb4f42e22014-04-10 09:46:28 -06002642 } else if ((unsigned long)bio_data(current_req->bio) < MAX_DMA_ADDRESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 unsigned long dma_limit;
2644 int direct, indirect;
2645
2646 indirect =
2647 transfer_size(ssize, max_sector,
2648 max_buffer_sectors * 2) - fsector_t;
2649
2650 /*
2651 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2652 * on a 64 bit machine!
2653 */
2654 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002655 dma_limit = (MAX_DMA_ADDRESS -
Jens Axboeb4f42e22014-04-10 09:46:28 -06002656 ((unsigned long)bio_data(current_req->bio))) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002657 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 /* 64 kb boundaries */
Jens Axboeb4f42e22014-04-10 09:46:28 -06002660 if (CROSS_64KB(bio_data(current_req->bio), max_size << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 max_size = (K_64 -
Jens Axboeb4f42e22014-04-10 09:46:28 -06002662 ((unsigned long)bio_data(current_req->bio)) %
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 K_64) >> 9;
2664 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2665 /*
2666 * We try to read tracks, but if we get too many errors, we
2667 * go back to reading just one sector at a time.
2668 *
2669 * This means we should be able to read a sector even if there
2670 * are other bad sectors on this track.
2671 */
2672 if (!direct ||
2673 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002674 *errors < DP->max_errors.read_track &&
2675 ((!probing ||
2676 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002677 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 } else {
Jens Axboeb4f42e22014-04-10 09:46:28 -06002679 raw_cmd->kernel_data = bio_data(current_req->bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 raw_cmd->length = current_count_sectors << 9;
2681 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002682 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002683 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 indirect, direct, fsector_t);
2685 return 0;
2686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 virtualdmabug_workaround();
2688 return 2;
2689 }
2690 }
2691
2692 if (CT(COMMAND) == FD_READ)
2693 max_size = max_sector; /* unbounded */
2694
2695 /* claim buffer track if needed */
2696 if (buffer_track != raw_cmd->track || /* bad track */
2697 buffer_drive != current_drive || /* bad drive */
2698 fsector_t > buffer_max ||
2699 fsector_t < buffer_min ||
2700 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002701 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002703 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2704 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 buffer_track = -1;
2706 buffer_drive = current_drive;
2707 buffer_max = buffer_min = aligned_sector_t;
2708 }
2709 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002710 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
2712 if (CT(COMMAND) == FD_WRITE) {
2713 /* copy write buffer to track buffer.
2714 * if we get here, we know that the write
2715 * is either aligned or the data already in the buffer
2716 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 if (in_sector_offset && buffer_track == -1)
2718 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 buffer_track = raw_cmd->track;
2720 buffer_drive = current_drive;
2721 copy_buffer(ssize, max_sector,
2722 2 * max_buffer_sectors + buffer_min);
2723 } else
2724 transfer_size(ssize, max_sector,
2725 2 * max_buffer_sectors + buffer_min -
2726 aligned_sector_t);
2727
2728 /* round up current_count_sectors to get dma xfer size */
2729 raw_cmd->length = in_sector_offset + current_count_sectors;
2730 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2731 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 if ((raw_cmd->length < current_count_sectors << 9) ||
Jens Axboeb4f42e22014-04-10 09:46:28 -06002733 (raw_cmd->kernel_data != bio_data(current_req->bio) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 CT(COMMAND) == FD_WRITE &&
2735 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2736 aligned_sector_t < buffer_min)) ||
2737 raw_cmd->length % (128 << SIZECODE) ||
2738 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2739 DPRINT("fractionary current count b=%lx s=%lx\n",
2740 raw_cmd->length, current_count_sectors);
Jens Axboeb4f42e22014-04-10 09:46:28 -06002741 if (raw_cmd->kernel_data != bio_data(current_req->bio))
Joe Perchesb46df352010-03-10 15:20:46 -08002742 pr_info("addr=%d, length=%ld\n",
2743 (int)((raw_cmd->kernel_data -
2744 floppy_track_buffer) >> 9),
2745 current_count_sectors);
2746 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2747 fsector_t, aligned_sector_t, max_sector, max_size);
2748 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2749 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2750 COMMAND, SECTOR, HEAD, TRACK);
2751 pr_info("buffer drive=%d\n", buffer_drive);
2752 pr_info("buffer track=%d\n", buffer_track);
2753 pr_info("buffer_min=%d\n", buffer_min);
2754 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 return 0;
2756 }
2757
Jens Axboeb4f42e22014-04-10 09:46:28 -06002758 if (raw_cmd->kernel_data != bio_data(current_req->bio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 if (raw_cmd->kernel_data < floppy_track_buffer ||
2760 current_count_sectors < 0 ||
2761 raw_cmd->length < 0 ||
2762 raw_cmd->kernel_data + raw_cmd->length >
2763 floppy_track_buffer + (max_buffer_sectors << 10)) {
2764 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002765 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2766 fsector_t, buffer_min, raw_cmd->length >> 9);
2767 pr_info("current_count_sectors=%ld\n",
2768 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002770 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002772 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 return 0;
2774 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002775 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002776 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 DPRINT("buffer overrun in direct transfer\n");
2778 return 0;
2779 } else if (raw_cmd->length < current_count_sectors << 9) {
2780 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002781 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2782 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 }
2784 if (raw_cmd->length == 0) {
2785 DPRINT("zero dma transfer attempted from make_raw_request\n");
2786 return 0;
2787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789 virtualdmabug_workaround();
2790 return 2;
2791}
2792
Jens Axboe48821182010-09-22 09:32:36 +02002793static int set_next_request(void)
2794{
Omar Sandovala9f38e12018-10-15 09:21:34 -06002795 current_req = list_first_entry_or_null(&floppy_reqs, struct request,
2796 queuelist);
2797 if (current_req) {
2798 current_req->error_count = 0;
2799 list_del_init(&current_req->queuelist);
2800 }
Jens Axboe48821182010-09-22 09:32:36 +02002801 return current_req != NULL;
2802}
2803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804static void redo_fd_request(void)
2805{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 int drive;
2807 int tmp;
2808
2809 lastredo = jiffies;
2810 if (current_drive < N_DRIVE)
2811 floppy_off(current_drive);
2812
Joe Perches0da31322010-03-10 15:21:03 -08002813do_request:
2814 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002815 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
Jens Axboe48821182010-09-22 09:32:36 +02002817 spin_lock_irq(&floppy_lock);
2818 pending = set_next_request();
2819 spin_unlock_irq(&floppy_lock);
Jens Axboe48821182010-09-22 09:32:36 +02002820 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002821 do_floppy = NULL;
2822 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 }
Joe Perches0da31322010-03-10 15:21:03 -08002826 drive = (long)current_req->rq_disk->private_data;
2827 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002828 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002829
2830 set_floppy(drive);
2831 raw_cmd = &default_raw_cmd;
2832 raw_cmd->flags = 0;
2833 if (start_motor(redo_fd_request))
2834 return;
2835
2836 disk_change(current_drive);
2837 if (test_bit(current_drive, &fake_change) ||
2838 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2839 DPRINT("disk absent or changed during operation\n");
2840 request_done(0);
2841 goto do_request;
2842 }
2843 if (!_floppy) { /* Autodetection */
2844 if (!probing) {
2845 DRS->probed_format = 0;
2846 if (next_valid_format()) {
2847 DPRINT("no autodetectable formats\n");
2848 _floppy = NULL;
2849 request_done(0);
2850 goto do_request;
2851 }
2852 }
2853 probing = 1;
2854 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2855 } else
2856 probing = 0;
Christoph Hellwig45908792017-04-20 16:03:12 +02002857 errors = &(current_req->error_count);
Joe Perches0da31322010-03-10 15:21:03 -08002858 tmp = make_raw_rw_request();
2859 if (tmp < 2) {
2860 request_done(tmp);
2861 goto do_request;
2862 }
2863
2864 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2865 twaddle();
2866 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002867 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002868 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869}
2870
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002871static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 .interrupt = rw_interrupt,
2873 .redo = redo_fd_request,
2874 .error = bad_flp_intr,
2875 .done = request_done
2876};
2877
2878static void process_fd_request(void)
2879{
2880 cont = &rw_cont;
2881 schedule_bh(redo_fd_request);
2882}
2883
Omar Sandovala9f38e12018-10-15 09:21:34 -06002884static blk_status_t floppy_queue_rq(struct blk_mq_hw_ctx *hctx,
2885 const struct blk_mq_queue_data *bd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886{
Omar Sandovala9f38e12018-10-15 09:21:34 -06002887 blk_mq_start_request(bd->rq);
2888
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002889 if (WARN(max_buffer_sectors == 0,
2890 "VFS: %s called on non-open device\n", __func__))
Omar Sandovala9f38e12018-10-15 09:21:34 -06002891 return BLK_STS_IOERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002893 if (WARN(atomic_read(&usage_count) == 0,
Christoph Hellwigaebf5262017-01-31 16:57:31 +01002894 "warning: usage count=0, current_req=%p sect=%ld flags=%llx\n",
2895 current_req, (long)blk_rq_pos(current_req),
Jens Axboe59533162013-05-23 12:25:08 +02002896 (unsigned long long) current_req->cmd_flags))
Omar Sandovala9f38e12018-10-15 09:21:34 -06002897 return BLK_STS_IOERR;
2898
2899 spin_lock_irq(&floppy_lock);
2900 list_add_tail(&bd->rq->queuelist, &floppy_reqs);
2901 spin_unlock_irq(&floppy_lock);
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002902
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002903 if (test_and_set_bit(0, &fdc_busy)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 /* fdc busy, this new request will be treated when the
2905 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002906 is_alive(__func__, "old request running");
Omar Sandovala9f38e12018-10-15 09:21:34 -06002907 return BLK_STS_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 }
Omar Sandovala9f38e12018-10-15 09:21:34 -06002909
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002910 command_status = FD_COMMAND_NONE;
2911 __reschedule_timeout(MAXTIMEOUT, "fd_request");
2912 set_fdc(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002914 is_alive(__func__, "");
Omar Sandovala9f38e12018-10-15 09:21:34 -06002915 return BLK_STS_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916}
2917
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002918static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 .interrupt = success_and_wakeup,
2920 .redo = floppy_ready,
2921 .error = generic_failure,
2922 .done = generic_done
2923};
2924
Joe Perches74f63f42010-03-10 15:20:58 -08002925static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 /* no auto-sense, just clear dcl */
2928 raw_cmd = &default_raw_cmd;
2929 raw_cmd->flags = flag;
2930 raw_cmd->track = 0;
2931 raw_cmd->cmd_count = 0;
2932 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002933 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002934 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002935
2936 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937}
2938
2939/*
2940 * User triggered reset
2941 * ====================
2942 */
2943
2944static void reset_intr(void)
2945{
Joe Perchesb46df352010-03-10 15:20:46 -08002946 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947}
2948
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002949static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 .interrupt = reset_intr,
2951 .redo = success_and_wakeup,
2952 .error = generic_failure,
2953 .done = generic_done
2954};
2955
Joe Perches74f63f42010-03-10 15:20:58 -08002956static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957{
2958 int ret;
2959
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01002960 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08002961 return -EINTR;
2962
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 if (arg == FD_RESET_ALWAYS)
2964 FDCS->reset = 1;
2965 if (FDCS->reset) {
2966 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002967 ret = wait_til_done(reset_fdc, interruptible);
2968 if (ret == -EINTR)
2969 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 }
2971 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002972 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973}
2974
2975/*
2976 * Misc Ioctl's and support
2977 * ========================
2978 */
2979static inline int fd_copyout(void __user *param, const void *address,
2980 unsigned long size)
2981{
2982 return copy_to_user(param, address, size) ? -EFAULT : 0;
2983}
2984
Joe Perches48c8cee2010-03-10 15:20:45 -08002985static inline int fd_copyin(void __user *param, void *address,
2986 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987{
2988 return copy_from_user(address, param, size) ? -EFAULT : 0;
2989}
2990
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02002991static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992{
2993 struct floppy_struct *floppy;
2994
2995 if (type)
2996 floppy = floppy_type + type;
2997 else {
2998 if (UDP->native_format)
2999 floppy = floppy_type + UDP->native_format;
3000 else
3001 return "(null)";
3002 }
3003 if (floppy->name)
3004 return floppy->name;
3005 else
3006 return "(null)";
3007}
3008
3009/* raw commands */
3010static void raw_cmd_done(int flag)
3011{
3012 int i;
3013
3014 if (!flag) {
3015 raw_cmd->flags |= FD_RAW_FAILURE;
3016 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3017 } else {
3018 raw_cmd->reply_count = inr;
3019 if (raw_cmd->reply_count > MAX_REPLIES)
3020 raw_cmd->reply_count = 0;
3021 for (i = 0; i < raw_cmd->reply_count; i++)
3022 raw_cmd->reply[i] = reply_buffer[i];
3023
3024 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3025 unsigned long flags;
3026 flags = claim_dma_lock();
3027 raw_cmd->length = fd_get_dma_residue();
3028 release_dma_lock(flags);
3029 }
3030
3031 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3032 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3033 raw_cmd->flags |= FD_RAW_FAILURE;
3034
3035 if (disk_change(current_drive))
3036 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3037 else
3038 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3039 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
Kees Cookb1bf4212017-10-04 17:49:29 -07003040 motor_off_callback(&motor_off_timer[current_drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
3042 if (raw_cmd->next &&
3043 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3044 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3045 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3046 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3047 raw_cmd = raw_cmd->next;
3048 return;
3049 }
3050 }
3051 generic_done(flag);
3052}
3053
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003054static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 .interrupt = success_and_wakeup,
3056 .redo = floppy_start,
3057 .error = generic_failure,
3058 .done = raw_cmd_done
3059};
3060
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003061static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 struct floppy_raw_cmd *ptr)
3063{
3064 int ret;
3065
3066 while (ptr) {
Matthew Daley2145e152014-04-28 19:05:21 +12003067 struct floppy_raw_cmd cmd = *ptr;
3068 cmd.next = NULL;
3069 cmd.kernel_data = NULL;
3070 ret = copy_to_user(param, &cmd, sizeof(cmd));
Joe Perches86b12b42010-03-10 15:20:56 -08003071 if (ret)
3072 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 param += sizeof(struct floppy_raw_cmd);
3074 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003075 if (ptr->length >= 0 &&
3076 ptr->length <= ptr->buffer_length) {
3077 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003078 ret = fd_copyout(ptr->data, ptr->kernel_data,
3079 length);
3080 if (ret)
3081 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 }
3084 ptr = ptr->next;
3085 }
Joe Perches7f252712010-03-10 15:21:08 -08003086
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 return 0;
3088}
3089
3090static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3091{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003092 struct floppy_raw_cmd *next;
3093 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
3095 this = *ptr;
3096 *ptr = NULL;
3097 while (this) {
3098 if (this->buffer_length) {
3099 fd_dma_mem_free((unsigned long)this->kernel_data,
3100 this->buffer_length);
3101 this->buffer_length = 0;
3102 }
3103 next = this->next;
3104 kfree(this);
3105 this = next;
3106 }
3107}
3108
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003109static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 struct floppy_raw_cmd **rcmd)
3111{
3112 struct floppy_raw_cmd *ptr;
3113 int ret;
3114 int i;
3115
3116 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003117
3118loop:
Vlastimil Babka1661f2e2017-01-04 11:19:31 +01003119 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_KERNEL);
Joe Perches7f252712010-03-10 15:21:08 -08003120 if (!ptr)
3121 return -ENOMEM;
3122 *rcmd = ptr;
3123 ret = copy_from_user(ptr, param, sizeof(*ptr));
Joe Perches7f252712010-03-10 15:21:08 -08003124 ptr->next = NULL;
3125 ptr->buffer_length = 0;
Matthew Daleyef87dbe2014-04-28 19:05:20 +12003126 ptr->kernel_data = NULL;
3127 if (ret)
3128 return -EFAULT;
Joe Perches7f252712010-03-10 15:21:08 -08003129 param += sizeof(struct floppy_raw_cmd);
3130 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 /* the command may now also take up the space
3132 * initially intended for the reply & the
3133 * reply count. Needed for long 82078 commands
3134 * such as RESTORE, which takes ... 17 command
3135 * bytes. Murphy's law #137: When you reserve
3136 * 16 bytes for a structure, you'll one day
3137 * discover that you really need 17...
3138 */
Joe Perches7f252712010-03-10 15:21:08 -08003139 return -EINVAL;
3140
3141 for (i = 0; i < 16; i++)
3142 ptr->reply[i] = 0;
3143 ptr->resultcode = 0;
Joe Perches7f252712010-03-10 15:21:08 -08003144
3145 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3146 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003148 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3149 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3150 if (!ptr->kernel_data)
3151 return -ENOMEM;
3152 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 }
Joe Perches7f252712010-03-10 15:21:08 -08003154 if (ptr->flags & FD_RAW_WRITE) {
3155 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3156 if (ret)
3157 return ret;
3158 }
3159
3160 if (ptr->flags & FD_RAW_MORE) {
3161 rcmd = &(ptr->next);
3162 ptr->rate &= 0x43;
3163 goto loop;
3164 }
3165
3166 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167}
3168
3169static int raw_cmd_ioctl(int cmd, void __user *param)
3170{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003172 int drive;
3173 int ret2;
3174 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
3176 if (FDCS->rawcmd <= 1)
3177 FDCS->rawcmd = 1;
3178 for (drive = 0; drive < N_DRIVE; drive++) {
3179 if (FDC(drive) != fdc)
3180 continue;
3181 if (drive == current_drive) {
3182 if (UDRS->fd_ref > 1) {
3183 FDCS->rawcmd = 2;
3184 break;
3185 }
3186 } else if (UDRS->fd_ref) {
3187 FDCS->rawcmd = 2;
3188 break;
3189 }
3190 }
3191
3192 if (FDCS->reset)
3193 return -EIO;
3194
3195 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3196 if (ret) {
3197 raw_cmd_free(&my_raw_cmd);
3198 return ret;
3199 }
3200
3201 raw_cmd = my_raw_cmd;
3202 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003203 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003204 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
3206 if (ret != -EINTR && FDCS->reset)
3207 ret = -EIO;
3208
3209 DRS->track = NO_TRACK;
3210
3211 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3212 if (!ret)
3213 ret = ret2;
3214 raw_cmd_free(&my_raw_cmd);
3215 return ret;
3216}
3217
3218static int invalidate_drive(struct block_device *bdev)
3219{
3220 /* invalidate the buffer track to force a reread */
3221 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3222 process_fd_request();
3223 check_disk_change(bdev);
3224 return 0;
3225}
3226
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003227static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 int drive, int type, struct block_device *bdev)
3229{
3230 int cnt;
3231
3232 /* sanity checking for parameters. */
3233 if (g->sect <= 0 ||
3234 g->head <= 0 ||
3235 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3236 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003237 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 return -EINVAL;
3239 if (type) {
3240 if (!capable(CAP_SYS_ADMIN))
3241 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003242 mutex_lock(&open_lock);
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003243 if (lock_fdc(drive)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003244 mutex_unlock(&open_lock);
3245 return -EINTR;
3246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 floppy_type[type] = *g;
3248 floppy_type[type].name = "user format";
3249 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3250 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3251 floppy_type[type].size + 1;
3252 process_fd_request();
3253 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3254 struct block_device *bdev = opened_bdev[cnt];
3255 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3256 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003257 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003259 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 } else {
3261 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003262
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003263 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003264 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003265 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 /* notice a disk change immediately, else
3267 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003268 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003269 return -EINTR;
3270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 oldStretch = g->stretch;
3272 user_params[drive] = *g;
3273 if (buffer_drive == drive)
3274 SUPBOUND(buffer_max, user_params[drive].sect);
3275 current_type[drive] = &user_params[drive];
3276 floppy_sizes[drive] = user_params[drive].size;
3277 if (cmd == FDDEFPRM)
3278 DRS->keep_data = -1;
3279 else
3280 DRS->keep_data = 1;
3281 /* invalidation. Invalidate only when needed, i.e.
3282 * when there are already sectors in the buffer cache
3283 * whose number will change. This is useful, because
3284 * mtools often changes the geometry of the disk after
3285 * looking at the boot block */
3286 if (DRS->maxblock > user_params[drive].sect ||
3287 DRS->maxtrack ||
3288 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003289 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 invalidate_drive(bdev);
3291 else
3292 process_fd_request();
3293 }
3294 return 0;
3295}
3296
3297/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003298static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 FDCLRPRM,
3300 FDSETPRM,
3301 FDDEFPRM,
3302 FDGETPRM,
3303 FDMSGON,
3304 FDMSGOFF,
3305 FDFMTBEG,
3306 FDFMTTRK,
3307 FDFMTEND,
3308 FDSETEMSGTRESH,
3309 FDFLUSH,
3310 FDSETMAXERRS,
3311 FDGETMAXERRS,
3312 FDGETDRVTYP,
3313 FDSETDRVPRM,
3314 FDGETDRVPRM,
3315 FDGETDRVSTAT,
3316 FDPOLLDRVSTAT,
3317 FDRESET,
3318 FDGETFDCSTAT,
3319 FDWERRORCLR,
3320 FDWERRORGET,
3321 FDRAWCMD,
3322 FDEJECT,
3323 FDTWADDLE
3324};
3325
Stephen Hemminger21af5442010-06-15 13:21:11 +02003326static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327{
3328 int i;
3329
3330 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3331 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3332 *size = _IOC_SIZE(*cmd);
3333 *cmd = ioctl_table[i];
3334 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003335 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 return -EFAULT;
3337 }
3338 return 0;
3339 }
3340 }
3341 return -EINVAL;
3342}
3343
3344static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3345{
3346 if (type)
3347 *g = &floppy_type[type];
3348 else {
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003349 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003350 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003351 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003352 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 process_fd_request();
3354 *g = current_type[drive];
3355 }
3356 if (!*g)
3357 return -ENODEV;
3358 return 0;
3359}
3360
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003361static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3362{
3363 int drive = (long)bdev->bd_disk->private_data;
3364 int type = ITYPE(drive_state[drive].fd_device);
3365 struct floppy_struct *g;
3366 int ret;
3367
3368 ret = get_floppy_geometry(drive, type, &g);
3369 if (ret)
3370 return ret;
3371
3372 geo->heads = g->head;
3373 geo->sectors = g->sect;
3374 geo->cylinders = g->track;
3375 return 0;
3376}
3377
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003378static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 unsigned long param)
3380{
Al Viroa4af9b42008-03-02 09:27:55 -05003381 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003382 int type = ITYPE(UDRS->fd_device);
3383 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 int ret;
3385 int size;
3386 union inparam {
3387 struct floppy_struct g; /* geometry */
3388 struct format_descr f;
3389 struct floppy_max_errors max_errors;
3390 struct floppy_drive_params dp;
3391 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003392 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393
3394 /* convert compatibility eject ioctls into floppy eject ioctl.
3395 * We do this in order to provide a means to eject floppy disks before
3396 * installing the new fdutils package */
3397 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003398 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 DPRINT("obsolete eject ioctl\n");
3400 DPRINT("please use floppycontrol --eject\n");
3401 cmd = FDEJECT;
3402 }
3403
Joe Perchesa81ee542010-03-10 15:20:46 -08003404 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 return -EINVAL;
3406
Joe Perchesa81ee542010-03-10 15:20:46 -08003407 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003408 ret = normalize_ioctl(&cmd, &size);
3409 if (ret)
3410 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003411
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003413 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3415 return -EPERM;
3416
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003417 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3418 return -EINVAL;
3419
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003421 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003422 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3423 ret = fd_copyin((void __user *)param, &inparam, size);
3424 if (ret)
3425 return ret;
3426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427
Joe Perchesda273652010-03-10 15:20:52 -08003428 switch (cmd) {
3429 case FDEJECT:
3430 if (UDRS->fd_ref != 1)
3431 /* somebody else has this drive open */
3432 return -EBUSY;
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003433 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003434 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435
Joe Perchesda273652010-03-10 15:20:52 -08003436 /* do the actual eject. Fails on
3437 * non-Sparc architectures */
3438 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439
Joe Perchese0298532010-03-10 15:20:55 -08003440 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3441 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003442 process_fd_request();
3443 return ret;
3444 case FDCLRPRM:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003445 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003446 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003447 current_type[drive] = NULL;
3448 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3449 UDRS->keep_data = 0;
3450 return invalidate_drive(bdev);
3451 case FDSETPRM:
3452 case FDDEFPRM:
3453 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3454 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003455 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003456 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003457 if (ret)
3458 return ret;
Andy Whitcroft65eea8e2018-09-20 09:09:48 -06003459 memcpy(&inparam.g, outparam,
3460 offsetof(struct floppy_struct, name));
3461 outparam = &inparam.g;
Joe Perchesda273652010-03-10 15:20:52 -08003462 break;
3463 case FDMSGON:
3464 UDP->flags |= FTD_MSG;
3465 return 0;
3466 case FDMSGOFF:
3467 UDP->flags &= ~FTD_MSG;
3468 return 0;
3469 case FDFMTBEG:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003470 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003471 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003472 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003473 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003474 ret = UDRS->flags;
3475 process_fd_request();
3476 if (ret & FD_VERIFY)
3477 return -ENODEV;
3478 if (!(ret & FD_DISK_WRITABLE))
3479 return -EROFS;
3480 return 0;
3481 case FDFMTTRK:
3482 if (UDRS->fd_ref != 1)
3483 return -EBUSY;
3484 return do_format(drive, &inparam.f);
3485 case FDFMTEND:
3486 case FDFLUSH:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003487 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003488 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003489 return invalidate_drive(bdev);
3490 case FDSETEMSGTRESH:
3491 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3492 return 0;
3493 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003494 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003495 break;
3496 case FDSETMAXERRS:
3497 UDP->max_errors = inparam.max_errors;
3498 break;
3499 case FDGETDRVTYP:
3500 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003501 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003502 break;
3503 case FDSETDRVPRM:
3504 *UDP = inparam.dp;
3505 break;
3506 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003507 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003508 break;
3509 case FDPOLLDRVSTAT:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003510 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003511 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003512 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003513 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003514 process_fd_request();
3515 /* fall through */
3516 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003517 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003518 break;
3519 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003520 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003521 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003522 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003523 break;
3524 case FDWERRORCLR:
3525 memset(UDRWE, 0, sizeof(*UDRWE));
3526 return 0;
3527 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003528 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003529 break;
3530 case FDRAWCMD:
3531 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 return -EINVAL;
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003533 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003534 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003535 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003536 i = raw_cmd_ioctl(cmd, (void __user *)param);
3537 if (i == -EINTR)
3538 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003539 process_fd_request();
3540 return i;
3541 case FDTWADDLE:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003542 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003543 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003544 twaddle();
3545 process_fd_request();
3546 return 0;
3547 default:
3548 return -EINVAL;
3549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
3551 if (_IOC_DIR(cmd) & _IOC_READ)
3552 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003553
3554 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555}
3556
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003557static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3558 unsigned int cmd, unsigned long param)
3559{
3560 int ret;
3561
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003562 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003563 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003564 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003565
3566 return ret;
3567}
3568
Al Viro229b53c2017-06-27 15:47:56 -04003569#ifdef CONFIG_COMPAT
3570
3571struct compat_floppy_drive_params {
3572 char cmos;
3573 compat_ulong_t max_dtr;
3574 compat_ulong_t hlt;
3575 compat_ulong_t hut;
3576 compat_ulong_t srt;
3577 compat_ulong_t spinup;
3578 compat_ulong_t spindown;
3579 unsigned char spindown_offset;
3580 unsigned char select_delay;
3581 unsigned char rps;
3582 unsigned char tracks;
3583 compat_ulong_t timeout;
3584 unsigned char interleave_sect;
3585 struct floppy_max_errors max_errors;
3586 char flags;
3587 char read_track;
3588 short autodetect[8];
3589 compat_int_t checkfreq;
3590 compat_int_t native_format;
3591};
3592
3593struct compat_floppy_drive_struct {
3594 signed char flags;
3595 compat_ulong_t spinup_date;
3596 compat_ulong_t select_date;
3597 compat_ulong_t first_read_date;
3598 short probed_format;
3599 short track;
3600 short maxblock;
3601 short maxtrack;
3602 compat_int_t generation;
3603 compat_int_t keep_data;
3604 compat_int_t fd_ref;
3605 compat_int_t fd_device;
3606 compat_int_t last_checked;
3607 compat_caddr_t dmabuf;
3608 compat_int_t bufblocks;
3609};
3610
3611struct compat_floppy_fdc_state {
3612 compat_int_t spec1;
3613 compat_int_t spec2;
3614 compat_int_t dtr;
3615 unsigned char version;
3616 unsigned char dor;
3617 compat_ulong_t address;
3618 unsigned int rawcmd:2;
3619 unsigned int reset:1;
3620 unsigned int need_configure:1;
3621 unsigned int perp_mode:2;
3622 unsigned int has_fifo:1;
3623 unsigned int driver_version;
3624 unsigned char track[4];
3625};
3626
3627struct compat_floppy_write_errors {
3628 unsigned int write_errors;
3629 compat_ulong_t first_error_sector;
3630 compat_int_t first_error_generation;
3631 compat_ulong_t last_error_sector;
3632 compat_int_t last_error_generation;
3633 compat_uint_t badness;
3634};
3635
3636#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
3637#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
3638#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
3639#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
3640#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
3641#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
3642#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
3643#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
3644
3645static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3646 struct compat_floppy_struct __user *arg)
3647{
3648 struct floppy_struct v;
3649 int drive, type;
3650 int err;
3651
3652 BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
3653 offsetof(struct compat_floppy_struct, name));
3654
3655 if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
3656 return -EPERM;
3657
3658 memset(&v, 0, sizeof(struct floppy_struct));
3659 if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
3660 return -EFAULT;
3661
3662 mutex_lock(&floppy_mutex);
3663 drive = (long)bdev->bd_disk->private_data;
3664 type = ITYPE(UDRS->fd_device);
3665 err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
3666 &v, drive, type, bdev);
3667 mutex_unlock(&floppy_mutex);
3668 return err;
3669}
3670
3671static int compat_get_prm(int drive,
3672 struct compat_floppy_struct __user *arg)
3673{
3674 struct compat_floppy_struct v;
3675 struct floppy_struct *p;
3676 int err;
3677
3678 memset(&v, 0, sizeof(v));
3679 mutex_lock(&floppy_mutex);
3680 err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
3681 if (err) {
3682 mutex_unlock(&floppy_mutex);
3683 return err;
3684 }
3685 memcpy(&v, p, offsetof(struct floppy_struct, name));
3686 mutex_unlock(&floppy_mutex);
3687 if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
3688 return -EFAULT;
3689 return 0;
3690}
3691
3692static int compat_setdrvprm(int drive,
3693 struct compat_floppy_drive_params __user *arg)
3694{
3695 struct compat_floppy_drive_params v;
3696
3697 if (!capable(CAP_SYS_ADMIN))
3698 return -EPERM;
3699 if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
3700 return -EFAULT;
3701 mutex_lock(&floppy_mutex);
3702 UDP->cmos = v.cmos;
3703 UDP->max_dtr = v.max_dtr;
3704 UDP->hlt = v.hlt;
3705 UDP->hut = v.hut;
3706 UDP->srt = v.srt;
3707 UDP->spinup = v.spinup;
3708 UDP->spindown = v.spindown;
3709 UDP->spindown_offset = v.spindown_offset;
3710 UDP->select_delay = v.select_delay;
3711 UDP->rps = v.rps;
3712 UDP->tracks = v.tracks;
3713 UDP->timeout = v.timeout;
3714 UDP->interleave_sect = v.interleave_sect;
3715 UDP->max_errors = v.max_errors;
3716 UDP->flags = v.flags;
3717 UDP->read_track = v.read_track;
3718 memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
3719 UDP->checkfreq = v.checkfreq;
3720 UDP->native_format = v.native_format;
3721 mutex_unlock(&floppy_mutex);
3722 return 0;
3723}
3724
3725static int compat_getdrvprm(int drive,
3726 struct compat_floppy_drive_params __user *arg)
3727{
3728 struct compat_floppy_drive_params v;
3729
3730 memset(&v, 0, sizeof(struct compat_floppy_drive_params));
3731 mutex_lock(&floppy_mutex);
3732 v.cmos = UDP->cmos;
3733 v.max_dtr = UDP->max_dtr;
3734 v.hlt = UDP->hlt;
3735 v.hut = UDP->hut;
3736 v.srt = UDP->srt;
3737 v.spinup = UDP->spinup;
3738 v.spindown = UDP->spindown;
3739 v.spindown_offset = UDP->spindown_offset;
3740 v.select_delay = UDP->select_delay;
3741 v.rps = UDP->rps;
3742 v.tracks = UDP->tracks;
3743 v.timeout = UDP->timeout;
3744 v.interleave_sect = UDP->interleave_sect;
3745 v.max_errors = UDP->max_errors;
3746 v.flags = UDP->flags;
3747 v.read_track = UDP->read_track;
3748 memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
3749 v.checkfreq = UDP->checkfreq;
3750 v.native_format = UDP->native_format;
3751 mutex_unlock(&floppy_mutex);
3752
3753 if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
3754 return -EFAULT;
3755 return 0;
3756}
3757
3758static int compat_getdrvstat(int drive, bool poll,
3759 struct compat_floppy_drive_struct __user *arg)
3760{
3761 struct compat_floppy_drive_struct v;
3762
3763 memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
3764 mutex_lock(&floppy_mutex);
3765
3766 if (poll) {
3767 if (lock_fdc(drive))
3768 goto Eintr;
3769 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
3770 goto Eintr;
3771 process_fd_request();
3772 }
3773 v.spinup_date = UDRS->spinup_date;
3774 v.select_date = UDRS->select_date;
3775 v.first_read_date = UDRS->first_read_date;
3776 v.probed_format = UDRS->probed_format;
3777 v.track = UDRS->track;
3778 v.maxblock = UDRS->maxblock;
3779 v.maxtrack = UDRS->maxtrack;
3780 v.generation = UDRS->generation;
3781 v.keep_data = UDRS->keep_data;
3782 v.fd_ref = UDRS->fd_ref;
3783 v.fd_device = UDRS->fd_device;
3784 v.last_checked = UDRS->last_checked;
3785 v.dmabuf = (uintptr_t)UDRS->dmabuf;
3786 v.bufblocks = UDRS->bufblocks;
3787 mutex_unlock(&floppy_mutex);
3788
3789 if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
3790 return -EFAULT;
3791 return 0;
3792Eintr:
3793 mutex_unlock(&floppy_mutex);
3794 return -EINTR;
3795}
3796
3797static int compat_getfdcstat(int drive,
3798 struct compat_floppy_fdc_state __user *arg)
3799{
3800 struct compat_floppy_fdc_state v32;
3801 struct floppy_fdc_state v;
3802
3803 mutex_lock(&floppy_mutex);
3804 v = *UFDCS;
3805 mutex_unlock(&floppy_mutex);
3806
3807 memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
3808 v32.spec1 = v.spec1;
3809 v32.spec2 = v.spec2;
3810 v32.dtr = v.dtr;
3811 v32.version = v.version;
3812 v32.dor = v.dor;
3813 v32.address = v.address;
3814 v32.rawcmd = v.rawcmd;
3815 v32.reset = v.reset;
3816 v32.need_configure = v.need_configure;
3817 v32.perp_mode = v.perp_mode;
3818 v32.has_fifo = v.has_fifo;
3819 v32.driver_version = v.driver_version;
3820 memcpy(v32.track, v.track, 4);
3821 if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
3822 return -EFAULT;
3823 return 0;
3824}
3825
3826static int compat_werrorget(int drive,
3827 struct compat_floppy_write_errors __user *arg)
3828{
3829 struct compat_floppy_write_errors v32;
3830 struct floppy_write_errors v;
3831
3832 memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
3833 mutex_lock(&floppy_mutex);
3834 v = *UDRWE;
3835 mutex_unlock(&floppy_mutex);
3836 v32.write_errors = v.write_errors;
3837 v32.first_error_sector = v.first_error_sector;
3838 v32.first_error_generation = v.first_error_generation;
3839 v32.last_error_sector = v.last_error_sector;
3840 v32.last_error_generation = v.last_error_generation;
3841 v32.badness = v.badness;
3842 if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
3843 return -EFAULT;
3844 return 0;
3845}
3846
3847static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3848 unsigned long param)
3849{
3850 int drive = (long)bdev->bd_disk->private_data;
3851 switch (cmd) {
3852 case FDMSGON:
3853 case FDMSGOFF:
3854 case FDSETEMSGTRESH:
3855 case FDFLUSH:
3856 case FDWERRORCLR:
3857 case FDEJECT:
3858 case FDCLRPRM:
3859 case FDFMTBEG:
3860 case FDRESET:
3861 case FDTWADDLE:
3862 return fd_ioctl(bdev, mode, cmd, param);
3863 case FDSETMAXERRS:
3864 case FDGETMAXERRS:
3865 case FDGETDRVTYP:
3866 case FDFMTEND:
3867 case FDFMTTRK:
3868 case FDRAWCMD:
3869 return fd_ioctl(bdev, mode, cmd,
3870 (unsigned long)compat_ptr(param));
3871 case FDSETPRM32:
3872 case FDDEFPRM32:
3873 return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
3874 case FDGETPRM32:
3875 return compat_get_prm(drive, compat_ptr(param));
3876 case FDSETDRVPRM32:
3877 return compat_setdrvprm(drive, compat_ptr(param));
3878 case FDGETDRVPRM32:
3879 return compat_getdrvprm(drive, compat_ptr(param));
3880 case FDPOLLDRVSTAT32:
3881 return compat_getdrvstat(drive, true, compat_ptr(param));
3882 case FDGETDRVSTAT32:
3883 return compat_getdrvstat(drive, false, compat_ptr(param));
3884 case FDGETFDCSTAT32:
3885 return compat_getfdcstat(drive, compat_ptr(param));
3886 case FDWERRORGET32:
3887 return compat_werrorget(drive, compat_ptr(param));
3888 }
3889 return -EINVAL;
3890}
3891#endif
3892
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893static void __init config_types(void)
3894{
Joe Perchesb46df352010-03-10 15:20:46 -08003895 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 int drive;
3897
3898 /* read drive info out of physical CMOS */
3899 drive = 0;
3900 if (!UDP->cmos)
3901 UDP->cmos = FLOPPY0_TYPE;
3902 drive = 1;
3903 if (!UDP->cmos && FLOPPY1_TYPE)
3904 UDP->cmos = FLOPPY1_TYPE;
3905
Jesper Juhl06f748c2007-10-16 23:30:57 -07003906 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
3908 for (drive = 0; drive < N_DRIVE; drive++) {
3909 unsigned int type = UDP->cmos;
3910 struct floppy_drive_params *params;
3911 const char *name = NULL;
Rasmus Villemoesbcf42992015-12-01 15:54:01 +01003912 char temparea[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913
Tobias Klauser945f3902006-01-08 01:05:11 -08003914 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 params = &default_drive_params[type].params;
3916 if (type) {
3917 name = default_drive_params[type].name;
3918 allowed_drive_mask |= 1 << drive;
3919 } else
3920 allowed_drive_mask &= ~(1 << drive);
3921 } else {
3922 params = &default_drive_params[0].params;
Rasmus Villemoesbcf42992015-12-01 15:54:01 +01003923 snprintf(temparea, sizeof(temparea),
3924 "unknown type %d (usb?)", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 name = temparea;
3926 }
3927 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003928 const char *prepend;
3929 if (!has_drive) {
3930 prepend = "";
3931 has_drive = true;
3932 pr_info("Floppy drive(s):");
3933 } else {
3934 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 }
Joe Perchesb46df352010-03-10 15:20:46 -08003936
3937 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 }
3939 *UDP = *params;
3940 }
Joe Perchesb46df352010-03-10 15:20:46 -08003941
3942 if (has_drive)
3943 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944}
3945
Al Virodb2a1442013-05-05 21:52:57 -04003946static void floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947{
Al Viroa4af9b42008-03-02 09:27:55 -05003948 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003950 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003951 mutex_lock(&open_lock);
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003952 if (!UDRS->fd_ref--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 DPRINT("floppy_release with fd_ref == 0");
3954 UDRS->fd_ref = 0;
3955 }
3956 if (!UDRS->fd_ref)
3957 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003958 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003959 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960}
3961
3962/*
3963 * floppy_open check for aliasing (/dev/fd0 can be the same as
3964 * /dev/PS0 etc), and disallows simultaneous access to the same
3965 * drive with different device numbers.
3966 */
Al Viroa4af9b42008-03-02 09:27:55 -05003967static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968{
Al Viroa4af9b42008-03-02 09:27:55 -05003969 int drive = (long)bdev->bd_disk->private_data;
3970 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 int try;
3972 int res = -EBUSY;
3973 char *tmp;
3974
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003975 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003976 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003978 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 goto out2;
3980
3981 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003982 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3983 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 }
3985
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003986 UDRS->fd_ref++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987
Al Viroa4af9b42008-03-02 09:27:55 -05003988 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989
3990 res = -ENXIO;
3991
3992 if (!floppy_track_buffer) {
3993 /* if opening an ED drive, reserve a big buffer,
3994 * else reserve a small one */
3995 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3996 try = 64; /* Only 48 actually useful */
3997 else
3998 try = 32; /* Only 24 actually useful */
3999
4000 tmp = (char *)fd_dma_mem_alloc(1024 * try);
4001 if (!tmp && !floppy_track_buffer) {
4002 try >>= 1; /* buffer only one side */
4003 INFBOUND(try, 16);
4004 tmp = (char *)fd_dma_mem_alloc(1024 * try);
4005 }
Joe Perchesa81ee542010-03-10 15:20:46 -08004006 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 if (!tmp && !floppy_track_buffer) {
4009 DPRINT("Unable to allocate DMA memory\n");
4010 goto out;
4011 }
4012 if (floppy_track_buffer) {
4013 if (tmp)
4014 fd_dma_mem_free((unsigned long)tmp, try * 1024);
4015 } else {
4016 buffer_min = buffer_max = -1;
4017 floppy_track_buffer = tmp;
4018 max_buffer_sectors = try;
4019 }
4020 }
4021
Al Viroa4af9b42008-03-02 09:27:55 -05004022 new_dev = MINOR(bdev->bd_dev);
4023 UDRS->fd_device = new_dev;
4024 set_capacity(disks[drive], floppy_sizes[new_dev]);
4025 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 if (buffer_drive == drive)
4027 buffer_track = -1;
4028 }
4029
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 if (UFDCS->rawcmd == 1)
4031 UFDCS->rawcmd = 2;
4032
Jens Axboef2791e72016-08-25 08:56:51 -06004033 if (!(mode & FMODE_NDELAY)) {
4034 if (mode & (FMODE_READ|FMODE_WRITE)) {
4035 UDRS->last_checked = 0;
4036 clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
4037 check_disk_change(bdev);
4038 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
4039 goto out;
4040 if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
4041 goto out;
4042 }
4043 res = -EROFS;
4044 if ((mode & FMODE_WRITE) &&
4045 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
4046 goto out;
4047 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004048 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004049 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 return 0;
4051out:
Jiri Kosinabfa10b82012-05-18 13:50:28 +02004052 UDRS->fd_ref--;
4053
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 if (!UDRS->fd_ref)
4055 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004057 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004058 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 return res;
4060}
4061
4062/*
4063 * Check if the disk has been changed or if a change has been faked.
4064 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004065static unsigned int floppy_check_events(struct gendisk *disk,
4066 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067{
4068 int drive = (long)disk->private_data;
4069
Joe Perchese0298532010-03-10 15:20:55 -08004070 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4071 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004072 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08004074 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01004075 if (lock_fdc(drive))
Yufen Yu96d7cb92019-01-29 16:34:04 +08004076 return 0;
Joe Perches74f63f42010-03-10 15:20:58 -08004077 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 }
4080
Joe Perchese0298532010-03-10 15:20:55 -08004081 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4082 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004084 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004085 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 return 0;
4087}
4088
4089/*
4090 * This implements "read block 0" for floppy_revalidate().
4091 * Needed for format autodetection, checking whether there is
4092 * a disk in the drive, and whether that disk is writable.
4093 */
4094
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004095struct rb0_cbdata {
4096 int drive;
4097 struct completion complete;
4098};
4099
Christoph Hellwig4246a0b2015-07-20 15:29:37 +02004100static void floppy_rb0_cb(struct bio *bio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101{
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004102 struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
4103 int drive = cbdata->drive;
4104
Christoph Hellwig4e4cbee2017-06-03 09:38:06 +02004105 if (bio->bi_status) {
Christoph Hellwig4246a0b2015-07-20 15:29:37 +02004106 pr_info("floppy: error %d while reading block 0\n",
Christoph Hellwig4e4cbee2017-06-03 09:38:06 +02004107 bio->bi_status);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004108 set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
4109 }
4110 complete(&cbdata->complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111}
4112
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004113static int __floppy_read_block_0(struct block_device *bdev, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114{
4115 struct bio bio;
4116 struct bio_vec bio_vec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 struct page *page;
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004118 struct rb0_cbdata cbdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 size_t size;
4120
4121 page = alloc_page(GFP_NOIO);
4122 if (!page) {
4123 process_fd_request();
4124 return -ENOMEM;
4125 }
4126
4127 size = bdev->bd_block_size;
4128 if (!size)
4129 size = 1024;
4130
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004131 cbdata.drive = drive;
4132
Ming Lei3a83f462016-11-22 08:57:21 -07004133 bio_init(&bio, &bio_vec, 1);
Christoph Hellwig74d46992017-08-23 19:10:32 +02004134 bio_set_dev(&bio, bdev);
Ming Lei2c73a602016-11-11 20:05:31 +08004135 bio_add_page(&bio, page, size, 0);
4136
Kent Overstreet4f024f32013-10-11 15:44:27 -07004137 bio.bi_iter.bi_sector = 0;
Jiri Kosina6314a102014-05-28 11:55:23 +02004138 bio.bi_flags |= (1 << BIO_QUIET);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004139 bio.bi_private = &cbdata;
4140 bio.bi_end_io = floppy_rb0_cb;
Mike Christie95fe6c12016-06-05 14:31:48 -05004141 bio_set_op_attrs(&bio, REQ_OP_READ, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
Jens Axboede7b75d2018-11-09 15:58:40 -07004143 init_completion(&cbdata.complete);
4144
Mike Christie4e49ea42016-06-05 14:31:41 -05004145 submit_bio(&bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 process_fd_request();
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004147
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004148 wait_for_completion(&cbdata.complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149
4150 __free_page(page);
4151
4152 return 0;
4153}
4154
4155/* revalidate the floppy disk, i.e. trigger format autodetection by reading
4156 * the bootblock (block 0). "Autodetection" is also needed to check whether
4157 * there is a disk in the drive at all... Thus we also do it for fixed
4158 * geometry formats */
4159static int floppy_revalidate(struct gendisk *disk)
4160{
4161 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 int cf;
4163 int res = 0;
4164
Joe Perchese0298532010-03-10 15:20:55 -08004165 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4166 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004167 test_bit(drive, &fake_change) ||
4168 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02004169 if (WARN(atomic_read(&usage_count) == 0,
4170 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02004172
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01004173 res = lock_fdc(drive);
4174 if (res)
4175 return res;
Joe Perchese0298532010-03-10 15:20:55 -08004176 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4177 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004178 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 process_fd_request(); /*already done by another thread */
4180 return 0;
4181 }
4182 UDRS->maxblock = 0;
4183 UDRS->maxtrack = 0;
4184 if (buffer_drive == drive)
4185 buffer_track = -1;
4186 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08004187 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 if (cf)
4189 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004190 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 /* auto-sensing */
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004192 res = __floppy_read_block_0(opened_bdev[drive], drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 } else {
4194 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08004195 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 process_fd_request();
4197 }
4198 }
4199 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
4200 return res;
4201}
4202
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07004203static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07004204 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05004205 .open = floppy_open,
4206 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02004207 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07004208 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004209 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07004210 .revalidate_disk = floppy_revalidate,
Al Viro229b53c2017-06-27 15:47:56 -04004211#ifdef CONFIG_COMPAT
4212 .compat_ioctl = fd_compat_ioctl,
4213#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216/*
4217 * Floppy Driver initialization
4218 * =============================
4219 */
4220
4221/* Determine the floppy disk controller type */
4222/* This routine was written by David C. Niemi */
4223static char __init get_fdc_version(void)
4224{
4225 int r;
4226
4227 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
4228 if (FDCS->reset)
4229 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004230 r = result();
4231 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 return FDC_NONE; /* No FDC present ??? */
4233 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004234 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
4236 }
4237 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08004238 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
4239 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 return FDC_UNKNOWN;
4241 }
4242
4243 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08004244 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 return FDC_82072; /* 82072 doesn't know CONFIGURE */
4246 }
4247
4248 output_byte(FD_PERPENDICULAR);
4249 if (need_more_output() == MORE_OUTPUT) {
4250 output_byte(0);
4251 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08004252 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 return FDC_82072A; /* 82072A as found on Sparcs. */
4254 }
4255
4256 output_byte(FD_UNLOCK);
4257 r = result();
4258 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004259 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004260 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 * LOCK/UNLOCK */
4262 }
4263 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004264 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
4265 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 return FDC_UNKNOWN;
4267 }
4268 output_byte(FD_PARTID);
4269 r = result();
4270 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08004271 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
4272 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 return FDC_UNKNOWN;
4274 }
4275 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08004276 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 return FDC_82077; /* Revised 82077AA passes all the tests */
4278 }
4279 switch (reply_buffer[0] >> 5) {
4280 case 0x0:
4281 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08004282 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 return FDC_82078;
4284 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004285 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 return FDC_82078;
4287 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004288 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 return FDC_S82078B;
4290 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004291 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 return FDC_87306;
4293 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004294 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4295 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 return FDC_82078_UNKN;
4297 }
4298} /* get_fdc_version */
4299
4300/* lilo configuration */
4301
4302static void __init floppy_set_flags(int *ints, int param, int param2)
4303{
4304 int i;
4305
4306 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4307 if (param)
4308 default_drive_params[i].params.flags |= param2;
4309 else
4310 default_drive_params[i].params.flags &= ~param2;
4311 }
4312 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4313}
4314
4315static void __init daring(int *ints, int param, int param2)
4316{
4317 int i;
4318
4319 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4320 if (param) {
4321 default_drive_params[i].params.select_delay = 0;
4322 default_drive_params[i].params.flags |=
4323 FD_SILENT_DCL_CLEAR;
4324 } else {
4325 default_drive_params[i].params.select_delay =
4326 2 * HZ / 100;
4327 default_drive_params[i].params.flags &=
4328 ~FD_SILENT_DCL_CLEAR;
4329 }
4330 }
4331 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4332}
4333
4334static void __init set_cmos(int *ints, int dummy, int dummy2)
4335{
4336 int current_drive = 0;
4337
4338 if (ints[0] != 2) {
4339 DPRINT("wrong number of parameters for CMOS\n");
4340 return;
4341 }
4342 current_drive = ints[1];
4343 if (current_drive < 0 || current_drive >= 8) {
4344 DPRINT("bad drive for set_cmos\n");
4345 return;
4346 }
4347#if N_FDC > 1
4348 if (current_drive >= 4 && !FDC2)
4349 FDC2 = 0x370;
4350#endif
4351 DP->cmos = ints[2];
4352 DPRINT("setting CMOS code to %d\n", ints[2]);
4353}
4354
4355static struct param_table {
4356 const char *name;
4357 void (*fn) (int *ints, int param, int param2);
4358 int *var;
4359 int def_param;
4360 int param2;
4361} config_params[] __initdata = {
4362 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4363 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4364 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4365 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4366 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4367 {"daring", daring, NULL, 1, 0},
4368#if N_FDC > 1
4369 {"two_fdc", NULL, &FDC2, 0x370, 0},
4370 {"one_fdc", NULL, &FDC2, 0, 0},
4371#endif
4372 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4373 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4374 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4375 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4376 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4377 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4378 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4379 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4380 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4381 {"nofifo", NULL, &no_fifo, 0x20, 0},
4382 {"usefifo", NULL, &no_fifo, 0, 0},
4383 {"cmos", set_cmos, NULL, 0, 0},
4384 {"slow", NULL, &slow_floppy, 1, 0},
4385 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4386 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4387 {"L40SX", NULL, &print_unex, 0, 0}
4388
4389 EXTRA_FLOPPY_PARAMS
4390};
4391
4392static int __init floppy_setup(char *str)
4393{
4394 int i;
4395 int param;
4396 int ints[11];
4397
4398 str = get_options(str, ARRAY_SIZE(ints), ints);
4399 if (str) {
4400 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4401 if (strcmp(str, config_params[i].name) == 0) {
4402 if (ints[0])
4403 param = ints[1];
4404 else
4405 param = config_params[i].def_param;
4406 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004407 config_params[i].fn(ints, param,
4408 config_params[i].
4409 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 if (config_params[i].var) {
4411 DPRINT("%s=%d\n", str, param);
4412 *config_params[i].var = param;
4413 }
4414 return 1;
4415 }
4416 }
4417 }
4418 if (str) {
4419 DPRINT("unknown floppy option [%s]\n", str);
4420
4421 DPRINT("allowed options are:");
4422 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004423 pr_cont(" %s", config_params[i].name);
4424 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 } else
4426 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004427 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 return 0;
4429}
4430
4431static int have_no_fdc = -ENODEV;
4432
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004433static ssize_t floppy_cmos_show(struct device *dev,
4434 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004435{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004436 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004437 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004438
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004439 drive = p->id;
4440 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004441}
Joe Perches48c8cee2010-03-10 15:20:45 -08004442
Joe Perches5657a812018-05-24 13:38:59 -06004443static DEVICE_ATTR(cmos, 0444, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004444
Takashi Iwaib7f120b2015-02-02 17:08:45 +01004445static struct attribute *floppy_dev_attrs[] = {
4446 &dev_attr_cmos.attr,
4447 NULL
4448};
4449
4450ATTRIBUTE_GROUPS(floppy_dev);
4451
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452static void floppy_device_release(struct device *dev)
4453{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454}
4455
Frans Popc90cd332009-07-25 22:24:54 +02004456static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004457{
4458 int fdc;
4459
4460 for (fdc = 0; fdc < N_FDC; fdc++)
4461 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004462 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004463
4464 return 0;
4465}
4466
Alexey Dobriyan47145212009-12-14 18:00:08 -08004467static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004468 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004469 .restore = floppy_resume,
4470};
4471
4472static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004473 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004474 .name = "floppy",
4475 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004476 },
4477};
4478
Omar Sandovala9f38e12018-10-15 09:21:34 -06004479static const struct blk_mq_ops floppy_mq_ops = {
4480 .queue_rq = floppy_queue_rq,
4481};
4482
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004483static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004485static bool floppy_available(int drive)
4486{
4487 if (!(allowed_drive_mask & (1 << drive)))
4488 return false;
4489 if (fdc_state[FDC(drive)].version == FDC_NONE)
4490 return false;
4491 return true;
4492}
4493
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4495{
4496 int drive = (*part & 3) | ((*part & 0x80) >> 5);
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004497 if (drive >= N_DRIVE || !floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004499 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 return NULL;
4501 *part = 0;
Jan Kara3079c222018-02-26 13:01:38 +01004502 return get_disk_and_module(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503}
4504
Andi Kleen0cc15d032012-07-02 17:27:04 -07004505static int __init do_floppy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506{
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004507 int i, unit, drive, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508
Stephen Hemminger285203c2010-06-15 13:21:11 +02004509 set_debugt();
4510 interruptjiffies = resultjiffies = jiffies;
4511
Kumar Gala68e1ee62008-09-22 14:41:31 -07004512#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004513 if (check_legacy_ioport(FDC1))
4514 return -ENODEV;
4515#endif
4516
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 raw_cmd = NULL;
4518
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004519 floppy_wq = alloc_ordered_workqueue("floppy", 0);
4520 if (!floppy_wq)
4521 return -ENOMEM;
4522
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004523 for (drive = 0; drive < N_DRIVE; drive++) {
4524 disks[drive] = alloc_disk(1);
4525 if (!disks[drive]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 err = -ENOMEM;
4527 goto out_put_disk;
4528 }
4529
Omar Sandovala9f38e12018-10-15 09:21:34 -06004530 disks[drive]->queue = blk_mq_init_sq_queue(&tag_sets[drive],
4531 &floppy_mq_ops, 2,
4532 BLK_MQ_F_SHOULD_MERGE);
4533 if (IS_ERR(disks[drive]->queue)) {
4534 err = PTR_ERR(disks[drive]->queue);
4535 disks[drive]->queue = NULL;
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004536 goto out_put_disk;
Jens Axboe48821182010-09-22 09:32:36 +02004537 }
4538
Christoph Hellwig8fc45042017-06-19 09:26:26 +02004539 blk_queue_bounce_limit(disks[drive]->queue, BLK_BOUNCE_HIGH);
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004540 blk_queue_max_hw_sectors(disks[drive]->queue, 64);
4541 disks[drive]->major = FLOPPY_MAJOR;
4542 disks[drive]->first_minor = TOMINOR(drive);
4543 disks[drive]->fops = &floppy_fops;
Martin Wilck773008f2019-03-27 14:51:04 +01004544 disks[drive]->events = DISK_EVENT_MEDIA_CHANGE;
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004545 sprintf(disks[drive]->disk_name, "fd%d", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546
Kees Cookb1bf4212017-10-04 17:49:29 -07004547 timer_setup(&motor_off_timer[drive], motor_off_callback, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 }
4549
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 err = register_blkdev(FLOPPY_MAJOR, "fd");
4551 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004552 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004554 err = platform_driver_register(&floppy_driver);
4555 if (err)
4556 goto out_unreg_blkdev;
4557
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4559 floppy_find, NULL, NULL);
4560
4561 for (i = 0; i < 256; i++)
4562 if (ITYPE(i))
4563 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4564 else
4565 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4566
Joe Perches73507e62010-03-10 15:21:03 -08004567 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 config_types();
4569
4570 for (i = 0; i < N_FDC; i++) {
4571 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004572 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 FDCS->dtr = -1;
4574 FDCS->dor = 0x4;
4575#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004576 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577#ifdef __mc68000__
4578 if (MACH_IS_SUN3X)
4579#endif
4580 FDCS->version = FDC_82072A;
4581#endif
4582 }
4583
4584 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 fdc_state[0].address = FDC1;
4586 if (fdc_state[0].address == -1) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004587 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 err = -ENODEV;
4589 goto out_unreg_region;
4590 }
4591#if N_FDC > 1
4592 fdc_state[1].address = FDC2;
4593#endif
4594
4595 fdc = 0; /* reset fdc in case of unexpected interrupt */
4596 err = floppy_grab_irq_and_dma();
4597 if (err) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004598 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 err = -EBUSY;
4600 goto out_unreg_region;
4601 }
4602
4603 /* initialise drive state */
4604 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004605 memset(UDRS, 0, sizeof(*UDRS));
4606 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004607 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4608 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4609 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 UDRS->fd_device = -1;
4611 floppy_track_buffer = NULL;
4612 max_buffer_sectors = 0;
4613 }
4614 /*
4615 * Small 10 msec delay to let through any interrupt that
4616 * initialization might have triggered, to not
4617 * confuse detection:
4618 */
4619 msleep(10);
4620
4621 for (i = 0; i < N_FDC; i++) {
4622 fdc = i;
4623 FDCS->driver_version = FD_DRIVER_VERSION;
4624 for (unit = 0; unit < 4; unit++)
4625 FDCS->track[unit] = 0;
4626 if (FDCS->address == -1)
4627 continue;
4628 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004629 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004631 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 FDCS->address = -1;
4633 FDCS->version = FDC_NONE;
4634 continue;
4635 }
4636 /* Try to determine the floppy controller type */
4637 FDCS->version = get_fdc_version();
4638 if (FDCS->version == FDC_NONE) {
4639 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004640 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 FDCS->address = -1;
4642 continue;
4643 }
4644 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4645 can_use_virtual_dma = 0;
4646
4647 have_no_fdc = 0;
4648 /* Not all FDCs seem to be able to handle the version command
4649 * properly, so force a reset for the standard FDC clones,
4650 * to avoid interrupt garbage.
4651 */
Joe Perches74f63f42010-03-10 15:20:58 -08004652 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 }
4654 fdc = 0;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004655 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004657 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 if (have_no_fdc) {
4659 DPRINT("no floppy controllers found\n");
4660 err = have_no_fdc;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004661 goto out_release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 }
4663
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 for (drive = 0; drive < N_DRIVE; drive++) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004665 if (!floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004667
4668 floppy_device[drive].name = floppy_device_name;
4669 floppy_device[drive].id = drive;
4670 floppy_device[drive].dev.release = floppy_device_release;
Takashi Iwaib7f120b2015-02-02 17:08:45 +01004671 floppy_device[drive].dev.groups = floppy_dev_groups;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004672
4673 err = platform_device_register(&floppy_device[drive]);
4674 if (err)
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004675 goto out_remove_drives;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004676
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 /* to be cleaned up... */
4678 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reineckefef912b2018-09-28 08:17:19 +02004680 device_add_disk(&floppy_device[drive].dev, disks[drive], NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 }
4682
4683 return 0;
4684
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004685out_remove_drives:
4686 while (drive--) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004687 if (floppy_available(drive)) {
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004688 del_gendisk(disks[drive]);
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004689 platform_device_unregister(&floppy_device[drive]);
4690 }
4691 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004692out_release_dma:
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004693 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 floppy_release_irq_and_dma();
4695out_unreg_region:
4696 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004697 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698out_unreg_blkdev:
4699 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700out_put_disk:
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004701 destroy_workqueue(floppy_wq);
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004702 for (drive = 0; drive < N_DRIVE; drive++) {
4703 if (!disks[drive])
4704 break;
4705 if (disks[drive]->queue) {
4706 del_timer_sync(&motor_off_timer[drive]);
4707 blk_cleanup_queue(disks[drive]->queue);
4708 disks[drive]->queue = NULL;
Omar Sandovala9f38e12018-10-15 09:21:34 -06004709 blk_mq_free_tag_set(&tag_sets[drive]);
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004710 }
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004711 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 }
4713 return err;
4714}
4715
Andi Kleen0cc15d032012-07-02 17:27:04 -07004716#ifndef MODULE
4717static __init void floppy_async_init(void *data, async_cookie_t cookie)
4718{
4719 do_floppy_init();
4720}
4721#endif
4722
4723static int __init floppy_init(void)
4724{
4725#ifdef MODULE
4726 return do_floppy_init();
4727#else
4728 /* Don't hold up the bootup by the floppy initialization */
4729 async_schedule(floppy_async_init, NULL);
4730 return 0;
4731#endif
4732}
4733
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004734static const struct io_region {
4735 int offset;
4736 int size;
4737} io_regions[] = {
4738 { 2, 1 },
4739 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4740 { 4, 2 },
4741 /* address + 6 is reserved, and may be taken by IDE.
4742 * Unfortunately, Adaptec doesn't know this :-(, */
4743 { 7, 1 },
4744};
4745
4746static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4747{
4748 while (p != io_regions) {
4749 p--;
4750 release_region(FDCS->address + p->offset, p->size);
4751 }
4752}
4753
4754#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4755
4756static int floppy_request_regions(int fdc)
4757{
4758 const struct io_region *p;
4759
4760 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004761 if (!request_region(FDCS->address + p->offset,
4762 p->size, "floppy")) {
4763 DPRINT("Floppy io-port 0x%04lx in use\n",
4764 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004765 floppy_release_allocated_regions(fdc, p);
4766 return -EBUSY;
4767 }
4768 }
4769 return 0;
4770}
4771
4772static void floppy_release_regions(int fdc)
4773{
4774 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4775}
4776
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777static int floppy_grab_irq_and_dma(void)
4778{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004779 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004781
4782 /*
4783 * We might have scheduled a free_irq(), wait it to
4784 * drain first:
4785 */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004786 flush_workqueue(floppy_wq);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004787
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 if (fd_request_irq()) {
4789 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4790 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004791 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 return -1;
4793 }
4794 if (fd_request_dma()) {
4795 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4796 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004797 if (can_use_virtual_dma & 2)
4798 use_virtual_dma = can_use_virtual_dma = 1;
4799 if (!(can_use_virtual_dma & 1)) {
4800 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004801 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004802 return -1;
4803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 }
4805
4806 for (fdc = 0; fdc < N_FDC; fdc++) {
4807 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004808 if (floppy_request_regions(fdc))
4809 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 }
4811 }
4812 for (fdc = 0; fdc < N_FDC; fdc++) {
4813 if (FDCS->address != -1) {
4814 reset_fdc_info(1);
4815 fd_outb(FDCS->dor, FD_DOR);
4816 }
4817 }
4818 fdc = 0;
4819 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4820
4821 for (fdc = 0; fdc < N_FDC; fdc++)
4822 if (FDCS->address != -1)
4823 fd_outb(FDCS->dor, FD_DOR);
4824 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004825 * The driver will try and free resources and relies on us
4826 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 */
4828 fdc = 0;
4829 irqdma_allocated = 1;
4830 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004831cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 fd_free_irq();
4833 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004834 while (--fdc >= 0)
4835 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004836 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 return -1;
4838}
4839
4840static void floppy_release_irq_and_dma(void)
4841{
4842 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843#ifndef __sparc__
4844 int drive;
4845#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 long tmpsize;
4847 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004849 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004851
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 if (irqdma_allocated) {
4853 fd_disable_dma();
4854 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004855 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 irqdma_allocated = 0;
4857 }
4858 set_dor(0, ~0, 8);
4859#if N_FDC > 1
4860 set_dor(1, ~8, 0);
4861#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862
4863 if (floppy_track_buffer && max_buffer_sectors) {
4864 tmpsize = max_buffer_sectors * 1024;
4865 tmpaddr = (unsigned long)floppy_track_buffer;
4866 floppy_track_buffer = NULL;
4867 max_buffer_sectors = 0;
4868 buffer_min = buffer_max = -1;
4869 fd_dma_mem_free(tmpaddr, tmpsize);
4870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871#ifndef __sparc__
4872 for (drive = 0; drive < N_FDC * 4; drive++)
4873 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004874 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875#endif
4876
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004877 if (delayed_work_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004878 pr_info("floppy timer still active:%s\n", timeout_message);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004879 if (delayed_work_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004880 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004881 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004882 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 old_fdc = fdc;
4884 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004885 if (FDCS->address != -1)
4886 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 fdc = old_fdc;
4888}
4889
4890#ifdef MODULE
4891
4892static char *floppy;
4893
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894static void __init parse_floppy_cfg_string(char *cfg)
4895{
4896 char *ptr;
4897
4898 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004899 ptr = cfg;
4900 while (*cfg && *cfg != ' ' && *cfg != '\t')
4901 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 if (*cfg) {
4903 *cfg = '\0';
4904 cfg++;
4905 }
4906 if (*ptr)
4907 floppy_setup(ptr);
4908 }
4909}
4910
Jon Schindler7afea3b2008-04-29 00:59:21 -07004911static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912{
4913 if (floppy)
4914 parse_floppy_cfg_string(floppy);
4915 return floppy_init();
4916}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004917module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918
Jon Schindler7afea3b2008-04-29 00:59:21 -07004919static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920{
4921 int drive;
4922
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4924 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004925 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004927 destroy_workqueue(floppy_wq);
4928
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 for (drive = 0; drive < N_DRIVE; drive++) {
4930 del_timer_sync(&motor_off_timer[drive]);
4931
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004932 if (floppy_available(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004934 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 }
Jens Axboe48821182010-09-22 09:32:36 +02004936 blk_cleanup_queue(disks[drive]->queue);
Omar Sandovala9f38e12018-10-15 09:21:34 -06004937 blk_mq_free_tag_set(&tag_sets[drive]);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004938
4939 /*
4940 * These disks have not called add_disk(). Don't put down
4941 * queue reference in put_disk().
4942 */
4943 if (!(allowed_drive_mask & (1 << drive)) ||
4944 fdc_state[FDC(drive)].version == FDC_NONE)
4945 disks[drive]->queue = NULL;
4946
Vivek Goyald017bf62010-11-06 08:16:05 -04004947 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004950 cancel_delayed_work_sync(&fd_timeout);
4951 cancel_delayed_work_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004953 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 floppy_release_irq_and_dma();
4955
4956 /* eject disk, if any */
4957 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958}
Joe Perches48c8cee2010-03-10 15:20:45 -08004959
Jon Schindler7afea3b2008-04-29 00:59:21 -07004960module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961
4962module_param(floppy, charp, 0);
4963module_param(FLOPPY_IRQ, int, 0);
4964module_param(FLOPPY_DMA, int, 0);
4965MODULE_AUTHOR("Alain L. Knaff");
4966MODULE_SUPPORTED_DEVICE("fd");
4967MODULE_LICENSE("GPL");
4968
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004969/* This doesn't actually get used other than for module information */
4970static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004971 {"PNP0700", 0},
4972 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004973};
Joe Perches48c8cee2010-03-10 15:20:45 -08004974
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004975MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4976
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977#else
4978
4979__setup("floppy=", floppy_setup);
4980module_init(floppy_init)
4981#endif
4982
4983MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);