blob: 945f93d1ffe762fbf357c7890ceecdbaec8fa951 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/block/floppy.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1993, 1994 Alain Knaff
6 * Copyright (C) 1998 Alan Cox
7 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009/*
10 * 02.12.91 - Changed to static variables to indicate need for reset
11 * and recalibrate. This makes some things easier (output_byte reset
12 * checking etc), and means less interrupt jumping in case of errors,
13 * so the code is hopefully easier to understand.
14 */
15
16/*
17 * This file is certainly a mess. I've tried my best to get it working,
18 * but I don't like programming floppies, and I have only one anyway.
19 * Urgel. I should check for more errors, and do more graceful error
20 * recovery. Seems there are problems with several drives. I've tried to
21 * correct them. No promises.
22 */
23
24/*
25 * As with hd.c, all routines within this file can (and will) be called
26 * by interrupts, so extreme caution is needed. A hardware interrupt
27 * handler may not sleep, or a kernel panic will happen. Thus I cannot
28 * call "floppy-on" directly, but have to set a special timer interrupt
29 * etc.
30 */
31
32/*
33 * 28.02.92 - made track-buffering routines, based on the routines written
34 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
35 */
36
37/*
38 * Automatic floppy-detection and formatting written by Werner Almesberger
39 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
40 * the floppy-change signal detection.
41 */
42
43/*
44 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
45 * FDC data overrun bug, added some preliminary stuff for vertical
46 * recording support.
47 *
48 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
49 *
50 * TODO: Errors are still not counted properly.
51 */
52
53/* 1992/9/20
54 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
55 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
56 * Christoph H. Hochst\"atter.
57 * I have fixed the shift values to the ones I always use. Maybe a new
58 * ioctl() should be created to be able to modify them.
59 * There is a bug in the driver that makes it impossible to format a
60 * floppy as the first thing after bootup.
61 */
62
63/*
64 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
65 * this helped the floppy driver as well. Much cleaner, and still seems to
66 * work.
67 */
68
69/* 1994/6/24 --bbroad-- added the floppy table entries and made
70 * minor modifications to allow 2.88 floppies to be run.
71 */
72
73/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
74 * disk types.
75 */
76
77/*
78 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
79 * format bug fixes, but unfortunately some new bugs too...
80 */
81
82/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
83 * errors to allow safe writing by specialized programs.
84 */
85
86/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
87 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
88 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
89 * drives are "upside-down").
90 */
91
92/*
93 * 1995/8/26 -- Andreas Busse -- added Mips support.
94 */
95
96/*
97 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
98 * features to asm/floppy.h.
99 */
100
101/*
James Nelsonb88b0982005-11-08 16:52:12 +0100102 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
103 */
104
105/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
107 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
108 * use of '0' for NULL.
109 */
110
111/*
112 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
113 * failures.
114 */
115
116/*
117 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
118 */
119
120/*
121 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
122 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
123 * being used to store jiffies, which are unsigned longs).
124 */
125
126/*
127 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
128 * - get rid of check_region
129 * - s/suser/capable/
130 */
131
132/*
133 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
134 * floppy controller (lingering task on list after module is gone... boom.)
135 */
136
137/*
138 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
139 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
140 * requires many non-obvious changes in arch dependent code.
141 */
142
143/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
144 * Better audit of register_blkdev.
145 */
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147#undef FLOPPY_SILENT_DCL_CLEAR
148
149#define REALLY_SLOW_IO
150
151#define DEBUGT 2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Joe Perches891eda82010-03-10 15:21:05 -0800153#define DPRINT(format, args...) \
154 pr_info("floppy%d: " format, current_drive, ##args)
155
156#define DCL_DEBUG /* debug disk change line */
Joe Perches87f530d2010-03-10 15:20:54 -0800157#ifdef DCL_DEBUG
158#define debug_dcl(test, fmt, args...) \
159 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
160#else
161#define debug_dcl(test, fmt, args...) \
162 do { if (0) DPRINT(fmt, ##args); } while (0)
163#endif
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165/* do print messages for unexpected interrupts */
166static int print_unex = 1;
167#include <linux/module.h>
168#include <linux/sched.h>
169#include <linux/fs.h>
170#include <linux/kernel.h>
171#include <linux/timer.h>
172#include <linux/workqueue.h>
173#define FDPATCHES
174#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#include <linux/fd.h>
176#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#include <linux/errno.h>
178#include <linux/slab.h>
179#include <linux/mm.h>
180#include <linux/bio.h>
181#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800182#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#include <linux/fcntl.h>
184#include <linux/delay.h>
185#include <linux/mc146818rtc.h> /* CMOS defines */
186#include <linux/ioport.h>
187#include <linux/interrupt.h>
188#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100189#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700190#include <linux/mod_devicetable.h>
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800191#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800192#include <linux/io.h>
193#include <linux/uaccess.h>
Andi Kleen0cc15d032012-07-02 17:27:04 -0700194#include <linux/async.h>
Al Viro06f9e7b2017-06-27 15:47:56 -0400195#include <linux/compat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197/*
198 * PS/2 floppies have much slower step rates than regular floppies.
199 * It's been recommended that take about 1/4 of the default speed
200 * in some more extreme cases.
201 */
Arnd Bergmann2a48fc02010-06-02 14:28:52 +0200202static DEFINE_MUTEX(floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203static int slow_floppy;
204
205#include <asm/dma.h>
206#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208static int FLOPPY_IRQ = 6;
209static int FLOPPY_DMA = 2;
210static int can_use_virtual_dma = 2;
211/* =======
212 * can use virtual DMA:
213 * 0 = use of virtual DMA disallowed by config
214 * 1 = use of virtual DMA prescribed by config
215 * 2 = no virtual DMA preference configured. By default try hard DMA,
216 * but fall back on virtual DMA when not enough memory available
217 */
218
219static int use_virtual_dma;
220/* =======
221 * use virtual DMA
222 * 0 using hard DMA
223 * 1 using virtual DMA
224 * This variable is set to virtual when a DMA mem problem arises, and
225 * reset back in floppy_grab_irq_and_dma.
226 * It is not safe to reset it in other circumstances, because the floppy
227 * driver may have several buffers in use at once, and we do currently not
228 * record each buffers capabilities
229 */
230
231static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100234irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237#define K_64 0x10000 /* 64KB */
238
239/* the following is the mask of allowed drives. By default units 2 and
240 * 3 of both floppy controllers are disabled, because switching on the
241 * motor of these drives causes system hangs on some PCI computers. drive
242 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
243 * a drive is allowed.
244 *
245 * NOTE: This must come before we include the arch floppy header because
246 * some ports reference this variable from there. -DaveM
247 */
248
249static int allowed_drive_mask = 0x33;
250
251#include <asm/floppy.h>
252
253static int irqdma_allocated;
254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255#include <linux/blkdev.h>
256#include <linux/blkpg.h>
257#include <linux/cdrom.h> /* for the compatibility eject ioctl */
258#include <linux/completion.h>
259
260static struct request *current_req;
Joe Perches48c8cee2010-03-10 15:20:45 -0800261static void do_fd_request(struct request_queue *q);
Jens Axboe48821182010-09-22 09:32:36 +0200262static int set_next_request(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264#ifndef fd_get_dma_residue
265#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
266#endif
267
268/* Dma Memory related stuff */
269
270#ifndef fd_dma_mem_free
271#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
272#endif
273
274#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800275#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276#endif
277
278static inline void fallback_on_nodma_alloc(char **addr, size_t l)
279{
280#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
281 if (*addr)
282 return; /* we have the memory */
283 if (can_use_virtual_dma != 2)
284 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800285 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 *addr = (char *)nodma_mem_alloc(l);
287#else
288 return;
289#endif
290}
291
292/* End dma memory related stuff */
293
294static unsigned long fake_change;
Joe Perches29f1c782010-03-10 15:21:00 -0800295static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Joe Perches48c8cee2010-03-10 15:20:45 -0800297#define ITYPE(x) (((x) >> 2) & 0x1f)
298#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
299#define UNIT(x) ((x) & 0x03) /* drive on fdc */
300#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700301 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Joe Perches48c8cee2010-03-10 15:20:45 -0800304#define DP (&drive_params[current_drive])
305#define DRS (&drive_state[current_drive])
306#define DRWE (&write_errors[current_drive])
307#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Joe Perches48c8cee2010-03-10 15:20:45 -0800309#define UDP (&drive_params[drive])
310#define UDRS (&drive_state[drive])
311#define UDRWE (&write_errors[drive])
312#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Joe Perches48c8cee2010-03-10 15:20:45 -0800314#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
315#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
316
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800318#define COMMAND (raw_cmd->cmd[0])
319#define DR_SELECT (raw_cmd->cmd[1])
320#define TRACK (raw_cmd->cmd[2])
321#define HEAD (raw_cmd->cmd[3])
322#define SECTOR (raw_cmd->cmd[4])
323#define SIZECODE (raw_cmd->cmd[5])
324#define SECT_PER_TRACK (raw_cmd->cmd[6])
325#define GAP (raw_cmd->cmd[7])
326#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327#define NR_RW 9
328
329/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800330#define F_SIZECODE (raw_cmd->cmd[2])
331#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
332#define F_GAP (raw_cmd->cmd[4])
333#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334#define NR_F 6
335
336/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800337 * Maximum disk size (in kilobytes).
338 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 * [Now it is rather a minimum]
340 */
341#define MAX_DISK_SIZE 4 /* 3984 */
342
343/*
344 * globals used by 'result()'
345 */
346#define MAX_REPLIES 16
347static unsigned char reply_buffer[MAX_REPLIES];
Joe Perches891eda82010-03-10 15:21:05 -0800348static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800349#define ST0 (reply_buffer[0])
350#define ST1 (reply_buffer[1])
351#define ST2 (reply_buffer[2])
352#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
353#define R_TRACK (reply_buffer[3])
354#define R_HEAD (reply_buffer[4])
355#define R_SECTOR (reply_buffer[5])
356#define R_SIZECODE (reply_buffer[6])
357
358#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360/*
361 * this struct defines the different floppy drive types.
362 */
363static struct {
364 struct floppy_drive_params params;
365 const char *name; /* name printed while booting */
366} default_drive_params[] = {
367/* NOTE: the time values in jiffies should be in msec!
368 CMOS drive type
369 | Maximum data rate supported by drive type
370 | | Head load time, msec
371 | | | Head unload time, msec (not used)
372 | | | | Step rate interval, usec
373 | | | | | Time needed for spinup time (jiffies)
374 | | | | | | Timeout for spinning down (jiffies)
375 | | | | | | | Spindown offset (where disk stops)
376 | | | | | | | | Select delay
377 | | | | | | | | | RPS
378 | | | | | | | | | | Max number of tracks
379 | | | | | | | | | | | Interrupt timeout
380 | | | | | | | | | | | | Max nonintlv. sectors
381 | | | | | | | | | | | | | -Max Errors- flags */
382{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
383 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
384
385{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
386 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
387
388{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
389 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
390
391{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
392 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
393
394{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
395 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
396
397{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
398 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
399
400{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
401 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
402/* | --autodetected formats--- | | |
403 * read_track | | Name printed when booting
404 * | Native format
405 * Frequency of disk change checks */
406};
407
408static struct floppy_drive_params drive_params[N_DRIVE];
409static struct floppy_drive_struct drive_state[N_DRIVE];
410static struct floppy_write_errors write_errors[N_DRIVE];
411static struct timer_list motor_off_timer[N_DRIVE];
412static struct gendisk *disks[N_DRIVE];
413static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800414static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
Jens Axboe48821182010-09-22 09:32:36 +0200416static int fdc_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418/*
419 * This struct defines the different floppy types.
420 *
421 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
422 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
423 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
424 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
425 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
426 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
427 * side 0 is on physical side 0 (but with the misnamed sector IDs).
428 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700429 * 'options'.
430 *
431 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
432 * The LSB (bit 2) is flipped. For most disks, the first sector
433 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
434 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
435 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
436 *
437 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 */
439/*
440 Size
441 | Sectors per track
442 | | Head
443 | | | Tracks
444 | | | | Stretch
445 | | | | | Gap 1 size
446 | | | | | | Data rate, | 0x40 for perp
447 | | | | | | | Spec1 (stepping rate, head unload
448 | | | | | | | | /fmt gap (gap2) */
449static struct floppy_struct floppy_type[32] = {
450 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
451 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
452 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
453 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
454 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
455 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
456 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
457 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
458 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
459 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
460
461 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
462 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
463 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
464 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
465 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
466 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
467 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
468 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
469 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
470 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
471
472 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
473 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
474 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
475 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
476 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
477 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
478 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
479 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
480 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
484 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
485};
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487#define SECTSIZE (_FD_SECTSIZE(*floppy))
488
489/* Auto-detection: Disk type used until the next media change occurs. */
490static struct floppy_struct *current_type[N_DRIVE];
491
492/*
493 * User-provided type information. current_type points to
494 * the respective entry of this array.
495 */
496static struct floppy_struct user_params[N_DRIVE];
497
498static sector_t floppy_sizes[256];
499
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200500static char floppy_device_name[] = "floppy";
501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502/*
503 * The driver is trying to determine the correct media format
504 * while probing is set. rw_interrupt() clears it after a
505 * successful access.
506 */
507static int probing;
508
509/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800510#define FD_COMMAND_NONE -1
511#define FD_COMMAND_ERROR 2
512#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514static volatile int command_status = FD_COMMAND_NONE;
515static unsigned long fdc_busy;
516static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
517static DECLARE_WAIT_QUEUE_HEAD(command_done);
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519/* Errors during formatting are counted here. */
520static int format_errors;
521
522/* Format request descriptor. */
523static struct format_descr format_req;
524
525/*
526 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
527 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
528 * H is head unload time (1=16ms, 2=32ms, etc)
529 */
530
531/*
532 * Track buffer
533 * Because these are written to by the DMA controller, they must
534 * not contain a 64k byte boundary crossing, or data will be
535 * corrupted/lost.
536 */
537static char *floppy_track_buffer;
538static int max_buffer_sectors;
539
540static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700541typedef void (*done_f)(int);
Stephen Hemminger3b06c212010-07-20 20:09:00 -0600542static const struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800543 void (*interrupt)(void);
544 /* this is called after the interrupt of the
545 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700546 void (*redo)(void); /* this is called to retry the operation */
547 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 done_f done; /* this is called to say if the operation has
549 * succeeded/failed */
550} *cont;
551
552static void floppy_ready(void);
553static void floppy_start(void);
554static void process_fd_request(void);
555static void recalibrate_floppy(void);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200556static void floppy_shutdown(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800558static int floppy_request_regions(int);
559static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560static int floppy_grab_irq_and_dma(void);
561static void floppy_release_irq_and_dma(void);
562
563/*
564 * The "reset" variable should be tested whenever an interrupt is scheduled,
565 * after the commands have been sent. This is to ensure that the driver doesn't
566 * get wedged when the interrupt doesn't come because of a failed command.
567 * reset doesn't need to be tested before sending commands, because
568 * output_byte is automatically disabled when reset is set.
569 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570static void reset_fdc(void);
571
572/*
573 * These are global variables, as that's the easiest way to give
574 * information to interrupts. They are the data used for the current
575 * request.
576 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800577#define NO_TRACK -1
578#define NEED_1_RECAL -2
579#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200581static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583/* buffer related variables */
584static int buffer_track = -1;
585static int buffer_drive = -1;
586static int buffer_min = -1;
587static int buffer_max = -1;
588
589/* fdc related variables, should end up in a struct */
590static struct floppy_fdc_state fdc_state[N_FDC];
591static int fdc; /* current fdc */
592
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200593static struct workqueue_struct *floppy_wq;
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595static struct floppy_struct *_floppy = floppy_type;
596static unsigned char current_drive;
597static long current_count_sectors;
598static unsigned char fsector_t; /* sector in track */
599static unsigned char in_sector_offset; /* offset within physical sector,
600 * expressed in units of 512 bytes */
601
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100602static inline bool drive_no_geom(int drive)
603{
604 return !current_type[drive] && !ITYPE(UDRS->fd_device);
605}
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607#ifndef fd_eject
608static inline int fd_eject(int drive)
609{
610 return -EINVAL;
611}
612#endif
613
614/*
615 * Debugging
616 * =========
617 */
618#ifdef DEBUGT
619static long unsigned debugtimer;
620
621static inline void set_debugt(void)
622{
623 debugtimer = jiffies;
624}
625
Joe Perchesded28632010-03-10 15:21:09 -0800626static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
628 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800629 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
631#else
632static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800633static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634#endif /* DEBUGT */
635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200637static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638static const char *timeout_message;
639
Joe Perches275176b2010-03-10 15:21:06 -0800640static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641{
642 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800643 if (test_bit(0, &fdc_busy) && command_status < 2 &&
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200644 !delayed_work_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800645 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
647}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Joe Perches48c8cee2010-03-10 15:20:45 -0800649static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651#define OLOGSIZE 20
652
Joe Perches48c8cee2010-03-10 15:20:45 -0800653static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654static unsigned long interruptjiffies;
655static unsigned long resultjiffies;
656static int resultsize;
657static unsigned long lastredo;
658
659static struct output_log {
660 unsigned char data;
661 unsigned char status;
662 unsigned long jiffies;
663} output_log[OLOGSIZE];
664
665static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667#define current_reqD -1
668#define MAXTIMEOUT -2
669
Joe Perches73507e62010-03-10 15:21:03 -0800670static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200672 unsigned long delay;
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (drive == current_reqD)
675 drive = current_drive;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200676
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700677 if (drive < 0 || drive >= N_DRIVE) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200678 delay = 20UL * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 drive = 0;
680 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200681 delay = UDP->timeout;
682
Tejun Heoe7c2f962012-08-21 13:18:24 -0700683 mod_delayed_work(floppy_wq, &fd_timeout, delay);
Joe Perchesa81ee542010-03-10 15:20:46 -0800684 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800685 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 timeout_message = message;
687}
688
Joe Perches73507e62010-03-10 15:21:03 -0800689static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
691 unsigned long flags;
692
693 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800694 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 spin_unlock_irqrestore(&floppy_lock, flags);
696}
697
Joe Perches48c8cee2010-03-10 15:20:45 -0800698#define INFBOUND(a, b) (a) = max_t(int, a, b)
699#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701/*
702 * Bottom half floppy driver.
703 * ==========================
704 *
705 * This part of the file contains the code talking directly to the hardware,
706 * and also the main service loop (seek-configure-spinup-command)
707 */
708
709/*
710 * disk change.
711 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
712 * and the last_checked date.
713 *
714 * last_checked is the date of the last check which showed 'no disk change'
715 * FD_DISK_CHANGE is set under two conditions:
716 * 1. The floppy has been changed after some i/o to that floppy already
717 * took place.
718 * 2. No floppy disk is in the drive. This is done in order to ensure that
719 * requests are quickly flushed in case there is no disk in the drive. It
720 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
721 * the drive.
722 *
723 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
724 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
725 * each seek. If a disk is present, the disk change line should also be
726 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
727 * change line is set, this means either that no disk is in the drive, or
728 * that it has been removed since the last seek.
729 *
730 * This means that we really have a third possibility too:
731 * The floppy has been changed after the last seek.
732 */
733
734static int disk_change(int drive)
735{
736 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700737
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800738 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 DPRINT("WARNING disk change called early\n");
740 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
741 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
742 DPRINT("probing disk change on unselected drive\n");
743 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
744 (unsigned int)FDCS->dor);
745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Joe Perches87f530d2010-03-10 15:20:54 -0800747 debug_dcl(UDP->flags,
748 "checking disk change line for drive %d\n", drive);
749 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
750 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
751 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
752
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800754 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800756 set_bit(FD_VERIFY_BIT, &UDRS->flags);
757 /* verify write protection */
758
759 if (UDRS->maxblock) /* mark it changed */
760 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 /* invalidate its geometry */
763 if (UDRS->keep_data >= 0) {
764 if ((UDP->flags & FTD_MSG) &&
765 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800766 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 current_type[drive] = NULL;
768 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
769 }
770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return 1;
772 } else {
773 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800774 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776 return 0;
777}
778
779static inline int is_selected(int dor, int unit)
780{
781 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
782}
783
Joe Perches57584c52010-03-10 15:21:00 -0800784static bool is_ready_state(int status)
785{
786 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
787 return state == STATUS_READY;
788}
789
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790static int set_dor(int fdc, char mask, char data)
791{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700792 unsigned char unit;
793 unsigned char drive;
794 unsigned char newdor;
795 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 if (FDCS->address == -1)
798 return -1;
799
800 olddor = FDCS->dor;
801 newdor = (olddor & mask) | data;
802 if (newdor != olddor) {
803 unit = olddor & 0x3;
804 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
805 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800806 debug_dcl(UDP->flags,
807 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 disk_change(drive);
809 }
810 FDCS->dor = newdor;
811 fd_outb(newdor, FD_DOR);
812
813 unit = newdor & 0x3;
814 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
815 drive = REVDRIVE(fdc, unit);
816 UDRS->select_date = jiffies;
817 }
818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return olddor;
820}
821
822static void twaddle(void)
823{
824 if (DP->select_delay)
825 return;
826 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
827 fd_outb(FDCS->dor, FD_DOR);
828 DRS->select_date = jiffies;
829}
830
Joe Perches57584c52010-03-10 15:21:00 -0800831/*
832 * Reset all driver information about the current fdc.
833 * This is needed after a reset, and after a raw command.
834 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835static void reset_fdc_info(int mode)
836{
837 int drive;
838
839 FDCS->spec1 = FDCS->spec2 = -1;
840 FDCS->need_configure = 1;
841 FDCS->perp_mode = 1;
842 FDCS->rawcmd = 0;
843 for (drive = 0; drive < N_DRIVE; drive++)
844 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
845 UDRS->track = NEED_2_RECAL;
846}
847
848/* selects the fdc and drive, and enables the fdc's input/dma. */
849static void set_fdc(int drive)
850{
851 if (drive >= 0 && drive < N_DRIVE) {
852 fdc = FDC(drive);
853 current_drive = drive;
854 }
855 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800856 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 return;
858 }
859 set_dor(fdc, ~0, 8);
860#if N_FDC > 1
861 set_dor(1 - fdc, ~8, 0);
862#endif
863 if (FDCS->rawcmd == 2)
864 reset_fdc_info(1);
865 if (fd_inb(FD_STATUS) != STATUS_READY)
866 FDCS->reset = 1;
867}
868
869/* locks the driver */
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +0100870static int lock_fdc(int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200872 if (WARN(atomic_read(&usage_count) == 0,
873 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200876 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
877 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 command_status = FD_COMMAND_NONE;
880
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200881 reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 set_fdc(drive);
883 return 0;
884}
885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200887static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 if (!test_bit(0, &fdc_busy))
890 DPRINT("FDC access conflict!\n");
891
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200892 raw_cmd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 command_status = FD_COMMAND_NONE;
Tejun Heo136b5722012-08-21 13:18:24 -0700894 cancel_delayed_work(&fd_timeout);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200895 do_floppy = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 cont = NULL;
897 clear_bit(0, &fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 wake_up(&fdc_wait);
899}
900
901/* switches the motor off after a given timeout */
902static void motor_off_callback(unsigned long nr)
903{
904 unsigned char mask = ~(0x10 << UNIT(nr));
905
906 set_dor(FDC(nr), mask, 0);
907}
908
909/* schedules motor off */
910static void floppy_off(unsigned int drive)
911{
912 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700913 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 if (!(FDCS->dor & (0x10 << UNIT(drive))))
916 return;
917
918 del_timer(motor_off_timer + drive);
919
920 /* make spindle stop in a position which minimizes spinup time
921 * next time */
922 if (UDP->rps) {
923 delta = jiffies - UDRS->first_read_date + HZ -
924 UDP->spindown_offset;
925 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
926 motor_off_timer[drive].expires =
927 jiffies + UDP->spindown - delta;
928 }
929 add_timer(motor_off_timer + drive);
930}
931
932/*
933 * cycle through all N_DRIVE floppy drives, for disk change testing.
934 * stopping at current drive. This is done before any long operation, to
935 * be sure to have up to date disk change information.
936 */
937static void scandrives(void)
938{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700939 int i;
940 int drive;
941 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 if (DP->select_delay)
944 return;
945
946 saved_drive = current_drive;
947 for (i = 0; i < N_DRIVE; i++) {
948 drive = (saved_drive + i + 1) % N_DRIVE;
949 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
950 continue; /* skip closed drives */
951 set_fdc(drive);
952 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
953 (0x10 << UNIT(drive))))
954 /* switch the motor off again, if it was off to
955 * begin with */
956 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
957 }
958 set_fdc(saved_drive);
959}
960
961static void empty(void)
962{
963}
964
Tejun Heo75ddb382014-03-07 10:24:48 -0500965static void (*floppy_work_fn)(void);
966
967static void floppy_work_workfn(struct work_struct *work)
968{
969 floppy_work_fn();
970}
971
972static DECLARE_WORK(floppy_work, floppy_work_workfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Joe Perches48c8cee2010-03-10 15:20:45 -0800974static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200976 WARN_ON(work_pending(&floppy_work));
977
Tejun Heo75ddb382014-03-07 10:24:48 -0500978 floppy_work_fn = handler;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200979 queue_work(floppy_wq, &floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
Tejun Heo75ddb382014-03-07 10:24:48 -0500982static void (*fd_timer_fn)(void) = NULL;
983
984static void fd_timer_workfn(struct work_struct *work)
985{
986 fd_timer_fn();
987}
988
989static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991static void cancel_activity(void)
992{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 do_floppy = NULL;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200994 cancel_delayed_work_sync(&fd_timer);
995 cancel_work_sync(&floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996}
997
998/* this function makes sure that the disk stays in the drive during the
999 * transfer */
Tejun Heo75ddb382014-03-07 10:24:48 -05001000static void fd_watchdog(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
Joe Perches87f530d2010-03-10 15:20:54 -08001002 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 if (disk_change(current_drive)) {
1005 DPRINT("disk removed during i/o\n");
1006 cancel_activity();
1007 cont->done(0);
1008 reset_fdc();
1009 } else {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001010 cancel_delayed_work(&fd_timer);
Tejun Heo75ddb382014-03-07 10:24:48 -05001011 fd_timer_fn = fd_watchdog;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001012 queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 }
1014}
1015
1016static void main_command_interrupt(void)
1017{
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001018 cancel_delayed_work(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 cont->interrupt();
1020}
1021
1022/* waits for a delay (spinup or select) to pass */
Tejun Heo75ddb382014-03-07 10:24:48 -05001023static int fd_wait_for_completion(unsigned long expires,
1024 void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025{
1026 if (FDCS->reset) {
1027 reset_fdc(); /* do the reset during sleep to win time
1028 * if we don't need to sleep, it's a good
1029 * occasion anyways */
1030 return 1;
1031 }
1032
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001033 if (time_before(jiffies, expires)) {
1034 cancel_delayed_work(&fd_timer);
Tejun Heo75ddb382014-03-07 10:24:48 -05001035 fd_timer_fn = function;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001036 queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 return 1;
1038 }
1039 return 0;
1040}
1041
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042static void setup_DMA(void)
1043{
1044 unsigned long f;
1045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 if (raw_cmd->length == 0) {
1047 int i;
1048
Joe Perchesb46df352010-03-10 15:20:46 -08001049 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001051 pr_cont("%x,", raw_cmd->cmd[i]);
1052 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 cont->done(0);
1054 FDCS->reset = 1;
1055 return;
1056 }
1057 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001058 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 cont->done(0);
1060 FDCS->reset = 1;
1061 return;
1062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 f = claim_dma_lock();
1064 fd_disable_dma();
1065#ifdef fd_dma_setup
1066 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1067 (raw_cmd->flags & FD_RAW_READ) ?
1068 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1069 release_dma_lock(f);
1070 cont->done(0);
1071 FDCS->reset = 1;
1072 return;
1073 }
1074 release_dma_lock(f);
1075#else
1076 fd_clear_dma_ff();
1077 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1078 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1079 DMA_MODE_READ : DMA_MODE_WRITE);
1080 fd_set_dma_addr(raw_cmd->kernel_data);
1081 fd_set_dma_count(raw_cmd->length);
1082 virtual_dma_port = FDCS->address;
1083 fd_enable_dma();
1084 release_dma_lock(f);
1085#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086}
1087
1088static void show_floppy(void);
1089
1090/* waits until the fdc becomes ready */
1091static int wait_til_ready(void)
1092{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001093 int status;
1094 int counter;
1095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 if (FDCS->reset)
1097 return -1;
1098 for (counter = 0; counter < 10000; counter++) {
1099 status = fd_inb(FD_STATUS);
1100 if (status & STATUS_READY)
1101 return status;
1102 }
Joe Perches29f1c782010-03-10 15:21:00 -08001103 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1105 show_floppy();
1106 }
1107 FDCS->reset = 1;
1108 return -1;
1109}
1110
1111/* sends a command byte to the fdc */
1112static int output_byte(char byte)
1113{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001114 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001116 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001118
1119 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 output_log[output_log_pos].data = byte;
1122 output_log[output_log_pos].status = status;
1123 output_log[output_log_pos].jiffies = jiffies;
1124 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 return 0;
1126 }
1127 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001128 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1130 byte, fdc, status);
1131 show_floppy();
1132 }
1133 return -1;
1134}
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136/* gets the response from the fdc */
1137static int result(void)
1138{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001139 int i;
1140 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001143 status = wait_til_ready();
1144 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 break;
1146 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1147 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 resultjiffies = jiffies;
1149 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 return i;
1151 }
1152 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1153 reply_buffer[i] = fd_inb(FD_DATA);
1154 else
1155 break;
1156 }
Joe Perches29f1c782010-03-10 15:21:00 -08001157 if (initialized) {
1158 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1159 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 show_floppy();
1161 }
1162 FDCS->reset = 1;
1163 return -1;
1164}
1165
1166#define MORE_OUTPUT -2
1167/* does the fdc need more output? */
1168static int need_more_output(void)
1169{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001170 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001171
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001172 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001174
1175 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001177
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 return result();
1179}
1180
1181/* Set perpendicular mode as required, based on data rate, if supported.
1182 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1183 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001184static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185{
1186 unsigned char perp_mode;
1187
1188 if (raw_cmd->rate & 0x40) {
1189 switch (raw_cmd->rate & 3) {
1190 case 0:
1191 perp_mode = 2;
1192 break;
1193 case 3:
1194 perp_mode = 3;
1195 break;
1196 default:
1197 DPRINT("Invalid data rate for perpendicular mode!\n");
1198 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001199 FDCS->reset = 1;
1200 /*
1201 * convenient way to return to
1202 * redo without too much hassle
1203 * (deep stack et al.)
1204 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 return;
1206 }
1207 } else
1208 perp_mode = 0;
1209
1210 if (FDCS->perp_mode == perp_mode)
1211 return;
1212 if (FDCS->version >= FDC_82077_ORIG) {
1213 output_byte(FD_PERPENDICULAR);
1214 output_byte(perp_mode);
1215 FDCS->perp_mode = perp_mode;
1216 } else if (perp_mode) {
1217 DPRINT("perpendicular mode not supported by this FDC.\n");
1218 }
1219} /* perpendicular_mode */
1220
1221static int fifo_depth = 0xa;
1222static int no_fifo;
1223
1224static int fdc_configure(void)
1225{
1226 /* Turn on FIFO */
1227 output_byte(FD_CONFIGURE);
1228 if (need_more_output() != MORE_OUTPUT)
1229 return 0;
1230 output_byte(0);
1231 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1232 output_byte(0); /* pre-compensation from track
1233 0 upwards */
1234 return 1;
1235}
1236
1237#define NOMINAL_DTR 500
1238
1239/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1240 * head load time, and DMA disable flag to values needed by floppy.
1241 *
1242 * The value "dtr" is the data transfer rate in Kbps. It is needed
1243 * to account for the data rate-based scaling done by the 82072 and 82077
1244 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1245 * 8272a).
1246 *
1247 * Note that changing the data transfer rate has a (probably deleterious)
1248 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1249 * fdc_specify is called again after each data transfer rate
1250 * change.
1251 *
1252 * srt: 1000 to 16000 in microseconds
1253 * hut: 16 to 240 milliseconds
1254 * hlt: 2 to 254 milliseconds
1255 *
1256 * These values are rounded up to the next highest available delay time.
1257 */
1258static void fdc_specify(void)
1259{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001260 unsigned char spec1;
1261 unsigned char spec2;
1262 unsigned long srt;
1263 unsigned long hlt;
1264 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 unsigned long dtr = NOMINAL_DTR;
1266 unsigned long scale_dtr = NOMINAL_DTR;
1267 int hlt_max_code = 0x7f;
1268 int hut_max_code = 0xf;
1269
1270 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1271 fdc_configure();
1272 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 }
1274
1275 switch (raw_cmd->rate & 0x03) {
1276 case 3:
1277 dtr = 1000;
1278 break;
1279 case 1:
1280 dtr = 300;
1281 if (FDCS->version >= FDC_82078) {
1282 /* chose the default rate table, not the one
1283 * where 1 = 2 Mbps */
1284 output_byte(FD_DRIVESPEC);
1285 if (need_more_output() == MORE_OUTPUT) {
1286 output_byte(UNIT(current_drive));
1287 output_byte(0xc0);
1288 }
1289 }
1290 break;
1291 case 2:
1292 dtr = 250;
1293 break;
1294 }
1295
1296 if (FDCS->version >= FDC_82072) {
1297 scale_dtr = dtr;
1298 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1299 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1300 }
1301
1302 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001303 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001304 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 SUPBOUND(srt, 0xf);
1308 INFBOUND(srt, 0);
1309
Julia Lawall061837b2008-09-22 14:57:16 -07001310 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (hlt < 0x01)
1312 hlt = 0x01;
1313 else if (hlt > 0x7f)
1314 hlt = hlt_max_code;
1315
Julia Lawall061837b2008-09-22 14:57:16 -07001316 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (hut < 0x1)
1318 hut = 0x1;
1319 else if (hut > 0xf)
1320 hut = hut_max_code;
1321
1322 spec1 = (srt << 4) | hut;
1323 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1324
1325 /* If these parameters did not change, just return with success */
1326 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1327 /* Go ahead and set spec1 and spec2 */
1328 output_byte(FD_SPECIFY);
1329 output_byte(FDCS->spec1 = spec1);
1330 output_byte(FDCS->spec2 = spec2);
1331 }
1332} /* fdc_specify */
1333
1334/* Set the FDC's data transfer rate on behalf of the specified drive.
1335 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1336 * of the specify command (i.e. using the fdc_specify function).
1337 */
1338static int fdc_dtr(void)
1339{
1340 /* If data rate not already set to desired value, set it. */
1341 if ((raw_cmd->rate & 3) == FDCS->dtr)
1342 return 0;
1343
1344 /* Set dtr */
1345 fd_outb(raw_cmd->rate & 3, FD_DCR);
1346
1347 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1348 * need a stabilization period of several milliseconds to be
1349 * enforced after data rate changes before R/W operations.
1350 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1351 */
1352 FDCS->dtr = raw_cmd->rate & 3;
Tejun Heo75ddb382014-03-07 10:24:48 -05001353 return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354} /* fdc_dtr */
1355
1356static void tell_sector(void)
1357{
Joe Perchesb46df352010-03-10 15:20:46 -08001358 pr_cont(": track %d, head %d, sector %d, size %d",
1359 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360} /* tell_sector */
1361
Joe Perchesb46df352010-03-10 15:20:46 -08001362static void print_errors(void)
1363{
1364 DPRINT("");
1365 if (ST0 & ST0_ECE) {
1366 pr_cont("Recalibrate failed!");
1367 } else if (ST2 & ST2_CRC) {
1368 pr_cont("data CRC error");
1369 tell_sector();
1370 } else if (ST1 & ST1_CRC) {
1371 pr_cont("CRC error");
1372 tell_sector();
1373 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1374 (ST2 & ST2_MAM)) {
1375 if (!probing) {
1376 pr_cont("sector not found");
1377 tell_sector();
1378 } else
1379 pr_cont("probe failed...");
1380 } else if (ST2 & ST2_WC) { /* seek error */
1381 pr_cont("wrong cylinder");
1382 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1383 pr_cont("bad cylinder");
1384 } else {
1385 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1386 ST0, ST1, ST2);
1387 tell_sector();
1388 }
1389 pr_cont("\n");
1390}
1391
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392/*
1393 * OK, this error interpreting routine is called after a
1394 * DMA read/write has succeeded
1395 * or failed, so we check the results, and copy any buffers.
1396 * hhb: Added better error reporting.
1397 * ak: Made this into a separate routine.
1398 */
1399static int interpret_errors(void)
1400{
1401 char bad;
1402
1403 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001404 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 FDCS->reset = 1;
1406 return 1;
1407 }
1408
1409 /* check IC to find cause of interrupt */
1410 switch (ST0 & ST0_INTR) {
1411 case 0x40: /* error occurred during command execution */
1412 if (ST1 & ST1_EOC)
1413 return 0; /* occurs with pseudo-DMA */
1414 bad = 1;
1415 if (ST1 & ST1_WP) {
1416 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001417 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 cont->done(0);
1419 bad = 2;
1420 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001421 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 } else if (ST1 & ST1_OR) {
1423 if (DP->flags & FTD_MSG)
1424 DPRINT("Over/Underrun - retrying\n");
1425 bad = 0;
1426 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001427 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 }
1429 if (ST2 & ST2_WC || ST2 & ST2_BC)
1430 /* wrong cylinder => recal */
1431 DRS->track = NEED_2_RECAL;
1432 return bad;
1433 case 0x80: /* invalid command given */
1434 DPRINT("Invalid FDC command given!\n");
1435 cont->done(0);
1436 return 2;
1437 case 0xc0:
1438 DPRINT("Abnormal termination caused by polling\n");
1439 cont->error();
1440 return 2;
1441 default: /* (0) Normal command termination */
1442 return 0;
1443 }
1444}
1445
1446/*
1447 * This routine is called when everything should be correctly set up
1448 * for the transfer (i.e. floppy motor is on, the correct floppy is
1449 * selected, and the head is sitting on the right track).
1450 */
1451static void setup_rw_floppy(void)
1452{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001453 int i;
1454 int r;
1455 int flags;
1456 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 unsigned long ready_date;
Tejun Heo75ddb382014-03-07 10:24:48 -05001458 void (*function)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
1460 flags = raw_cmd->flags;
1461 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1462 flags |= FD_RAW_INTR;
1463
1464 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1465 ready_date = DRS->spinup_date + DP->spinup;
1466 /* If spinup will take a long time, rerun scandrives
1467 * again just before spinup completion. Beware that
1468 * after scandrives, we must again wait for selection.
1469 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001470 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 ready_date -= DP->select_delay;
Tejun Heo75ddb382014-03-07 10:24:48 -05001472 function = floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 } else
Tejun Heo75ddb382014-03-07 10:24:48 -05001474 function = setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476 /* wait until the floppy is spinning fast enough */
1477 if (fd_wait_for_completion(ready_date, function))
1478 return;
1479 }
1480 dflags = DRS->flags;
1481
1482 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1483 setup_DMA();
1484
1485 if (flags & FD_RAW_INTR)
1486 do_floppy = main_command_interrupt;
1487
1488 r = 0;
1489 for (i = 0; i < raw_cmd->cmd_count; i++)
1490 r |= output_byte(raw_cmd->cmd[i]);
1491
Joe Perchesded28632010-03-10 15:21:09 -08001492 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
1494 if (r) {
1495 cont->error();
1496 reset_fdc();
1497 return;
1498 }
1499
1500 if (!(flags & FD_RAW_INTR)) {
1501 inr = result();
1502 cont->interrupt();
1503 } else if (flags & FD_RAW_NEED_DISK)
Tejun Heo75ddb382014-03-07 10:24:48 -05001504 fd_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505}
1506
1507static int blind_seek;
1508
1509/*
1510 * This is the routine called after every seek (or recalibrate) interrupt
1511 * from the floppy controller.
1512 */
1513static void seek_interrupt(void)
1514{
Joe Perchesded28632010-03-10 15:21:09 -08001515 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1517 DPRINT("seek failed\n");
1518 DRS->track = NEED_2_RECAL;
1519 cont->error();
1520 cont->redo();
1521 return;
1522 }
1523 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001524 debug_dcl(DP->flags,
1525 "clearing NEWCHANGE flag because of effective seek\n");
1526 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001527 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1528 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 DRS->select_date = jiffies;
1530 }
1531 DRS->track = ST1;
1532 floppy_ready();
1533}
1534
1535static void check_wp(void)
1536{
Joe Perchese0298532010-03-10 15:20:55 -08001537 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1538 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 output_byte(FD_GETSTATUS);
1540 output_byte(UNIT(current_drive));
1541 if (result() != 1) {
1542 FDCS->reset = 1;
1543 return;
1544 }
Joe Perchese0298532010-03-10 15:20:55 -08001545 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1546 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001547 debug_dcl(DP->flags,
1548 "checking whether disk is write protected\n");
1549 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001551 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 else
Joe Perchese0298532010-03-10 15:20:55 -08001553 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 }
1555}
1556
1557static void seek_floppy(void)
1558{
1559 int track;
1560
1561 blind_seek = 0;
1562
Joe Perchesded28632010-03-10 15:21:09 -08001563 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
Joe Perchese0298532010-03-10 15:20:55 -08001565 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1567 /* the media changed flag should be cleared after the seek.
1568 * If it isn't, this means that there is really no disk in
1569 * the drive.
1570 */
Joe Perchese0298532010-03-10 15:20:55 -08001571 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 cont->done(0);
1573 cont->redo();
1574 return;
1575 }
1576 if (DRS->track <= NEED_1_RECAL) {
1577 recalibrate_floppy();
1578 return;
Joe Perchese0298532010-03-10 15:20:55 -08001579 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1581 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1582 /* we seek to clear the media-changed condition. Does anybody
1583 * know a more elegant way, which works on all drives? */
1584 if (raw_cmd->track)
1585 track = raw_cmd->track - 1;
1586 else {
1587 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1588 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1589 blind_seek = 1;
1590 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1591 }
1592 track = 1;
1593 }
1594 } else {
1595 check_wp();
1596 if (raw_cmd->track != DRS->track &&
1597 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1598 track = raw_cmd->track;
1599 else {
1600 setup_rw_floppy();
1601 return;
1602 }
1603 }
1604
1605 do_floppy = seek_interrupt;
1606 output_byte(FD_SEEK);
1607 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001608 if (output_byte(track) < 0) {
1609 reset_fdc();
1610 return;
1611 }
Joe Perchesded28632010-03-10 15:21:09 -08001612 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613}
1614
1615static void recal_interrupt(void)
1616{
Joe Perchesded28632010-03-10 15:21:09 -08001617 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if (inr != 2)
1619 FDCS->reset = 1;
1620 else if (ST0 & ST0_ECE) {
1621 switch (DRS->track) {
1622 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001623 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 /* after a second recalibrate, we still haven't
1625 * reached track 0. Probably no drive. Raise an
1626 * error, as failing immediately might upset
1627 * computers possessed by the Devil :-) */
1628 cont->error();
1629 cont->redo();
1630 return;
1631 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001632 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 /* If we already did a recalibrate,
1634 * and we are not at track 0, this
1635 * means we have moved. (The only way
1636 * not to move at recalibration is to
1637 * be already at track 0.) Clear the
1638 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001639 debug_dcl(DP->flags,
1640 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Joe Perchese0298532010-03-10 15:20:55 -08001642 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 DRS->select_date = jiffies;
1644 /* fall through */
1645 default:
Joe Perchesded28632010-03-10 15:21:09 -08001646 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 /* Recalibrate moves the head by at
1648 * most 80 steps. If after one
1649 * recalibrate we don't have reached
1650 * track 0, this might mean that we
1651 * started beyond track 80. Try
1652 * again. */
1653 DRS->track = NEED_1_RECAL;
1654 break;
1655 }
1656 } else
1657 DRS->track = ST1;
1658 floppy_ready();
1659}
1660
1661static void print_result(char *message, int inr)
1662{
1663 int i;
1664
1665 DPRINT("%s ", message);
1666 if (inr >= 0)
1667 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001668 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1669 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670}
1671
1672/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001673irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 int do_print;
1676 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001677 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 lasthandler = handler;
1680 interruptjiffies = jiffies;
1681
1682 f = claim_dma_lock();
1683 fd_disable_dma();
1684 release_dma_lock(f);
1685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 do_floppy = NULL;
1687 if (fdc >= N_FDC || FDCS->address == -1) {
1688 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001689 pr_info("DOR0=%x\n", fdc_state[0].dor);
1690 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001691 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001692 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 return IRQ_NONE;
1694 }
1695
1696 FDCS->reset = 0;
1697 /* We have to clear the reset flag here, because apparently on boxes
1698 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1699 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1700 * emission of the SENSEI's.
1701 * It is OK to emit floppy commands because we are in an interrupt
1702 * handler here, and thus we have to fear no interference of other
1703 * activity.
1704 */
1705
Joe Perches29f1c782010-03-10 15:21:00 -08001706 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 inr = result();
1709 if (do_print)
1710 print_result("unexpected interrupt", inr);
1711 if (inr == 0) {
1712 int max_sensei = 4;
1713 do {
1714 output_byte(FD_SENSEI);
1715 inr = result();
1716 if (do_print)
1717 print_result("sensei", inr);
1718 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001719 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1720 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 }
1722 if (!handler) {
1723 FDCS->reset = 1;
1724 return IRQ_NONE;
1725 }
1726 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001727 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 /* FIXME! Was it really for us? */
1730 return IRQ_HANDLED;
1731}
1732
1733static void recalibrate_floppy(void)
1734{
Joe Perchesded28632010-03-10 15:21:09 -08001735 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 do_floppy = recal_interrupt;
1737 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001738 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001739 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740}
1741
1742/*
1743 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1744 */
1745static void reset_interrupt(void)
1746{
Joe Perchesded28632010-03-10 15:21:09 -08001747 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 result(); /* get the status ready for set_fdc */
1749 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001750 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 cont->error(); /* a reset just after a reset. BAD! */
1752 }
1753 cont->redo();
1754}
1755
1756/*
1757 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1758 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1759 */
1760static void reset_fdc(void)
1761{
1762 unsigned long flags;
1763
1764 do_floppy = reset_interrupt;
1765 FDCS->reset = 0;
1766 reset_fdc_info(0);
1767
1768 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1769 /* Irrelevant for systems with true DMA (i386). */
1770
1771 flags = claim_dma_lock();
1772 fd_disable_dma();
1773 release_dma_lock(flags);
1774
1775 if (FDCS->version >= FDC_82072A)
1776 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1777 else {
1778 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1779 udelay(FD_RESET_DELAY);
1780 fd_outb(FDCS->dor, FD_DOR);
1781 }
1782}
1783
1784static void show_floppy(void)
1785{
1786 int i;
1787
Joe Perchesb46df352010-03-10 15:20:46 -08001788 pr_info("\n");
1789 pr_info("floppy driver state\n");
1790 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001791 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001792 jiffies, interruptjiffies, jiffies - interruptjiffies,
1793 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794
Joe Perchesb46df352010-03-10 15:20:46 -08001795 pr_info("timeout_message=%s\n", timeout_message);
1796 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001798 pr_info("%2x %2x %lu\n",
1799 output_log[(i + output_log_pos) % OLOGSIZE].data,
1800 output_log[(i + output_log_pos) % OLOGSIZE].status,
1801 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1802 pr_info("last result at %lu\n", resultjiffies);
1803 pr_info("last redo_fd_request at %lu\n", lastredo);
1804 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1805 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
Joe Perchesb46df352010-03-10 15:20:46 -08001807 pr_info("status=%x\n", fd_inb(FD_STATUS));
1808 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001810 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001811 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001812 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001813 if (delayed_work_pending(&fd_timer))
1814 pr_info("delayed work.function=%p expires=%ld\n",
1815 fd_timer.work.func,
1816 fd_timer.timer.expires - jiffies);
1817 if (delayed_work_pending(&fd_timeout))
1818 pr_info("timer_function=%p expires=%ld\n",
1819 fd_timeout.work.func,
1820 fd_timeout.timer.expires - jiffies);
1821
Joe Perchesb46df352010-03-10 15:20:46 -08001822 pr_info("cont=%p\n", cont);
1823 pr_info("current_req=%p\n", current_req);
1824 pr_info("command_status=%d\n", command_status);
1825 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826}
1827
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001828static void floppy_shutdown(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829{
1830 unsigned long flags;
1831
Joe Perches29f1c782010-03-10 15:21:00 -08001832 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 show_floppy();
1834 cancel_activity();
1835
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 flags = claim_dma_lock();
1837 fd_disable_dma();
1838 release_dma_lock(flags);
1839
1840 /* avoid dma going to a random drive after shutdown */
1841
Joe Perches29f1c782010-03-10 15:21:00 -08001842 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 DPRINT("floppy timeout called\n");
1844 FDCS->reset = 1;
1845 if (cont) {
1846 cont->done(0);
1847 cont->redo(); /* this will recall reset when needed */
1848 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001849 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 process_fd_request();
1851 }
Joe Perches275176b2010-03-10 15:21:06 -08001852 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853}
1854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001856static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001858 int mask;
1859 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
1861 mask = 0xfc;
1862 data = UNIT(current_drive);
1863 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1864 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1865 set_debugt();
1866 /* no read since this drive is running */
1867 DRS->first_read_date = 0;
1868 /* note motor start time if motor is not yet running */
1869 DRS->spinup_date = jiffies;
1870 data |= (0x10 << UNIT(current_drive));
1871 }
1872 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1873 mask &= ~(0x10 << UNIT(current_drive));
1874
1875 /* starts motor and selects floppy */
1876 del_timer(motor_off_timer + current_drive);
1877 set_dor(fdc, mask, data);
1878
1879 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001880 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
Tejun Heo75ddb382014-03-07 10:24:48 -05001881 function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882}
1883
1884static void floppy_ready(void)
1885{
Joe Perches045f9832010-03-10 15:20:47 -08001886 if (FDCS->reset) {
1887 reset_fdc();
1888 return;
1889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (start_motor(floppy_ready))
1891 return;
1892 if (fdc_dtr())
1893 return;
1894
Joe Perches87f530d2010-03-10 15:20:54 -08001895 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1897 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001898 twaddle(); /* this clears the dcl on certain
1899 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901#ifdef fd_chose_dma_mode
1902 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1903 unsigned long flags = claim_dma_lock();
1904 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1905 release_dma_lock(flags);
1906 }
1907#endif
1908
1909 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1910 perpendicular_mode();
1911 fdc_specify(); /* must be done here because of hut, hlt ... */
1912 seek_floppy();
1913 } else {
1914 if ((raw_cmd->flags & FD_RAW_READ) ||
1915 (raw_cmd->flags & FD_RAW_WRITE))
1916 fdc_specify();
1917 setup_rw_floppy();
1918 }
1919}
1920
1921static void floppy_start(void)
1922{
Joe Perches73507e62010-03-10 15:21:03 -08001923 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001926 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001927 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 floppy_ready();
1929}
1930
1931/*
1932 * ========================================================================
1933 * here ends the bottom half. Exported routines are:
1934 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1935 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1936 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1937 * and set_dor.
1938 * ========================================================================
1939 */
1940/*
1941 * General purpose continuations.
1942 * ==============================
1943 */
1944
1945static void do_wakeup(void)
1946{
Joe Perches73507e62010-03-10 15:21:03 -08001947 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 cont = NULL;
1949 command_status += 2;
1950 wake_up(&command_done);
1951}
1952
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001953static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 .interrupt = empty,
1955 .redo = do_wakeup,
1956 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001957 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958};
1959
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001960static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 .interrupt = empty,
1962 .redo = process_fd_request,
1963 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001964 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965};
1966
Joe Perches74f63f42010-03-10 15:20:58 -08001967static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968{
1969 int ret;
1970
1971 schedule_bh(handler);
1972
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001973 if (interruptible)
1974 wait_event_interruptible(command_done, command_status >= 2);
1975 else
1976 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
1978 if (command_status < 2) {
1979 cancel_activity();
1980 cont = &intr_cont;
1981 reset_fdc();
1982 return -EINTR;
1983 }
1984
1985 if (FDCS->reset)
1986 command_status = FD_COMMAND_ERROR;
1987 if (command_status == FD_COMMAND_OKAY)
1988 ret = 0;
1989 else
1990 ret = -EIO;
1991 command_status = FD_COMMAND_NONE;
1992 return ret;
1993}
1994
1995static void generic_done(int result)
1996{
1997 command_status = result;
1998 cont = &wakeup_cont;
1999}
2000
2001static void generic_success(void)
2002{
2003 cont->done(1);
2004}
2005
2006static void generic_failure(void)
2007{
2008 cont->done(0);
2009}
2010
2011static void success_and_wakeup(void)
2012{
2013 generic_success();
2014 cont->redo();
2015}
2016
2017/*
2018 * formatting and rw support.
2019 * ==========================
2020 */
2021
2022static int next_valid_format(void)
2023{
2024 int probed_format;
2025
2026 probed_format = DRS->probed_format;
2027 while (1) {
2028 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2029 DRS->probed_format = 0;
2030 return 1;
2031 }
2032 if (floppy_type[DP->autodetect[probed_format]].sect) {
2033 DRS->probed_format = probed_format;
2034 return 0;
2035 }
2036 probed_format++;
2037 }
2038}
2039
2040static void bad_flp_intr(void)
2041{
2042 int err_count;
2043
2044 if (probing) {
2045 DRS->probed_format++;
2046 if (!next_valid_format())
2047 return;
2048 }
2049 err_count = ++(*errors);
2050 INFBOUND(DRWE->badness, err_count);
2051 if (err_count > DP->max_errors.abort)
2052 cont->done(0);
2053 if (err_count > DP->max_errors.reset)
2054 FDCS->reset = 1;
2055 else if (err_count > DP->max_errors.recal)
2056 DRS->track = NEED_2_RECAL;
2057}
2058
2059static void set_floppy(int drive)
2060{
2061 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002062
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 if (type)
2064 _floppy = floppy_type + type;
2065 else
2066 _floppy = current_type[drive];
2067}
2068
2069/*
2070 * formatting support.
2071 * ===================
2072 */
2073static void format_interrupt(void)
2074{
2075 switch (interpret_errors()) {
2076 case 1:
2077 cont->error();
2078 case 2:
2079 break;
2080 case 0:
2081 cont->done(1);
2082 }
2083 cont->redo();
2084}
2085
Joe Perches48c8cee2010-03-10 15:20:45 -08002086#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002088
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089static void setup_format_params(int track)
2090{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002091 int n;
2092 int il;
2093 int count;
2094 int head_shift;
2095 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 struct fparm {
2097 unsigned char track, head, sect, size;
2098 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
2100 raw_cmd = &default_raw_cmd;
2101 raw_cmd->track = track;
2102
Joe Perches48c8cee2010-03-10 15:20:45 -08002103 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2104 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 raw_cmd->rate = _floppy->rate & 0x43;
2106 raw_cmd->cmd_count = NR_F;
2107 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2108 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2109 F_SIZECODE = FD_SIZECODE(_floppy);
2110 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2111 F_GAP = _floppy->fmt_gap;
2112 F_FILL = FD_FILL_BYTE;
2113
2114 raw_cmd->kernel_data = floppy_track_buffer;
2115 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2116
Denis Efremov604206c2019-07-12 21:55:20 +03002117 if (!F_SECT_PER_TRACK)
2118 return;
2119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 /* allow for about 30ms for data transport per track */
2121 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2122
2123 /* a ``cylinder'' is two tracks plus a little stepping time */
2124 track_shift = 2 * head_shift + 3;
2125
2126 /* position of logical sector 1 on this track */
2127 n = (track_shift * format_req.track + head_shift * format_req.head)
2128 % F_SECT_PER_TRACK;
2129
2130 /* determine interleave */
2131 il = 1;
2132 if (_floppy->fmt_gap < 0x22)
2133 il++;
2134
2135 /* initialize field */
2136 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2137 here[count].track = format_req.track;
2138 here[count].head = format_req.head;
2139 here[count].sect = 0;
2140 here[count].size = F_SIZECODE;
2141 }
2142 /* place logical sectors */
2143 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2144 here[n].sect = count;
2145 n = (n + il) % F_SECT_PER_TRACK;
2146 if (here[n].sect) { /* sector busy, find next free sector */
2147 ++n;
2148 if (n >= F_SECT_PER_TRACK) {
2149 n -= F_SECT_PER_TRACK;
2150 while (here[n].sect)
2151 ++n;
2152 }
2153 }
2154 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002155 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002157 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 }
2159}
2160
2161static void redo_format(void)
2162{
2163 buffer_track = -1;
2164 setup_format_params(format_req.track << STRETCH(_floppy));
2165 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002166 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167}
2168
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002169static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 .interrupt = format_interrupt,
2171 .redo = redo_format,
2172 .error = bad_flp_intr,
2173 .done = generic_done
2174};
2175
2176static int do_format(int drive, struct format_descr *tmp_format_req)
2177{
2178 int ret;
2179
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01002180 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08002181 return -EINTR;
2182
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 set_floppy(drive);
2184 if (!_floppy ||
2185 _floppy->track > DP->tracks ||
2186 tmp_format_req->track >= _floppy->track ||
2187 tmp_format_req->head >= _floppy->head ||
2188 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2189 !_floppy->fmt_gap) {
2190 process_fd_request();
2191 return -EINVAL;
2192 }
2193 format_req = *tmp_format_req;
2194 format_errors = 0;
2195 cont = &format_cont;
2196 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002197 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002198 if (ret == -EINTR)
2199 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 process_fd_request();
2201 return ret;
2202}
2203
2204/*
2205 * Buffer read/write and support
2206 * =============================
2207 */
2208
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002209static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210{
2211 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002212 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
2214 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002215 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002216 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002217 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
2220 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002221 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 current_req = NULL;
2223}
2224
2225/* new request_done. Can handle physical sectors which are smaller than a
2226 * logical buffer */
2227static void request_done(int uptodate)
2228{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 struct request *req = current_req;
Jens Axboe48821182010-09-22 09:32:36 +02002230 struct request_queue *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 unsigned long flags;
2232 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002233 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
2235 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002236 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2237 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
2239 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002240 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 return;
2242 }
2243
Jens Axboe48821182010-09-22 09:32:36 +02002244 q = req->q;
2245
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 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
2254 /* unlock chained buffers */
2255 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002256 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 spin_unlock_irqrestore(q->queue_lock, flags);
2258 } else {
2259 if (rq_data_dir(req) == WRITE) {
2260 /* record write error information */
2261 DRWE->write_errors++;
2262 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002263 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 DRWE->first_error_generation = DRS->generation;
2265 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002266 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 DRWE->last_error_generation = DRS->generation;
2268 }
2269 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002270 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 spin_unlock_irqrestore(q->queue_lock, flags);
2272 }
2273}
2274
2275/* Interrupt handler evaluating the result of the r/w operation */
2276static void rw_interrupt(void)
2277{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002278 int eoc;
2279 int ssize;
2280 int heads;
2281 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
2283 if (R_HEAD >= 2) {
2284 /* some Toshiba floppy controllers occasionnally seem to
2285 * return bogus interrupts after read/write operations, which
2286 * can be recognized by a bad head number (>= 2) */
2287 return;
2288 }
2289
2290 if (!DRS->first_read_date)
2291 DRS->first_read_date = jiffies;
2292
2293 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002294 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
2296 if (ST1 & ST1_EOC)
2297 eoc = 1;
2298 else
2299 eoc = 0;
2300
2301 if (COMMAND & 0x80)
2302 heads = 2;
2303 else
2304 heads = 1;
2305
2306 nr_sectors = (((R_TRACK - TRACK) * heads +
2307 R_HEAD - HEAD) * SECT_PER_TRACK +
2308 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2309
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002311 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 DPRINT("long rw: %x instead of %lx\n",
2313 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002314 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2315 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2316 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2317 pr_info("heads=%d eoc=%d\n", heads, eoc);
2318 pr_info("spt=%d st=%d ss=%d\n",
2319 SECT_PER_TRACK, fsector_t, ssize);
2320 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
2323 nr_sectors -= in_sector_offset;
2324 INFBOUND(nr_sectors, 0);
2325 SUPBOUND(current_count_sectors, nr_sectors);
2326
2327 switch (interpret_errors()) {
2328 case 2:
2329 cont->redo();
2330 return;
2331 case 1:
2332 if (!current_count_sectors) {
2333 cont->error();
2334 cont->redo();
2335 return;
2336 }
2337 break;
2338 case 0:
2339 if (!current_count_sectors) {
2340 cont->redo();
2341 return;
2342 }
2343 current_type[current_drive] = _floppy;
2344 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2345 break;
2346 }
2347
2348 if (probing) {
2349 if (DP->flags & FTD_MSG)
2350 DPRINT("Auto-detected floppy type %s in fd%d\n",
2351 _floppy->name, current_drive);
2352 current_type[current_drive] = _floppy;
2353 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2354 probing = 0;
2355 }
2356
2357 if (CT(COMMAND) != FD_READ ||
Jens Axboeb4f42e22014-04-10 09:46:28 -06002358 raw_cmd->kernel_data == bio_data(current_req->bio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 /* transfer directly from buffer */
2360 cont->done(1);
2361 } else if (CT(COMMAND) == FD_READ) {
2362 buffer_track = raw_cmd->track;
2363 buffer_drive = current_drive;
2364 INFBOUND(buffer_max, nr_sectors + fsector_t);
2365 }
2366 cont->redo();
2367}
2368
2369/* Compute maximal contiguous buffer size. */
2370static int buffer_chain_size(void)
2371{
Kent Overstreet79886132013-11-23 17:19:00 -08002372 struct bio_vec bv;
NeilBrown5705f702007-09-25 12:35:59 +02002373 int size;
2374 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 char *base;
2376
2377 base = bio_data(current_req->bio);
2378 size = 0;
2379
NeilBrown5705f702007-09-25 12:35:59 +02002380 rq_for_each_segment(bv, current_req, iter) {
Kent Overstreet79886132013-11-23 17:19:00 -08002381 if (page_address(bv.bv_page) + bv.bv_offset != base + size)
NeilBrown5705f702007-09-25 12:35:59 +02002382 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
Kent Overstreet79886132013-11-23 17:19:00 -08002384 size += bv.bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 }
2386
2387 return size >> 9;
2388}
2389
2390/* Compute the maximal transfer size */
2391static int transfer_size(int ssize, int max_sector, int max_size)
2392{
2393 SUPBOUND(max_sector, fsector_t + max_size);
2394
2395 /* alignment */
2396 max_sector -= (max_sector % _floppy->sect) % ssize;
2397
2398 /* transfer size, beginning not aligned */
2399 current_count_sectors = max_sector - fsector_t;
2400
2401 return max_sector;
2402}
2403
2404/*
2405 * Move data from/to the track buffer to/from the buffer cache.
2406 */
2407static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2408{
2409 int remaining; /* number of transferred 512-byte sectors */
Kent Overstreet79886132013-11-23 17:19:00 -08002410 struct bio_vec bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002411 char *buffer;
2412 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002413 int size;
2414 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
2416 max_sector = transfer_size(ssize,
2417 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002418 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002421 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002423 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002426 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002428 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2429 pr_info("remaining=%d\n", remaining >> 9);
2430 pr_info("current_req->nr_sectors=%u\n",
2431 blk_rq_sectors(current_req));
2432 pr_info("current_req->current_nr_sectors=%u\n",
2433 blk_rq_cur_sectors(current_req));
2434 pr_info("max_sector=%d\n", max_sector);
2435 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
2438 buffer_max = max(max_sector, buffer_max);
2439
2440 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2441
Tejun Heo1011c1b2009-05-07 22:24:45 +09002442 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
NeilBrown5705f702007-09-25 12:35:59 +02002444 rq_for_each_segment(bv, current_req, iter) {
2445 if (!remaining)
2446 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
Kent Overstreet79886132013-11-23 17:19:00 -08002448 size = bv.bv_len;
NeilBrown5705f702007-09-25 12:35:59 +02002449 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
Kent Overstreet79886132013-11-23 17:19:00 -08002451 buffer = page_address(bv.bv_page) + bv.bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002452 if (dma_buffer + size >
2453 floppy_track_buffer + (max_buffer_sectors << 10) ||
2454 dma_buffer < floppy_track_buffer) {
2455 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002456 (int)((floppy_track_buffer - dma_buffer) >> 9));
2457 pr_info("fsector_t=%d buffer_min=%d\n",
2458 fsector_t, buffer_min);
2459 pr_info("current_count_sectors=%ld\n",
2460 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002462 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002463 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002464 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002465 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 }
NeilBrown5705f702007-09-25 12:35:59 +02002467 if (((unsigned long)buffer) % 512)
2468 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002469
NeilBrown5705f702007-09-25 12:35:59 +02002470 if (CT(COMMAND) == FD_READ)
2471 memcpy(buffer, dma_buffer, size);
2472 else
2473 memcpy(dma_buffer, buffer, size);
2474
2475 remaining -= size;
2476 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 if (remaining) {
2479 if (remaining > 0)
2480 max_sector -= remaining >> 9;
2481 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483}
2484
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485/* work around a bug in pseudo DMA
2486 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2487 * sending data. Hence we need a different way to signal the
2488 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2489 * does not work with MT, hence we can only transfer one head at
2490 * a time
2491 */
2492static void virtualdmabug_workaround(void)
2493{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002494 int hard_sectors;
2495 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
2497 if (CT(COMMAND) == FD_WRITE) {
2498 COMMAND &= ~0x80; /* switch off multiple track mode */
2499
2500 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2501 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002503 pr_info("too many sectors %d > %d\n",
2504 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 return;
2506 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002507 SECT_PER_TRACK = end_sector;
2508 /* make sure SECT_PER_TRACK
2509 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 }
2511}
2512
2513/*
2514 * Formulate a read/write request.
2515 * this routine decides where to load the data (directly to buffer, or to
2516 * tmp floppy area), how much data to load (the size of the buffer, the whole
2517 * track, or a single sector)
2518 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2519 * allocation on the fly, it should be done here. No other part should need
2520 * modification.
2521 */
2522
2523static int make_raw_rw_request(void)
2524{
2525 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002526 int max_sector;
2527 int max_size;
2528 int tracksize;
2529 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002531 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533
2534 set_fdc((long)current_req->rq_disk->private_data);
2535
2536 raw_cmd = &default_raw_cmd;
Fengguang Wu2fb2ca62012-07-28 19:45:59 +08002537 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 raw_cmd->cmd_count = NR_RW;
2539 if (rq_data_dir(current_req) == READ) {
2540 raw_cmd->flags |= FD_RAW_READ;
2541 COMMAND = FM_MODE(_floppy, FD_READ);
2542 } else if (rq_data_dir(current_req) == WRITE) {
2543 raw_cmd->flags |= FD_RAW_WRITE;
2544 COMMAND = FM_MODE(_floppy, FD_WRITE);
2545 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002546 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 return 0;
2548 }
2549
2550 max_sector = _floppy->sect * _floppy->head;
2551
Tejun Heo83096eb2009-05-07 22:24:39 +09002552 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2553 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002555 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 current_count_sectors = 1;
2557 return 1;
2558 } else
2559 return 0;
2560 }
2561 HEAD = fsector_t / _floppy->sect;
2562
Keith Wansbrough9e491842008-09-22 14:57:17 -07002563 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002564 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2565 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 max_sector = _floppy->sect;
2567
2568 /* 2M disks have phantom sectors on the first track */
2569 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2570 max_sector = 2 * _floppy->sect / 3;
2571 if (fsector_t >= max_sector) {
2572 current_count_sectors =
2573 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002574 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 return 1;
2576 }
2577 SIZECODE = 2;
2578 } else
2579 SIZECODE = FD_SIZECODE(_floppy);
2580 raw_cmd->rate = _floppy->rate & 0x43;
2581 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2582 raw_cmd->rate = 1;
2583
2584 if (SIZECODE)
2585 SIZECODE2 = 0xff;
2586 else
2587 SIZECODE2 = 0x80;
2588 raw_cmd->track = TRACK << STRETCH(_floppy);
2589 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2590 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002591 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2593 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002594 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595
2596 /* tracksize describes the size which can be filled up with sectors
2597 * of size ssize.
2598 */
2599 tracksize = _floppy->sect - _floppy->sect % ssize;
2600 if (tracksize < _floppy->sect) {
2601 SECT_PER_TRACK++;
2602 if (tracksize <= fsector_t % _floppy->sect)
2603 SECTOR--;
2604
2605 /* if we are beyond tracksize, fill up using smaller sectors */
2606 while (tracksize <= fsector_t % _floppy->sect) {
2607 while (tracksize + ssize > _floppy->sect) {
2608 SIZECODE--;
2609 ssize >>= 1;
2610 }
2611 SECTOR++;
2612 SECT_PER_TRACK++;
2613 tracksize += ssize;
2614 }
2615 max_sector = HEAD * _floppy->sect + tracksize;
2616 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2617 max_sector = _floppy->sect;
2618 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2619 /* for virtual DMA bug workaround */
2620 max_sector = _floppy->sect;
2621 }
2622
2623 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2624 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002625 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 if ((raw_cmd->track == buffer_track) &&
2627 (current_drive == buffer_drive) &&
2628 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2629 /* data already in track buffer */
2630 if (CT(COMMAND) == FD_READ) {
2631 copy_buffer(1, max_sector, buffer_max);
2632 return 1;
2633 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002634 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002636 unsigned int sectors;
2637
2638 sectors = fsector_t + blk_rq_sectors(current_req);
2639 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 max_size = ssize + ssize;
2641 else
2642 max_size = ssize;
2643 }
2644 raw_cmd->flags &= ~FD_RAW_WRITE;
2645 raw_cmd->flags |= FD_RAW_READ;
2646 COMMAND = FM_MODE(_floppy, FD_READ);
Jens Axboeb4f42e22014-04-10 09:46:28 -06002647 } else if ((unsigned long)bio_data(current_req->bio) < MAX_DMA_ADDRESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 unsigned long dma_limit;
2649 int direct, indirect;
2650
2651 indirect =
2652 transfer_size(ssize, max_sector,
2653 max_buffer_sectors * 2) - fsector_t;
2654
2655 /*
2656 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2657 * on a 64 bit machine!
2658 */
2659 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002660 dma_limit = (MAX_DMA_ADDRESS -
Jens Axboeb4f42e22014-04-10 09:46:28 -06002661 ((unsigned long)bio_data(current_req->bio))) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002662 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 /* 64 kb boundaries */
Jens Axboeb4f42e22014-04-10 09:46:28 -06002665 if (CROSS_64KB(bio_data(current_req->bio), max_size << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 max_size = (K_64 -
Jens Axboeb4f42e22014-04-10 09:46:28 -06002667 ((unsigned long)bio_data(current_req->bio)) %
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 K_64) >> 9;
2669 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2670 /*
2671 * We try to read tracks, but if we get too many errors, we
2672 * go back to reading just one sector at a time.
2673 *
2674 * This means we should be able to read a sector even if there
2675 * are other bad sectors on this track.
2676 */
2677 if (!direct ||
2678 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002679 *errors < DP->max_errors.read_track &&
2680 ((!probing ||
2681 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002682 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 } else {
Jens Axboeb4f42e22014-04-10 09:46:28 -06002684 raw_cmd->kernel_data = bio_data(current_req->bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 raw_cmd->length = current_count_sectors << 9;
2686 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002687 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002688 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 indirect, direct, fsector_t);
2690 return 0;
2691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 virtualdmabug_workaround();
2693 return 2;
2694 }
2695 }
2696
2697 if (CT(COMMAND) == FD_READ)
2698 max_size = max_sector; /* unbounded */
2699
2700 /* claim buffer track if needed */
2701 if (buffer_track != raw_cmd->track || /* bad track */
2702 buffer_drive != current_drive || /* bad drive */
2703 fsector_t > buffer_max ||
2704 fsector_t < buffer_min ||
2705 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002706 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002708 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2709 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 buffer_track = -1;
2711 buffer_drive = current_drive;
2712 buffer_max = buffer_min = aligned_sector_t;
2713 }
2714 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002715 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
2717 if (CT(COMMAND) == FD_WRITE) {
2718 /* copy write buffer to track buffer.
2719 * if we get here, we know that the write
2720 * is either aligned or the data already in the buffer
2721 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 if (in_sector_offset && buffer_track == -1)
2723 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 buffer_track = raw_cmd->track;
2725 buffer_drive = current_drive;
2726 copy_buffer(ssize, max_sector,
2727 2 * max_buffer_sectors + buffer_min);
2728 } else
2729 transfer_size(ssize, max_sector,
2730 2 * max_buffer_sectors + buffer_min -
2731 aligned_sector_t);
2732
2733 /* round up current_count_sectors to get dma xfer size */
2734 raw_cmd->length = in_sector_offset + current_count_sectors;
2735 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2736 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 if ((raw_cmd->length < current_count_sectors << 9) ||
Jens Axboeb4f42e22014-04-10 09:46:28 -06002738 (raw_cmd->kernel_data != bio_data(current_req->bio) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 CT(COMMAND) == FD_WRITE &&
2740 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2741 aligned_sector_t < buffer_min)) ||
2742 raw_cmd->length % (128 << SIZECODE) ||
2743 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2744 DPRINT("fractionary current count b=%lx s=%lx\n",
2745 raw_cmd->length, current_count_sectors);
Jens Axboeb4f42e22014-04-10 09:46:28 -06002746 if (raw_cmd->kernel_data != bio_data(current_req->bio))
Joe Perchesb46df352010-03-10 15:20:46 -08002747 pr_info("addr=%d, length=%ld\n",
2748 (int)((raw_cmd->kernel_data -
2749 floppy_track_buffer) >> 9),
2750 current_count_sectors);
2751 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2752 fsector_t, aligned_sector_t, max_sector, max_size);
2753 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2754 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2755 COMMAND, SECTOR, HEAD, TRACK);
2756 pr_info("buffer drive=%d\n", buffer_drive);
2757 pr_info("buffer track=%d\n", buffer_track);
2758 pr_info("buffer_min=%d\n", buffer_min);
2759 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 return 0;
2761 }
2762
Jens Axboeb4f42e22014-04-10 09:46:28 -06002763 if (raw_cmd->kernel_data != bio_data(current_req->bio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 if (raw_cmd->kernel_data < floppy_track_buffer ||
2765 current_count_sectors < 0 ||
2766 raw_cmd->length < 0 ||
2767 raw_cmd->kernel_data + raw_cmd->length >
2768 floppy_track_buffer + (max_buffer_sectors << 10)) {
2769 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002770 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2771 fsector_t, buffer_min, raw_cmd->length >> 9);
2772 pr_info("current_count_sectors=%ld\n",
2773 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002775 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002777 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 return 0;
2779 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002780 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002781 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 DPRINT("buffer overrun in direct transfer\n");
2783 return 0;
2784 } else if (raw_cmd->length < current_count_sectors << 9) {
2785 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002786 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2787 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 }
2789 if (raw_cmd->length == 0) {
2790 DPRINT("zero dma transfer attempted from make_raw_request\n");
2791 return 0;
2792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
2794 virtualdmabug_workaround();
2795 return 2;
2796}
2797
Jens Axboe48821182010-09-22 09:32:36 +02002798/*
2799 * Round-robin between our available drives, doing one request from each
2800 */
2801static int set_next_request(void)
2802{
2803 struct request_queue *q;
2804 int old_pos = fdc_queue;
2805
2806 do {
2807 q = disks[fdc_queue]->queue;
2808 if (++fdc_queue == N_DRIVE)
2809 fdc_queue = 0;
2810 if (q) {
2811 current_req = blk_fetch_request(q);
2812 if (current_req)
2813 break;
2814 }
2815 } while (fdc_queue != old_pos);
2816
2817 return current_req != NULL;
2818}
2819
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820static void redo_fd_request(void)
2821{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 int drive;
2823 int tmp;
2824
2825 lastredo = jiffies;
2826 if (current_drive < N_DRIVE)
2827 floppy_off(current_drive);
2828
Joe Perches0da31322010-03-10 15:21:03 -08002829do_request:
2830 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002831 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832
Jens Axboe48821182010-09-22 09:32:36 +02002833 spin_lock_irq(&floppy_lock);
2834 pending = set_next_request();
2835 spin_unlock_irq(&floppy_lock);
Jens Axboe48821182010-09-22 09:32:36 +02002836 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002837 do_floppy = NULL;
2838 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 }
Joe Perches0da31322010-03-10 15:21:03 -08002842 drive = (long)current_req->rq_disk->private_data;
2843 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002844 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002845
2846 set_floppy(drive);
2847 raw_cmd = &default_raw_cmd;
2848 raw_cmd->flags = 0;
2849 if (start_motor(redo_fd_request))
2850 return;
2851
2852 disk_change(current_drive);
2853 if (test_bit(current_drive, &fake_change) ||
2854 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2855 DPRINT("disk absent or changed during operation\n");
2856 request_done(0);
2857 goto do_request;
2858 }
2859 if (!_floppy) { /* Autodetection */
2860 if (!probing) {
2861 DRS->probed_format = 0;
2862 if (next_valid_format()) {
2863 DPRINT("no autodetectable formats\n");
2864 _floppy = NULL;
2865 request_done(0);
2866 goto do_request;
2867 }
2868 }
2869 probing = 1;
2870 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2871 } else
2872 probing = 0;
2873 errors = &(current_req->errors);
2874 tmp = make_raw_rw_request();
2875 if (tmp < 2) {
2876 request_done(tmp);
2877 goto do_request;
2878 }
2879
2880 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2881 twaddle();
2882 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002883 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002884 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885}
2886
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002887static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 .interrupt = rw_interrupt,
2889 .redo = redo_fd_request,
2890 .error = bad_flp_intr,
2891 .done = request_done
2892};
2893
2894static void process_fd_request(void)
2895{
2896 cont = &rw_cont;
2897 schedule_bh(redo_fd_request);
2898}
2899
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002900static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901{
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002902 if (WARN(max_buffer_sectors == 0,
2903 "VFS: %s called on non-open device\n", __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002906 if (WARN(atomic_read(&usage_count) == 0,
Jens Axboe59533162013-05-23 12:25:08 +02002907 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%llx\n",
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002908 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
Jens Axboe59533162013-05-23 12:25:08 +02002909 (unsigned long long) current_req->cmd_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 return;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002911
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002912 if (test_and_set_bit(0, &fdc_busy)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 /* fdc busy, this new request will be treated when the
2914 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002915 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 return;
2917 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002918 command_status = FD_COMMAND_NONE;
2919 __reschedule_timeout(MAXTIMEOUT, "fd_request");
2920 set_fdc(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002922 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923}
2924
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002925static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 .interrupt = success_and_wakeup,
2927 .redo = floppy_ready,
2928 .error = generic_failure,
2929 .done = generic_done
2930};
2931
Joe Perches74f63f42010-03-10 15:20:58 -08002932static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 /* no auto-sense, just clear dcl */
2935 raw_cmd = &default_raw_cmd;
2936 raw_cmd->flags = flag;
2937 raw_cmd->track = 0;
2938 raw_cmd->cmd_count = 0;
2939 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002940 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002941 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002942
2943 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944}
2945
2946/*
2947 * User triggered reset
2948 * ====================
2949 */
2950
2951static void reset_intr(void)
2952{
Joe Perchesb46df352010-03-10 15:20:46 -08002953 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954}
2955
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002956static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 .interrupt = reset_intr,
2958 .redo = success_and_wakeup,
2959 .error = generic_failure,
2960 .done = generic_done
2961};
2962
Joe Perches74f63f42010-03-10 15:20:58 -08002963static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964{
2965 int ret;
2966
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01002967 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08002968 return -EINTR;
2969
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 if (arg == FD_RESET_ALWAYS)
2971 FDCS->reset = 1;
2972 if (FDCS->reset) {
2973 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002974 ret = wait_til_done(reset_fdc, interruptible);
2975 if (ret == -EINTR)
2976 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 }
2978 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002979 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980}
2981
2982/*
2983 * Misc Ioctl's and support
2984 * ========================
2985 */
2986static inline int fd_copyout(void __user *param, const void *address,
2987 unsigned long size)
2988{
2989 return copy_to_user(param, address, size) ? -EFAULT : 0;
2990}
2991
Joe Perches48c8cee2010-03-10 15:20:45 -08002992static inline int fd_copyin(void __user *param, void *address,
2993 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994{
2995 return copy_from_user(address, param, size) ? -EFAULT : 0;
2996}
2997
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02002998static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999{
3000 struct floppy_struct *floppy;
3001
3002 if (type)
3003 floppy = floppy_type + type;
3004 else {
3005 if (UDP->native_format)
3006 floppy = floppy_type + UDP->native_format;
3007 else
3008 return "(null)";
3009 }
3010 if (floppy->name)
3011 return floppy->name;
3012 else
3013 return "(null)";
3014}
3015
3016/* raw commands */
3017static void raw_cmd_done(int flag)
3018{
3019 int i;
3020
3021 if (!flag) {
3022 raw_cmd->flags |= FD_RAW_FAILURE;
3023 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3024 } else {
3025 raw_cmd->reply_count = inr;
3026 if (raw_cmd->reply_count > MAX_REPLIES)
3027 raw_cmd->reply_count = 0;
3028 for (i = 0; i < raw_cmd->reply_count; i++)
3029 raw_cmd->reply[i] = reply_buffer[i];
3030
3031 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3032 unsigned long flags;
3033 flags = claim_dma_lock();
3034 raw_cmd->length = fd_get_dma_residue();
3035 release_dma_lock(flags);
3036 }
3037
3038 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3039 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3040 raw_cmd->flags |= FD_RAW_FAILURE;
3041
3042 if (disk_change(current_drive))
3043 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3044 else
3045 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3046 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3047 motor_off_callback(current_drive);
3048
3049 if (raw_cmd->next &&
3050 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3051 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3052 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3053 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3054 raw_cmd = raw_cmd->next;
3055 return;
3056 }
3057 }
3058 generic_done(flag);
3059}
3060
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003061static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 .interrupt = success_and_wakeup,
3063 .redo = floppy_start,
3064 .error = generic_failure,
3065 .done = raw_cmd_done
3066};
3067
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003068static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 struct floppy_raw_cmd *ptr)
3070{
3071 int ret;
3072
3073 while (ptr) {
Matthew Daley2145e152014-04-28 19:05:21 +12003074 struct floppy_raw_cmd cmd = *ptr;
3075 cmd.next = NULL;
3076 cmd.kernel_data = NULL;
3077 ret = copy_to_user(param, &cmd, sizeof(cmd));
Joe Perches86b12b42010-03-10 15:20:56 -08003078 if (ret)
3079 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 param += sizeof(struct floppy_raw_cmd);
3081 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003082 if (ptr->length >= 0 &&
3083 ptr->length <= ptr->buffer_length) {
3084 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003085 ret = fd_copyout(ptr->data, ptr->kernel_data,
3086 length);
3087 if (ret)
3088 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 }
3091 ptr = ptr->next;
3092 }
Joe Perches7f252712010-03-10 15:21:08 -08003093
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 return 0;
3095}
3096
3097static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3098{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003099 struct floppy_raw_cmd *next;
3100 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101
3102 this = *ptr;
3103 *ptr = NULL;
3104 while (this) {
3105 if (this->buffer_length) {
3106 fd_dma_mem_free((unsigned long)this->kernel_data,
3107 this->buffer_length);
3108 this->buffer_length = 0;
3109 }
3110 next = this->next;
3111 kfree(this);
3112 this = next;
3113 }
3114}
3115
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003116static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 struct floppy_raw_cmd **rcmd)
3118{
3119 struct floppy_raw_cmd *ptr;
3120 int ret;
3121 int i;
3122
3123 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003124
3125loop:
3126 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3127 if (!ptr)
3128 return -ENOMEM;
3129 *rcmd = ptr;
3130 ret = copy_from_user(ptr, param, sizeof(*ptr));
Joe Perches7f252712010-03-10 15:21:08 -08003131 ptr->next = NULL;
3132 ptr->buffer_length = 0;
Matthew Daleyef87dbe2014-04-28 19:05:20 +12003133 ptr->kernel_data = NULL;
3134 if (ret)
3135 return -EFAULT;
Joe Perches7f252712010-03-10 15:21:08 -08003136 param += sizeof(struct floppy_raw_cmd);
3137 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 /* the command may now also take up the space
3139 * initially intended for the reply & the
3140 * reply count. Needed for long 82078 commands
3141 * such as RESTORE, which takes ... 17 command
3142 * bytes. Murphy's law #137: When you reserve
3143 * 16 bytes for a structure, you'll one day
3144 * discover that you really need 17...
3145 */
Joe Perches7f252712010-03-10 15:21:08 -08003146 return -EINVAL;
3147
3148 for (i = 0; i < 16; i++)
3149 ptr->reply[i] = 0;
3150 ptr->resultcode = 0;
Joe Perches7f252712010-03-10 15:21:08 -08003151
3152 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3153 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003155 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3156 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3157 if (!ptr->kernel_data)
3158 return -ENOMEM;
3159 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 }
Joe Perches7f252712010-03-10 15:21:08 -08003161 if (ptr->flags & FD_RAW_WRITE) {
3162 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3163 if (ret)
3164 return ret;
3165 }
3166
3167 if (ptr->flags & FD_RAW_MORE) {
3168 rcmd = &(ptr->next);
3169 ptr->rate &= 0x43;
3170 goto loop;
3171 }
3172
3173 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174}
3175
3176static int raw_cmd_ioctl(int cmd, void __user *param)
3177{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003179 int drive;
3180 int ret2;
3181 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
3183 if (FDCS->rawcmd <= 1)
3184 FDCS->rawcmd = 1;
3185 for (drive = 0; drive < N_DRIVE; drive++) {
3186 if (FDC(drive) != fdc)
3187 continue;
3188 if (drive == current_drive) {
3189 if (UDRS->fd_ref > 1) {
3190 FDCS->rawcmd = 2;
3191 break;
3192 }
3193 } else if (UDRS->fd_ref) {
3194 FDCS->rawcmd = 2;
3195 break;
3196 }
3197 }
3198
3199 if (FDCS->reset)
3200 return -EIO;
3201
3202 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3203 if (ret) {
3204 raw_cmd_free(&my_raw_cmd);
3205 return ret;
3206 }
3207
3208 raw_cmd = my_raw_cmd;
3209 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003210 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003211 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212
3213 if (ret != -EINTR && FDCS->reset)
3214 ret = -EIO;
3215
3216 DRS->track = NO_TRACK;
3217
3218 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3219 if (!ret)
3220 ret = ret2;
3221 raw_cmd_free(&my_raw_cmd);
3222 return ret;
3223}
3224
3225static int invalidate_drive(struct block_device *bdev)
3226{
3227 /* invalidate the buffer track to force a reread */
3228 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3229 process_fd_request();
3230 check_disk_change(bdev);
3231 return 0;
3232}
3233
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003234static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 int drive, int type, struct block_device *bdev)
3236{
3237 int cnt;
3238
3239 /* sanity checking for parameters. */
3240 if (g->sect <= 0 ||
3241 g->head <= 0 ||
Denis Efremov604206c2019-07-12 21:55:20 +03003242 /* check for zero in F_SECT_PER_TRACK */
3243 (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3245 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003246 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 return -EINVAL;
3248 if (type) {
3249 if (!capable(CAP_SYS_ADMIN))
3250 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003251 mutex_lock(&open_lock);
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003252 if (lock_fdc(drive)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003253 mutex_unlock(&open_lock);
3254 return -EINTR;
3255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 floppy_type[type] = *g;
3257 floppy_type[type].name = "user format";
3258 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3259 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3260 floppy_type[type].size + 1;
3261 process_fd_request();
3262 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3263 struct block_device *bdev = opened_bdev[cnt];
3264 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3265 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003266 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003268 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 } else {
3270 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003271
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003272 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003273 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003274 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 /* notice a disk change immediately, else
3276 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003277 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003278 return -EINTR;
3279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 oldStretch = g->stretch;
3281 user_params[drive] = *g;
3282 if (buffer_drive == drive)
3283 SUPBOUND(buffer_max, user_params[drive].sect);
3284 current_type[drive] = &user_params[drive];
3285 floppy_sizes[drive] = user_params[drive].size;
3286 if (cmd == FDDEFPRM)
3287 DRS->keep_data = -1;
3288 else
3289 DRS->keep_data = 1;
3290 /* invalidation. Invalidate only when needed, i.e.
3291 * when there are already sectors in the buffer cache
3292 * whose number will change. This is useful, because
3293 * mtools often changes the geometry of the disk after
3294 * looking at the boot block */
3295 if (DRS->maxblock > user_params[drive].sect ||
3296 DRS->maxtrack ||
3297 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003298 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 invalidate_drive(bdev);
3300 else
3301 process_fd_request();
3302 }
3303 return 0;
3304}
3305
3306/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003307static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 FDCLRPRM,
3309 FDSETPRM,
3310 FDDEFPRM,
3311 FDGETPRM,
3312 FDMSGON,
3313 FDMSGOFF,
3314 FDFMTBEG,
3315 FDFMTTRK,
3316 FDFMTEND,
3317 FDSETEMSGTRESH,
3318 FDFLUSH,
3319 FDSETMAXERRS,
3320 FDGETMAXERRS,
3321 FDGETDRVTYP,
3322 FDSETDRVPRM,
3323 FDGETDRVPRM,
3324 FDGETDRVSTAT,
3325 FDPOLLDRVSTAT,
3326 FDRESET,
3327 FDGETFDCSTAT,
3328 FDWERRORCLR,
3329 FDWERRORGET,
3330 FDRAWCMD,
3331 FDEJECT,
3332 FDTWADDLE
3333};
3334
Stephen Hemminger21af5442010-06-15 13:21:11 +02003335static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336{
3337 int i;
3338
3339 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3340 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3341 *size = _IOC_SIZE(*cmd);
3342 *cmd = ioctl_table[i];
3343 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003344 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 return -EFAULT;
3346 }
3347 return 0;
3348 }
3349 }
3350 return -EINVAL;
3351}
3352
3353static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3354{
3355 if (type)
3356 *g = &floppy_type[type];
3357 else {
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003358 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003359 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003360 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003361 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 process_fd_request();
3363 *g = current_type[drive];
3364 }
3365 if (!*g)
3366 return -ENODEV;
3367 return 0;
3368}
3369
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003370static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3371{
3372 int drive = (long)bdev->bd_disk->private_data;
3373 int type = ITYPE(drive_state[drive].fd_device);
3374 struct floppy_struct *g;
3375 int ret;
3376
3377 ret = get_floppy_geometry(drive, type, &g);
3378 if (ret)
3379 return ret;
3380
3381 geo->heads = g->head;
3382 geo->sectors = g->sect;
3383 geo->cylinders = g->track;
3384 return 0;
3385}
3386
Denis Efremov93f89552019-07-12 21:55:21 +03003387static bool valid_floppy_drive_params(const short autodetect[8])
3388{
3389 size_t floppy_type_size = ARRAY_SIZE(floppy_type);
3390 size_t i = 0;
3391
3392 for (i = 0; i < 8; ++i) {
3393 if (autodetect[i] < 0 ||
3394 autodetect[i] >= floppy_type_size)
3395 return false;
3396 }
3397
3398 return true;
3399}
3400
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003401static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 unsigned long param)
3403{
Al Viroa4af9b42008-03-02 09:27:55 -05003404 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003405 int type = ITYPE(UDRS->fd_device);
3406 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 int ret;
3408 int size;
3409 union inparam {
3410 struct floppy_struct g; /* geometry */
3411 struct format_descr f;
3412 struct floppy_max_errors max_errors;
3413 struct floppy_drive_params dp;
3414 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003415 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416
3417 /* convert compatibility eject ioctls into floppy eject ioctl.
3418 * We do this in order to provide a means to eject floppy disks before
3419 * installing the new fdutils package */
3420 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003421 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 DPRINT("obsolete eject ioctl\n");
3423 DPRINT("please use floppycontrol --eject\n");
3424 cmd = FDEJECT;
3425 }
3426
Joe Perchesa81ee542010-03-10 15:20:46 -08003427 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 return -EINVAL;
3429
Joe Perchesa81ee542010-03-10 15:20:46 -08003430 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003431 ret = normalize_ioctl(&cmd, &size);
3432 if (ret)
3433 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003434
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003436 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3438 return -EPERM;
3439
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003440 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3441 return -EINVAL;
3442
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003444 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003445 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3446 ret = fd_copyin((void __user *)param, &inparam, size);
3447 if (ret)
3448 return ret;
3449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450
Joe Perchesda273652010-03-10 15:20:52 -08003451 switch (cmd) {
3452 case FDEJECT:
3453 if (UDRS->fd_ref != 1)
3454 /* somebody else has this drive open */
3455 return -EBUSY;
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003456 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003457 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
Joe Perchesda273652010-03-10 15:20:52 -08003459 /* do the actual eject. Fails on
3460 * non-Sparc architectures */
3461 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462
Joe Perchese0298532010-03-10 15:20:55 -08003463 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3464 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003465 process_fd_request();
3466 return ret;
3467 case FDCLRPRM:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003468 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003469 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003470 current_type[drive] = NULL;
3471 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3472 UDRS->keep_data = 0;
3473 return invalidate_drive(bdev);
3474 case FDSETPRM:
3475 case FDDEFPRM:
3476 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3477 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003478 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003479 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003480 if (ret)
3481 return ret;
Andy Whitcroft3da4db12018-09-20 09:09:48 -06003482 memcpy(&inparam.g, outparam,
3483 offsetof(struct floppy_struct, name));
3484 outparam = &inparam.g;
Joe Perchesda273652010-03-10 15:20:52 -08003485 break;
3486 case FDMSGON:
3487 UDP->flags |= FTD_MSG;
3488 return 0;
3489 case FDMSGOFF:
3490 UDP->flags &= ~FTD_MSG;
3491 return 0;
3492 case FDFMTBEG:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003493 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003494 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003495 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003496 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003497 ret = UDRS->flags;
3498 process_fd_request();
3499 if (ret & FD_VERIFY)
3500 return -ENODEV;
3501 if (!(ret & FD_DISK_WRITABLE))
3502 return -EROFS;
3503 return 0;
3504 case FDFMTTRK:
3505 if (UDRS->fd_ref != 1)
3506 return -EBUSY;
3507 return do_format(drive, &inparam.f);
3508 case FDFMTEND:
3509 case FDFLUSH:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003510 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003511 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003512 return invalidate_drive(bdev);
3513 case FDSETEMSGTRESH:
3514 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3515 return 0;
3516 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003517 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003518 break;
3519 case FDSETMAXERRS:
3520 UDP->max_errors = inparam.max_errors;
3521 break;
3522 case FDGETDRVTYP:
3523 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003524 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003525 break;
3526 case FDSETDRVPRM:
Denis Efremov93f89552019-07-12 21:55:21 +03003527 if (!valid_floppy_drive_params(inparam.dp.autodetect))
3528 return -EINVAL;
Joe Perchesda273652010-03-10 15:20:52 -08003529 *UDP = inparam.dp;
3530 break;
3531 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003532 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003533 break;
3534 case FDPOLLDRVSTAT:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003535 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003536 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003537 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003538 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003539 process_fd_request();
3540 /* fall through */
3541 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003542 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003543 break;
3544 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003545 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003546 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003547 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003548 break;
3549 case FDWERRORCLR:
3550 memset(UDRWE, 0, sizeof(*UDRWE));
3551 return 0;
3552 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003553 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003554 break;
3555 case FDRAWCMD:
3556 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 return -EINVAL;
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003558 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003559 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003560 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003561 i = raw_cmd_ioctl(cmd, (void __user *)param);
3562 if (i == -EINTR)
3563 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003564 process_fd_request();
3565 return i;
3566 case FDTWADDLE:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003567 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003568 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003569 twaddle();
3570 process_fd_request();
3571 return 0;
3572 default:
3573 return -EINVAL;
3574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
3576 if (_IOC_DIR(cmd) & _IOC_READ)
3577 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003578
3579 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580}
3581
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003582static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3583 unsigned int cmd, unsigned long param)
3584{
3585 int ret;
3586
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003587 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003588 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003589 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003590
3591 return ret;
3592}
3593
Al Viro06f9e7b2017-06-27 15:47:56 -04003594#ifdef CONFIG_COMPAT
3595
3596struct compat_floppy_drive_params {
3597 char cmos;
3598 compat_ulong_t max_dtr;
3599 compat_ulong_t hlt;
3600 compat_ulong_t hut;
3601 compat_ulong_t srt;
3602 compat_ulong_t spinup;
3603 compat_ulong_t spindown;
3604 unsigned char spindown_offset;
3605 unsigned char select_delay;
3606 unsigned char rps;
3607 unsigned char tracks;
3608 compat_ulong_t timeout;
3609 unsigned char interleave_sect;
3610 struct floppy_max_errors max_errors;
3611 char flags;
3612 char read_track;
3613 short autodetect[8];
3614 compat_int_t checkfreq;
3615 compat_int_t native_format;
3616};
3617
3618struct compat_floppy_drive_struct {
3619 signed char flags;
3620 compat_ulong_t spinup_date;
3621 compat_ulong_t select_date;
3622 compat_ulong_t first_read_date;
3623 short probed_format;
3624 short track;
3625 short maxblock;
3626 short maxtrack;
3627 compat_int_t generation;
3628 compat_int_t keep_data;
3629 compat_int_t fd_ref;
3630 compat_int_t fd_device;
3631 compat_int_t last_checked;
3632 compat_caddr_t dmabuf;
3633 compat_int_t bufblocks;
3634};
3635
3636struct compat_floppy_fdc_state {
3637 compat_int_t spec1;
3638 compat_int_t spec2;
3639 compat_int_t dtr;
3640 unsigned char version;
3641 unsigned char dor;
3642 compat_ulong_t address;
3643 unsigned int rawcmd:2;
3644 unsigned int reset:1;
3645 unsigned int need_configure:1;
3646 unsigned int perp_mode:2;
3647 unsigned int has_fifo:1;
3648 unsigned int driver_version;
3649 unsigned char track[4];
3650};
3651
3652struct compat_floppy_write_errors {
3653 unsigned int write_errors;
3654 compat_ulong_t first_error_sector;
3655 compat_int_t first_error_generation;
3656 compat_ulong_t last_error_sector;
3657 compat_int_t last_error_generation;
3658 compat_uint_t badness;
3659};
3660
3661#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
3662#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
3663#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
3664#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
3665#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
3666#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
3667#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
3668#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
3669
3670static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3671 struct compat_floppy_struct __user *arg)
3672{
3673 struct floppy_struct v;
3674 int drive, type;
3675 int err;
3676
3677 BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
3678 offsetof(struct compat_floppy_struct, name));
3679
3680 if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
3681 return -EPERM;
3682
3683 memset(&v, 0, sizeof(struct floppy_struct));
3684 if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
3685 return -EFAULT;
3686
3687 mutex_lock(&floppy_mutex);
3688 drive = (long)bdev->bd_disk->private_data;
3689 type = ITYPE(UDRS->fd_device);
3690 err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
3691 &v, drive, type, bdev);
3692 mutex_unlock(&floppy_mutex);
3693 return err;
3694}
3695
3696static int compat_get_prm(int drive,
3697 struct compat_floppy_struct __user *arg)
3698{
3699 struct compat_floppy_struct v;
3700 struct floppy_struct *p;
3701 int err;
3702
3703 memset(&v, 0, sizeof(v));
3704 mutex_lock(&floppy_mutex);
3705 err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
3706 if (err) {
3707 mutex_unlock(&floppy_mutex);
3708 return err;
3709 }
3710 memcpy(&v, p, offsetof(struct floppy_struct, name));
3711 mutex_unlock(&floppy_mutex);
3712 if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
3713 return -EFAULT;
3714 return 0;
3715}
3716
3717static int compat_setdrvprm(int drive,
3718 struct compat_floppy_drive_params __user *arg)
3719{
3720 struct compat_floppy_drive_params v;
3721
3722 if (!capable(CAP_SYS_ADMIN))
3723 return -EPERM;
3724 if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
3725 return -EFAULT;
Denis Efremov93f89552019-07-12 21:55:21 +03003726 if (!valid_floppy_drive_params(v.autodetect))
3727 return -EINVAL;
Al Viro06f9e7b2017-06-27 15:47:56 -04003728 mutex_lock(&floppy_mutex);
3729 UDP->cmos = v.cmos;
3730 UDP->max_dtr = v.max_dtr;
3731 UDP->hlt = v.hlt;
3732 UDP->hut = v.hut;
3733 UDP->srt = v.srt;
3734 UDP->spinup = v.spinup;
3735 UDP->spindown = v.spindown;
3736 UDP->spindown_offset = v.spindown_offset;
3737 UDP->select_delay = v.select_delay;
3738 UDP->rps = v.rps;
3739 UDP->tracks = v.tracks;
3740 UDP->timeout = v.timeout;
3741 UDP->interleave_sect = v.interleave_sect;
3742 UDP->max_errors = v.max_errors;
3743 UDP->flags = v.flags;
3744 UDP->read_track = v.read_track;
3745 memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
3746 UDP->checkfreq = v.checkfreq;
3747 UDP->native_format = v.native_format;
3748 mutex_unlock(&floppy_mutex);
3749 return 0;
3750}
3751
3752static int compat_getdrvprm(int drive,
3753 struct compat_floppy_drive_params __user *arg)
3754{
3755 struct compat_floppy_drive_params v;
3756
3757 memset(&v, 0, sizeof(struct compat_floppy_drive_params));
3758 mutex_lock(&floppy_mutex);
3759 v.cmos = UDP->cmos;
3760 v.max_dtr = UDP->max_dtr;
3761 v.hlt = UDP->hlt;
3762 v.hut = UDP->hut;
3763 v.srt = UDP->srt;
3764 v.spinup = UDP->spinup;
3765 v.spindown = UDP->spindown;
3766 v.spindown_offset = UDP->spindown_offset;
3767 v.select_delay = UDP->select_delay;
3768 v.rps = UDP->rps;
3769 v.tracks = UDP->tracks;
3770 v.timeout = UDP->timeout;
3771 v.interleave_sect = UDP->interleave_sect;
3772 v.max_errors = UDP->max_errors;
3773 v.flags = UDP->flags;
3774 v.read_track = UDP->read_track;
3775 memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
3776 v.checkfreq = UDP->checkfreq;
3777 v.native_format = UDP->native_format;
3778 mutex_unlock(&floppy_mutex);
3779
3780 if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
3781 return -EFAULT;
3782 return 0;
3783}
3784
3785static int compat_getdrvstat(int drive, bool poll,
3786 struct compat_floppy_drive_struct __user *arg)
3787{
3788 struct compat_floppy_drive_struct v;
3789
3790 memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
3791 mutex_lock(&floppy_mutex);
3792
3793 if (poll) {
3794 if (lock_fdc(drive))
3795 goto Eintr;
3796 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
3797 goto Eintr;
3798 process_fd_request();
3799 }
3800 v.spinup_date = UDRS->spinup_date;
3801 v.select_date = UDRS->select_date;
3802 v.first_read_date = UDRS->first_read_date;
3803 v.probed_format = UDRS->probed_format;
3804 v.track = UDRS->track;
3805 v.maxblock = UDRS->maxblock;
3806 v.maxtrack = UDRS->maxtrack;
3807 v.generation = UDRS->generation;
3808 v.keep_data = UDRS->keep_data;
3809 v.fd_ref = UDRS->fd_ref;
3810 v.fd_device = UDRS->fd_device;
3811 v.last_checked = UDRS->last_checked;
3812 v.dmabuf = (uintptr_t)UDRS->dmabuf;
3813 v.bufblocks = UDRS->bufblocks;
3814 mutex_unlock(&floppy_mutex);
3815
3816 if (copy_from_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
3817 return -EFAULT;
3818 return 0;
3819Eintr:
3820 mutex_unlock(&floppy_mutex);
3821 return -EINTR;
3822}
3823
3824static int compat_getfdcstat(int drive,
3825 struct compat_floppy_fdc_state __user *arg)
3826{
3827 struct compat_floppy_fdc_state v32;
3828 struct floppy_fdc_state v;
3829
3830 mutex_lock(&floppy_mutex);
3831 v = *UFDCS;
3832 mutex_unlock(&floppy_mutex);
3833
3834 memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
3835 v32.spec1 = v.spec1;
3836 v32.spec2 = v.spec2;
3837 v32.dtr = v.dtr;
3838 v32.version = v.version;
3839 v32.dor = v.dor;
3840 v32.address = v.address;
3841 v32.rawcmd = v.rawcmd;
3842 v32.reset = v.reset;
3843 v32.need_configure = v.need_configure;
3844 v32.perp_mode = v.perp_mode;
3845 v32.has_fifo = v.has_fifo;
3846 v32.driver_version = v.driver_version;
3847 memcpy(v32.track, v.track, 4);
3848 if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
3849 return -EFAULT;
3850 return 0;
3851}
3852
3853static int compat_werrorget(int drive,
3854 struct compat_floppy_write_errors __user *arg)
3855{
3856 struct compat_floppy_write_errors v32;
3857 struct floppy_write_errors v;
3858
3859 memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
3860 mutex_lock(&floppy_mutex);
3861 v = *UDRWE;
3862 mutex_unlock(&floppy_mutex);
3863 v32.write_errors = v.write_errors;
3864 v32.first_error_sector = v.first_error_sector;
3865 v32.first_error_generation = v.first_error_generation;
3866 v32.last_error_sector = v.last_error_sector;
3867 v32.last_error_generation = v.last_error_generation;
3868 v32.badness = v.badness;
3869 if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
3870 return -EFAULT;
3871 return 0;
3872}
3873
3874static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3875 unsigned long param)
3876{
3877 int drive = (long)bdev->bd_disk->private_data;
3878 switch (cmd) {
3879 case FDMSGON:
3880 case FDMSGOFF:
3881 case FDSETEMSGTRESH:
3882 case FDFLUSH:
3883 case FDWERRORCLR:
3884 case FDEJECT:
3885 case FDCLRPRM:
3886 case FDFMTBEG:
3887 case FDRESET:
3888 case FDTWADDLE:
3889 return fd_ioctl(bdev, mode, cmd, param);
3890 case FDSETMAXERRS:
3891 case FDGETMAXERRS:
3892 case FDGETDRVTYP:
3893 case FDFMTEND:
3894 case FDFMTTRK:
3895 case FDRAWCMD:
3896 return fd_ioctl(bdev, mode, cmd,
3897 (unsigned long)compat_ptr(param));
3898 case FDSETPRM32:
3899 case FDDEFPRM32:
3900 return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
3901 case FDGETPRM32:
3902 return compat_get_prm(drive, compat_ptr(param));
3903 case FDSETDRVPRM32:
3904 return compat_setdrvprm(drive, compat_ptr(param));
3905 case FDGETDRVPRM32:
3906 return compat_getdrvprm(drive, compat_ptr(param));
3907 case FDPOLLDRVSTAT32:
3908 return compat_getdrvstat(drive, true, compat_ptr(param));
3909 case FDGETDRVSTAT32:
3910 return compat_getdrvstat(drive, false, compat_ptr(param));
3911 case FDGETFDCSTAT32:
3912 return compat_getfdcstat(drive, compat_ptr(param));
3913 case FDWERRORGET32:
3914 return compat_werrorget(drive, compat_ptr(param));
3915 }
3916 return -EINVAL;
3917}
3918#endif
3919
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920static void __init config_types(void)
3921{
Joe Perchesb46df352010-03-10 15:20:46 -08003922 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 int drive;
3924
3925 /* read drive info out of physical CMOS */
3926 drive = 0;
3927 if (!UDP->cmos)
3928 UDP->cmos = FLOPPY0_TYPE;
3929 drive = 1;
3930 if (!UDP->cmos && FLOPPY1_TYPE)
3931 UDP->cmos = FLOPPY1_TYPE;
3932
Jesper Juhl06f748c2007-10-16 23:30:57 -07003933 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
3935 for (drive = 0; drive < N_DRIVE; drive++) {
3936 unsigned int type = UDP->cmos;
3937 struct floppy_drive_params *params;
3938 const char *name = NULL;
Rasmus Villemoesbcf42992015-12-01 15:54:01 +01003939 char temparea[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940
Tobias Klauser945f3902006-01-08 01:05:11 -08003941 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 params = &default_drive_params[type].params;
3943 if (type) {
3944 name = default_drive_params[type].name;
3945 allowed_drive_mask |= 1 << drive;
3946 } else
3947 allowed_drive_mask &= ~(1 << drive);
3948 } else {
3949 params = &default_drive_params[0].params;
Rasmus Villemoesbcf42992015-12-01 15:54:01 +01003950 snprintf(temparea, sizeof(temparea),
3951 "unknown type %d (usb?)", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 name = temparea;
3953 }
3954 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003955 const char *prepend;
3956 if (!has_drive) {
3957 prepend = "";
3958 has_drive = true;
3959 pr_info("Floppy drive(s):");
3960 } else {
3961 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 }
Joe Perchesb46df352010-03-10 15:20:46 -08003963
3964 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 }
3966 *UDP = *params;
3967 }
Joe Perchesb46df352010-03-10 15:20:46 -08003968
3969 if (has_drive)
3970 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971}
3972
Al Virodb2a1442013-05-05 21:52:57 -04003973static void floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974{
Al Viroa4af9b42008-03-02 09:27:55 -05003975 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003977 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003978 mutex_lock(&open_lock);
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003979 if (!UDRS->fd_ref--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 DPRINT("floppy_release with fd_ref == 0");
3981 UDRS->fd_ref = 0;
3982 }
3983 if (!UDRS->fd_ref)
3984 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003985 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003986 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987}
3988
3989/*
3990 * floppy_open check for aliasing (/dev/fd0 can be the same as
3991 * /dev/PS0 etc), and disallows simultaneous access to the same
3992 * drive with different device numbers.
3993 */
Al Viroa4af9b42008-03-02 09:27:55 -05003994static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995{
Al Viroa4af9b42008-03-02 09:27:55 -05003996 int drive = (long)bdev->bd_disk->private_data;
3997 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 int try;
3999 int res = -EBUSY;
4000 char *tmp;
4001
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004002 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004003 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05004005 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 goto out2;
4007
4008 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08004009 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4010 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 }
4012
Jiri Kosinabfa10b82012-05-18 13:50:28 +02004013 UDRS->fd_ref++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
Al Viroa4af9b42008-03-02 09:27:55 -05004015 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016
4017 res = -ENXIO;
4018
4019 if (!floppy_track_buffer) {
4020 /* if opening an ED drive, reserve a big buffer,
4021 * else reserve a small one */
4022 if ((UDP->cmos == 6) || (UDP->cmos == 5))
4023 try = 64; /* Only 48 actually useful */
4024 else
4025 try = 32; /* Only 24 actually useful */
4026
4027 tmp = (char *)fd_dma_mem_alloc(1024 * try);
4028 if (!tmp && !floppy_track_buffer) {
4029 try >>= 1; /* buffer only one side */
4030 INFBOUND(try, 16);
4031 tmp = (char *)fd_dma_mem_alloc(1024 * try);
4032 }
Joe Perchesa81ee542010-03-10 15:20:46 -08004033 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 if (!tmp && !floppy_track_buffer) {
4036 DPRINT("Unable to allocate DMA memory\n");
4037 goto out;
4038 }
4039 if (floppy_track_buffer) {
4040 if (tmp)
4041 fd_dma_mem_free((unsigned long)tmp, try * 1024);
4042 } else {
4043 buffer_min = buffer_max = -1;
4044 floppy_track_buffer = tmp;
4045 max_buffer_sectors = try;
4046 }
4047 }
4048
Al Viroa4af9b42008-03-02 09:27:55 -05004049 new_dev = MINOR(bdev->bd_dev);
4050 UDRS->fd_device = new_dev;
4051 set_capacity(disks[drive], floppy_sizes[new_dev]);
4052 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 if (buffer_drive == drive)
4054 buffer_track = -1;
4055 }
4056
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 if (UFDCS->rawcmd == 1)
4058 UFDCS->rawcmd = 2;
4059
Jens Axboef2791e72016-08-25 08:56:51 -06004060 if (!(mode & FMODE_NDELAY)) {
4061 if (mode & (FMODE_READ|FMODE_WRITE)) {
4062 UDRS->last_checked = 0;
4063 clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
4064 check_disk_change(bdev);
4065 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
4066 goto out;
4067 if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
4068 goto out;
4069 }
4070 res = -EROFS;
4071 if ((mode & FMODE_WRITE) &&
4072 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
4073 goto out;
4074 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004075 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004076 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 return 0;
4078out:
Jiri Kosinabfa10b82012-05-18 13:50:28 +02004079 UDRS->fd_ref--;
4080
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 if (!UDRS->fd_ref)
4082 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004084 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004085 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 return res;
4087}
4088
4089/*
4090 * Check if the disk has been changed or if a change has been faked.
4091 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004092static unsigned int floppy_check_events(struct gendisk *disk,
4093 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094{
4095 int drive = (long)disk->private_data;
4096
Joe Perchese0298532010-03-10 15:20:55 -08004097 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4098 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004099 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08004101 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01004102 if (lock_fdc(drive))
Yufen Yu489a9ab2019-01-29 16:34:04 +08004103 return 0;
Joe Perches74f63f42010-03-10 15:20:58 -08004104 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 }
4107
Joe Perchese0298532010-03-10 15:20:55 -08004108 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4109 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004111 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004112 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 return 0;
4114}
4115
4116/*
4117 * This implements "read block 0" for floppy_revalidate().
4118 * Needed for format autodetection, checking whether there is
4119 * a disk in the drive, and whether that disk is writable.
4120 */
4121
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004122struct rb0_cbdata {
4123 int drive;
4124 struct completion complete;
4125};
4126
Christoph Hellwig4246a0b2015-07-20 15:29:37 +02004127static void floppy_rb0_cb(struct bio *bio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128{
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004129 struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
4130 int drive = cbdata->drive;
4131
Christoph Hellwig4246a0b2015-07-20 15:29:37 +02004132 if (bio->bi_error) {
4133 pr_info("floppy: error %d while reading block 0\n",
4134 bio->bi_error);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004135 set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
4136 }
4137 complete(&cbdata->complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138}
4139
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004140static int __floppy_read_block_0(struct block_device *bdev, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141{
4142 struct bio bio;
4143 struct bio_vec bio_vec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 struct page *page;
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004145 struct rb0_cbdata cbdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 size_t size;
4147
4148 page = alloc_page(GFP_NOIO);
4149 if (!page) {
4150 process_fd_request();
4151 return -ENOMEM;
4152 }
4153
4154 size = bdev->bd_block_size;
4155 if (!size)
4156 size = 1024;
4157
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004158 cbdata.drive = drive;
4159
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 bio_init(&bio);
4161 bio.bi_io_vec = &bio_vec;
4162 bio_vec.bv_page = page;
4163 bio_vec.bv_len = size;
4164 bio_vec.bv_offset = 0;
4165 bio.bi_vcnt = 1;
Kent Overstreet4f024f32013-10-11 15:44:27 -07004166 bio.bi_iter.bi_size = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 bio.bi_bdev = bdev;
Kent Overstreet4f024f32013-10-11 15:44:27 -07004168 bio.bi_iter.bi_sector = 0;
Jiri Kosina6314a102014-05-28 11:55:23 +02004169 bio.bi_flags |= (1 << BIO_QUIET);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004170 bio.bi_private = &cbdata;
4171 bio.bi_end_io = floppy_rb0_cb;
Mike Christie95fe6c12016-06-05 14:31:48 -05004172 bio_set_op_attrs(&bio, REQ_OP_READ, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173
Jens Axboe03781eb2018-11-09 15:58:40 -07004174 init_completion(&cbdata.complete);
4175
Mike Christie4e49ea42016-06-05 14:31:41 -05004176 submit_bio(&bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 process_fd_request();
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004178
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004179 wait_for_completion(&cbdata.complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
4181 __free_page(page);
4182
4183 return 0;
4184}
4185
4186/* revalidate the floppy disk, i.e. trigger format autodetection by reading
4187 * the bootblock (block 0). "Autodetection" is also needed to check whether
4188 * there is a disk in the drive at all... Thus we also do it for fixed
4189 * geometry formats */
4190static int floppy_revalidate(struct gendisk *disk)
4191{
4192 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 int cf;
4194 int res = 0;
4195
Joe Perchese0298532010-03-10 15:20:55 -08004196 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4197 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004198 test_bit(drive, &fake_change) ||
4199 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02004200 if (WARN(atomic_read(&usage_count) == 0,
4201 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02004203
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01004204 res = lock_fdc(drive);
4205 if (res)
4206 return res;
Joe Perchese0298532010-03-10 15:20:55 -08004207 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4208 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004209 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 process_fd_request(); /*already done by another thread */
4211 return 0;
4212 }
4213 UDRS->maxblock = 0;
4214 UDRS->maxtrack = 0;
4215 if (buffer_drive == drive)
4216 buffer_track = -1;
4217 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08004218 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 if (cf)
4220 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004221 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 /* auto-sensing */
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004223 res = __floppy_read_block_0(opened_bdev[drive], drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 } else {
4225 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08004226 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 process_fd_request();
4228 }
4229 }
4230 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
4231 return res;
4232}
4233
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07004234static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07004235 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05004236 .open = floppy_open,
4237 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02004238 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07004239 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004240 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07004241 .revalidate_disk = floppy_revalidate,
Al Viro06f9e7b2017-06-27 15:47:56 -04004242#ifdef CONFIG_COMPAT
4243 .compat_ioctl = fd_compat_ioctl,
4244#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247/*
4248 * Floppy Driver initialization
4249 * =============================
4250 */
4251
4252/* Determine the floppy disk controller type */
4253/* This routine was written by David C. Niemi */
4254static char __init get_fdc_version(void)
4255{
4256 int r;
4257
4258 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
4259 if (FDCS->reset)
4260 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004261 r = result();
4262 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 return FDC_NONE; /* No FDC present ??? */
4264 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004265 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
4267 }
4268 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08004269 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
4270 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 return FDC_UNKNOWN;
4272 }
4273
4274 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08004275 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 return FDC_82072; /* 82072 doesn't know CONFIGURE */
4277 }
4278
4279 output_byte(FD_PERPENDICULAR);
4280 if (need_more_output() == MORE_OUTPUT) {
4281 output_byte(0);
4282 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08004283 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 return FDC_82072A; /* 82072A as found on Sparcs. */
4285 }
4286
4287 output_byte(FD_UNLOCK);
4288 r = result();
4289 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004290 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004291 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 * LOCK/UNLOCK */
4293 }
4294 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004295 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
4296 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 return FDC_UNKNOWN;
4298 }
4299 output_byte(FD_PARTID);
4300 r = result();
4301 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08004302 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
4303 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 return FDC_UNKNOWN;
4305 }
4306 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08004307 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 return FDC_82077; /* Revised 82077AA passes all the tests */
4309 }
4310 switch (reply_buffer[0] >> 5) {
4311 case 0x0:
4312 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08004313 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 return FDC_82078;
4315 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004316 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 return FDC_82078;
4318 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004319 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 return FDC_S82078B;
4321 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004322 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 return FDC_87306;
4324 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004325 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4326 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 return FDC_82078_UNKN;
4328 }
4329} /* get_fdc_version */
4330
4331/* lilo configuration */
4332
4333static void __init floppy_set_flags(int *ints, int param, int param2)
4334{
4335 int i;
4336
4337 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4338 if (param)
4339 default_drive_params[i].params.flags |= param2;
4340 else
4341 default_drive_params[i].params.flags &= ~param2;
4342 }
4343 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4344}
4345
4346static void __init daring(int *ints, int param, int param2)
4347{
4348 int i;
4349
4350 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4351 if (param) {
4352 default_drive_params[i].params.select_delay = 0;
4353 default_drive_params[i].params.flags |=
4354 FD_SILENT_DCL_CLEAR;
4355 } else {
4356 default_drive_params[i].params.select_delay =
4357 2 * HZ / 100;
4358 default_drive_params[i].params.flags &=
4359 ~FD_SILENT_DCL_CLEAR;
4360 }
4361 }
4362 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4363}
4364
4365static void __init set_cmos(int *ints, int dummy, int dummy2)
4366{
4367 int current_drive = 0;
4368
4369 if (ints[0] != 2) {
4370 DPRINT("wrong number of parameters for CMOS\n");
4371 return;
4372 }
4373 current_drive = ints[1];
4374 if (current_drive < 0 || current_drive >= 8) {
4375 DPRINT("bad drive for set_cmos\n");
4376 return;
4377 }
4378#if N_FDC > 1
4379 if (current_drive >= 4 && !FDC2)
4380 FDC2 = 0x370;
4381#endif
4382 DP->cmos = ints[2];
4383 DPRINT("setting CMOS code to %d\n", ints[2]);
4384}
4385
4386static struct param_table {
4387 const char *name;
4388 void (*fn) (int *ints, int param, int param2);
4389 int *var;
4390 int def_param;
4391 int param2;
4392} config_params[] __initdata = {
4393 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4394 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4395 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4396 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4397 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4398 {"daring", daring, NULL, 1, 0},
4399#if N_FDC > 1
4400 {"two_fdc", NULL, &FDC2, 0x370, 0},
4401 {"one_fdc", NULL, &FDC2, 0, 0},
4402#endif
4403 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4404 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4405 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4406 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4407 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4408 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4409 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4410 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4411 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4412 {"nofifo", NULL, &no_fifo, 0x20, 0},
4413 {"usefifo", NULL, &no_fifo, 0, 0},
4414 {"cmos", set_cmos, NULL, 0, 0},
4415 {"slow", NULL, &slow_floppy, 1, 0},
4416 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4417 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4418 {"L40SX", NULL, &print_unex, 0, 0}
4419
4420 EXTRA_FLOPPY_PARAMS
4421};
4422
4423static int __init floppy_setup(char *str)
4424{
4425 int i;
4426 int param;
4427 int ints[11];
4428
4429 str = get_options(str, ARRAY_SIZE(ints), ints);
4430 if (str) {
4431 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4432 if (strcmp(str, config_params[i].name) == 0) {
4433 if (ints[0])
4434 param = ints[1];
4435 else
4436 param = config_params[i].def_param;
4437 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004438 config_params[i].fn(ints, param,
4439 config_params[i].
4440 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 if (config_params[i].var) {
4442 DPRINT("%s=%d\n", str, param);
4443 *config_params[i].var = param;
4444 }
4445 return 1;
4446 }
4447 }
4448 }
4449 if (str) {
4450 DPRINT("unknown floppy option [%s]\n", str);
4451
4452 DPRINT("allowed options are:");
4453 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004454 pr_cont(" %s", config_params[i].name);
4455 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 } else
4457 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004458 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 return 0;
4460}
4461
4462static int have_no_fdc = -ENODEV;
4463
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004464static ssize_t floppy_cmos_show(struct device *dev,
4465 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004466{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004467 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004468 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004469
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004470 drive = p->id;
4471 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004472}
Joe Perches48c8cee2010-03-10 15:20:45 -08004473
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004474static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004475
Takashi Iwaib7f120b2015-02-02 17:08:45 +01004476static struct attribute *floppy_dev_attrs[] = {
4477 &dev_attr_cmos.attr,
4478 NULL
4479};
4480
4481ATTRIBUTE_GROUPS(floppy_dev);
4482
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483static void floppy_device_release(struct device *dev)
4484{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485}
4486
Frans Popc90cd332009-07-25 22:24:54 +02004487static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004488{
4489 int fdc;
4490
4491 for (fdc = 0; fdc < N_FDC; fdc++)
4492 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004493 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004494
4495 return 0;
4496}
4497
Alexey Dobriyan47145212009-12-14 18:00:08 -08004498static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004499 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004500 .restore = floppy_resume,
4501};
4502
4503static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004504 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004505 .name = "floppy",
4506 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004507 },
4508};
4509
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004510static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004512static bool floppy_available(int drive)
4513{
4514 if (!(allowed_drive_mask & (1 << drive)))
4515 return false;
4516 if (fdc_state[FDC(drive)].version == FDC_NONE)
4517 return false;
4518 return true;
4519}
4520
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4522{
4523 int drive = (*part & 3) | ((*part & 0x80) >> 5);
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004524 if (drive >= N_DRIVE || !floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004526 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 return NULL;
4528 *part = 0;
4529 return get_disk(disks[drive]);
4530}
4531
Andi Kleen0cc15d032012-07-02 17:27:04 -07004532static int __init do_floppy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533{
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004534 int i, unit, drive, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535
Stephen Hemminger285203c2010-06-15 13:21:11 +02004536 set_debugt();
4537 interruptjiffies = resultjiffies = jiffies;
4538
Kumar Gala68e1ee62008-09-22 14:41:31 -07004539#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004540 if (check_legacy_ioport(FDC1))
4541 return -ENODEV;
4542#endif
4543
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 raw_cmd = NULL;
4545
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004546 floppy_wq = alloc_ordered_workqueue("floppy", 0);
4547 if (!floppy_wq)
4548 return -ENOMEM;
4549
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004550 for (drive = 0; drive < N_DRIVE; drive++) {
4551 disks[drive] = alloc_disk(1);
4552 if (!disks[drive]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 err = -ENOMEM;
4554 goto out_put_disk;
4555 }
4556
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004557 disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4558 if (!disks[drive]->queue) {
Jens Axboe48821182010-09-22 09:32:36 +02004559 err = -ENOMEM;
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004560 goto out_put_disk;
Jens Axboe48821182010-09-22 09:32:36 +02004561 }
4562
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004563 blk_queue_max_hw_sectors(disks[drive]->queue, 64);
4564 disks[drive]->major = FLOPPY_MAJOR;
4565 disks[drive]->first_minor = TOMINOR(drive);
4566 disks[drive]->fops = &floppy_fops;
4567 sprintf(disks[drive]->disk_name, "fd%d", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004569 init_timer(&motor_off_timer[drive]);
4570 motor_off_timer[drive].data = drive;
4571 motor_off_timer[drive].function = motor_off_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 }
4573
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 err = register_blkdev(FLOPPY_MAJOR, "fd");
4575 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004576 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004578 err = platform_driver_register(&floppy_driver);
4579 if (err)
4580 goto out_unreg_blkdev;
4581
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4583 floppy_find, NULL, NULL);
4584
4585 for (i = 0; i < 256; i++)
4586 if (ITYPE(i))
4587 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4588 else
4589 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4590
Joe Perches73507e62010-03-10 15:21:03 -08004591 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 config_types();
4593
4594 for (i = 0; i < N_FDC; i++) {
4595 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004596 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 FDCS->dtr = -1;
4598 FDCS->dor = 0x4;
4599#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004600 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601#ifdef __mc68000__
4602 if (MACH_IS_SUN3X)
4603#endif
4604 FDCS->version = FDC_82072A;
4605#endif
4606 }
4607
4608 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 fdc_state[0].address = FDC1;
4610 if (fdc_state[0].address == -1) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004611 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 err = -ENODEV;
4613 goto out_unreg_region;
4614 }
4615#if N_FDC > 1
4616 fdc_state[1].address = FDC2;
4617#endif
4618
4619 fdc = 0; /* reset fdc in case of unexpected interrupt */
4620 err = floppy_grab_irq_and_dma();
4621 if (err) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004622 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 err = -EBUSY;
4624 goto out_unreg_region;
4625 }
4626
4627 /* initialise drive state */
4628 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004629 memset(UDRS, 0, sizeof(*UDRS));
4630 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004631 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4632 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4633 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 UDRS->fd_device = -1;
4635 floppy_track_buffer = NULL;
4636 max_buffer_sectors = 0;
4637 }
4638 /*
4639 * Small 10 msec delay to let through any interrupt that
4640 * initialization might have triggered, to not
4641 * confuse detection:
4642 */
4643 msleep(10);
4644
4645 for (i = 0; i < N_FDC; i++) {
4646 fdc = i;
4647 FDCS->driver_version = FD_DRIVER_VERSION;
4648 for (unit = 0; unit < 4; unit++)
4649 FDCS->track[unit] = 0;
4650 if (FDCS->address == -1)
4651 continue;
4652 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004653 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004655 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 FDCS->address = -1;
4657 FDCS->version = FDC_NONE;
4658 continue;
4659 }
4660 /* Try to determine the floppy controller type */
4661 FDCS->version = get_fdc_version();
4662 if (FDCS->version == FDC_NONE) {
4663 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004664 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 FDCS->address = -1;
4666 continue;
4667 }
4668 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4669 can_use_virtual_dma = 0;
4670
4671 have_no_fdc = 0;
4672 /* Not all FDCs seem to be able to handle the version command
4673 * properly, so force a reset for the standard FDC clones,
4674 * to avoid interrupt garbage.
4675 */
Joe Perches74f63f42010-03-10 15:20:58 -08004676 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 }
4678 fdc = 0;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004679 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004681 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 if (have_no_fdc) {
4683 DPRINT("no floppy controllers found\n");
4684 err = have_no_fdc;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004685 goto out_release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 }
4687
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 for (drive = 0; drive < N_DRIVE; drive++) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004689 if (!floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004691
4692 floppy_device[drive].name = floppy_device_name;
4693 floppy_device[drive].id = drive;
4694 floppy_device[drive].dev.release = floppy_device_release;
Takashi Iwaib7f120b2015-02-02 17:08:45 +01004695 floppy_device[drive].dev.groups = floppy_dev_groups;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004696
4697 err = platform_device_register(&floppy_device[drive]);
4698 if (err)
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004699 goto out_remove_drives;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004700
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 /* to be cleaned up... */
4702 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Dan Williams0d52c7562016-06-15 19:44:20 -07004704 device_add_disk(&floppy_device[drive].dev, disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 }
4706
4707 return 0;
4708
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004709out_remove_drives:
4710 while (drive--) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004711 if (floppy_available(drive)) {
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004712 del_gendisk(disks[drive]);
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004713 platform_device_unregister(&floppy_device[drive]);
4714 }
4715 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004716out_release_dma:
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004717 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 floppy_release_irq_and_dma();
4719out_unreg_region:
4720 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004721 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722out_unreg_blkdev:
4723 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724out_put_disk:
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004725 destroy_workqueue(floppy_wq);
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004726 for (drive = 0; drive < N_DRIVE; drive++) {
4727 if (!disks[drive])
4728 break;
4729 if (disks[drive]->queue) {
4730 del_timer_sync(&motor_off_timer[drive]);
4731 blk_cleanup_queue(disks[drive]->queue);
4732 disks[drive]->queue = NULL;
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004733 }
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004734 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 }
4736 return err;
4737}
4738
Andi Kleen0cc15d032012-07-02 17:27:04 -07004739#ifndef MODULE
4740static __init void floppy_async_init(void *data, async_cookie_t cookie)
4741{
4742 do_floppy_init();
4743}
4744#endif
4745
4746static int __init floppy_init(void)
4747{
4748#ifdef MODULE
4749 return do_floppy_init();
4750#else
4751 /* Don't hold up the bootup by the floppy initialization */
4752 async_schedule(floppy_async_init, NULL);
4753 return 0;
4754#endif
4755}
4756
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004757static const struct io_region {
4758 int offset;
4759 int size;
4760} io_regions[] = {
4761 { 2, 1 },
4762 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4763 { 4, 2 },
4764 /* address + 6 is reserved, and may be taken by IDE.
4765 * Unfortunately, Adaptec doesn't know this :-(, */
4766 { 7, 1 },
4767};
4768
4769static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4770{
4771 while (p != io_regions) {
4772 p--;
4773 release_region(FDCS->address + p->offset, p->size);
4774 }
4775}
4776
4777#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4778
4779static int floppy_request_regions(int fdc)
4780{
4781 const struct io_region *p;
4782
4783 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004784 if (!request_region(FDCS->address + p->offset,
4785 p->size, "floppy")) {
4786 DPRINT("Floppy io-port 0x%04lx in use\n",
4787 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004788 floppy_release_allocated_regions(fdc, p);
4789 return -EBUSY;
4790 }
4791 }
4792 return 0;
4793}
4794
4795static void floppy_release_regions(int fdc)
4796{
4797 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4798}
4799
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800static int floppy_grab_irq_and_dma(void)
4801{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004802 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004804
4805 /*
4806 * We might have scheduled a free_irq(), wait it to
4807 * drain first:
4808 */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004809 flush_workqueue(floppy_wq);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004810
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 if (fd_request_irq()) {
4812 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4813 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004814 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 return -1;
4816 }
4817 if (fd_request_dma()) {
4818 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4819 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004820 if (can_use_virtual_dma & 2)
4821 use_virtual_dma = can_use_virtual_dma = 1;
4822 if (!(can_use_virtual_dma & 1)) {
4823 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004824 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004825 return -1;
4826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 }
4828
4829 for (fdc = 0; fdc < N_FDC; fdc++) {
4830 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004831 if (floppy_request_regions(fdc))
4832 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 }
4834 }
4835 for (fdc = 0; fdc < N_FDC; fdc++) {
4836 if (FDCS->address != -1) {
4837 reset_fdc_info(1);
4838 fd_outb(FDCS->dor, FD_DOR);
4839 }
4840 }
4841 fdc = 0;
4842 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4843
4844 for (fdc = 0; fdc < N_FDC; fdc++)
4845 if (FDCS->address != -1)
4846 fd_outb(FDCS->dor, FD_DOR);
4847 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004848 * The driver will try and free resources and relies on us
4849 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 */
4851 fdc = 0;
4852 irqdma_allocated = 1;
4853 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004854cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 fd_free_irq();
4856 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004857 while (--fdc >= 0)
4858 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004859 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 return -1;
4861}
4862
4863static void floppy_release_irq_and_dma(void)
4864{
4865 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866#ifndef __sparc__
4867 int drive;
4868#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 long tmpsize;
4870 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004872 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004874
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 if (irqdma_allocated) {
4876 fd_disable_dma();
4877 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004878 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 irqdma_allocated = 0;
4880 }
4881 set_dor(0, ~0, 8);
4882#if N_FDC > 1
4883 set_dor(1, ~8, 0);
4884#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885
4886 if (floppy_track_buffer && max_buffer_sectors) {
4887 tmpsize = max_buffer_sectors * 1024;
4888 tmpaddr = (unsigned long)floppy_track_buffer;
4889 floppy_track_buffer = NULL;
4890 max_buffer_sectors = 0;
4891 buffer_min = buffer_max = -1;
4892 fd_dma_mem_free(tmpaddr, tmpsize);
4893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894#ifndef __sparc__
4895 for (drive = 0; drive < N_FDC * 4; drive++)
4896 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004897 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898#endif
4899
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004900 if (delayed_work_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004901 pr_info("floppy timer still active:%s\n", timeout_message);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004902 if (delayed_work_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004903 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004904 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004905 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 old_fdc = fdc;
4907 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004908 if (FDCS->address != -1)
4909 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 fdc = old_fdc;
4911}
4912
4913#ifdef MODULE
4914
4915static char *floppy;
4916
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917static void __init parse_floppy_cfg_string(char *cfg)
4918{
4919 char *ptr;
4920
4921 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004922 ptr = cfg;
4923 while (*cfg && *cfg != ' ' && *cfg != '\t')
4924 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 if (*cfg) {
4926 *cfg = '\0';
4927 cfg++;
4928 }
4929 if (*ptr)
4930 floppy_setup(ptr);
4931 }
4932}
4933
Jon Schindler7afea3b2008-04-29 00:59:21 -07004934static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935{
4936 if (floppy)
4937 parse_floppy_cfg_string(floppy);
4938 return floppy_init();
4939}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004940module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941
Jon Schindler7afea3b2008-04-29 00:59:21 -07004942static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943{
4944 int drive;
4945
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4947 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004948 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004950 destroy_workqueue(floppy_wq);
4951
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 for (drive = 0; drive < N_DRIVE; drive++) {
4953 del_timer_sync(&motor_off_timer[drive]);
4954
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004955 if (floppy_available(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004957 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958 }
Jens Axboe48821182010-09-22 09:32:36 +02004959 blk_cleanup_queue(disks[drive]->queue);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004960
4961 /*
4962 * These disks have not called add_disk(). Don't put down
4963 * queue reference in put_disk().
4964 */
4965 if (!(allowed_drive_mask & (1 << drive)) ||
4966 fdc_state[FDC(drive)].version == FDC_NONE)
4967 disks[drive]->queue = NULL;
4968
Vivek Goyald017bf62010-11-06 08:16:05 -04004969 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004972 cancel_delayed_work_sync(&fd_timeout);
4973 cancel_delayed_work_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004975 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 floppy_release_irq_and_dma();
4977
4978 /* eject disk, if any */
4979 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980}
Joe Perches48c8cee2010-03-10 15:20:45 -08004981
Jon Schindler7afea3b2008-04-29 00:59:21 -07004982module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983
4984module_param(floppy, charp, 0);
4985module_param(FLOPPY_IRQ, int, 0);
4986module_param(FLOPPY_DMA, int, 0);
4987MODULE_AUTHOR("Alain L. Knaff");
4988MODULE_SUPPORTED_DEVICE("fd");
4989MODULE_LICENSE("GPL");
4990
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004991/* This doesn't actually get used other than for module information */
4992static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004993 {"PNP0700", 0},
4994 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004995};
Joe Perches48c8cee2010-03-10 15:20:45 -08004996
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004997MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4998
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999#else
5000
5001__setup("floppy=", floppy_setup);
5002module_init(floppy_init)
5003#endif
5004
5005MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);