blob: ece4f706b38fb89732bcdf072c9266952f93cfca [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. */
Denis Efremov1fdefbb2019-07-12 21:55:23 +03003240 if ((int)g->sect <= 0 ||
3241 (int)g->head <= 0 ||
3242 /* check for overflow in max_sector */
3243 (int)(g->sect * g->head) <= 0 ||
Denis Efremov604206c2019-07-12 21:55:20 +03003244 /* check for zero in F_SECT_PER_TRACK */
3245 (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3247 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003248 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 return -EINVAL;
3250 if (type) {
3251 if (!capable(CAP_SYS_ADMIN))
3252 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003253 mutex_lock(&open_lock);
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003254 if (lock_fdc(drive)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003255 mutex_unlock(&open_lock);
3256 return -EINTR;
3257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 floppy_type[type] = *g;
3259 floppy_type[type].name = "user format";
3260 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3261 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3262 floppy_type[type].size + 1;
3263 process_fd_request();
3264 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3265 struct block_device *bdev = opened_bdev[cnt];
3266 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3267 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003268 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003270 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 } else {
3272 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003273
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003274 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003275 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003276 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 /* notice a disk change immediately, else
3278 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003279 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003280 return -EINTR;
3281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 oldStretch = g->stretch;
3283 user_params[drive] = *g;
3284 if (buffer_drive == drive)
3285 SUPBOUND(buffer_max, user_params[drive].sect);
3286 current_type[drive] = &user_params[drive];
3287 floppy_sizes[drive] = user_params[drive].size;
3288 if (cmd == FDDEFPRM)
3289 DRS->keep_data = -1;
3290 else
3291 DRS->keep_data = 1;
3292 /* invalidation. Invalidate only when needed, i.e.
3293 * when there are already sectors in the buffer cache
3294 * whose number will change. This is useful, because
3295 * mtools often changes the geometry of the disk after
3296 * looking at the boot block */
3297 if (DRS->maxblock > user_params[drive].sect ||
3298 DRS->maxtrack ||
3299 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003300 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 invalidate_drive(bdev);
3302 else
3303 process_fd_request();
3304 }
3305 return 0;
3306}
3307
3308/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003309static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 FDCLRPRM,
3311 FDSETPRM,
3312 FDDEFPRM,
3313 FDGETPRM,
3314 FDMSGON,
3315 FDMSGOFF,
3316 FDFMTBEG,
3317 FDFMTTRK,
3318 FDFMTEND,
3319 FDSETEMSGTRESH,
3320 FDFLUSH,
3321 FDSETMAXERRS,
3322 FDGETMAXERRS,
3323 FDGETDRVTYP,
3324 FDSETDRVPRM,
3325 FDGETDRVPRM,
3326 FDGETDRVSTAT,
3327 FDPOLLDRVSTAT,
3328 FDRESET,
3329 FDGETFDCSTAT,
3330 FDWERRORCLR,
3331 FDWERRORGET,
3332 FDRAWCMD,
3333 FDEJECT,
3334 FDTWADDLE
3335};
3336
Stephen Hemminger21af5442010-06-15 13:21:11 +02003337static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338{
3339 int i;
3340
3341 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3342 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3343 *size = _IOC_SIZE(*cmd);
3344 *cmd = ioctl_table[i];
3345 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003346 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 return -EFAULT;
3348 }
3349 return 0;
3350 }
3351 }
3352 return -EINVAL;
3353}
3354
3355static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3356{
3357 if (type)
3358 *g = &floppy_type[type];
3359 else {
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003360 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003361 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003362 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003363 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 process_fd_request();
3365 *g = current_type[drive];
3366 }
3367 if (!*g)
3368 return -ENODEV;
3369 return 0;
3370}
3371
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003372static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3373{
3374 int drive = (long)bdev->bd_disk->private_data;
3375 int type = ITYPE(drive_state[drive].fd_device);
3376 struct floppy_struct *g;
3377 int ret;
3378
3379 ret = get_floppy_geometry(drive, type, &g);
3380 if (ret)
3381 return ret;
3382
3383 geo->heads = g->head;
3384 geo->sectors = g->sect;
3385 geo->cylinders = g->track;
3386 return 0;
3387}
3388
Denis Efremov5d6d6392019-07-12 21:55:22 +03003389static bool valid_floppy_drive_params(const short autodetect[8],
3390 int native_format)
Denis Efremov93f89552019-07-12 21:55:21 +03003391{
3392 size_t floppy_type_size = ARRAY_SIZE(floppy_type);
3393 size_t i = 0;
3394
3395 for (i = 0; i < 8; ++i) {
3396 if (autodetect[i] < 0 ||
3397 autodetect[i] >= floppy_type_size)
3398 return false;
3399 }
3400
Denis Efremov5d6d6392019-07-12 21:55:22 +03003401 if (native_format < 0 || native_format >= floppy_type_size)
3402 return false;
3403
Denis Efremov93f89552019-07-12 21:55:21 +03003404 return true;
3405}
3406
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003407static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 unsigned long param)
3409{
Al Viroa4af9b42008-03-02 09:27:55 -05003410 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003411 int type = ITYPE(UDRS->fd_device);
3412 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 int ret;
3414 int size;
3415 union inparam {
3416 struct floppy_struct g; /* geometry */
3417 struct format_descr f;
3418 struct floppy_max_errors max_errors;
3419 struct floppy_drive_params dp;
3420 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003421 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422
3423 /* convert compatibility eject ioctls into floppy eject ioctl.
3424 * We do this in order to provide a means to eject floppy disks before
3425 * installing the new fdutils package */
3426 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003427 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 DPRINT("obsolete eject ioctl\n");
3429 DPRINT("please use floppycontrol --eject\n");
3430 cmd = FDEJECT;
3431 }
3432
Joe Perchesa81ee542010-03-10 15:20:46 -08003433 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 return -EINVAL;
3435
Joe Perchesa81ee542010-03-10 15:20:46 -08003436 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003437 ret = normalize_ioctl(&cmd, &size);
3438 if (ret)
3439 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003440
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003442 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3444 return -EPERM;
3445
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003446 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3447 return -EINVAL;
3448
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003450 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003451 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3452 ret = fd_copyin((void __user *)param, &inparam, size);
3453 if (ret)
3454 return ret;
3455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
Joe Perchesda273652010-03-10 15:20:52 -08003457 switch (cmd) {
3458 case FDEJECT:
3459 if (UDRS->fd_ref != 1)
3460 /* somebody else has this drive open */
3461 return -EBUSY;
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003462 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003463 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
Joe Perchesda273652010-03-10 15:20:52 -08003465 /* do the actual eject. Fails on
3466 * non-Sparc architectures */
3467 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468
Joe Perchese0298532010-03-10 15:20:55 -08003469 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3470 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003471 process_fd_request();
3472 return ret;
3473 case FDCLRPRM:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003474 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003475 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003476 current_type[drive] = NULL;
3477 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3478 UDRS->keep_data = 0;
3479 return invalidate_drive(bdev);
3480 case FDSETPRM:
3481 case FDDEFPRM:
3482 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3483 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003484 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003485 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003486 if (ret)
3487 return ret;
Andy Whitcroft3da4db12018-09-20 09:09:48 -06003488 memcpy(&inparam.g, outparam,
3489 offsetof(struct floppy_struct, name));
3490 outparam = &inparam.g;
Joe Perchesda273652010-03-10 15:20:52 -08003491 break;
3492 case FDMSGON:
3493 UDP->flags |= FTD_MSG;
3494 return 0;
3495 case FDMSGOFF:
3496 UDP->flags &= ~FTD_MSG;
3497 return 0;
3498 case FDFMTBEG:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003499 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003500 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003501 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003502 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003503 ret = UDRS->flags;
3504 process_fd_request();
3505 if (ret & FD_VERIFY)
3506 return -ENODEV;
3507 if (!(ret & FD_DISK_WRITABLE))
3508 return -EROFS;
3509 return 0;
3510 case FDFMTTRK:
3511 if (UDRS->fd_ref != 1)
3512 return -EBUSY;
3513 return do_format(drive, &inparam.f);
3514 case FDFMTEND:
3515 case FDFLUSH:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003516 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003517 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003518 return invalidate_drive(bdev);
3519 case FDSETEMSGTRESH:
3520 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3521 return 0;
3522 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003523 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003524 break;
3525 case FDSETMAXERRS:
3526 UDP->max_errors = inparam.max_errors;
3527 break;
3528 case FDGETDRVTYP:
3529 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003530 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003531 break;
3532 case FDSETDRVPRM:
Denis Efremov5d6d6392019-07-12 21:55:22 +03003533 if (!valid_floppy_drive_params(inparam.dp.autodetect,
3534 inparam.dp.native_format))
Denis Efremov93f89552019-07-12 21:55:21 +03003535 return -EINVAL;
Joe Perchesda273652010-03-10 15:20:52 -08003536 *UDP = inparam.dp;
3537 break;
3538 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003539 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003540 break;
3541 case FDPOLLDRVSTAT:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003542 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003543 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003544 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003545 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003546 process_fd_request();
3547 /* fall through */
3548 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003549 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003550 break;
3551 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003552 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003553 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003554 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003555 break;
3556 case FDWERRORCLR:
3557 memset(UDRWE, 0, sizeof(*UDRWE));
3558 return 0;
3559 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003560 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003561 break;
3562 case FDRAWCMD:
3563 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 return -EINVAL;
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003565 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003566 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003567 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003568 i = raw_cmd_ioctl(cmd, (void __user *)param);
3569 if (i == -EINTR)
3570 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003571 process_fd_request();
3572 return i;
3573 case FDTWADDLE:
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01003574 if (lock_fdc(drive))
Joe Perches52a0d612010-03-10 15:20:53 -08003575 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003576 twaddle();
3577 process_fd_request();
3578 return 0;
3579 default:
3580 return -EINVAL;
3581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
3583 if (_IOC_DIR(cmd) & _IOC_READ)
3584 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003585
3586 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587}
3588
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003589static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3590 unsigned int cmd, unsigned long param)
3591{
3592 int ret;
3593
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003594 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003595 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003596 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003597
3598 return ret;
3599}
3600
Al Viro06f9e7b2017-06-27 15:47:56 -04003601#ifdef CONFIG_COMPAT
3602
3603struct compat_floppy_drive_params {
3604 char cmos;
3605 compat_ulong_t max_dtr;
3606 compat_ulong_t hlt;
3607 compat_ulong_t hut;
3608 compat_ulong_t srt;
3609 compat_ulong_t spinup;
3610 compat_ulong_t spindown;
3611 unsigned char spindown_offset;
3612 unsigned char select_delay;
3613 unsigned char rps;
3614 unsigned char tracks;
3615 compat_ulong_t timeout;
3616 unsigned char interleave_sect;
3617 struct floppy_max_errors max_errors;
3618 char flags;
3619 char read_track;
3620 short autodetect[8];
3621 compat_int_t checkfreq;
3622 compat_int_t native_format;
3623};
3624
3625struct compat_floppy_drive_struct {
3626 signed char flags;
3627 compat_ulong_t spinup_date;
3628 compat_ulong_t select_date;
3629 compat_ulong_t first_read_date;
3630 short probed_format;
3631 short track;
3632 short maxblock;
3633 short maxtrack;
3634 compat_int_t generation;
3635 compat_int_t keep_data;
3636 compat_int_t fd_ref;
3637 compat_int_t fd_device;
3638 compat_int_t last_checked;
3639 compat_caddr_t dmabuf;
3640 compat_int_t bufblocks;
3641};
3642
3643struct compat_floppy_fdc_state {
3644 compat_int_t spec1;
3645 compat_int_t spec2;
3646 compat_int_t dtr;
3647 unsigned char version;
3648 unsigned char dor;
3649 compat_ulong_t address;
3650 unsigned int rawcmd:2;
3651 unsigned int reset:1;
3652 unsigned int need_configure:1;
3653 unsigned int perp_mode:2;
3654 unsigned int has_fifo:1;
3655 unsigned int driver_version;
3656 unsigned char track[4];
3657};
3658
3659struct compat_floppy_write_errors {
3660 unsigned int write_errors;
3661 compat_ulong_t first_error_sector;
3662 compat_int_t first_error_generation;
3663 compat_ulong_t last_error_sector;
3664 compat_int_t last_error_generation;
3665 compat_uint_t badness;
3666};
3667
3668#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
3669#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
3670#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
3671#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
3672#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
3673#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
3674#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
3675#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
3676
3677static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3678 struct compat_floppy_struct __user *arg)
3679{
3680 struct floppy_struct v;
3681 int drive, type;
3682 int err;
3683
3684 BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
3685 offsetof(struct compat_floppy_struct, name));
3686
3687 if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
3688 return -EPERM;
3689
3690 memset(&v, 0, sizeof(struct floppy_struct));
3691 if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
3692 return -EFAULT;
3693
3694 mutex_lock(&floppy_mutex);
3695 drive = (long)bdev->bd_disk->private_data;
3696 type = ITYPE(UDRS->fd_device);
3697 err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
3698 &v, drive, type, bdev);
3699 mutex_unlock(&floppy_mutex);
3700 return err;
3701}
3702
3703static int compat_get_prm(int drive,
3704 struct compat_floppy_struct __user *arg)
3705{
3706 struct compat_floppy_struct v;
3707 struct floppy_struct *p;
3708 int err;
3709
3710 memset(&v, 0, sizeof(v));
3711 mutex_lock(&floppy_mutex);
3712 err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
3713 if (err) {
3714 mutex_unlock(&floppy_mutex);
3715 return err;
3716 }
3717 memcpy(&v, p, offsetof(struct floppy_struct, name));
3718 mutex_unlock(&floppy_mutex);
3719 if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
3720 return -EFAULT;
3721 return 0;
3722}
3723
3724static int compat_setdrvprm(int drive,
3725 struct compat_floppy_drive_params __user *arg)
3726{
3727 struct compat_floppy_drive_params v;
3728
3729 if (!capable(CAP_SYS_ADMIN))
3730 return -EPERM;
3731 if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
3732 return -EFAULT;
Denis Efremov5d6d6392019-07-12 21:55:22 +03003733 if (!valid_floppy_drive_params(v.autodetect, v.native_format))
Denis Efremov93f89552019-07-12 21:55:21 +03003734 return -EINVAL;
Al Viro06f9e7b2017-06-27 15:47:56 -04003735 mutex_lock(&floppy_mutex);
3736 UDP->cmos = v.cmos;
3737 UDP->max_dtr = v.max_dtr;
3738 UDP->hlt = v.hlt;
3739 UDP->hut = v.hut;
3740 UDP->srt = v.srt;
3741 UDP->spinup = v.spinup;
3742 UDP->spindown = v.spindown;
3743 UDP->spindown_offset = v.spindown_offset;
3744 UDP->select_delay = v.select_delay;
3745 UDP->rps = v.rps;
3746 UDP->tracks = v.tracks;
3747 UDP->timeout = v.timeout;
3748 UDP->interleave_sect = v.interleave_sect;
3749 UDP->max_errors = v.max_errors;
3750 UDP->flags = v.flags;
3751 UDP->read_track = v.read_track;
3752 memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
3753 UDP->checkfreq = v.checkfreq;
3754 UDP->native_format = v.native_format;
3755 mutex_unlock(&floppy_mutex);
3756 return 0;
3757}
3758
3759static int compat_getdrvprm(int drive,
3760 struct compat_floppy_drive_params __user *arg)
3761{
3762 struct compat_floppy_drive_params v;
3763
3764 memset(&v, 0, sizeof(struct compat_floppy_drive_params));
3765 mutex_lock(&floppy_mutex);
3766 v.cmos = UDP->cmos;
3767 v.max_dtr = UDP->max_dtr;
3768 v.hlt = UDP->hlt;
3769 v.hut = UDP->hut;
3770 v.srt = UDP->srt;
3771 v.spinup = UDP->spinup;
3772 v.spindown = UDP->spindown;
3773 v.spindown_offset = UDP->spindown_offset;
3774 v.select_delay = UDP->select_delay;
3775 v.rps = UDP->rps;
3776 v.tracks = UDP->tracks;
3777 v.timeout = UDP->timeout;
3778 v.interleave_sect = UDP->interleave_sect;
3779 v.max_errors = UDP->max_errors;
3780 v.flags = UDP->flags;
3781 v.read_track = UDP->read_track;
3782 memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
3783 v.checkfreq = UDP->checkfreq;
3784 v.native_format = UDP->native_format;
3785 mutex_unlock(&floppy_mutex);
3786
Jann Horne07fb662019-03-26 23:03:48 +01003787 if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
Al Viro06f9e7b2017-06-27 15:47:56 -04003788 return -EFAULT;
3789 return 0;
3790}
3791
3792static int compat_getdrvstat(int drive, bool poll,
3793 struct compat_floppy_drive_struct __user *arg)
3794{
3795 struct compat_floppy_drive_struct v;
3796
3797 memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
3798 mutex_lock(&floppy_mutex);
3799
3800 if (poll) {
3801 if (lock_fdc(drive))
3802 goto Eintr;
3803 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
3804 goto Eintr;
3805 process_fd_request();
3806 }
3807 v.spinup_date = UDRS->spinup_date;
3808 v.select_date = UDRS->select_date;
3809 v.first_read_date = UDRS->first_read_date;
3810 v.probed_format = UDRS->probed_format;
3811 v.track = UDRS->track;
3812 v.maxblock = UDRS->maxblock;
3813 v.maxtrack = UDRS->maxtrack;
3814 v.generation = UDRS->generation;
3815 v.keep_data = UDRS->keep_data;
3816 v.fd_ref = UDRS->fd_ref;
3817 v.fd_device = UDRS->fd_device;
3818 v.last_checked = UDRS->last_checked;
3819 v.dmabuf = (uintptr_t)UDRS->dmabuf;
3820 v.bufblocks = UDRS->bufblocks;
3821 mutex_unlock(&floppy_mutex);
3822
Jann Horne07fb662019-03-26 23:03:48 +01003823 if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
Al Viro06f9e7b2017-06-27 15:47:56 -04003824 return -EFAULT;
3825 return 0;
3826Eintr:
3827 mutex_unlock(&floppy_mutex);
3828 return -EINTR;
3829}
3830
3831static int compat_getfdcstat(int drive,
3832 struct compat_floppy_fdc_state __user *arg)
3833{
3834 struct compat_floppy_fdc_state v32;
3835 struct floppy_fdc_state v;
3836
3837 mutex_lock(&floppy_mutex);
3838 v = *UFDCS;
3839 mutex_unlock(&floppy_mutex);
3840
3841 memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
3842 v32.spec1 = v.spec1;
3843 v32.spec2 = v.spec2;
3844 v32.dtr = v.dtr;
3845 v32.version = v.version;
3846 v32.dor = v.dor;
3847 v32.address = v.address;
3848 v32.rawcmd = v.rawcmd;
3849 v32.reset = v.reset;
3850 v32.need_configure = v.need_configure;
3851 v32.perp_mode = v.perp_mode;
3852 v32.has_fifo = v.has_fifo;
3853 v32.driver_version = v.driver_version;
3854 memcpy(v32.track, v.track, 4);
3855 if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
3856 return -EFAULT;
3857 return 0;
3858}
3859
3860static int compat_werrorget(int drive,
3861 struct compat_floppy_write_errors __user *arg)
3862{
3863 struct compat_floppy_write_errors v32;
3864 struct floppy_write_errors v;
3865
3866 memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
3867 mutex_lock(&floppy_mutex);
3868 v = *UDRWE;
3869 mutex_unlock(&floppy_mutex);
3870 v32.write_errors = v.write_errors;
3871 v32.first_error_sector = v.first_error_sector;
3872 v32.first_error_generation = v.first_error_generation;
3873 v32.last_error_sector = v.last_error_sector;
3874 v32.last_error_generation = v.last_error_generation;
3875 v32.badness = v.badness;
3876 if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
3877 return -EFAULT;
3878 return 0;
3879}
3880
3881static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3882 unsigned long param)
3883{
3884 int drive = (long)bdev->bd_disk->private_data;
3885 switch (cmd) {
3886 case FDMSGON:
3887 case FDMSGOFF:
3888 case FDSETEMSGTRESH:
3889 case FDFLUSH:
3890 case FDWERRORCLR:
3891 case FDEJECT:
3892 case FDCLRPRM:
3893 case FDFMTBEG:
3894 case FDRESET:
3895 case FDTWADDLE:
3896 return fd_ioctl(bdev, mode, cmd, param);
3897 case FDSETMAXERRS:
3898 case FDGETMAXERRS:
3899 case FDGETDRVTYP:
3900 case FDFMTEND:
3901 case FDFMTTRK:
3902 case FDRAWCMD:
3903 return fd_ioctl(bdev, mode, cmd,
3904 (unsigned long)compat_ptr(param));
3905 case FDSETPRM32:
3906 case FDDEFPRM32:
3907 return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
3908 case FDGETPRM32:
3909 return compat_get_prm(drive, compat_ptr(param));
3910 case FDSETDRVPRM32:
3911 return compat_setdrvprm(drive, compat_ptr(param));
3912 case FDGETDRVPRM32:
3913 return compat_getdrvprm(drive, compat_ptr(param));
3914 case FDPOLLDRVSTAT32:
3915 return compat_getdrvstat(drive, true, compat_ptr(param));
3916 case FDGETDRVSTAT32:
3917 return compat_getdrvstat(drive, false, compat_ptr(param));
3918 case FDGETFDCSTAT32:
3919 return compat_getfdcstat(drive, compat_ptr(param));
3920 case FDWERRORGET32:
3921 return compat_werrorget(drive, compat_ptr(param));
3922 }
3923 return -EINVAL;
3924}
3925#endif
3926
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927static void __init config_types(void)
3928{
Joe Perchesb46df352010-03-10 15:20:46 -08003929 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 int drive;
3931
3932 /* read drive info out of physical CMOS */
3933 drive = 0;
3934 if (!UDP->cmos)
3935 UDP->cmos = FLOPPY0_TYPE;
3936 drive = 1;
3937 if (!UDP->cmos && FLOPPY1_TYPE)
3938 UDP->cmos = FLOPPY1_TYPE;
3939
Jesper Juhl06f748c2007-10-16 23:30:57 -07003940 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941
3942 for (drive = 0; drive < N_DRIVE; drive++) {
3943 unsigned int type = UDP->cmos;
3944 struct floppy_drive_params *params;
3945 const char *name = NULL;
Rasmus Villemoesbcf42992015-12-01 15:54:01 +01003946 char temparea[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947
Tobias Klauser945f3902006-01-08 01:05:11 -08003948 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 params = &default_drive_params[type].params;
3950 if (type) {
3951 name = default_drive_params[type].name;
3952 allowed_drive_mask |= 1 << drive;
3953 } else
3954 allowed_drive_mask &= ~(1 << drive);
3955 } else {
3956 params = &default_drive_params[0].params;
Rasmus Villemoesbcf42992015-12-01 15:54:01 +01003957 snprintf(temparea, sizeof(temparea),
3958 "unknown type %d (usb?)", type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 name = temparea;
3960 }
3961 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003962 const char *prepend;
3963 if (!has_drive) {
3964 prepend = "";
3965 has_drive = true;
3966 pr_info("Floppy drive(s):");
3967 } else {
3968 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 }
Joe Perchesb46df352010-03-10 15:20:46 -08003970
3971 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 }
3973 *UDP = *params;
3974 }
Joe Perchesb46df352010-03-10 15:20:46 -08003975
3976 if (has_drive)
3977 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978}
3979
Al Virodb2a1442013-05-05 21:52:57 -04003980static void floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981{
Al Viroa4af9b42008-03-02 09:27:55 -05003982 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003984 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003985 mutex_lock(&open_lock);
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003986 if (!UDRS->fd_ref--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 DPRINT("floppy_release with fd_ref == 0");
3988 UDRS->fd_ref = 0;
3989 }
3990 if (!UDRS->fd_ref)
3991 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003992 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003993 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994}
3995
3996/*
3997 * floppy_open check for aliasing (/dev/fd0 can be the same as
3998 * /dev/PS0 etc), and disallows simultaneous access to the same
3999 * drive with different device numbers.
4000 */
Al Viroa4af9b42008-03-02 09:27:55 -05004001static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002{
Al Viroa4af9b42008-03-02 09:27:55 -05004003 int drive = (long)bdev->bd_disk->private_data;
4004 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 int try;
4006 int res = -EBUSY;
4007 char *tmp;
4008
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004009 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004010 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05004012 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 goto out2;
4014
4015 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08004016 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4017 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 }
4019
Jiri Kosinabfa10b82012-05-18 13:50:28 +02004020 UDRS->fd_ref++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021
Al Viroa4af9b42008-03-02 09:27:55 -05004022 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023
4024 res = -ENXIO;
4025
4026 if (!floppy_track_buffer) {
4027 /* if opening an ED drive, reserve a big buffer,
4028 * else reserve a small one */
4029 if ((UDP->cmos == 6) || (UDP->cmos == 5))
4030 try = 64; /* Only 48 actually useful */
4031 else
4032 try = 32; /* Only 24 actually useful */
4033
4034 tmp = (char *)fd_dma_mem_alloc(1024 * try);
4035 if (!tmp && !floppy_track_buffer) {
4036 try >>= 1; /* buffer only one side */
4037 INFBOUND(try, 16);
4038 tmp = (char *)fd_dma_mem_alloc(1024 * try);
4039 }
Joe Perchesa81ee542010-03-10 15:20:46 -08004040 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 if (!tmp && !floppy_track_buffer) {
4043 DPRINT("Unable to allocate DMA memory\n");
4044 goto out;
4045 }
4046 if (floppy_track_buffer) {
4047 if (tmp)
4048 fd_dma_mem_free((unsigned long)tmp, try * 1024);
4049 } else {
4050 buffer_min = buffer_max = -1;
4051 floppy_track_buffer = tmp;
4052 max_buffer_sectors = try;
4053 }
4054 }
4055
Al Viroa4af9b42008-03-02 09:27:55 -05004056 new_dev = MINOR(bdev->bd_dev);
4057 UDRS->fd_device = new_dev;
4058 set_capacity(disks[drive], floppy_sizes[new_dev]);
4059 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 if (buffer_drive == drive)
4061 buffer_track = -1;
4062 }
4063
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 if (UFDCS->rawcmd == 1)
4065 UFDCS->rawcmd = 2;
4066
Jens Axboef2791e72016-08-25 08:56:51 -06004067 if (!(mode & FMODE_NDELAY)) {
4068 if (mode & (FMODE_READ|FMODE_WRITE)) {
4069 UDRS->last_checked = 0;
4070 clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
4071 check_disk_change(bdev);
4072 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
4073 goto out;
4074 if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
4075 goto out;
4076 }
4077 res = -EROFS;
4078 if ((mode & FMODE_WRITE) &&
4079 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
4080 goto out;
4081 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004082 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004083 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 return 0;
4085out:
Jiri Kosinabfa10b82012-05-18 13:50:28 +02004086 UDRS->fd_ref--;
4087
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 if (!UDRS->fd_ref)
4089 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08004091 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02004092 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093 return res;
4094}
4095
4096/*
4097 * Check if the disk has been changed or if a change has been faked.
4098 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004099static unsigned int floppy_check_events(struct gendisk *disk,
4100 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101{
4102 int drive = (long)disk->private_data;
4103
Joe Perchese0298532010-03-10 15:20:55 -08004104 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4105 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004106 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08004108 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01004109 if (lock_fdc(drive))
Yufen Yu489a9ab2019-01-29 16:34:04 +08004110 return 0;
Joe Perches74f63f42010-03-10 15:20:58 -08004111 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 }
4114
Joe Perchese0298532010-03-10 15:20:55 -08004115 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4116 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004118 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004119 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 return 0;
4121}
4122
4123/*
4124 * This implements "read block 0" for floppy_revalidate().
4125 * Needed for format autodetection, checking whether there is
4126 * a disk in the drive, and whether that disk is writable.
4127 */
4128
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004129struct rb0_cbdata {
4130 int drive;
4131 struct completion complete;
4132};
4133
Christoph Hellwig4246a0b2015-07-20 15:29:37 +02004134static void floppy_rb0_cb(struct bio *bio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135{
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004136 struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
4137 int drive = cbdata->drive;
4138
Christoph Hellwig4246a0b2015-07-20 15:29:37 +02004139 if (bio->bi_error) {
4140 pr_info("floppy: error %d while reading block 0\n",
4141 bio->bi_error);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004142 set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
4143 }
4144 complete(&cbdata->complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145}
4146
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004147static int __floppy_read_block_0(struct block_device *bdev, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148{
4149 struct bio bio;
4150 struct bio_vec bio_vec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 struct page *page;
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004152 struct rb0_cbdata cbdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 size_t size;
4154
4155 page = alloc_page(GFP_NOIO);
4156 if (!page) {
4157 process_fd_request();
4158 return -ENOMEM;
4159 }
4160
4161 size = bdev->bd_block_size;
4162 if (!size)
4163 size = 1024;
4164
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004165 cbdata.drive = drive;
4166
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 bio_init(&bio);
4168 bio.bi_io_vec = &bio_vec;
4169 bio_vec.bv_page = page;
4170 bio_vec.bv_len = size;
4171 bio_vec.bv_offset = 0;
4172 bio.bi_vcnt = 1;
Kent Overstreet4f024f32013-10-11 15:44:27 -07004173 bio.bi_iter.bi_size = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 bio.bi_bdev = bdev;
Kent Overstreet4f024f32013-10-11 15:44:27 -07004175 bio.bi_iter.bi_sector = 0;
Jiri Kosina6314a102014-05-28 11:55:23 +02004176 bio.bi_flags |= (1 << BIO_QUIET);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004177 bio.bi_private = &cbdata;
4178 bio.bi_end_io = floppy_rb0_cb;
Mike Christie95fe6c12016-06-05 14:31:48 -05004179 bio_set_op_attrs(&bio, REQ_OP_READ, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
Jens Axboe03781eb2018-11-09 15:58:40 -07004181 init_completion(&cbdata.complete);
4182
Mike Christie4e49ea42016-06-05 14:31:41 -05004183 submit_bio(&bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 process_fd_request();
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004185
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004186 wait_for_completion(&cbdata.complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
4188 __free_page(page);
4189
4190 return 0;
4191}
4192
4193/* revalidate the floppy disk, i.e. trigger format autodetection by reading
4194 * the bootblock (block 0). "Autodetection" is also needed to check whether
4195 * there is a disk in the drive at all... Thus we also do it for fixed
4196 * geometry formats */
4197static int floppy_revalidate(struct gendisk *disk)
4198{
4199 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 int cf;
4201 int res = 0;
4202
Joe Perchese0298532010-03-10 15:20:55 -08004203 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4204 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004205 test_bit(drive, &fake_change) ||
4206 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02004207 if (WARN(atomic_read(&usage_count) == 0,
4208 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02004210
Jiri Kosinaa0c80ef2016-02-01 11:19:17 +01004211 res = lock_fdc(drive);
4212 if (res)
4213 return res;
Joe Perchese0298532010-03-10 15:20:55 -08004214 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
4215 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004216 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 process_fd_request(); /*already done by another thread */
4218 return 0;
4219 }
4220 UDRS->maxblock = 0;
4221 UDRS->maxtrack = 0;
4222 if (buffer_drive == drive)
4223 buffer_track = -1;
4224 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08004225 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 if (cf)
4227 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01004228 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 /* auto-sensing */
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01004230 res = __floppy_read_block_0(opened_bdev[drive], drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 } else {
4232 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08004233 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 process_fd_request();
4235 }
4236 }
4237 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
4238 return res;
4239}
4240
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07004241static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07004242 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05004243 .open = floppy_open,
4244 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02004245 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07004246 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01004247 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07004248 .revalidate_disk = floppy_revalidate,
Al Viro06f9e7b2017-06-27 15:47:56 -04004249#ifdef CONFIG_COMPAT
4250 .compat_ioctl = fd_compat_ioctl,
4251#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254/*
4255 * Floppy Driver initialization
4256 * =============================
4257 */
4258
4259/* Determine the floppy disk controller type */
4260/* This routine was written by David C. Niemi */
4261static char __init get_fdc_version(void)
4262{
4263 int r;
4264
4265 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
4266 if (FDCS->reset)
4267 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004268 r = result();
4269 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 return FDC_NONE; /* No FDC present ??? */
4271 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004272 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
4274 }
4275 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08004276 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
4277 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 return FDC_UNKNOWN;
4279 }
4280
4281 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08004282 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 return FDC_82072; /* 82072 doesn't know CONFIGURE */
4284 }
4285
4286 output_byte(FD_PERPENDICULAR);
4287 if (need_more_output() == MORE_OUTPUT) {
4288 output_byte(0);
4289 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08004290 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 return FDC_82072A; /* 82072A as found on Sparcs. */
4292 }
4293
4294 output_byte(FD_UNLOCK);
4295 r = result();
4296 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004297 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004298 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 * LOCK/UNLOCK */
4300 }
4301 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08004302 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
4303 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 return FDC_UNKNOWN;
4305 }
4306 output_byte(FD_PARTID);
4307 r = result();
4308 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08004309 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
4310 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 return FDC_UNKNOWN;
4312 }
4313 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08004314 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 return FDC_82077; /* Revised 82077AA passes all the tests */
4316 }
4317 switch (reply_buffer[0] >> 5) {
4318 case 0x0:
4319 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08004320 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 return FDC_82078;
4322 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004323 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 return FDC_82078;
4325 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004326 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 return FDC_S82078B;
4328 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004329 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 return FDC_87306;
4331 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004332 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4333 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 return FDC_82078_UNKN;
4335 }
4336} /* get_fdc_version */
4337
4338/* lilo configuration */
4339
4340static void __init floppy_set_flags(int *ints, int param, int param2)
4341{
4342 int i;
4343
4344 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4345 if (param)
4346 default_drive_params[i].params.flags |= param2;
4347 else
4348 default_drive_params[i].params.flags &= ~param2;
4349 }
4350 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4351}
4352
4353static void __init daring(int *ints, int param, int param2)
4354{
4355 int i;
4356
4357 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4358 if (param) {
4359 default_drive_params[i].params.select_delay = 0;
4360 default_drive_params[i].params.flags |=
4361 FD_SILENT_DCL_CLEAR;
4362 } else {
4363 default_drive_params[i].params.select_delay =
4364 2 * HZ / 100;
4365 default_drive_params[i].params.flags &=
4366 ~FD_SILENT_DCL_CLEAR;
4367 }
4368 }
4369 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4370}
4371
4372static void __init set_cmos(int *ints, int dummy, int dummy2)
4373{
4374 int current_drive = 0;
4375
4376 if (ints[0] != 2) {
4377 DPRINT("wrong number of parameters for CMOS\n");
4378 return;
4379 }
4380 current_drive = ints[1];
4381 if (current_drive < 0 || current_drive >= 8) {
4382 DPRINT("bad drive for set_cmos\n");
4383 return;
4384 }
4385#if N_FDC > 1
4386 if (current_drive >= 4 && !FDC2)
4387 FDC2 = 0x370;
4388#endif
4389 DP->cmos = ints[2];
4390 DPRINT("setting CMOS code to %d\n", ints[2]);
4391}
4392
4393static struct param_table {
4394 const char *name;
4395 void (*fn) (int *ints, int param, int param2);
4396 int *var;
4397 int def_param;
4398 int param2;
4399} config_params[] __initdata = {
4400 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4401 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4402 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4403 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4404 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4405 {"daring", daring, NULL, 1, 0},
4406#if N_FDC > 1
4407 {"two_fdc", NULL, &FDC2, 0x370, 0},
4408 {"one_fdc", NULL, &FDC2, 0, 0},
4409#endif
4410 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4411 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4412 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4413 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4414 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4415 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4416 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4417 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4418 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4419 {"nofifo", NULL, &no_fifo, 0x20, 0},
4420 {"usefifo", NULL, &no_fifo, 0, 0},
4421 {"cmos", set_cmos, NULL, 0, 0},
4422 {"slow", NULL, &slow_floppy, 1, 0},
4423 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4424 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4425 {"L40SX", NULL, &print_unex, 0, 0}
4426
4427 EXTRA_FLOPPY_PARAMS
4428};
4429
4430static int __init floppy_setup(char *str)
4431{
4432 int i;
4433 int param;
4434 int ints[11];
4435
4436 str = get_options(str, ARRAY_SIZE(ints), ints);
4437 if (str) {
4438 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4439 if (strcmp(str, config_params[i].name) == 0) {
4440 if (ints[0])
4441 param = ints[1];
4442 else
4443 param = config_params[i].def_param;
4444 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004445 config_params[i].fn(ints, param,
4446 config_params[i].
4447 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 if (config_params[i].var) {
4449 DPRINT("%s=%d\n", str, param);
4450 *config_params[i].var = param;
4451 }
4452 return 1;
4453 }
4454 }
4455 }
4456 if (str) {
4457 DPRINT("unknown floppy option [%s]\n", str);
4458
4459 DPRINT("allowed options are:");
4460 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004461 pr_cont(" %s", config_params[i].name);
4462 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 } else
4464 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004465 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 return 0;
4467}
4468
4469static int have_no_fdc = -ENODEV;
4470
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004471static ssize_t floppy_cmos_show(struct device *dev,
4472 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004473{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004474 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004475 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004476
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004477 drive = p->id;
4478 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004479}
Joe Perches48c8cee2010-03-10 15:20:45 -08004480
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004481static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004482
Takashi Iwaib7f120b2015-02-02 17:08:45 +01004483static struct attribute *floppy_dev_attrs[] = {
4484 &dev_attr_cmos.attr,
4485 NULL
4486};
4487
4488ATTRIBUTE_GROUPS(floppy_dev);
4489
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490static void floppy_device_release(struct device *dev)
4491{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492}
4493
Frans Popc90cd332009-07-25 22:24:54 +02004494static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004495{
4496 int fdc;
4497
4498 for (fdc = 0; fdc < N_FDC; fdc++)
4499 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004500 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004501
4502 return 0;
4503}
4504
Alexey Dobriyan47145212009-12-14 18:00:08 -08004505static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004506 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004507 .restore = floppy_resume,
4508};
4509
4510static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004511 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004512 .name = "floppy",
4513 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004514 },
4515};
4516
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004517static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004519static bool floppy_available(int drive)
4520{
4521 if (!(allowed_drive_mask & (1 << drive)))
4522 return false;
4523 if (fdc_state[FDC(drive)].version == FDC_NONE)
4524 return false;
4525 return true;
4526}
4527
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4529{
4530 int drive = (*part & 3) | ((*part & 0x80) >> 5);
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004531 if (drive >= N_DRIVE || !floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004533 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 return NULL;
4535 *part = 0;
4536 return get_disk(disks[drive]);
4537}
4538
Andi Kleen0cc15d032012-07-02 17:27:04 -07004539static int __init do_floppy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540{
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004541 int i, unit, drive, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542
Stephen Hemminger285203c2010-06-15 13:21:11 +02004543 set_debugt();
4544 interruptjiffies = resultjiffies = jiffies;
4545
Kumar Gala68e1ee62008-09-22 14:41:31 -07004546#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004547 if (check_legacy_ioport(FDC1))
4548 return -ENODEV;
4549#endif
4550
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 raw_cmd = NULL;
4552
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004553 floppy_wq = alloc_ordered_workqueue("floppy", 0);
4554 if (!floppy_wq)
4555 return -ENOMEM;
4556
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004557 for (drive = 0; drive < N_DRIVE; drive++) {
4558 disks[drive] = alloc_disk(1);
4559 if (!disks[drive]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 err = -ENOMEM;
4561 goto out_put_disk;
4562 }
4563
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004564 disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4565 if (!disks[drive]->queue) {
Jens Axboe48821182010-09-22 09:32:36 +02004566 err = -ENOMEM;
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004567 goto out_put_disk;
Jens Axboe48821182010-09-22 09:32:36 +02004568 }
4569
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004570 blk_queue_max_hw_sectors(disks[drive]->queue, 64);
4571 disks[drive]->major = FLOPPY_MAJOR;
4572 disks[drive]->first_minor = TOMINOR(drive);
4573 disks[drive]->fops = &floppy_fops;
4574 sprintf(disks[drive]->disk_name, "fd%d", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004576 init_timer(&motor_off_timer[drive]);
4577 motor_off_timer[drive].data = drive;
4578 motor_off_timer[drive].function = motor_off_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 }
4580
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 err = register_blkdev(FLOPPY_MAJOR, "fd");
4582 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004583 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004585 err = platform_driver_register(&floppy_driver);
4586 if (err)
4587 goto out_unreg_blkdev;
4588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4590 floppy_find, NULL, NULL);
4591
4592 for (i = 0; i < 256; i++)
4593 if (ITYPE(i))
4594 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4595 else
4596 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4597
Joe Perches73507e62010-03-10 15:21:03 -08004598 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 config_types();
4600
4601 for (i = 0; i < N_FDC; i++) {
4602 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004603 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 FDCS->dtr = -1;
4605 FDCS->dor = 0x4;
4606#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004607 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608#ifdef __mc68000__
4609 if (MACH_IS_SUN3X)
4610#endif
4611 FDCS->version = FDC_82072A;
4612#endif
4613 }
4614
4615 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 fdc_state[0].address = FDC1;
4617 if (fdc_state[0].address == -1) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004618 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 err = -ENODEV;
4620 goto out_unreg_region;
4621 }
4622#if N_FDC > 1
4623 fdc_state[1].address = FDC2;
4624#endif
4625
4626 fdc = 0; /* reset fdc in case of unexpected interrupt */
4627 err = floppy_grab_irq_and_dma();
4628 if (err) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004629 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 err = -EBUSY;
4631 goto out_unreg_region;
4632 }
4633
4634 /* initialise drive state */
4635 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004636 memset(UDRS, 0, sizeof(*UDRS));
4637 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004638 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4639 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4640 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 UDRS->fd_device = -1;
4642 floppy_track_buffer = NULL;
4643 max_buffer_sectors = 0;
4644 }
4645 /*
4646 * Small 10 msec delay to let through any interrupt that
4647 * initialization might have triggered, to not
4648 * confuse detection:
4649 */
4650 msleep(10);
4651
4652 for (i = 0; i < N_FDC; i++) {
4653 fdc = i;
4654 FDCS->driver_version = FD_DRIVER_VERSION;
4655 for (unit = 0; unit < 4; unit++)
4656 FDCS->track[unit] = 0;
4657 if (FDCS->address == -1)
4658 continue;
4659 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004660 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004662 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 FDCS->address = -1;
4664 FDCS->version = FDC_NONE;
4665 continue;
4666 }
4667 /* Try to determine the floppy controller type */
4668 FDCS->version = get_fdc_version();
4669 if (FDCS->version == FDC_NONE) {
4670 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004671 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 FDCS->address = -1;
4673 continue;
4674 }
4675 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4676 can_use_virtual_dma = 0;
4677
4678 have_no_fdc = 0;
4679 /* Not all FDCs seem to be able to handle the version command
4680 * properly, so force a reset for the standard FDC clones,
4681 * to avoid interrupt garbage.
4682 */
Joe Perches74f63f42010-03-10 15:20:58 -08004683 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 }
4685 fdc = 0;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004686 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004688 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 if (have_no_fdc) {
4690 DPRINT("no floppy controllers found\n");
4691 err = have_no_fdc;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004692 goto out_release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 }
4694
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 for (drive = 0; drive < N_DRIVE; drive++) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004696 if (!floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004698
4699 floppy_device[drive].name = floppy_device_name;
4700 floppy_device[drive].id = drive;
4701 floppy_device[drive].dev.release = floppy_device_release;
Takashi Iwaib7f120b2015-02-02 17:08:45 +01004702 floppy_device[drive].dev.groups = floppy_dev_groups;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004703
4704 err = platform_device_register(&floppy_device[drive]);
4705 if (err)
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004706 goto out_remove_drives;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004707
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 /* to be cleaned up... */
4709 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Dan Williams0d52c7562016-06-15 19:44:20 -07004711 device_add_disk(&floppy_device[drive].dev, disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 }
4713
4714 return 0;
4715
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004716out_remove_drives:
4717 while (drive--) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004718 if (floppy_available(drive)) {
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004719 del_gendisk(disks[drive]);
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004720 platform_device_unregister(&floppy_device[drive]);
4721 }
4722 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004723out_release_dma:
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004724 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 floppy_release_irq_and_dma();
4726out_unreg_region:
4727 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004728 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729out_unreg_blkdev:
4730 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731out_put_disk:
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004732 destroy_workqueue(floppy_wq);
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004733 for (drive = 0; drive < N_DRIVE; drive++) {
4734 if (!disks[drive])
4735 break;
4736 if (disks[drive]->queue) {
4737 del_timer_sync(&motor_off_timer[drive]);
4738 blk_cleanup_queue(disks[drive]->queue);
4739 disks[drive]->queue = NULL;
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004740 }
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004741 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 }
4743 return err;
4744}
4745
Andi Kleen0cc15d032012-07-02 17:27:04 -07004746#ifndef MODULE
4747static __init void floppy_async_init(void *data, async_cookie_t cookie)
4748{
4749 do_floppy_init();
4750}
4751#endif
4752
4753static int __init floppy_init(void)
4754{
4755#ifdef MODULE
4756 return do_floppy_init();
4757#else
4758 /* Don't hold up the bootup by the floppy initialization */
4759 async_schedule(floppy_async_init, NULL);
4760 return 0;
4761#endif
4762}
4763
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004764static const struct io_region {
4765 int offset;
4766 int size;
4767} io_regions[] = {
4768 { 2, 1 },
4769 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4770 { 4, 2 },
4771 /* address + 6 is reserved, and may be taken by IDE.
4772 * Unfortunately, Adaptec doesn't know this :-(, */
4773 { 7, 1 },
4774};
4775
4776static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4777{
4778 while (p != io_regions) {
4779 p--;
4780 release_region(FDCS->address + p->offset, p->size);
4781 }
4782}
4783
4784#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4785
4786static int floppy_request_regions(int fdc)
4787{
4788 const struct io_region *p;
4789
4790 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004791 if (!request_region(FDCS->address + p->offset,
4792 p->size, "floppy")) {
4793 DPRINT("Floppy io-port 0x%04lx in use\n",
4794 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004795 floppy_release_allocated_regions(fdc, p);
4796 return -EBUSY;
4797 }
4798 }
4799 return 0;
4800}
4801
4802static void floppy_release_regions(int fdc)
4803{
4804 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4805}
4806
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807static int floppy_grab_irq_and_dma(void)
4808{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004809 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004811
4812 /*
4813 * We might have scheduled a free_irq(), wait it to
4814 * drain first:
4815 */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004816 flush_workqueue(floppy_wq);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004817
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 if (fd_request_irq()) {
4819 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4820 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004821 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 return -1;
4823 }
4824 if (fd_request_dma()) {
4825 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4826 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004827 if (can_use_virtual_dma & 2)
4828 use_virtual_dma = can_use_virtual_dma = 1;
4829 if (!(can_use_virtual_dma & 1)) {
4830 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004831 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004832 return -1;
4833 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 }
4835
4836 for (fdc = 0; fdc < N_FDC; fdc++) {
4837 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004838 if (floppy_request_regions(fdc))
4839 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 }
4841 }
4842 for (fdc = 0; fdc < N_FDC; fdc++) {
4843 if (FDCS->address != -1) {
4844 reset_fdc_info(1);
4845 fd_outb(FDCS->dor, FD_DOR);
4846 }
4847 }
4848 fdc = 0;
4849 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4850
4851 for (fdc = 0; fdc < N_FDC; fdc++)
4852 if (FDCS->address != -1)
4853 fd_outb(FDCS->dor, FD_DOR);
4854 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004855 * The driver will try and free resources and relies on us
4856 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 */
4858 fdc = 0;
4859 irqdma_allocated = 1;
4860 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004861cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 fd_free_irq();
4863 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004864 while (--fdc >= 0)
4865 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004866 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 return -1;
4868}
4869
4870static void floppy_release_irq_and_dma(void)
4871{
4872 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873#ifndef __sparc__
4874 int drive;
4875#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 long tmpsize;
4877 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004879 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004881
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 if (irqdma_allocated) {
4883 fd_disable_dma();
4884 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004885 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 irqdma_allocated = 0;
4887 }
4888 set_dor(0, ~0, 8);
4889#if N_FDC > 1
4890 set_dor(1, ~8, 0);
4891#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
4893 if (floppy_track_buffer && max_buffer_sectors) {
4894 tmpsize = max_buffer_sectors * 1024;
4895 tmpaddr = (unsigned long)floppy_track_buffer;
4896 floppy_track_buffer = NULL;
4897 max_buffer_sectors = 0;
4898 buffer_min = buffer_max = -1;
4899 fd_dma_mem_free(tmpaddr, tmpsize);
4900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901#ifndef __sparc__
4902 for (drive = 0; drive < N_FDC * 4; drive++)
4903 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004904 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905#endif
4906
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004907 if (delayed_work_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004908 pr_info("floppy timer still active:%s\n", timeout_message);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004909 if (delayed_work_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004910 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004911 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004912 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 old_fdc = fdc;
4914 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004915 if (FDCS->address != -1)
4916 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 fdc = old_fdc;
4918}
4919
4920#ifdef MODULE
4921
4922static char *floppy;
4923
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924static void __init parse_floppy_cfg_string(char *cfg)
4925{
4926 char *ptr;
4927
4928 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004929 ptr = cfg;
4930 while (*cfg && *cfg != ' ' && *cfg != '\t')
4931 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 if (*cfg) {
4933 *cfg = '\0';
4934 cfg++;
4935 }
4936 if (*ptr)
4937 floppy_setup(ptr);
4938 }
4939}
4940
Jon Schindler7afea3b2008-04-29 00:59:21 -07004941static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942{
4943 if (floppy)
4944 parse_floppy_cfg_string(floppy);
4945 return floppy_init();
4946}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004947module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948
Jon Schindler7afea3b2008-04-29 00:59:21 -07004949static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950{
4951 int drive;
4952
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4954 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004955 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004957 destroy_workqueue(floppy_wq);
4958
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 for (drive = 0; drive < N_DRIVE; drive++) {
4960 del_timer_sync(&motor_off_timer[drive]);
4961
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004962 if (floppy_available(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004964 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 }
Jens Axboe48821182010-09-22 09:32:36 +02004966 blk_cleanup_queue(disks[drive]->queue);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004967
4968 /*
4969 * These disks have not called add_disk(). Don't put down
4970 * queue reference in put_disk().
4971 */
4972 if (!(allowed_drive_mask & (1 << drive)) ||
4973 fdc_state[FDC(drive)].version == FDC_NONE)
4974 disks[drive]->queue = NULL;
4975
Vivek Goyald017bf62010-11-06 08:16:05 -04004976 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004979 cancel_delayed_work_sync(&fd_timeout);
4980 cancel_delayed_work_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004982 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983 floppy_release_irq_and_dma();
4984
4985 /* eject disk, if any */
4986 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987}
Joe Perches48c8cee2010-03-10 15:20:45 -08004988
Jon Schindler7afea3b2008-04-29 00:59:21 -07004989module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990
4991module_param(floppy, charp, 0);
4992module_param(FLOPPY_IRQ, int, 0);
4993module_param(FLOPPY_DMA, int, 0);
4994MODULE_AUTHOR("Alain L. Knaff");
4995MODULE_SUPPORTED_DEVICE("fd");
4996MODULE_LICENSE("GPL");
4997
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004998/* This doesn't actually get used other than for module information */
4999static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08005000 {"PNP0700", 0},
5001 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07005002};
Joe Perches48c8cee2010-03-10 15:20:45 -08005003
Scott James Remnant83f9ef42009-04-02 16:56:47 -07005004MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
5005
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006#else
5007
5008__setup("floppy=", floppy_setup);
5009module_init(floppy_init)
5010#endif
5011
5012MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);