blob: f0c95df1f14a277846aceec859390f21c7a84360 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/*
197 * PS/2 floppies have much slower step rates than regular floppies.
198 * It's been recommended that take about 1/4 of the default speed
199 * in some more extreme cases.
200 */
Arnd Bergmann2a48fc02010-06-02 14:28:52 +0200201static DEFINE_MUTEX(floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static int slow_floppy;
203
204#include <asm/dma.h>
205#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207static int FLOPPY_IRQ = 6;
208static int FLOPPY_DMA = 2;
209static int can_use_virtual_dma = 2;
210/* =======
211 * can use virtual DMA:
212 * 0 = use of virtual DMA disallowed by config
213 * 1 = use of virtual DMA prescribed by config
214 * 2 = no virtual DMA preference configured. By default try hard DMA,
215 * but fall back on virtual DMA when not enough memory available
216 */
217
218static int use_virtual_dma;
219/* =======
220 * use virtual DMA
221 * 0 using hard DMA
222 * 1 using virtual DMA
223 * This variable is set to virtual when a DMA mem problem arises, and
224 * reset back in floppy_grab_irq_and_dma.
225 * It is not safe to reset it in other circumstances, because the floppy
226 * driver may have several buffers in use at once, and we do currently not
227 * record each buffers capabilities
228 */
229
230static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100233irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236#define K_64 0x10000 /* 64KB */
237
238/* the following is the mask of allowed drives. By default units 2 and
239 * 3 of both floppy controllers are disabled, because switching on the
240 * motor of these drives causes system hangs on some PCI computers. drive
241 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
242 * a drive is allowed.
243 *
244 * NOTE: This must come before we include the arch floppy header because
245 * some ports reference this variable from there. -DaveM
246 */
247
248static int allowed_drive_mask = 0x33;
249
250#include <asm/floppy.h>
251
252static int irqdma_allocated;
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254#include <linux/blkdev.h>
255#include <linux/blkpg.h>
256#include <linux/cdrom.h> /* for the compatibility eject ioctl */
257#include <linux/completion.h>
258
259static struct request *current_req;
Joe Perches48c8cee2010-03-10 15:20:45 -0800260static void do_fd_request(struct request_queue *q);
Jens Axboe48821182010-09-22 09:32:36 +0200261static int set_next_request(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263#ifndef fd_get_dma_residue
264#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
265#endif
266
267/* Dma Memory related stuff */
268
269#ifndef fd_dma_mem_free
270#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
271#endif
272
273#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800274#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275#endif
276
277static inline void fallback_on_nodma_alloc(char **addr, size_t l)
278{
279#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
280 if (*addr)
281 return; /* we have the memory */
282 if (can_use_virtual_dma != 2)
283 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800284 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 *addr = (char *)nodma_mem_alloc(l);
286#else
287 return;
288#endif
289}
290
291/* End dma memory related stuff */
292
293static unsigned long fake_change;
Joe Perches29f1c782010-03-10 15:21:00 -0800294static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Joe Perches48c8cee2010-03-10 15:20:45 -0800296#define ITYPE(x) (((x) >> 2) & 0x1f)
297#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
298#define UNIT(x) ((x) & 0x03) /* drive on fdc */
299#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700300 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Joe Perches48c8cee2010-03-10 15:20:45 -0800303#define DP (&drive_params[current_drive])
304#define DRS (&drive_state[current_drive])
305#define DRWE (&write_errors[current_drive])
306#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Joe Perches48c8cee2010-03-10 15:20:45 -0800308#define UDP (&drive_params[drive])
309#define UDRS (&drive_state[drive])
310#define UDRWE (&write_errors[drive])
311#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Joe Perches48c8cee2010-03-10 15:20:45 -0800313#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
314#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800317#define COMMAND (raw_cmd->cmd[0])
318#define DR_SELECT (raw_cmd->cmd[1])
319#define TRACK (raw_cmd->cmd[2])
320#define HEAD (raw_cmd->cmd[3])
321#define SECTOR (raw_cmd->cmd[4])
322#define SIZECODE (raw_cmd->cmd[5])
323#define SECT_PER_TRACK (raw_cmd->cmd[6])
324#define GAP (raw_cmd->cmd[7])
325#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326#define NR_RW 9
327
328/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800329#define F_SIZECODE (raw_cmd->cmd[2])
330#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
331#define F_GAP (raw_cmd->cmd[4])
332#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333#define NR_F 6
334
335/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800336 * Maximum disk size (in kilobytes).
337 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 * [Now it is rather a minimum]
339 */
340#define MAX_DISK_SIZE 4 /* 3984 */
341
342/*
343 * globals used by 'result()'
344 */
345#define MAX_REPLIES 16
346static unsigned char reply_buffer[MAX_REPLIES];
Joe Perches891eda82010-03-10 15:21:05 -0800347static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800348#define ST0 (reply_buffer[0])
349#define ST1 (reply_buffer[1])
350#define ST2 (reply_buffer[2])
351#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
352#define R_TRACK (reply_buffer[3])
353#define R_HEAD (reply_buffer[4])
354#define R_SECTOR (reply_buffer[5])
355#define R_SIZECODE (reply_buffer[6])
356
357#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359/*
360 * this struct defines the different floppy drive types.
361 */
362static struct {
363 struct floppy_drive_params params;
364 const char *name; /* name printed while booting */
365} default_drive_params[] = {
366/* NOTE: the time values in jiffies should be in msec!
367 CMOS drive type
368 | Maximum data rate supported by drive type
369 | | Head load time, msec
370 | | | Head unload time, msec (not used)
371 | | | | Step rate interval, usec
372 | | | | | Time needed for spinup time (jiffies)
373 | | | | | | Timeout for spinning down (jiffies)
374 | | | | | | | Spindown offset (where disk stops)
375 | | | | | | | | Select delay
376 | | | | | | | | | RPS
377 | | | | | | | | | | Max number of tracks
378 | | | | | | | | | | | Interrupt timeout
379 | | | | | | | | | | | | Max nonintlv. sectors
380 | | | | | | | | | | | | | -Max Errors- flags */
381{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
382 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
383
384{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
385 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
386
387{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
388 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
389
390{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
391 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
392
393{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
394 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
395
396{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
397 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
398
399{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
400 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
401/* | --autodetected formats--- | | |
402 * read_track | | Name printed when booting
403 * | Native format
404 * Frequency of disk change checks */
405};
406
407static struct floppy_drive_params drive_params[N_DRIVE];
408static struct floppy_drive_struct drive_state[N_DRIVE];
409static struct floppy_write_errors write_errors[N_DRIVE];
410static struct timer_list motor_off_timer[N_DRIVE];
411static struct gendisk *disks[N_DRIVE];
412static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800413static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
Jens Axboe48821182010-09-22 09:32:36 +0200415static int fdc_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
417/*
418 * This struct defines the different floppy types.
419 *
420 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
421 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
422 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
423 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
424 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
425 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
426 * side 0 is on physical side 0 (but with the misnamed sector IDs).
427 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700428 * 'options'.
429 *
430 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
431 * The LSB (bit 2) is flipped. For most disks, the first sector
432 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
433 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
434 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
435 *
436 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 */
438/*
439 Size
440 | Sectors per track
441 | | Head
442 | | | Tracks
443 | | | | Stretch
444 | | | | | Gap 1 size
445 | | | | | | Data rate, | 0x40 for perp
446 | | | | | | | Spec1 (stepping rate, head unload
447 | | | | | | | | /fmt gap (gap2) */
448static struct floppy_struct floppy_type[32] = {
449 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
450 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
451 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
452 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
453 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
454 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
455 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
456 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
457 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
458 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
459
460 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
461 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
462 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
463 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
464 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
465 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
466 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
467 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
468 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
469 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
470
471 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
472 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
473 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
474 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
475 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
476 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
477 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
478 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
479 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
483 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
484};
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486#define SECTSIZE (_FD_SECTSIZE(*floppy))
487
488/* Auto-detection: Disk type used until the next media change occurs. */
489static struct floppy_struct *current_type[N_DRIVE];
490
491/*
492 * User-provided type information. current_type points to
493 * the respective entry of this array.
494 */
495static struct floppy_struct user_params[N_DRIVE];
496
497static sector_t floppy_sizes[256];
498
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200499static char floppy_device_name[] = "floppy";
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501/*
502 * The driver is trying to determine the correct media format
503 * while probing is set. rw_interrupt() clears it after a
504 * successful access.
505 */
506static int probing;
507
508/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800509#define FD_COMMAND_NONE -1
510#define FD_COMMAND_ERROR 2
511#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513static volatile int command_status = FD_COMMAND_NONE;
514static unsigned long fdc_busy;
515static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
516static DECLARE_WAIT_QUEUE_HEAD(command_done);
517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518/* Errors during formatting are counted here. */
519static int format_errors;
520
521/* Format request descriptor. */
522static struct format_descr format_req;
523
524/*
525 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
526 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
527 * H is head unload time (1=16ms, 2=32ms, etc)
528 */
529
530/*
531 * Track buffer
532 * Because these are written to by the DMA controller, they must
533 * not contain a 64k byte boundary crossing, or data will be
534 * corrupted/lost.
535 */
536static char *floppy_track_buffer;
537static int max_buffer_sectors;
538
539static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700540typedef void (*done_f)(int);
Stephen Hemminger3b06c212010-07-20 20:09:00 -0600541static const struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800542 void (*interrupt)(void);
543 /* this is called after the interrupt of the
544 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700545 void (*redo)(void); /* this is called to retry the operation */
546 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 done_f done; /* this is called to say if the operation has
548 * succeeded/failed */
549} *cont;
550
551static void floppy_ready(void);
552static void floppy_start(void);
553static void process_fd_request(void);
554static void recalibrate_floppy(void);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200555static void floppy_shutdown(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800557static int floppy_request_regions(int);
558static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559static int floppy_grab_irq_and_dma(void);
560static void floppy_release_irq_and_dma(void);
561
562/*
563 * The "reset" variable should be tested whenever an interrupt is scheduled,
564 * after the commands have been sent. This is to ensure that the driver doesn't
565 * get wedged when the interrupt doesn't come because of a failed command.
566 * reset doesn't need to be tested before sending commands, because
567 * output_byte is automatically disabled when reset is set.
568 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569static void reset_fdc(void);
570
571/*
572 * These are global variables, as that's the easiest way to give
573 * information to interrupts. They are the data used for the current
574 * request.
575 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800576#define NO_TRACK -1
577#define NEED_1_RECAL -2
578#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200580static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582/* buffer related variables */
583static int buffer_track = -1;
584static int buffer_drive = -1;
585static int buffer_min = -1;
586static int buffer_max = -1;
587
588/* fdc related variables, should end up in a struct */
589static struct floppy_fdc_state fdc_state[N_FDC];
590static int fdc; /* current fdc */
591
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200592static struct workqueue_struct *floppy_wq;
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594static struct floppy_struct *_floppy = floppy_type;
595static unsigned char current_drive;
596static long current_count_sectors;
597static unsigned char fsector_t; /* sector in track */
598static unsigned char in_sector_offset; /* offset within physical sector,
599 * expressed in units of 512 bytes */
600
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100601static inline bool drive_no_geom(int drive)
602{
603 return !current_type[drive] && !ITYPE(UDRS->fd_device);
604}
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606#ifndef fd_eject
607static inline int fd_eject(int drive)
608{
609 return -EINVAL;
610}
611#endif
612
613/*
614 * Debugging
615 * =========
616 */
617#ifdef DEBUGT
618static long unsigned debugtimer;
619
620static inline void set_debugt(void)
621{
622 debugtimer = jiffies;
623}
624
Joe Perchesded28632010-03-10 15:21:09 -0800625static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
627 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800628 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629}
630#else
631static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800632static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633#endif /* DEBUGT */
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200636static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637static const char *timeout_message;
638
Joe Perches275176b2010-03-10 15:21:06 -0800639static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
641 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800642 if (test_bit(0, &fdc_busy) && command_status < 2 &&
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200643 !delayed_work_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800644 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
646}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Joe Perches48c8cee2010-03-10 15:20:45 -0800648static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650#define OLOGSIZE 20
651
Joe Perches48c8cee2010-03-10 15:20:45 -0800652static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653static unsigned long interruptjiffies;
654static unsigned long resultjiffies;
655static int resultsize;
656static unsigned long lastredo;
657
658static struct output_log {
659 unsigned char data;
660 unsigned char status;
661 unsigned long jiffies;
662} output_log[OLOGSIZE];
663
664static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666#define current_reqD -1
667#define MAXTIMEOUT -2
668
Joe Perches73507e62010-03-10 15:21:03 -0800669static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200671 unsigned long delay;
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (drive == current_reqD)
674 drive = current_drive;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200675
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700676 if (drive < 0 || drive >= N_DRIVE) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200677 delay = 20UL * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 drive = 0;
679 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200680 delay = UDP->timeout;
681
Tejun Heoe7c2f962012-08-21 13:18:24 -0700682 mod_delayed_work(floppy_wq, &fd_timeout, delay);
Joe Perchesa81ee542010-03-10 15:20:46 -0800683 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800684 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 timeout_message = message;
686}
687
Joe Perches73507e62010-03-10 15:21:03 -0800688static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
690 unsigned long flags;
691
692 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800693 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 spin_unlock_irqrestore(&floppy_lock, flags);
695}
696
Joe Perches48c8cee2010-03-10 15:20:45 -0800697#define INFBOUND(a, b) (a) = max_t(int, a, b)
698#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700/*
701 * Bottom half floppy driver.
702 * ==========================
703 *
704 * This part of the file contains the code talking directly to the hardware,
705 * and also the main service loop (seek-configure-spinup-command)
706 */
707
708/*
709 * disk change.
710 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
711 * and the last_checked date.
712 *
713 * last_checked is the date of the last check which showed 'no disk change'
714 * FD_DISK_CHANGE is set under two conditions:
715 * 1. The floppy has been changed after some i/o to that floppy already
716 * took place.
717 * 2. No floppy disk is in the drive. This is done in order to ensure that
718 * requests are quickly flushed in case there is no disk in the drive. It
719 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
720 * the drive.
721 *
722 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
723 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
724 * each seek. If a disk is present, the disk change line should also be
725 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
726 * change line is set, this means either that no disk is in the drive, or
727 * that it has been removed since the last seek.
728 *
729 * This means that we really have a third possibility too:
730 * The floppy has been changed after the last seek.
731 */
732
733static int disk_change(int drive)
734{
735 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700736
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800737 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 DPRINT("WARNING disk change called early\n");
739 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
740 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
741 DPRINT("probing disk change on unselected drive\n");
742 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
743 (unsigned int)FDCS->dor);
744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Joe Perches87f530d2010-03-10 15:20:54 -0800746 debug_dcl(UDP->flags,
747 "checking disk change line for drive %d\n", drive);
748 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
749 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
750 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800753 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800755 set_bit(FD_VERIFY_BIT, &UDRS->flags);
756 /* verify write protection */
757
758 if (UDRS->maxblock) /* mark it changed */
759 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
761 /* invalidate its geometry */
762 if (UDRS->keep_data >= 0) {
763 if ((UDP->flags & FTD_MSG) &&
764 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800765 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 current_type[drive] = NULL;
767 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
768 }
769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return 1;
771 } else {
772 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800773 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
775 return 0;
776}
777
778static inline int is_selected(int dor, int unit)
779{
780 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
781}
782
Joe Perches57584c52010-03-10 15:21:00 -0800783static bool is_ready_state(int status)
784{
785 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
786 return state == STATUS_READY;
787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789static int set_dor(int fdc, char mask, char data)
790{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700791 unsigned char unit;
792 unsigned char drive;
793 unsigned char newdor;
794 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 if (FDCS->address == -1)
797 return -1;
798
799 olddor = FDCS->dor;
800 newdor = (olddor & mask) | data;
801 if (newdor != olddor) {
802 unit = olddor & 0x3;
803 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
804 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800805 debug_dcl(UDP->flags,
806 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 disk_change(drive);
808 }
809 FDCS->dor = newdor;
810 fd_outb(newdor, FD_DOR);
811
812 unit = newdor & 0x3;
813 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
814 drive = REVDRIVE(fdc, unit);
815 UDRS->select_date = jiffies;
816 }
817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 return olddor;
819}
820
821static void twaddle(void)
822{
823 if (DP->select_delay)
824 return;
825 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
826 fd_outb(FDCS->dor, FD_DOR);
827 DRS->select_date = jiffies;
828}
829
Joe Perches57584c52010-03-10 15:21:00 -0800830/*
831 * Reset all driver information about the current fdc.
832 * This is needed after a reset, and after a raw command.
833 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834static void reset_fdc_info(int mode)
835{
836 int drive;
837
838 FDCS->spec1 = FDCS->spec2 = -1;
839 FDCS->need_configure = 1;
840 FDCS->perp_mode = 1;
841 FDCS->rawcmd = 0;
842 for (drive = 0; drive < N_DRIVE; drive++)
843 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
844 UDRS->track = NEED_2_RECAL;
845}
846
847/* selects the fdc and drive, and enables the fdc's input/dma. */
848static void set_fdc(int drive)
849{
850 if (drive >= 0 && drive < N_DRIVE) {
851 fdc = FDC(drive);
852 current_drive = drive;
853 }
854 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800855 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return;
857 }
858 set_dor(fdc, ~0, 8);
859#if N_FDC > 1
860 set_dor(1 - fdc, ~8, 0);
861#endif
862 if (FDCS->rawcmd == 2)
863 reset_fdc_info(1);
864 if (fd_inb(FD_STATUS) != STATUS_READY)
865 FDCS->reset = 1;
866}
867
868/* locks the driver */
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200869static int lock_fdc(int drive, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200871 if (WARN(atomic_read(&usage_count) == 0,
872 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200875 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
876 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 command_status = FD_COMMAND_NONE;
879
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200880 reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 set_fdc(drive);
882 return 0;
883}
884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200886static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if (!test_bit(0, &fdc_busy))
889 DPRINT("FDC access conflict!\n");
890
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200891 raw_cmd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 command_status = FD_COMMAND_NONE;
Tejun Heo136b5722012-08-21 13:18:24 -0700893 cancel_delayed_work(&fd_timeout);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200894 do_floppy = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 cont = NULL;
896 clear_bit(0, &fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 wake_up(&fdc_wait);
898}
899
900/* switches the motor off after a given timeout */
901static void motor_off_callback(unsigned long nr)
902{
903 unsigned char mask = ~(0x10 << UNIT(nr));
904
905 set_dor(FDC(nr), mask, 0);
906}
907
908/* schedules motor off */
909static void floppy_off(unsigned int drive)
910{
911 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700912 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 if (!(FDCS->dor & (0x10 << UNIT(drive))))
915 return;
916
917 del_timer(motor_off_timer + drive);
918
919 /* make spindle stop in a position which minimizes spinup time
920 * next time */
921 if (UDP->rps) {
922 delta = jiffies - UDRS->first_read_date + HZ -
923 UDP->spindown_offset;
924 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
925 motor_off_timer[drive].expires =
926 jiffies + UDP->spindown - delta;
927 }
928 add_timer(motor_off_timer + drive);
929}
930
931/*
932 * cycle through all N_DRIVE floppy drives, for disk change testing.
933 * stopping at current drive. This is done before any long operation, to
934 * be sure to have up to date disk change information.
935 */
936static void scandrives(void)
937{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700938 int i;
939 int drive;
940 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 if (DP->select_delay)
943 return;
944
945 saved_drive = current_drive;
946 for (i = 0; i < N_DRIVE; i++) {
947 drive = (saved_drive + i + 1) % N_DRIVE;
948 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
949 continue; /* skip closed drives */
950 set_fdc(drive);
951 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
952 (0x10 << UNIT(drive))))
953 /* switch the motor off again, if it was off to
954 * begin with */
955 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
956 }
957 set_fdc(saved_drive);
958}
959
960static void empty(void)
961{
962}
963
Tejun Heo75ddb382014-03-07 10:24:48 -0500964static void (*floppy_work_fn)(void);
965
966static void floppy_work_workfn(struct work_struct *work)
967{
968 floppy_work_fn();
969}
970
971static DECLARE_WORK(floppy_work, floppy_work_workfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Joe Perches48c8cee2010-03-10 15:20:45 -0800973static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200975 WARN_ON(work_pending(&floppy_work));
976
Tejun Heo75ddb382014-03-07 10:24:48 -0500977 floppy_work_fn = handler;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200978 queue_work(floppy_wq, &floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979}
980
Tejun Heo75ddb382014-03-07 10:24:48 -0500981static void (*fd_timer_fn)(void) = NULL;
982
983static void fd_timer_workfn(struct work_struct *work)
984{
985 fd_timer_fn();
986}
987
988static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990static void cancel_activity(void)
991{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 do_floppy = NULL;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200993 cancel_delayed_work_sync(&fd_timer);
994 cancel_work_sync(&floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995}
996
997/* this function makes sure that the disk stays in the drive during the
998 * transfer */
Tejun Heo75ddb382014-03-07 10:24:48 -0500999static void fd_watchdog(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
Joe Perches87f530d2010-03-10 15:20:54 -08001001 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 if (disk_change(current_drive)) {
1004 DPRINT("disk removed during i/o\n");
1005 cancel_activity();
1006 cont->done(0);
1007 reset_fdc();
1008 } else {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001009 cancel_delayed_work(&fd_timer);
Tejun Heo75ddb382014-03-07 10:24:48 -05001010 fd_timer_fn = fd_watchdog;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001011 queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 }
1013}
1014
1015static void main_command_interrupt(void)
1016{
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001017 cancel_delayed_work(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 cont->interrupt();
1019}
1020
1021/* waits for a delay (spinup or select) to pass */
Tejun Heo75ddb382014-03-07 10:24:48 -05001022static int fd_wait_for_completion(unsigned long expires,
1023 void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 if (FDCS->reset) {
1026 reset_fdc(); /* do the reset during sleep to win time
1027 * if we don't need to sleep, it's a good
1028 * occasion anyways */
1029 return 1;
1030 }
1031
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001032 if (time_before(jiffies, expires)) {
1033 cancel_delayed_work(&fd_timer);
Tejun Heo75ddb382014-03-07 10:24:48 -05001034 fd_timer_fn = function;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001035 queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return 1;
1037 }
1038 return 0;
1039}
1040
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041static void setup_DMA(void)
1042{
1043 unsigned long f;
1044
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 if (raw_cmd->length == 0) {
1046 int i;
1047
Joe Perchesb46df352010-03-10 15:20:46 -08001048 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001050 pr_cont("%x,", raw_cmd->cmd[i]);
1051 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 cont->done(0);
1053 FDCS->reset = 1;
1054 return;
1055 }
1056 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001057 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 cont->done(0);
1059 FDCS->reset = 1;
1060 return;
1061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 f = claim_dma_lock();
1063 fd_disable_dma();
1064#ifdef fd_dma_setup
1065 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1066 (raw_cmd->flags & FD_RAW_READ) ?
1067 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1068 release_dma_lock(f);
1069 cont->done(0);
1070 FDCS->reset = 1;
1071 return;
1072 }
1073 release_dma_lock(f);
1074#else
1075 fd_clear_dma_ff();
1076 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1077 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1078 DMA_MODE_READ : DMA_MODE_WRITE);
1079 fd_set_dma_addr(raw_cmd->kernel_data);
1080 fd_set_dma_count(raw_cmd->length);
1081 virtual_dma_port = FDCS->address;
1082 fd_enable_dma();
1083 release_dma_lock(f);
1084#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085}
1086
1087static void show_floppy(void);
1088
1089/* waits until the fdc becomes ready */
1090static int wait_til_ready(void)
1091{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001092 int status;
1093 int counter;
1094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 if (FDCS->reset)
1096 return -1;
1097 for (counter = 0; counter < 10000; counter++) {
1098 status = fd_inb(FD_STATUS);
1099 if (status & STATUS_READY)
1100 return status;
1101 }
Joe Perches29f1c782010-03-10 15:21:00 -08001102 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1104 show_floppy();
1105 }
1106 FDCS->reset = 1;
1107 return -1;
1108}
1109
1110/* sends a command byte to the fdc */
1111static int output_byte(char byte)
1112{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001113 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001115 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001117
1118 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 output_log[output_log_pos].data = byte;
1121 output_log[output_log_pos].status = status;
1122 output_log[output_log_pos].jiffies = jiffies;
1123 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 return 0;
1125 }
1126 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001127 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1129 byte, fdc, status);
1130 show_floppy();
1131 }
1132 return -1;
1133}
1134
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135/* gets the response from the fdc */
1136static int result(void)
1137{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001138 int i;
1139 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
1141 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001142 status = wait_til_ready();
1143 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 break;
1145 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1146 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 resultjiffies = jiffies;
1148 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return i;
1150 }
1151 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1152 reply_buffer[i] = fd_inb(FD_DATA);
1153 else
1154 break;
1155 }
Joe Perches29f1c782010-03-10 15:21:00 -08001156 if (initialized) {
1157 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1158 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 show_floppy();
1160 }
1161 FDCS->reset = 1;
1162 return -1;
1163}
1164
1165#define MORE_OUTPUT -2
1166/* does the fdc need more output? */
1167static int need_more_output(void)
1168{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001169 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001170
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001171 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001173
1174 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return result();
1178}
1179
1180/* Set perpendicular mode as required, based on data rate, if supported.
1181 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1182 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001183static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184{
1185 unsigned char perp_mode;
1186
1187 if (raw_cmd->rate & 0x40) {
1188 switch (raw_cmd->rate & 3) {
1189 case 0:
1190 perp_mode = 2;
1191 break;
1192 case 3:
1193 perp_mode = 3;
1194 break;
1195 default:
1196 DPRINT("Invalid data rate for perpendicular mode!\n");
1197 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001198 FDCS->reset = 1;
1199 /*
1200 * convenient way to return to
1201 * redo without too much hassle
1202 * (deep stack et al.)
1203 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return;
1205 }
1206 } else
1207 perp_mode = 0;
1208
1209 if (FDCS->perp_mode == perp_mode)
1210 return;
1211 if (FDCS->version >= FDC_82077_ORIG) {
1212 output_byte(FD_PERPENDICULAR);
1213 output_byte(perp_mode);
1214 FDCS->perp_mode = perp_mode;
1215 } else if (perp_mode) {
1216 DPRINT("perpendicular mode not supported by this FDC.\n");
1217 }
1218} /* perpendicular_mode */
1219
1220static int fifo_depth = 0xa;
1221static int no_fifo;
1222
1223static int fdc_configure(void)
1224{
1225 /* Turn on FIFO */
1226 output_byte(FD_CONFIGURE);
1227 if (need_more_output() != MORE_OUTPUT)
1228 return 0;
1229 output_byte(0);
1230 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1231 output_byte(0); /* pre-compensation from track
1232 0 upwards */
1233 return 1;
1234}
1235
1236#define NOMINAL_DTR 500
1237
1238/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1239 * head load time, and DMA disable flag to values needed by floppy.
1240 *
1241 * The value "dtr" is the data transfer rate in Kbps. It is needed
1242 * to account for the data rate-based scaling done by the 82072 and 82077
1243 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1244 * 8272a).
1245 *
1246 * Note that changing the data transfer rate has a (probably deleterious)
1247 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1248 * fdc_specify is called again after each data transfer rate
1249 * change.
1250 *
1251 * srt: 1000 to 16000 in microseconds
1252 * hut: 16 to 240 milliseconds
1253 * hlt: 2 to 254 milliseconds
1254 *
1255 * These values are rounded up to the next highest available delay time.
1256 */
1257static void fdc_specify(void)
1258{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001259 unsigned char spec1;
1260 unsigned char spec2;
1261 unsigned long srt;
1262 unsigned long hlt;
1263 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 unsigned long dtr = NOMINAL_DTR;
1265 unsigned long scale_dtr = NOMINAL_DTR;
1266 int hlt_max_code = 0x7f;
1267 int hut_max_code = 0xf;
1268
1269 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1270 fdc_configure();
1271 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 }
1273
1274 switch (raw_cmd->rate & 0x03) {
1275 case 3:
1276 dtr = 1000;
1277 break;
1278 case 1:
1279 dtr = 300;
1280 if (FDCS->version >= FDC_82078) {
1281 /* chose the default rate table, not the one
1282 * where 1 = 2 Mbps */
1283 output_byte(FD_DRIVESPEC);
1284 if (need_more_output() == MORE_OUTPUT) {
1285 output_byte(UNIT(current_drive));
1286 output_byte(0xc0);
1287 }
1288 }
1289 break;
1290 case 2:
1291 dtr = 250;
1292 break;
1293 }
1294
1295 if (FDCS->version >= FDC_82072) {
1296 scale_dtr = dtr;
1297 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1298 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1299 }
1300
1301 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001302 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001303 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001305
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 SUPBOUND(srt, 0xf);
1307 INFBOUND(srt, 0);
1308
Julia Lawall061837b2008-09-22 14:57:16 -07001309 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 if (hlt < 0x01)
1311 hlt = 0x01;
1312 else if (hlt > 0x7f)
1313 hlt = hlt_max_code;
1314
Julia Lawall061837b2008-09-22 14:57:16 -07001315 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 if (hut < 0x1)
1317 hut = 0x1;
1318 else if (hut > 0xf)
1319 hut = hut_max_code;
1320
1321 spec1 = (srt << 4) | hut;
1322 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1323
1324 /* If these parameters did not change, just return with success */
1325 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1326 /* Go ahead and set spec1 and spec2 */
1327 output_byte(FD_SPECIFY);
1328 output_byte(FDCS->spec1 = spec1);
1329 output_byte(FDCS->spec2 = spec2);
1330 }
1331} /* fdc_specify */
1332
1333/* Set the FDC's data transfer rate on behalf of the specified drive.
1334 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1335 * of the specify command (i.e. using the fdc_specify function).
1336 */
1337static int fdc_dtr(void)
1338{
1339 /* If data rate not already set to desired value, set it. */
1340 if ((raw_cmd->rate & 3) == FDCS->dtr)
1341 return 0;
1342
1343 /* Set dtr */
1344 fd_outb(raw_cmd->rate & 3, FD_DCR);
1345
1346 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1347 * need a stabilization period of several milliseconds to be
1348 * enforced after data rate changes before R/W operations.
1349 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1350 */
1351 FDCS->dtr = raw_cmd->rate & 3;
Tejun Heo75ddb382014-03-07 10:24:48 -05001352 return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353} /* fdc_dtr */
1354
1355static void tell_sector(void)
1356{
Joe Perchesb46df352010-03-10 15:20:46 -08001357 pr_cont(": track %d, head %d, sector %d, size %d",
1358 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359} /* tell_sector */
1360
Joe Perchesb46df352010-03-10 15:20:46 -08001361static void print_errors(void)
1362{
1363 DPRINT("");
1364 if (ST0 & ST0_ECE) {
1365 pr_cont("Recalibrate failed!");
1366 } else if (ST2 & ST2_CRC) {
1367 pr_cont("data CRC error");
1368 tell_sector();
1369 } else if (ST1 & ST1_CRC) {
1370 pr_cont("CRC error");
1371 tell_sector();
1372 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1373 (ST2 & ST2_MAM)) {
1374 if (!probing) {
1375 pr_cont("sector not found");
1376 tell_sector();
1377 } else
1378 pr_cont("probe failed...");
1379 } else if (ST2 & ST2_WC) { /* seek error */
1380 pr_cont("wrong cylinder");
1381 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1382 pr_cont("bad cylinder");
1383 } else {
1384 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1385 ST0, ST1, ST2);
1386 tell_sector();
1387 }
1388 pr_cont("\n");
1389}
1390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391/*
1392 * OK, this error interpreting routine is called after a
1393 * DMA read/write has succeeded
1394 * or failed, so we check the results, and copy any buffers.
1395 * hhb: Added better error reporting.
1396 * ak: Made this into a separate routine.
1397 */
1398static int interpret_errors(void)
1399{
1400 char bad;
1401
1402 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001403 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 FDCS->reset = 1;
1405 return 1;
1406 }
1407
1408 /* check IC to find cause of interrupt */
1409 switch (ST0 & ST0_INTR) {
1410 case 0x40: /* error occurred during command execution */
1411 if (ST1 & ST1_EOC)
1412 return 0; /* occurs with pseudo-DMA */
1413 bad = 1;
1414 if (ST1 & ST1_WP) {
1415 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001416 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 cont->done(0);
1418 bad = 2;
1419 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001420 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 } else if (ST1 & ST1_OR) {
1422 if (DP->flags & FTD_MSG)
1423 DPRINT("Over/Underrun - retrying\n");
1424 bad = 0;
1425 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001426 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 }
1428 if (ST2 & ST2_WC || ST2 & ST2_BC)
1429 /* wrong cylinder => recal */
1430 DRS->track = NEED_2_RECAL;
1431 return bad;
1432 case 0x80: /* invalid command given */
1433 DPRINT("Invalid FDC command given!\n");
1434 cont->done(0);
1435 return 2;
1436 case 0xc0:
1437 DPRINT("Abnormal termination caused by polling\n");
1438 cont->error();
1439 return 2;
1440 default: /* (0) Normal command termination */
1441 return 0;
1442 }
1443}
1444
1445/*
1446 * This routine is called when everything should be correctly set up
1447 * for the transfer (i.e. floppy motor is on, the correct floppy is
1448 * selected, and the head is sitting on the right track).
1449 */
1450static void setup_rw_floppy(void)
1451{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001452 int i;
1453 int r;
1454 int flags;
1455 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 unsigned long ready_date;
Tejun Heo75ddb382014-03-07 10:24:48 -05001457 void (*function)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459 flags = raw_cmd->flags;
1460 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1461 flags |= FD_RAW_INTR;
1462
1463 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1464 ready_date = DRS->spinup_date + DP->spinup;
1465 /* If spinup will take a long time, rerun scandrives
1466 * again just before spinup completion. Beware that
1467 * after scandrives, we must again wait for selection.
1468 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001469 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 ready_date -= DP->select_delay;
Tejun Heo75ddb382014-03-07 10:24:48 -05001471 function = floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 } else
Tejun Heo75ddb382014-03-07 10:24:48 -05001473 function = setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
1475 /* wait until the floppy is spinning fast enough */
1476 if (fd_wait_for_completion(ready_date, function))
1477 return;
1478 }
1479 dflags = DRS->flags;
1480
1481 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1482 setup_DMA();
1483
1484 if (flags & FD_RAW_INTR)
1485 do_floppy = main_command_interrupt;
1486
1487 r = 0;
1488 for (i = 0; i < raw_cmd->cmd_count; i++)
1489 r |= output_byte(raw_cmd->cmd[i]);
1490
Joe Perchesded28632010-03-10 15:21:09 -08001491 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
1493 if (r) {
1494 cont->error();
1495 reset_fdc();
1496 return;
1497 }
1498
1499 if (!(flags & FD_RAW_INTR)) {
1500 inr = result();
1501 cont->interrupt();
1502 } else if (flags & FD_RAW_NEED_DISK)
Tejun Heo75ddb382014-03-07 10:24:48 -05001503 fd_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504}
1505
1506static int blind_seek;
1507
1508/*
1509 * This is the routine called after every seek (or recalibrate) interrupt
1510 * from the floppy controller.
1511 */
1512static void seek_interrupt(void)
1513{
Joe Perchesded28632010-03-10 15:21:09 -08001514 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1516 DPRINT("seek failed\n");
1517 DRS->track = NEED_2_RECAL;
1518 cont->error();
1519 cont->redo();
1520 return;
1521 }
1522 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001523 debug_dcl(DP->flags,
1524 "clearing NEWCHANGE flag because of effective seek\n");
1525 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001526 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1527 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 DRS->select_date = jiffies;
1529 }
1530 DRS->track = ST1;
1531 floppy_ready();
1532}
1533
1534static void check_wp(void)
1535{
Joe Perchese0298532010-03-10 15:20:55 -08001536 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1537 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 output_byte(FD_GETSTATUS);
1539 output_byte(UNIT(current_drive));
1540 if (result() != 1) {
1541 FDCS->reset = 1;
1542 return;
1543 }
Joe Perchese0298532010-03-10 15:20:55 -08001544 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1545 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001546 debug_dcl(DP->flags,
1547 "checking whether disk is write protected\n");
1548 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001550 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 else
Joe Perchese0298532010-03-10 15:20:55 -08001552 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 }
1554}
1555
1556static void seek_floppy(void)
1557{
1558 int track;
1559
1560 blind_seek = 0;
1561
Joe Perchesded28632010-03-10 15:21:09 -08001562 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
Joe Perchese0298532010-03-10 15:20:55 -08001564 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1566 /* the media changed flag should be cleared after the seek.
1567 * If it isn't, this means that there is really no disk in
1568 * the drive.
1569 */
Joe Perchese0298532010-03-10 15:20:55 -08001570 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 cont->done(0);
1572 cont->redo();
1573 return;
1574 }
1575 if (DRS->track <= NEED_1_RECAL) {
1576 recalibrate_floppy();
1577 return;
Joe Perchese0298532010-03-10 15:20:55 -08001578 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1580 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1581 /* we seek to clear the media-changed condition. Does anybody
1582 * know a more elegant way, which works on all drives? */
1583 if (raw_cmd->track)
1584 track = raw_cmd->track - 1;
1585 else {
1586 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1587 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1588 blind_seek = 1;
1589 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1590 }
1591 track = 1;
1592 }
1593 } else {
1594 check_wp();
1595 if (raw_cmd->track != DRS->track &&
1596 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1597 track = raw_cmd->track;
1598 else {
1599 setup_rw_floppy();
1600 return;
1601 }
1602 }
1603
1604 do_floppy = seek_interrupt;
1605 output_byte(FD_SEEK);
1606 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001607 if (output_byte(track) < 0) {
1608 reset_fdc();
1609 return;
1610 }
Joe Perchesded28632010-03-10 15:21:09 -08001611 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612}
1613
1614static void recal_interrupt(void)
1615{
Joe Perchesded28632010-03-10 15:21:09 -08001616 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 if (inr != 2)
1618 FDCS->reset = 1;
1619 else if (ST0 & ST0_ECE) {
1620 switch (DRS->track) {
1621 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001622 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 /* after a second recalibrate, we still haven't
1624 * reached track 0. Probably no drive. Raise an
1625 * error, as failing immediately might upset
1626 * computers possessed by the Devil :-) */
1627 cont->error();
1628 cont->redo();
1629 return;
1630 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001631 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 /* If we already did a recalibrate,
1633 * and we are not at track 0, this
1634 * means we have moved. (The only way
1635 * not to move at recalibration is to
1636 * be already at track 0.) Clear the
1637 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001638 debug_dcl(DP->flags,
1639 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
Joe Perchese0298532010-03-10 15:20:55 -08001641 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 DRS->select_date = jiffies;
1643 /* fall through */
1644 default:
Joe Perchesded28632010-03-10 15:21:09 -08001645 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 /* Recalibrate moves the head by at
1647 * most 80 steps. If after one
1648 * recalibrate we don't have reached
1649 * track 0, this might mean that we
1650 * started beyond track 80. Try
1651 * again. */
1652 DRS->track = NEED_1_RECAL;
1653 break;
1654 }
1655 } else
1656 DRS->track = ST1;
1657 floppy_ready();
1658}
1659
1660static void print_result(char *message, int inr)
1661{
1662 int i;
1663
1664 DPRINT("%s ", message);
1665 if (inr >= 0)
1666 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001667 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1668 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669}
1670
1671/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001672irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 int do_print;
1675 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001676 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678 lasthandler = handler;
1679 interruptjiffies = jiffies;
1680
1681 f = claim_dma_lock();
1682 fd_disable_dma();
1683 release_dma_lock(f);
1684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 do_floppy = NULL;
1686 if (fdc >= N_FDC || FDCS->address == -1) {
1687 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001688 pr_info("DOR0=%x\n", fdc_state[0].dor);
1689 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001690 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001691 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 return IRQ_NONE;
1693 }
1694
1695 FDCS->reset = 0;
1696 /* We have to clear the reset flag here, because apparently on boxes
1697 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1698 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1699 * emission of the SENSEI's.
1700 * It is OK to emit floppy commands because we are in an interrupt
1701 * handler here, and thus we have to fear no interference of other
1702 * activity.
1703 */
1704
Joe Perches29f1c782010-03-10 15:21:00 -08001705 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
1707 inr = result();
1708 if (do_print)
1709 print_result("unexpected interrupt", inr);
1710 if (inr == 0) {
1711 int max_sensei = 4;
1712 do {
1713 output_byte(FD_SENSEI);
1714 inr = result();
1715 if (do_print)
1716 print_result("sensei", inr);
1717 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001718 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1719 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 }
1721 if (!handler) {
1722 FDCS->reset = 1;
1723 return IRQ_NONE;
1724 }
1725 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001726 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 /* FIXME! Was it really for us? */
1729 return IRQ_HANDLED;
1730}
1731
1732static void recalibrate_floppy(void)
1733{
Joe Perchesded28632010-03-10 15:21:09 -08001734 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 do_floppy = recal_interrupt;
1736 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001737 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001738 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739}
1740
1741/*
1742 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1743 */
1744static void reset_interrupt(void)
1745{
Joe Perchesded28632010-03-10 15:21:09 -08001746 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 result(); /* get the status ready for set_fdc */
1748 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001749 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 cont->error(); /* a reset just after a reset. BAD! */
1751 }
1752 cont->redo();
1753}
1754
1755/*
1756 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1757 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1758 */
1759static void reset_fdc(void)
1760{
1761 unsigned long flags;
1762
1763 do_floppy = reset_interrupt;
1764 FDCS->reset = 0;
1765 reset_fdc_info(0);
1766
1767 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1768 /* Irrelevant for systems with true DMA (i386). */
1769
1770 flags = claim_dma_lock();
1771 fd_disable_dma();
1772 release_dma_lock(flags);
1773
1774 if (FDCS->version >= FDC_82072A)
1775 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1776 else {
1777 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1778 udelay(FD_RESET_DELAY);
1779 fd_outb(FDCS->dor, FD_DOR);
1780 }
1781}
1782
1783static void show_floppy(void)
1784{
1785 int i;
1786
Joe Perchesb46df352010-03-10 15:20:46 -08001787 pr_info("\n");
1788 pr_info("floppy driver state\n");
1789 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001790 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001791 jiffies, interruptjiffies, jiffies - interruptjiffies,
1792 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Joe Perchesb46df352010-03-10 15:20:46 -08001794 pr_info("timeout_message=%s\n", timeout_message);
1795 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001797 pr_info("%2x %2x %lu\n",
1798 output_log[(i + output_log_pos) % OLOGSIZE].data,
1799 output_log[(i + output_log_pos) % OLOGSIZE].status,
1800 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1801 pr_info("last result at %lu\n", resultjiffies);
1802 pr_info("last redo_fd_request at %lu\n", lastredo);
1803 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1804 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Joe Perchesb46df352010-03-10 15:20:46 -08001806 pr_info("status=%x\n", fd_inb(FD_STATUS));
1807 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001809 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001810 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001811 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001812 if (delayed_work_pending(&fd_timer))
1813 pr_info("delayed work.function=%p expires=%ld\n",
1814 fd_timer.work.func,
1815 fd_timer.timer.expires - jiffies);
1816 if (delayed_work_pending(&fd_timeout))
1817 pr_info("timer_function=%p expires=%ld\n",
1818 fd_timeout.work.func,
1819 fd_timeout.timer.expires - jiffies);
1820
Joe Perchesb46df352010-03-10 15:20:46 -08001821 pr_info("cont=%p\n", cont);
1822 pr_info("current_req=%p\n", current_req);
1823 pr_info("command_status=%d\n", command_status);
1824 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825}
1826
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001827static void floppy_shutdown(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828{
1829 unsigned long flags;
1830
Joe Perches29f1c782010-03-10 15:21:00 -08001831 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 show_floppy();
1833 cancel_activity();
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 flags = claim_dma_lock();
1836 fd_disable_dma();
1837 release_dma_lock(flags);
1838
1839 /* avoid dma going to a random drive after shutdown */
1840
Joe Perches29f1c782010-03-10 15:21:00 -08001841 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 DPRINT("floppy timeout called\n");
1843 FDCS->reset = 1;
1844 if (cont) {
1845 cont->done(0);
1846 cont->redo(); /* this will recall reset when needed */
1847 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001848 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 process_fd_request();
1850 }
Joe Perches275176b2010-03-10 15:21:06 -08001851 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852}
1853
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001855static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001857 int mask;
1858 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
1860 mask = 0xfc;
1861 data = UNIT(current_drive);
1862 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1863 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1864 set_debugt();
1865 /* no read since this drive is running */
1866 DRS->first_read_date = 0;
1867 /* note motor start time if motor is not yet running */
1868 DRS->spinup_date = jiffies;
1869 data |= (0x10 << UNIT(current_drive));
1870 }
1871 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1872 mask &= ~(0x10 << UNIT(current_drive));
1873
1874 /* starts motor and selects floppy */
1875 del_timer(motor_off_timer + current_drive);
1876 set_dor(fdc, mask, data);
1877
1878 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001879 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
Tejun Heo75ddb382014-03-07 10:24:48 -05001880 function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881}
1882
1883static void floppy_ready(void)
1884{
Joe Perches045f9832010-03-10 15:20:47 -08001885 if (FDCS->reset) {
1886 reset_fdc();
1887 return;
1888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (start_motor(floppy_ready))
1890 return;
1891 if (fdc_dtr())
1892 return;
1893
Joe Perches87f530d2010-03-10 15:20:54 -08001894 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1896 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001897 twaddle(); /* this clears the dcl on certain
1898 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900#ifdef fd_chose_dma_mode
1901 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1902 unsigned long flags = claim_dma_lock();
1903 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1904 release_dma_lock(flags);
1905 }
1906#endif
1907
1908 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1909 perpendicular_mode();
1910 fdc_specify(); /* must be done here because of hut, hlt ... */
1911 seek_floppy();
1912 } else {
1913 if ((raw_cmd->flags & FD_RAW_READ) ||
1914 (raw_cmd->flags & FD_RAW_WRITE))
1915 fdc_specify();
1916 setup_rw_floppy();
1917 }
1918}
1919
1920static void floppy_start(void)
1921{
Joe Perches73507e62010-03-10 15:21:03 -08001922 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001925 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001926 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 floppy_ready();
1928}
1929
1930/*
1931 * ========================================================================
1932 * here ends the bottom half. Exported routines are:
1933 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1934 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1935 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1936 * and set_dor.
1937 * ========================================================================
1938 */
1939/*
1940 * General purpose continuations.
1941 * ==============================
1942 */
1943
1944static void do_wakeup(void)
1945{
Joe Perches73507e62010-03-10 15:21:03 -08001946 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 cont = NULL;
1948 command_status += 2;
1949 wake_up(&command_done);
1950}
1951
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001952static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 .interrupt = empty,
1954 .redo = do_wakeup,
1955 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001956 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957};
1958
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001959static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 .interrupt = empty,
1961 .redo = process_fd_request,
1962 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001963 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964};
1965
Joe Perches74f63f42010-03-10 15:20:58 -08001966static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967{
1968 int ret;
1969
1970 schedule_bh(handler);
1971
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001972 if (interruptible)
1973 wait_event_interruptible(command_done, command_status >= 2);
1974 else
1975 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 if (command_status < 2) {
1978 cancel_activity();
1979 cont = &intr_cont;
1980 reset_fdc();
1981 return -EINTR;
1982 }
1983
1984 if (FDCS->reset)
1985 command_status = FD_COMMAND_ERROR;
1986 if (command_status == FD_COMMAND_OKAY)
1987 ret = 0;
1988 else
1989 ret = -EIO;
1990 command_status = FD_COMMAND_NONE;
1991 return ret;
1992}
1993
1994static void generic_done(int result)
1995{
1996 command_status = result;
1997 cont = &wakeup_cont;
1998}
1999
2000static void generic_success(void)
2001{
2002 cont->done(1);
2003}
2004
2005static void generic_failure(void)
2006{
2007 cont->done(0);
2008}
2009
2010static void success_and_wakeup(void)
2011{
2012 generic_success();
2013 cont->redo();
2014}
2015
2016/*
2017 * formatting and rw support.
2018 * ==========================
2019 */
2020
2021static int next_valid_format(void)
2022{
2023 int probed_format;
2024
2025 probed_format = DRS->probed_format;
2026 while (1) {
2027 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2028 DRS->probed_format = 0;
2029 return 1;
2030 }
2031 if (floppy_type[DP->autodetect[probed_format]].sect) {
2032 DRS->probed_format = probed_format;
2033 return 0;
2034 }
2035 probed_format++;
2036 }
2037}
2038
2039static void bad_flp_intr(void)
2040{
2041 int err_count;
2042
2043 if (probing) {
2044 DRS->probed_format++;
2045 if (!next_valid_format())
2046 return;
2047 }
2048 err_count = ++(*errors);
2049 INFBOUND(DRWE->badness, err_count);
2050 if (err_count > DP->max_errors.abort)
2051 cont->done(0);
2052 if (err_count > DP->max_errors.reset)
2053 FDCS->reset = 1;
2054 else if (err_count > DP->max_errors.recal)
2055 DRS->track = NEED_2_RECAL;
2056}
2057
2058static void set_floppy(int drive)
2059{
2060 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002061
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (type)
2063 _floppy = floppy_type + type;
2064 else
2065 _floppy = current_type[drive];
2066}
2067
2068/*
2069 * formatting support.
2070 * ===================
2071 */
2072static void format_interrupt(void)
2073{
2074 switch (interpret_errors()) {
2075 case 1:
2076 cont->error();
2077 case 2:
2078 break;
2079 case 0:
2080 cont->done(1);
2081 }
2082 cont->redo();
2083}
2084
Joe Perches48c8cee2010-03-10 15:20:45 -08002085#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002087
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088static void setup_format_params(int track)
2089{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002090 int n;
2091 int il;
2092 int count;
2093 int head_shift;
2094 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 struct fparm {
2096 unsigned char track, head, sect, size;
2097 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
2099 raw_cmd = &default_raw_cmd;
2100 raw_cmd->track = track;
2101
Joe Perches48c8cee2010-03-10 15:20:45 -08002102 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2103 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 raw_cmd->rate = _floppy->rate & 0x43;
2105 raw_cmd->cmd_count = NR_F;
2106 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2107 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2108 F_SIZECODE = FD_SIZECODE(_floppy);
2109 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2110 F_GAP = _floppy->fmt_gap;
2111 F_FILL = FD_FILL_BYTE;
2112
2113 raw_cmd->kernel_data = floppy_track_buffer;
2114 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2115
2116 /* allow for about 30ms for data transport per track */
2117 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2118
2119 /* a ``cylinder'' is two tracks plus a little stepping time */
2120 track_shift = 2 * head_shift + 3;
2121
2122 /* position of logical sector 1 on this track */
2123 n = (track_shift * format_req.track + head_shift * format_req.head)
2124 % F_SECT_PER_TRACK;
2125
2126 /* determine interleave */
2127 il = 1;
2128 if (_floppy->fmt_gap < 0x22)
2129 il++;
2130
2131 /* initialize field */
2132 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2133 here[count].track = format_req.track;
2134 here[count].head = format_req.head;
2135 here[count].sect = 0;
2136 here[count].size = F_SIZECODE;
2137 }
2138 /* place logical sectors */
2139 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2140 here[n].sect = count;
2141 n = (n + il) % F_SECT_PER_TRACK;
2142 if (here[n].sect) { /* sector busy, find next free sector */
2143 ++n;
2144 if (n >= F_SECT_PER_TRACK) {
2145 n -= F_SECT_PER_TRACK;
2146 while (here[n].sect)
2147 ++n;
2148 }
2149 }
2150 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002151 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002153 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 }
2155}
2156
2157static void redo_format(void)
2158{
2159 buffer_track = -1;
2160 setup_format_params(format_req.track << STRETCH(_floppy));
2161 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002162 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163}
2164
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002165static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 .interrupt = format_interrupt,
2167 .redo = redo_format,
2168 .error = bad_flp_intr,
2169 .done = generic_done
2170};
2171
2172static int do_format(int drive, struct format_descr *tmp_format_req)
2173{
2174 int ret;
2175
Joe Perches74f63f42010-03-10 15:20:58 -08002176 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002177 return -EINTR;
2178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 set_floppy(drive);
2180 if (!_floppy ||
2181 _floppy->track > DP->tracks ||
2182 tmp_format_req->track >= _floppy->track ||
2183 tmp_format_req->head >= _floppy->head ||
2184 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2185 !_floppy->fmt_gap) {
2186 process_fd_request();
2187 return -EINVAL;
2188 }
2189 format_req = *tmp_format_req;
2190 format_errors = 0;
2191 cont = &format_cont;
2192 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002193 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002194 if (ret == -EINTR)
2195 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 process_fd_request();
2197 return ret;
2198}
2199
2200/*
2201 * Buffer read/write and support
2202 * =============================
2203 */
2204
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002205static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206{
2207 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002208 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
2210 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002211 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002212 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002213 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
2216 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002217 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 current_req = NULL;
2219}
2220
2221/* new request_done. Can handle physical sectors which are smaller than a
2222 * logical buffer */
2223static void request_done(int uptodate)
2224{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 struct request *req = current_req;
Jens Axboe48821182010-09-22 09:32:36 +02002226 struct request_queue *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 unsigned long flags;
2228 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002229 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
2231 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002232 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2233 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
2235 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002236 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 return;
2238 }
2239
Jens Axboe48821182010-09-22 09:32:36 +02002240 q = req->q;
2241
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 if (uptodate) {
2243 /* maintain values for invalidation on geometry
2244 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002245 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 INFBOUND(DRS->maxblock, block);
2247 if (block > _floppy->sect)
2248 DRS->maxtrack = 1;
2249
2250 /* unlock chained buffers */
2251 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002252 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 spin_unlock_irqrestore(q->queue_lock, flags);
2254 } else {
2255 if (rq_data_dir(req) == WRITE) {
2256 /* record write error information */
2257 DRWE->write_errors++;
2258 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002259 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 DRWE->first_error_generation = DRS->generation;
2261 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002262 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 DRWE->last_error_generation = DRS->generation;
2264 }
2265 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002266 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 spin_unlock_irqrestore(q->queue_lock, flags);
2268 }
2269}
2270
2271/* Interrupt handler evaluating the result of the r/w operation */
2272static void rw_interrupt(void)
2273{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002274 int eoc;
2275 int ssize;
2276 int heads;
2277 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278
2279 if (R_HEAD >= 2) {
2280 /* some Toshiba floppy controllers occasionnally seem to
2281 * return bogus interrupts after read/write operations, which
2282 * can be recognized by a bad head number (>= 2) */
2283 return;
2284 }
2285
2286 if (!DRS->first_read_date)
2287 DRS->first_read_date = jiffies;
2288
2289 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002290 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 if (ST1 & ST1_EOC)
2293 eoc = 1;
2294 else
2295 eoc = 0;
2296
2297 if (COMMAND & 0x80)
2298 heads = 2;
2299 else
2300 heads = 1;
2301
2302 nr_sectors = (((R_TRACK - TRACK) * heads +
2303 R_HEAD - HEAD) * SECT_PER_TRACK +
2304 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002307 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 DPRINT("long rw: %x instead of %lx\n",
2309 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002310 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2311 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2312 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2313 pr_info("heads=%d eoc=%d\n", heads, eoc);
2314 pr_info("spt=%d st=%d ss=%d\n",
2315 SECT_PER_TRACK, fsector_t, ssize);
2316 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
2319 nr_sectors -= in_sector_offset;
2320 INFBOUND(nr_sectors, 0);
2321 SUPBOUND(current_count_sectors, nr_sectors);
2322
2323 switch (interpret_errors()) {
2324 case 2:
2325 cont->redo();
2326 return;
2327 case 1:
2328 if (!current_count_sectors) {
2329 cont->error();
2330 cont->redo();
2331 return;
2332 }
2333 break;
2334 case 0:
2335 if (!current_count_sectors) {
2336 cont->redo();
2337 return;
2338 }
2339 current_type[current_drive] = _floppy;
2340 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2341 break;
2342 }
2343
2344 if (probing) {
2345 if (DP->flags & FTD_MSG)
2346 DPRINT("Auto-detected floppy type %s in fd%d\n",
2347 _floppy->name, current_drive);
2348 current_type[current_drive] = _floppy;
2349 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2350 probing = 0;
2351 }
2352
2353 if (CT(COMMAND) != FD_READ ||
Jens Axboeb4f42e22014-04-10 09:46:28 -06002354 raw_cmd->kernel_data == bio_data(current_req->bio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 /* transfer directly from buffer */
2356 cont->done(1);
2357 } else if (CT(COMMAND) == FD_READ) {
2358 buffer_track = raw_cmd->track;
2359 buffer_drive = current_drive;
2360 INFBOUND(buffer_max, nr_sectors + fsector_t);
2361 }
2362 cont->redo();
2363}
2364
2365/* Compute maximal contiguous buffer size. */
2366static int buffer_chain_size(void)
2367{
Kent Overstreet79886132013-11-23 17:19:00 -08002368 struct bio_vec bv;
NeilBrown5705f702007-09-25 12:35:59 +02002369 int size;
2370 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 char *base;
2372
2373 base = bio_data(current_req->bio);
2374 size = 0;
2375
NeilBrown5705f702007-09-25 12:35:59 +02002376 rq_for_each_segment(bv, current_req, iter) {
Kent Overstreet79886132013-11-23 17:19:00 -08002377 if (page_address(bv.bv_page) + bv.bv_offset != base + size)
NeilBrown5705f702007-09-25 12:35:59 +02002378 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379
Kent Overstreet79886132013-11-23 17:19:00 -08002380 size += bv.bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 }
2382
2383 return size >> 9;
2384}
2385
2386/* Compute the maximal transfer size */
2387static int transfer_size(int ssize, int max_sector, int max_size)
2388{
2389 SUPBOUND(max_sector, fsector_t + max_size);
2390
2391 /* alignment */
2392 max_sector -= (max_sector % _floppy->sect) % ssize;
2393
2394 /* transfer size, beginning not aligned */
2395 current_count_sectors = max_sector - fsector_t;
2396
2397 return max_sector;
2398}
2399
2400/*
2401 * Move data from/to the track buffer to/from the buffer cache.
2402 */
2403static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2404{
2405 int remaining; /* number of transferred 512-byte sectors */
Kent Overstreet79886132013-11-23 17:19:00 -08002406 struct bio_vec bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002407 char *buffer;
2408 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002409 int size;
2410 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
2412 max_sector = transfer_size(ssize,
2413 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002414 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
2416 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002417 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002419 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
2421 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002422 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002424 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2425 pr_info("remaining=%d\n", remaining >> 9);
2426 pr_info("current_req->nr_sectors=%u\n",
2427 blk_rq_sectors(current_req));
2428 pr_info("current_req->current_nr_sectors=%u\n",
2429 blk_rq_cur_sectors(current_req));
2430 pr_info("max_sector=%d\n", max_sector);
2431 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434 buffer_max = max(max_sector, buffer_max);
2435
2436 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2437
Tejun Heo1011c1b2009-05-07 22:24:45 +09002438 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
NeilBrown5705f702007-09-25 12:35:59 +02002440 rq_for_each_segment(bv, current_req, iter) {
2441 if (!remaining)
2442 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Kent Overstreet79886132013-11-23 17:19:00 -08002444 size = bv.bv_len;
NeilBrown5705f702007-09-25 12:35:59 +02002445 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446
Kent Overstreet79886132013-11-23 17:19:00 -08002447 buffer = page_address(bv.bv_page) + bv.bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002448 if (dma_buffer + size >
2449 floppy_track_buffer + (max_buffer_sectors << 10) ||
2450 dma_buffer < floppy_track_buffer) {
2451 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002452 (int)((floppy_track_buffer - dma_buffer) >> 9));
2453 pr_info("fsector_t=%d buffer_min=%d\n",
2454 fsector_t, buffer_min);
2455 pr_info("current_count_sectors=%ld\n",
2456 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002458 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002459 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002460 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002461 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 }
NeilBrown5705f702007-09-25 12:35:59 +02002463 if (((unsigned long)buffer) % 512)
2464 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002465
NeilBrown5705f702007-09-25 12:35:59 +02002466 if (CT(COMMAND) == FD_READ)
2467 memcpy(buffer, dma_buffer, size);
2468 else
2469 memcpy(dma_buffer, buffer, size);
2470
2471 remaining -= size;
2472 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 if (remaining) {
2475 if (remaining > 0)
2476 max_sector -= remaining >> 9;
2477 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479}
2480
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481/* work around a bug in pseudo DMA
2482 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2483 * sending data. Hence we need a different way to signal the
2484 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2485 * does not work with MT, hence we can only transfer one head at
2486 * a time
2487 */
2488static void virtualdmabug_workaround(void)
2489{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002490 int hard_sectors;
2491 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
2493 if (CT(COMMAND) == FD_WRITE) {
2494 COMMAND &= ~0x80; /* switch off multiple track mode */
2495
2496 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2497 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002499 pr_info("too many sectors %d > %d\n",
2500 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 return;
2502 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002503 SECT_PER_TRACK = end_sector;
2504 /* make sure SECT_PER_TRACK
2505 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 }
2507}
2508
2509/*
2510 * Formulate a read/write request.
2511 * this routine decides where to load the data (directly to buffer, or to
2512 * tmp floppy area), how much data to load (the size of the buffer, the whole
2513 * track, or a single sector)
2514 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2515 * allocation on the fly, it should be done here. No other part should need
2516 * modification.
2517 */
2518
2519static int make_raw_rw_request(void)
2520{
2521 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002522 int max_sector;
2523 int max_size;
2524 int tracksize;
2525 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002527 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530 set_fdc((long)current_req->rq_disk->private_data);
2531
2532 raw_cmd = &default_raw_cmd;
Fengguang Wu2fb2ca62012-07-28 19:45:59 +08002533 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 raw_cmd->cmd_count = NR_RW;
2535 if (rq_data_dir(current_req) == READ) {
2536 raw_cmd->flags |= FD_RAW_READ;
2537 COMMAND = FM_MODE(_floppy, FD_READ);
2538 } else if (rq_data_dir(current_req) == WRITE) {
2539 raw_cmd->flags |= FD_RAW_WRITE;
2540 COMMAND = FM_MODE(_floppy, FD_WRITE);
2541 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002542 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 return 0;
2544 }
2545
2546 max_sector = _floppy->sect * _floppy->head;
2547
Tejun Heo83096eb2009-05-07 22:24:39 +09002548 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2549 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002551 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 current_count_sectors = 1;
2553 return 1;
2554 } else
2555 return 0;
2556 }
2557 HEAD = fsector_t / _floppy->sect;
2558
Keith Wansbrough9e491842008-09-22 14:57:17 -07002559 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002560 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2561 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 max_sector = _floppy->sect;
2563
2564 /* 2M disks have phantom sectors on the first track */
2565 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2566 max_sector = 2 * _floppy->sect / 3;
2567 if (fsector_t >= max_sector) {
2568 current_count_sectors =
2569 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002570 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 return 1;
2572 }
2573 SIZECODE = 2;
2574 } else
2575 SIZECODE = FD_SIZECODE(_floppy);
2576 raw_cmd->rate = _floppy->rate & 0x43;
2577 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2578 raw_cmd->rate = 1;
2579
2580 if (SIZECODE)
2581 SIZECODE2 = 0xff;
2582 else
2583 SIZECODE2 = 0x80;
2584 raw_cmd->track = TRACK << STRETCH(_floppy);
2585 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2586 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002587 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2589 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002590 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
2592 /* tracksize describes the size which can be filled up with sectors
2593 * of size ssize.
2594 */
2595 tracksize = _floppy->sect - _floppy->sect % ssize;
2596 if (tracksize < _floppy->sect) {
2597 SECT_PER_TRACK++;
2598 if (tracksize <= fsector_t % _floppy->sect)
2599 SECTOR--;
2600
2601 /* if we are beyond tracksize, fill up using smaller sectors */
2602 while (tracksize <= fsector_t % _floppy->sect) {
2603 while (tracksize + ssize > _floppy->sect) {
2604 SIZECODE--;
2605 ssize >>= 1;
2606 }
2607 SECTOR++;
2608 SECT_PER_TRACK++;
2609 tracksize += ssize;
2610 }
2611 max_sector = HEAD * _floppy->sect + tracksize;
2612 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2613 max_sector = _floppy->sect;
2614 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2615 /* for virtual DMA bug workaround */
2616 max_sector = _floppy->sect;
2617 }
2618
2619 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2620 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002621 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 if ((raw_cmd->track == buffer_track) &&
2623 (current_drive == buffer_drive) &&
2624 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2625 /* data already in track buffer */
2626 if (CT(COMMAND) == FD_READ) {
2627 copy_buffer(1, max_sector, buffer_max);
2628 return 1;
2629 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002630 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002632 unsigned int sectors;
2633
2634 sectors = fsector_t + blk_rq_sectors(current_req);
2635 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 max_size = ssize + ssize;
2637 else
2638 max_size = ssize;
2639 }
2640 raw_cmd->flags &= ~FD_RAW_WRITE;
2641 raw_cmd->flags |= FD_RAW_READ;
2642 COMMAND = FM_MODE(_floppy, FD_READ);
Jens Axboeb4f42e22014-04-10 09:46:28 -06002643 } else if ((unsigned long)bio_data(current_req->bio) < MAX_DMA_ADDRESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 unsigned long dma_limit;
2645 int direct, indirect;
2646
2647 indirect =
2648 transfer_size(ssize, max_sector,
2649 max_buffer_sectors * 2) - fsector_t;
2650
2651 /*
2652 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2653 * on a 64 bit machine!
2654 */
2655 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002656 dma_limit = (MAX_DMA_ADDRESS -
Jens Axboeb4f42e22014-04-10 09:46:28 -06002657 ((unsigned long)bio_data(current_req->bio))) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002658 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 /* 64 kb boundaries */
Jens Axboeb4f42e22014-04-10 09:46:28 -06002661 if (CROSS_64KB(bio_data(current_req->bio), max_size << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 max_size = (K_64 -
Jens Axboeb4f42e22014-04-10 09:46:28 -06002663 ((unsigned long)bio_data(current_req->bio)) %
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 K_64) >> 9;
2665 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2666 /*
2667 * We try to read tracks, but if we get too many errors, we
2668 * go back to reading just one sector at a time.
2669 *
2670 * This means we should be able to read a sector even if there
2671 * are other bad sectors on this track.
2672 */
2673 if (!direct ||
2674 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002675 *errors < DP->max_errors.read_track &&
2676 ((!probing ||
2677 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002678 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 } else {
Jens Axboeb4f42e22014-04-10 09:46:28 -06002680 raw_cmd->kernel_data = bio_data(current_req->bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 raw_cmd->length = current_count_sectors << 9;
2682 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002683 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002684 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 indirect, direct, fsector_t);
2686 return 0;
2687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 virtualdmabug_workaround();
2689 return 2;
2690 }
2691 }
2692
2693 if (CT(COMMAND) == FD_READ)
2694 max_size = max_sector; /* unbounded */
2695
2696 /* claim buffer track if needed */
2697 if (buffer_track != raw_cmd->track || /* bad track */
2698 buffer_drive != current_drive || /* bad drive */
2699 fsector_t > buffer_max ||
2700 fsector_t < buffer_min ||
2701 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002702 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002704 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2705 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 buffer_track = -1;
2707 buffer_drive = current_drive;
2708 buffer_max = buffer_min = aligned_sector_t;
2709 }
2710 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002711 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
2713 if (CT(COMMAND) == FD_WRITE) {
2714 /* copy write buffer to track buffer.
2715 * if we get here, we know that the write
2716 * is either aligned or the data already in the buffer
2717 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 if (in_sector_offset && buffer_track == -1)
2719 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 buffer_track = raw_cmd->track;
2721 buffer_drive = current_drive;
2722 copy_buffer(ssize, max_sector,
2723 2 * max_buffer_sectors + buffer_min);
2724 } else
2725 transfer_size(ssize, max_sector,
2726 2 * max_buffer_sectors + buffer_min -
2727 aligned_sector_t);
2728
2729 /* round up current_count_sectors to get dma xfer size */
2730 raw_cmd->length = in_sector_offset + current_count_sectors;
2731 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2732 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 if ((raw_cmd->length < current_count_sectors << 9) ||
Jens Axboeb4f42e22014-04-10 09:46:28 -06002734 (raw_cmd->kernel_data != bio_data(current_req->bio) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 CT(COMMAND) == FD_WRITE &&
2736 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2737 aligned_sector_t < buffer_min)) ||
2738 raw_cmd->length % (128 << SIZECODE) ||
2739 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2740 DPRINT("fractionary current count b=%lx s=%lx\n",
2741 raw_cmd->length, current_count_sectors);
Jens Axboeb4f42e22014-04-10 09:46:28 -06002742 if (raw_cmd->kernel_data != bio_data(current_req->bio))
Joe Perchesb46df352010-03-10 15:20:46 -08002743 pr_info("addr=%d, length=%ld\n",
2744 (int)((raw_cmd->kernel_data -
2745 floppy_track_buffer) >> 9),
2746 current_count_sectors);
2747 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2748 fsector_t, aligned_sector_t, max_sector, max_size);
2749 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2750 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2751 COMMAND, SECTOR, HEAD, TRACK);
2752 pr_info("buffer drive=%d\n", buffer_drive);
2753 pr_info("buffer track=%d\n", buffer_track);
2754 pr_info("buffer_min=%d\n", buffer_min);
2755 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 return 0;
2757 }
2758
Jens Axboeb4f42e22014-04-10 09:46:28 -06002759 if (raw_cmd->kernel_data != bio_data(current_req->bio)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 if (raw_cmd->kernel_data < floppy_track_buffer ||
2761 current_count_sectors < 0 ||
2762 raw_cmd->length < 0 ||
2763 raw_cmd->kernel_data + raw_cmd->length >
2764 floppy_track_buffer + (max_buffer_sectors << 10)) {
2765 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002766 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2767 fsector_t, buffer_min, raw_cmd->length >> 9);
2768 pr_info("current_count_sectors=%ld\n",
2769 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002771 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002773 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return 0;
2775 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002776 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002777 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 DPRINT("buffer overrun in direct transfer\n");
2779 return 0;
2780 } else if (raw_cmd->length < current_count_sectors << 9) {
2781 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002782 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2783 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 }
2785 if (raw_cmd->length == 0) {
2786 DPRINT("zero dma transfer attempted from make_raw_request\n");
2787 return 0;
2788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
2790 virtualdmabug_workaround();
2791 return 2;
2792}
2793
Jens Axboe48821182010-09-22 09:32:36 +02002794/*
2795 * Round-robin between our available drives, doing one request from each
2796 */
2797static int set_next_request(void)
2798{
2799 struct request_queue *q;
2800 int old_pos = fdc_queue;
2801
2802 do {
2803 q = disks[fdc_queue]->queue;
2804 if (++fdc_queue == N_DRIVE)
2805 fdc_queue = 0;
2806 if (q) {
2807 current_req = blk_fetch_request(q);
2808 if (current_req)
2809 break;
2810 }
2811 } while (fdc_queue != old_pos);
2812
2813 return current_req != NULL;
2814}
2815
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816static void redo_fd_request(void)
2817{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 int drive;
2819 int tmp;
2820
2821 lastredo = jiffies;
2822 if (current_drive < N_DRIVE)
2823 floppy_off(current_drive);
2824
Joe Perches0da31322010-03-10 15:21:03 -08002825do_request:
2826 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002827 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828
Jens Axboe48821182010-09-22 09:32:36 +02002829 spin_lock_irq(&floppy_lock);
2830 pending = set_next_request();
2831 spin_unlock_irq(&floppy_lock);
Jens Axboe48821182010-09-22 09:32:36 +02002832 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002833 do_floppy = NULL;
2834 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 }
Joe Perches0da31322010-03-10 15:21:03 -08002838 drive = (long)current_req->rq_disk->private_data;
2839 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002840 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002841
2842 set_floppy(drive);
2843 raw_cmd = &default_raw_cmd;
2844 raw_cmd->flags = 0;
2845 if (start_motor(redo_fd_request))
2846 return;
2847
2848 disk_change(current_drive);
2849 if (test_bit(current_drive, &fake_change) ||
2850 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2851 DPRINT("disk absent or changed during operation\n");
2852 request_done(0);
2853 goto do_request;
2854 }
2855 if (!_floppy) { /* Autodetection */
2856 if (!probing) {
2857 DRS->probed_format = 0;
2858 if (next_valid_format()) {
2859 DPRINT("no autodetectable formats\n");
2860 _floppy = NULL;
2861 request_done(0);
2862 goto do_request;
2863 }
2864 }
2865 probing = 1;
2866 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2867 } else
2868 probing = 0;
2869 errors = &(current_req->errors);
2870 tmp = make_raw_rw_request();
2871 if (tmp < 2) {
2872 request_done(tmp);
2873 goto do_request;
2874 }
2875
2876 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2877 twaddle();
2878 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002879 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002880 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881}
2882
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002883static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 .interrupt = rw_interrupt,
2885 .redo = redo_fd_request,
2886 .error = bad_flp_intr,
2887 .done = request_done
2888};
2889
2890static void process_fd_request(void)
2891{
2892 cont = &rw_cont;
2893 schedule_bh(redo_fd_request);
2894}
2895
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002896static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897{
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002898 if (WARN(max_buffer_sectors == 0,
2899 "VFS: %s called on non-open device\n", __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002902 if (WARN(atomic_read(&usage_count) == 0,
Jens Axboe59533162013-05-23 12:25:08 +02002903 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%llx\n",
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002904 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
Jens Axboe59533162013-05-23 12:25:08 +02002905 (unsigned long long) current_req->cmd_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 return;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002907
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002908 if (test_and_set_bit(0, &fdc_busy)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 /* fdc busy, this new request will be treated when the
2910 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002911 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 return;
2913 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002914 command_status = FD_COMMAND_NONE;
2915 __reschedule_timeout(MAXTIMEOUT, "fd_request");
2916 set_fdc(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002918 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919}
2920
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002921static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 .interrupt = success_and_wakeup,
2923 .redo = floppy_ready,
2924 .error = generic_failure,
2925 .done = generic_done
2926};
2927
Joe Perches74f63f42010-03-10 15:20:58 -08002928static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 /* no auto-sense, just clear dcl */
2931 raw_cmd = &default_raw_cmd;
2932 raw_cmd->flags = flag;
2933 raw_cmd->track = 0;
2934 raw_cmd->cmd_count = 0;
2935 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002936 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002937 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002938
2939 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940}
2941
2942/*
2943 * User triggered reset
2944 * ====================
2945 */
2946
2947static void reset_intr(void)
2948{
Joe Perchesb46df352010-03-10 15:20:46 -08002949 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950}
2951
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002952static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 .interrupt = reset_intr,
2954 .redo = success_and_wakeup,
2955 .error = generic_failure,
2956 .done = generic_done
2957};
2958
Joe Perches74f63f42010-03-10 15:20:58 -08002959static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960{
2961 int ret;
2962
Joe Perches52a0d612010-03-10 15:20:53 -08002963 if (lock_fdc(drive, interruptible))
2964 return -EINTR;
2965
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 if (arg == FD_RESET_ALWAYS)
2967 FDCS->reset = 1;
2968 if (FDCS->reset) {
2969 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002970 ret = wait_til_done(reset_fdc, interruptible);
2971 if (ret == -EINTR)
2972 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 }
2974 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002975 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976}
2977
2978/*
2979 * Misc Ioctl's and support
2980 * ========================
2981 */
2982static inline int fd_copyout(void __user *param, const void *address,
2983 unsigned long size)
2984{
2985 return copy_to_user(param, address, size) ? -EFAULT : 0;
2986}
2987
Joe Perches48c8cee2010-03-10 15:20:45 -08002988static inline int fd_copyin(void __user *param, void *address,
2989 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990{
2991 return copy_from_user(address, param, size) ? -EFAULT : 0;
2992}
2993
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02002994static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995{
2996 struct floppy_struct *floppy;
2997
2998 if (type)
2999 floppy = floppy_type + type;
3000 else {
3001 if (UDP->native_format)
3002 floppy = floppy_type + UDP->native_format;
3003 else
3004 return "(null)";
3005 }
3006 if (floppy->name)
3007 return floppy->name;
3008 else
3009 return "(null)";
3010}
3011
3012/* raw commands */
3013static void raw_cmd_done(int flag)
3014{
3015 int i;
3016
3017 if (!flag) {
3018 raw_cmd->flags |= FD_RAW_FAILURE;
3019 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3020 } else {
3021 raw_cmd->reply_count = inr;
3022 if (raw_cmd->reply_count > MAX_REPLIES)
3023 raw_cmd->reply_count = 0;
3024 for (i = 0; i < raw_cmd->reply_count; i++)
3025 raw_cmd->reply[i] = reply_buffer[i];
3026
3027 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3028 unsigned long flags;
3029 flags = claim_dma_lock();
3030 raw_cmd->length = fd_get_dma_residue();
3031 release_dma_lock(flags);
3032 }
3033
3034 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3035 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3036 raw_cmd->flags |= FD_RAW_FAILURE;
3037
3038 if (disk_change(current_drive))
3039 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3040 else
3041 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3042 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3043 motor_off_callback(current_drive);
3044
3045 if (raw_cmd->next &&
3046 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3047 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3048 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3049 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3050 raw_cmd = raw_cmd->next;
3051 return;
3052 }
3053 }
3054 generic_done(flag);
3055}
3056
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003057static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 .interrupt = success_and_wakeup,
3059 .redo = floppy_start,
3060 .error = generic_failure,
3061 .done = raw_cmd_done
3062};
3063
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003064static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 struct floppy_raw_cmd *ptr)
3066{
3067 int ret;
3068
3069 while (ptr) {
Joe Perchesce2f11f2010-03-10 15:21:08 -08003070 ret = copy_to_user(param, ptr, sizeof(*ptr));
Joe Perches86b12b42010-03-10 15:20:56 -08003071 if (ret)
3072 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 param += sizeof(struct floppy_raw_cmd);
3074 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003075 if (ptr->length >= 0 &&
3076 ptr->length <= ptr->buffer_length) {
3077 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003078 ret = fd_copyout(ptr->data, ptr->kernel_data,
3079 length);
3080 if (ret)
3081 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 }
3084 ptr = ptr->next;
3085 }
Joe Perches7f252712010-03-10 15:21:08 -08003086
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 return 0;
3088}
3089
3090static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3091{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003092 struct floppy_raw_cmd *next;
3093 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
3095 this = *ptr;
3096 *ptr = NULL;
3097 while (this) {
3098 if (this->buffer_length) {
3099 fd_dma_mem_free((unsigned long)this->kernel_data,
3100 this->buffer_length);
3101 this->buffer_length = 0;
3102 }
3103 next = this->next;
3104 kfree(this);
3105 this = next;
3106 }
3107}
3108
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003109static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 struct floppy_raw_cmd **rcmd)
3111{
3112 struct floppy_raw_cmd *ptr;
3113 int ret;
3114 int i;
3115
3116 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003117
3118loop:
3119 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3120 if (!ptr)
3121 return -ENOMEM;
3122 *rcmd = ptr;
3123 ret = copy_from_user(ptr, param, sizeof(*ptr));
3124 if (ret)
3125 return -EFAULT;
3126 ptr->next = NULL;
3127 ptr->buffer_length = 0;
3128 param += sizeof(struct floppy_raw_cmd);
3129 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 /* the command may now also take up the space
3131 * initially intended for the reply & the
3132 * reply count. Needed for long 82078 commands
3133 * such as RESTORE, which takes ... 17 command
3134 * bytes. Murphy's law #137: When you reserve
3135 * 16 bytes for a structure, you'll one day
3136 * discover that you really need 17...
3137 */
Joe Perches7f252712010-03-10 15:21:08 -08003138 return -EINVAL;
3139
3140 for (i = 0; i < 16; i++)
3141 ptr->reply[i] = 0;
3142 ptr->resultcode = 0;
3143 ptr->kernel_data = NULL;
3144
3145 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3146 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003148 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3149 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3150 if (!ptr->kernel_data)
3151 return -ENOMEM;
3152 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 }
Joe Perches7f252712010-03-10 15:21:08 -08003154 if (ptr->flags & FD_RAW_WRITE) {
3155 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3156 if (ret)
3157 return ret;
3158 }
3159
3160 if (ptr->flags & FD_RAW_MORE) {
3161 rcmd = &(ptr->next);
3162 ptr->rate &= 0x43;
3163 goto loop;
3164 }
3165
3166 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167}
3168
3169static int raw_cmd_ioctl(int cmd, void __user *param)
3170{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003172 int drive;
3173 int ret2;
3174 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
3176 if (FDCS->rawcmd <= 1)
3177 FDCS->rawcmd = 1;
3178 for (drive = 0; drive < N_DRIVE; drive++) {
3179 if (FDC(drive) != fdc)
3180 continue;
3181 if (drive == current_drive) {
3182 if (UDRS->fd_ref > 1) {
3183 FDCS->rawcmd = 2;
3184 break;
3185 }
3186 } else if (UDRS->fd_ref) {
3187 FDCS->rawcmd = 2;
3188 break;
3189 }
3190 }
3191
3192 if (FDCS->reset)
3193 return -EIO;
3194
3195 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3196 if (ret) {
3197 raw_cmd_free(&my_raw_cmd);
3198 return ret;
3199 }
3200
3201 raw_cmd = my_raw_cmd;
3202 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003203 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003204 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
3206 if (ret != -EINTR && FDCS->reset)
3207 ret = -EIO;
3208
3209 DRS->track = NO_TRACK;
3210
3211 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3212 if (!ret)
3213 ret = ret2;
3214 raw_cmd_free(&my_raw_cmd);
3215 return ret;
3216}
3217
3218static int invalidate_drive(struct block_device *bdev)
3219{
3220 /* invalidate the buffer track to force a reread */
3221 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3222 process_fd_request();
3223 check_disk_change(bdev);
3224 return 0;
3225}
3226
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003227static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 int drive, int type, struct block_device *bdev)
3229{
3230 int cnt;
3231
3232 /* sanity checking for parameters. */
3233 if (g->sect <= 0 ||
3234 g->head <= 0 ||
3235 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3236 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003237 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 return -EINVAL;
3239 if (type) {
3240 if (!capable(CAP_SYS_ADMIN))
3241 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003242 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003243 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003244 mutex_unlock(&open_lock);
3245 return -EINTR;
3246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 floppy_type[type] = *g;
3248 floppy_type[type].name = "user format";
3249 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3250 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3251 floppy_type[type].size + 1;
3252 process_fd_request();
3253 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3254 struct block_device *bdev = opened_bdev[cnt];
3255 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3256 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003257 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003259 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 } else {
3261 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003262
Joe Perches74f63f42010-03-10 15:20:58 -08003263 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003264 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003265 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 /* notice a disk change immediately, else
3267 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003268 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003269 return -EINTR;
3270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 oldStretch = g->stretch;
3272 user_params[drive] = *g;
3273 if (buffer_drive == drive)
3274 SUPBOUND(buffer_max, user_params[drive].sect);
3275 current_type[drive] = &user_params[drive];
3276 floppy_sizes[drive] = user_params[drive].size;
3277 if (cmd == FDDEFPRM)
3278 DRS->keep_data = -1;
3279 else
3280 DRS->keep_data = 1;
3281 /* invalidation. Invalidate only when needed, i.e.
3282 * when there are already sectors in the buffer cache
3283 * whose number will change. This is useful, because
3284 * mtools often changes the geometry of the disk after
3285 * looking at the boot block */
3286 if (DRS->maxblock > user_params[drive].sect ||
3287 DRS->maxtrack ||
3288 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003289 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 invalidate_drive(bdev);
3291 else
3292 process_fd_request();
3293 }
3294 return 0;
3295}
3296
3297/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003298static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 FDCLRPRM,
3300 FDSETPRM,
3301 FDDEFPRM,
3302 FDGETPRM,
3303 FDMSGON,
3304 FDMSGOFF,
3305 FDFMTBEG,
3306 FDFMTTRK,
3307 FDFMTEND,
3308 FDSETEMSGTRESH,
3309 FDFLUSH,
3310 FDSETMAXERRS,
3311 FDGETMAXERRS,
3312 FDGETDRVTYP,
3313 FDSETDRVPRM,
3314 FDGETDRVPRM,
3315 FDGETDRVSTAT,
3316 FDPOLLDRVSTAT,
3317 FDRESET,
3318 FDGETFDCSTAT,
3319 FDWERRORCLR,
3320 FDWERRORGET,
3321 FDRAWCMD,
3322 FDEJECT,
3323 FDTWADDLE
3324};
3325
Stephen Hemminger21af5442010-06-15 13:21:11 +02003326static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327{
3328 int i;
3329
3330 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3331 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3332 *size = _IOC_SIZE(*cmd);
3333 *cmd = ioctl_table[i];
3334 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003335 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 return -EFAULT;
3337 }
3338 return 0;
3339 }
3340 }
3341 return -EINVAL;
3342}
3343
3344static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3345{
3346 if (type)
3347 *g = &floppy_type[type];
3348 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003349 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003350 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003351 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003352 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 process_fd_request();
3354 *g = current_type[drive];
3355 }
3356 if (!*g)
3357 return -ENODEV;
3358 return 0;
3359}
3360
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003361static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3362{
3363 int drive = (long)bdev->bd_disk->private_data;
3364 int type = ITYPE(drive_state[drive].fd_device);
3365 struct floppy_struct *g;
3366 int ret;
3367
3368 ret = get_floppy_geometry(drive, type, &g);
3369 if (ret)
3370 return ret;
3371
3372 geo->heads = g->head;
3373 geo->sectors = g->sect;
3374 geo->cylinders = g->track;
3375 return 0;
3376}
3377
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003378static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 unsigned long param)
3380{
Al Viroa4af9b42008-03-02 09:27:55 -05003381 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003382 int type = ITYPE(UDRS->fd_device);
3383 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 int ret;
3385 int size;
3386 union inparam {
3387 struct floppy_struct g; /* geometry */
3388 struct format_descr f;
3389 struct floppy_max_errors max_errors;
3390 struct floppy_drive_params dp;
3391 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003392 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393
3394 /* convert compatibility eject ioctls into floppy eject ioctl.
3395 * We do this in order to provide a means to eject floppy disks before
3396 * installing the new fdutils package */
3397 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003398 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 DPRINT("obsolete eject ioctl\n");
3400 DPRINT("please use floppycontrol --eject\n");
3401 cmd = FDEJECT;
3402 }
3403
Joe Perchesa81ee542010-03-10 15:20:46 -08003404 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 return -EINVAL;
3406
Joe Perchesa81ee542010-03-10 15:20:46 -08003407 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003408 ret = normalize_ioctl(&cmd, &size);
3409 if (ret)
3410 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003411
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003413 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3415 return -EPERM;
3416
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003417 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3418 return -EINVAL;
3419
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003421 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003422 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3423 ret = fd_copyin((void __user *)param, &inparam, size);
3424 if (ret)
3425 return ret;
3426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427
Joe Perchesda273652010-03-10 15:20:52 -08003428 switch (cmd) {
3429 case FDEJECT:
3430 if (UDRS->fd_ref != 1)
3431 /* somebody else has this drive open */
3432 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003433 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003434 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435
Joe Perchesda273652010-03-10 15:20:52 -08003436 /* do the actual eject. Fails on
3437 * non-Sparc architectures */
3438 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439
Joe Perchese0298532010-03-10 15:20:55 -08003440 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3441 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003442 process_fd_request();
3443 return ret;
3444 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003445 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003446 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003447 current_type[drive] = NULL;
3448 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3449 UDRS->keep_data = 0;
3450 return invalidate_drive(bdev);
3451 case FDSETPRM:
3452 case FDDEFPRM:
3453 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3454 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003455 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003456 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003457 if (ret)
3458 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003459 break;
3460 case FDMSGON:
3461 UDP->flags |= FTD_MSG;
3462 return 0;
3463 case FDMSGOFF:
3464 UDP->flags &= ~FTD_MSG;
3465 return 0;
3466 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003467 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003468 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003469 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003470 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003471 ret = UDRS->flags;
3472 process_fd_request();
3473 if (ret & FD_VERIFY)
3474 return -ENODEV;
3475 if (!(ret & FD_DISK_WRITABLE))
3476 return -EROFS;
3477 return 0;
3478 case FDFMTTRK:
3479 if (UDRS->fd_ref != 1)
3480 return -EBUSY;
3481 return do_format(drive, &inparam.f);
3482 case FDFMTEND:
3483 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003484 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003485 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003486 return invalidate_drive(bdev);
3487 case FDSETEMSGTRESH:
3488 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3489 return 0;
3490 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003491 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003492 break;
3493 case FDSETMAXERRS:
3494 UDP->max_errors = inparam.max_errors;
3495 break;
3496 case FDGETDRVTYP:
3497 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003498 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003499 break;
3500 case FDSETDRVPRM:
3501 *UDP = inparam.dp;
3502 break;
3503 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003504 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003505 break;
3506 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003507 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003508 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003509 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003510 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003511 process_fd_request();
3512 /* fall through */
3513 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003514 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003515 break;
3516 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003517 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003518 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003519 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003520 break;
3521 case FDWERRORCLR:
3522 memset(UDRWE, 0, sizeof(*UDRWE));
3523 return 0;
3524 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003525 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003526 break;
3527 case FDRAWCMD:
3528 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003530 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003531 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003532 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003533 i = raw_cmd_ioctl(cmd, (void __user *)param);
3534 if (i == -EINTR)
3535 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003536 process_fd_request();
3537 return i;
3538 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003539 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003540 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003541 twaddle();
3542 process_fd_request();
3543 return 0;
3544 default:
3545 return -EINVAL;
3546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547
3548 if (_IOC_DIR(cmd) & _IOC_READ)
3549 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003550
3551 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552}
3553
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003554static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3555 unsigned int cmd, unsigned long param)
3556{
3557 int ret;
3558
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003559 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003560 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003561 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003562
3563 return ret;
3564}
3565
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566static void __init config_types(void)
3567{
Joe Perchesb46df352010-03-10 15:20:46 -08003568 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 int drive;
3570
3571 /* read drive info out of physical CMOS */
3572 drive = 0;
3573 if (!UDP->cmos)
3574 UDP->cmos = FLOPPY0_TYPE;
3575 drive = 1;
3576 if (!UDP->cmos && FLOPPY1_TYPE)
3577 UDP->cmos = FLOPPY1_TYPE;
3578
Jesper Juhl06f748c2007-10-16 23:30:57 -07003579 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
3581 for (drive = 0; drive < N_DRIVE; drive++) {
3582 unsigned int type = UDP->cmos;
3583 struct floppy_drive_params *params;
3584 const char *name = NULL;
3585 static char temparea[32];
3586
Tobias Klauser945f3902006-01-08 01:05:11 -08003587 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 params = &default_drive_params[type].params;
3589 if (type) {
3590 name = default_drive_params[type].name;
3591 allowed_drive_mask |= 1 << drive;
3592 } else
3593 allowed_drive_mask &= ~(1 << drive);
3594 } else {
3595 params = &default_drive_params[0].params;
3596 sprintf(temparea, "unknown type %d (usb?)", type);
3597 name = temparea;
3598 }
3599 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003600 const char *prepend;
3601 if (!has_drive) {
3602 prepend = "";
3603 has_drive = true;
3604 pr_info("Floppy drive(s):");
3605 } else {
3606 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 }
Joe Perchesb46df352010-03-10 15:20:46 -08003608
3609 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 }
3611 *UDP = *params;
3612 }
Joe Perchesb46df352010-03-10 15:20:46 -08003613
3614 if (has_drive)
3615 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616}
3617
Al Virodb2a1442013-05-05 21:52:57 -04003618static void floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619{
Al Viroa4af9b42008-03-02 09:27:55 -05003620 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003622 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003623 mutex_lock(&open_lock);
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003624 if (!UDRS->fd_ref--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 DPRINT("floppy_release with fd_ref == 0");
3626 UDRS->fd_ref = 0;
3627 }
3628 if (!UDRS->fd_ref)
3629 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003630 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003631 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632}
3633
3634/*
3635 * floppy_open check for aliasing (/dev/fd0 can be the same as
3636 * /dev/PS0 etc), and disallows simultaneous access to the same
3637 * drive with different device numbers.
3638 */
Al Viroa4af9b42008-03-02 09:27:55 -05003639static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640{
Al Viroa4af9b42008-03-02 09:27:55 -05003641 int drive = (long)bdev->bd_disk->private_data;
3642 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 int try;
3644 int res = -EBUSY;
3645 char *tmp;
3646
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003647 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003648 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003650 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 goto out2;
3652
3653 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003654 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3655 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 }
3657
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003658 UDRS->fd_ref++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659
Al Viroa4af9b42008-03-02 09:27:55 -05003660 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661
3662 res = -ENXIO;
3663
3664 if (!floppy_track_buffer) {
3665 /* if opening an ED drive, reserve a big buffer,
3666 * else reserve a small one */
3667 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3668 try = 64; /* Only 48 actually useful */
3669 else
3670 try = 32; /* Only 24 actually useful */
3671
3672 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3673 if (!tmp && !floppy_track_buffer) {
3674 try >>= 1; /* buffer only one side */
3675 INFBOUND(try, 16);
3676 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3677 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003678 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 if (!tmp && !floppy_track_buffer) {
3681 DPRINT("Unable to allocate DMA memory\n");
3682 goto out;
3683 }
3684 if (floppy_track_buffer) {
3685 if (tmp)
3686 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3687 } else {
3688 buffer_min = buffer_max = -1;
3689 floppy_track_buffer = tmp;
3690 max_buffer_sectors = try;
3691 }
3692 }
3693
Al Viroa4af9b42008-03-02 09:27:55 -05003694 new_dev = MINOR(bdev->bd_dev);
3695 UDRS->fd_device = new_dev;
3696 set_capacity(disks[drive], floppy_sizes[new_dev]);
3697 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 if (buffer_drive == drive)
3699 buffer_track = -1;
3700 }
3701
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 if (UFDCS->rawcmd == 1)
3703 UFDCS->rawcmd = 2;
3704
Al Viroa4af9b42008-03-02 09:27:55 -05003705 if (!(mode & FMODE_NDELAY)) {
3706 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 UDRS->last_checked = 0;
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003708 clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
Al Viroa4af9b42008-03-02 09:27:55 -05003709 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003710 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 goto out;
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003712 if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
3713 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 }
3715 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003716 if ((mode & FMODE_WRITE) &&
3717 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 goto out;
3719 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003720 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003721 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 return 0;
3723out:
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003724 UDRS->fd_ref--;
3725
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 if (!UDRS->fd_ref)
3727 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003729 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003730 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 return res;
3732}
3733
3734/*
3735 * Check if the disk has been changed or if a change has been faked.
3736 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003737static unsigned int floppy_check_events(struct gendisk *disk,
3738 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739{
3740 int drive = (long)disk->private_data;
3741
Joe Perchese0298532010-03-10 15:20:55 -08003742 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3743 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003744 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003746 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003747 lock_fdc(drive, false);
3748 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 }
3751
Joe Perchese0298532010-03-10 15:20:55 -08003752 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3753 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003755 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003756 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 return 0;
3758}
3759
3760/*
3761 * This implements "read block 0" for floppy_revalidate().
3762 * Needed for format autodetection, checking whether there is
3763 * a disk in the drive, and whether that disk is writable.
3764 */
3765
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003766struct rb0_cbdata {
3767 int drive;
3768 struct completion complete;
3769};
3770
3771static void floppy_rb0_cb(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772{
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003773 struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
3774 int drive = cbdata->drive;
3775
3776 if (err) {
Jiri Kosina1c65df32014-06-18 13:44:18 +02003777 pr_info("floppy: error %d while reading block 0\n", err);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003778 set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
3779 }
3780 complete(&cbdata->complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781}
3782
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003783static int __floppy_read_block_0(struct block_device *bdev, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784{
3785 struct bio bio;
3786 struct bio_vec bio_vec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 struct page *page;
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003788 struct rb0_cbdata cbdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 size_t size;
3790
3791 page = alloc_page(GFP_NOIO);
3792 if (!page) {
3793 process_fd_request();
3794 return -ENOMEM;
3795 }
3796
3797 size = bdev->bd_block_size;
3798 if (!size)
3799 size = 1024;
3800
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003801 cbdata.drive = drive;
3802
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 bio_init(&bio);
3804 bio.bi_io_vec = &bio_vec;
3805 bio_vec.bv_page = page;
3806 bio_vec.bv_len = size;
3807 bio_vec.bv_offset = 0;
3808 bio.bi_vcnt = 1;
Kent Overstreet4f024f32013-10-11 15:44:27 -07003809 bio.bi_iter.bi_size = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 bio.bi_bdev = bdev;
Kent Overstreet4f024f32013-10-11 15:44:27 -07003811 bio.bi_iter.bi_sector = 0;
Jiri Kosina6314a102014-05-28 11:55:23 +02003812 bio.bi_flags |= (1 << BIO_QUIET);
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003813 bio.bi_private = &cbdata;
3814 bio.bi_end_io = floppy_rb0_cb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815
3816 submit_bio(READ, &bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 process_fd_request();
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003818
3819 init_completion(&cbdata.complete);
3820 wait_for_completion(&cbdata.complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821
3822 __free_page(page);
3823
3824 return 0;
3825}
3826
3827/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3828 * the bootblock (block 0). "Autodetection" is also needed to check whether
3829 * there is a disk in the drive at all... Thus we also do it for fixed
3830 * geometry formats */
3831static int floppy_revalidate(struct gendisk *disk)
3832{
3833 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 int cf;
3835 int res = 0;
3836
Joe Perchese0298532010-03-10 15:20:55 -08003837 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3838 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003839 test_bit(drive, &fake_change) ||
3840 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003841 if (WARN(atomic_read(&usage_count) == 0,
3842 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003844
Joe Perches74f63f42010-03-10 15:20:58 -08003845 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003846 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3847 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003848 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 process_fd_request(); /*already done by another thread */
3850 return 0;
3851 }
3852 UDRS->maxblock = 0;
3853 UDRS->maxtrack = 0;
3854 if (buffer_drive == drive)
3855 buffer_track = -1;
3856 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003857 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 if (cf)
3859 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003860 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 /* auto-sensing */
Jiri Kosina7b7b68bb2014-01-10 02:08:13 +01003862 res = __floppy_read_block_0(opened_bdev[drive], drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 } else {
3864 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003865 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 process_fd_request();
3867 }
3868 }
3869 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3870 return res;
3871}
3872
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003873static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003874 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003875 .open = floppy_open,
3876 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003877 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003878 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003879 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003880 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883/*
3884 * Floppy Driver initialization
3885 * =============================
3886 */
3887
3888/* Determine the floppy disk controller type */
3889/* This routine was written by David C. Niemi */
3890static char __init get_fdc_version(void)
3891{
3892 int r;
3893
3894 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3895 if (FDCS->reset)
3896 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003897 r = result();
3898 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 return FDC_NONE; /* No FDC present ??? */
3900 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003901 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3903 }
3904 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003905 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3906 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 return FDC_UNKNOWN;
3908 }
3909
3910 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003911 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3913 }
3914
3915 output_byte(FD_PERPENDICULAR);
3916 if (need_more_output() == MORE_OUTPUT) {
3917 output_byte(0);
3918 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003919 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 return FDC_82072A; /* 82072A as found on Sparcs. */
3921 }
3922
3923 output_byte(FD_UNLOCK);
3924 r = result();
3925 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003926 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003927 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 * LOCK/UNLOCK */
3929 }
3930 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003931 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3932 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 return FDC_UNKNOWN;
3934 }
3935 output_byte(FD_PARTID);
3936 r = result();
3937 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003938 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3939 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 return FDC_UNKNOWN;
3941 }
3942 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003943 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 return FDC_82077; /* Revised 82077AA passes all the tests */
3945 }
3946 switch (reply_buffer[0] >> 5) {
3947 case 0x0:
3948 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003949 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 return FDC_82078;
3951 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003952 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 return FDC_82078;
3954 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003955 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 return FDC_S82078B;
3957 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003958 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 return FDC_87306;
3960 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003961 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3962 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 return FDC_82078_UNKN;
3964 }
3965} /* get_fdc_version */
3966
3967/* lilo configuration */
3968
3969static void __init floppy_set_flags(int *ints, int param, int param2)
3970{
3971 int i;
3972
3973 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3974 if (param)
3975 default_drive_params[i].params.flags |= param2;
3976 else
3977 default_drive_params[i].params.flags &= ~param2;
3978 }
3979 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
3980}
3981
3982static void __init daring(int *ints, int param, int param2)
3983{
3984 int i;
3985
3986 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3987 if (param) {
3988 default_drive_params[i].params.select_delay = 0;
3989 default_drive_params[i].params.flags |=
3990 FD_SILENT_DCL_CLEAR;
3991 } else {
3992 default_drive_params[i].params.select_delay =
3993 2 * HZ / 100;
3994 default_drive_params[i].params.flags &=
3995 ~FD_SILENT_DCL_CLEAR;
3996 }
3997 }
3998 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
3999}
4000
4001static void __init set_cmos(int *ints, int dummy, int dummy2)
4002{
4003 int current_drive = 0;
4004
4005 if (ints[0] != 2) {
4006 DPRINT("wrong number of parameters for CMOS\n");
4007 return;
4008 }
4009 current_drive = ints[1];
4010 if (current_drive < 0 || current_drive >= 8) {
4011 DPRINT("bad drive for set_cmos\n");
4012 return;
4013 }
4014#if N_FDC > 1
4015 if (current_drive >= 4 && !FDC2)
4016 FDC2 = 0x370;
4017#endif
4018 DP->cmos = ints[2];
4019 DPRINT("setting CMOS code to %d\n", ints[2]);
4020}
4021
4022static struct param_table {
4023 const char *name;
4024 void (*fn) (int *ints, int param, int param2);
4025 int *var;
4026 int def_param;
4027 int param2;
4028} config_params[] __initdata = {
4029 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4030 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4031 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4032 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4033 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4034 {"daring", daring, NULL, 1, 0},
4035#if N_FDC > 1
4036 {"two_fdc", NULL, &FDC2, 0x370, 0},
4037 {"one_fdc", NULL, &FDC2, 0, 0},
4038#endif
4039 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4040 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4041 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4042 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4043 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4044 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4045 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4046 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4047 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4048 {"nofifo", NULL, &no_fifo, 0x20, 0},
4049 {"usefifo", NULL, &no_fifo, 0, 0},
4050 {"cmos", set_cmos, NULL, 0, 0},
4051 {"slow", NULL, &slow_floppy, 1, 0},
4052 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4053 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4054 {"L40SX", NULL, &print_unex, 0, 0}
4055
4056 EXTRA_FLOPPY_PARAMS
4057};
4058
4059static int __init floppy_setup(char *str)
4060{
4061 int i;
4062 int param;
4063 int ints[11];
4064
4065 str = get_options(str, ARRAY_SIZE(ints), ints);
4066 if (str) {
4067 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4068 if (strcmp(str, config_params[i].name) == 0) {
4069 if (ints[0])
4070 param = ints[1];
4071 else
4072 param = config_params[i].def_param;
4073 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004074 config_params[i].fn(ints, param,
4075 config_params[i].
4076 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 if (config_params[i].var) {
4078 DPRINT("%s=%d\n", str, param);
4079 *config_params[i].var = param;
4080 }
4081 return 1;
4082 }
4083 }
4084 }
4085 if (str) {
4086 DPRINT("unknown floppy option [%s]\n", str);
4087
4088 DPRINT("allowed options are:");
4089 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004090 pr_cont(" %s", config_params[i].name);
4091 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 } else
4093 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004094 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 return 0;
4096}
4097
4098static int have_no_fdc = -ENODEV;
4099
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004100static ssize_t floppy_cmos_show(struct device *dev,
4101 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004102{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004103 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004104 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004105
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004106 drive = p->id;
4107 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004108}
Joe Perches48c8cee2010-03-10 15:20:45 -08004109
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004110static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004111
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112static void floppy_device_release(struct device *dev)
4113{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114}
4115
Frans Popc90cd332009-07-25 22:24:54 +02004116static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004117{
4118 int fdc;
4119
4120 for (fdc = 0; fdc < N_FDC; fdc++)
4121 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004122 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004123
4124 return 0;
4125}
4126
Alexey Dobriyan47145212009-12-14 18:00:08 -08004127static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004128 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004129 .restore = floppy_resume,
4130};
4131
4132static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004133 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004134 .name = "floppy",
4135 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004136 },
4137};
4138
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004139static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004141static bool floppy_available(int drive)
4142{
4143 if (!(allowed_drive_mask & (1 << drive)))
4144 return false;
4145 if (fdc_state[FDC(drive)].version == FDC_NONE)
4146 return false;
4147 return true;
4148}
4149
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4151{
4152 int drive = (*part & 3) | ((*part & 0x80) >> 5);
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004153 if (drive >= N_DRIVE || !floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004155 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 return NULL;
4157 *part = 0;
4158 return get_disk(disks[drive]);
4159}
4160
Andi Kleen0cc15d032012-07-02 17:27:04 -07004161static int __init do_floppy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162{
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004163 int i, unit, drive, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164
Stephen Hemminger285203c2010-06-15 13:21:11 +02004165 set_debugt();
4166 interruptjiffies = resultjiffies = jiffies;
4167
Kumar Gala68e1ee62008-09-22 14:41:31 -07004168#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004169 if (check_legacy_ioport(FDC1))
4170 return -ENODEV;
4171#endif
4172
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 raw_cmd = NULL;
4174
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004175 floppy_wq = alloc_ordered_workqueue("floppy", 0);
4176 if (!floppy_wq)
4177 return -ENOMEM;
4178
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004179 for (drive = 0; drive < N_DRIVE; drive++) {
4180 disks[drive] = alloc_disk(1);
4181 if (!disks[drive]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 err = -ENOMEM;
4183 goto out_put_disk;
4184 }
4185
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004186 disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4187 if (!disks[drive]->queue) {
Jens Axboe48821182010-09-22 09:32:36 +02004188 err = -ENOMEM;
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004189 goto out_put_disk;
Jens Axboe48821182010-09-22 09:32:36 +02004190 }
4191
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004192 blk_queue_max_hw_sectors(disks[drive]->queue, 64);
4193 disks[drive]->major = FLOPPY_MAJOR;
4194 disks[drive]->first_minor = TOMINOR(drive);
4195 disks[drive]->fops = &floppy_fops;
4196 sprintf(disks[drive]->disk_name, "fd%d", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004198 init_timer(&motor_off_timer[drive]);
4199 motor_off_timer[drive].data = drive;
4200 motor_off_timer[drive].function = motor_off_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 }
4202
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 err = register_blkdev(FLOPPY_MAJOR, "fd");
4204 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004205 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004207 err = platform_driver_register(&floppy_driver);
4208 if (err)
4209 goto out_unreg_blkdev;
4210
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4212 floppy_find, NULL, NULL);
4213
4214 for (i = 0; i < 256; i++)
4215 if (ITYPE(i))
4216 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4217 else
4218 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4219
Joe Perches73507e62010-03-10 15:21:03 -08004220 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 config_types();
4222
4223 for (i = 0; i < N_FDC; i++) {
4224 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004225 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 FDCS->dtr = -1;
4227 FDCS->dor = 0x4;
4228#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004229 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230#ifdef __mc68000__
4231 if (MACH_IS_SUN3X)
4232#endif
4233 FDCS->version = FDC_82072A;
4234#endif
4235 }
4236
4237 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 fdc_state[0].address = FDC1;
4239 if (fdc_state[0].address == -1) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004240 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 err = -ENODEV;
4242 goto out_unreg_region;
4243 }
4244#if N_FDC > 1
4245 fdc_state[1].address = FDC2;
4246#endif
4247
4248 fdc = 0; /* reset fdc in case of unexpected interrupt */
4249 err = floppy_grab_irq_and_dma();
4250 if (err) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004251 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 err = -EBUSY;
4253 goto out_unreg_region;
4254 }
4255
4256 /* initialise drive state */
4257 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004258 memset(UDRS, 0, sizeof(*UDRS));
4259 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004260 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4261 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4262 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 UDRS->fd_device = -1;
4264 floppy_track_buffer = NULL;
4265 max_buffer_sectors = 0;
4266 }
4267 /*
4268 * Small 10 msec delay to let through any interrupt that
4269 * initialization might have triggered, to not
4270 * confuse detection:
4271 */
4272 msleep(10);
4273
4274 for (i = 0; i < N_FDC; i++) {
4275 fdc = i;
4276 FDCS->driver_version = FD_DRIVER_VERSION;
4277 for (unit = 0; unit < 4; unit++)
4278 FDCS->track[unit] = 0;
4279 if (FDCS->address == -1)
4280 continue;
4281 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004282 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004284 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 FDCS->address = -1;
4286 FDCS->version = FDC_NONE;
4287 continue;
4288 }
4289 /* Try to determine the floppy controller type */
4290 FDCS->version = get_fdc_version();
4291 if (FDCS->version == FDC_NONE) {
4292 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004293 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 FDCS->address = -1;
4295 continue;
4296 }
4297 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4298 can_use_virtual_dma = 0;
4299
4300 have_no_fdc = 0;
4301 /* Not all FDCs seem to be able to handle the version command
4302 * properly, so force a reset for the standard FDC clones,
4303 * to avoid interrupt garbage.
4304 */
Joe Perches74f63f42010-03-10 15:20:58 -08004305 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 }
4307 fdc = 0;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004308 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004310 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 if (have_no_fdc) {
4312 DPRINT("no floppy controllers found\n");
4313 err = have_no_fdc;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004314 goto out_release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 }
4316
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 for (drive = 0; drive < N_DRIVE; drive++) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004318 if (!floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004320
4321 floppy_device[drive].name = floppy_device_name;
4322 floppy_device[drive].id = drive;
4323 floppy_device[drive].dev.release = floppy_device_release;
4324
4325 err = platform_device_register(&floppy_device[drive]);
4326 if (err)
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004327 goto out_remove_drives;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004328
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004329 err = device_create_file(&floppy_device[drive].dev,
4330 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004331 if (err)
4332 goto out_unreg_platform_dev;
4333
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 /* to be cleaned up... */
4335 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004337 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 add_disk(disks[drive]);
4339 }
4340
4341 return 0;
4342
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004343out_unreg_platform_dev:
4344 platform_device_unregister(&floppy_device[drive]);
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004345out_remove_drives:
4346 while (drive--) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004347 if (floppy_available(drive)) {
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004348 del_gendisk(disks[drive]);
4349 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4350 platform_device_unregister(&floppy_device[drive]);
4351 }
4352 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004353out_release_dma:
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004354 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 floppy_release_irq_and_dma();
4356out_unreg_region:
4357 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004358 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359out_unreg_blkdev:
4360 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361out_put_disk:
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004362 destroy_workqueue(floppy_wq);
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004363 for (drive = 0; drive < N_DRIVE; drive++) {
4364 if (!disks[drive])
4365 break;
4366 if (disks[drive]->queue) {
4367 del_timer_sync(&motor_off_timer[drive]);
4368 blk_cleanup_queue(disks[drive]->queue);
4369 disks[drive]->queue = NULL;
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004370 }
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004371 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 }
4373 return err;
4374}
4375
Andi Kleen0cc15d032012-07-02 17:27:04 -07004376#ifndef MODULE
4377static __init void floppy_async_init(void *data, async_cookie_t cookie)
4378{
4379 do_floppy_init();
4380}
4381#endif
4382
4383static int __init floppy_init(void)
4384{
4385#ifdef MODULE
4386 return do_floppy_init();
4387#else
4388 /* Don't hold up the bootup by the floppy initialization */
4389 async_schedule(floppy_async_init, NULL);
4390 return 0;
4391#endif
4392}
4393
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004394static const struct io_region {
4395 int offset;
4396 int size;
4397} io_regions[] = {
4398 { 2, 1 },
4399 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4400 { 4, 2 },
4401 /* address + 6 is reserved, and may be taken by IDE.
4402 * Unfortunately, Adaptec doesn't know this :-(, */
4403 { 7, 1 },
4404};
4405
4406static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4407{
4408 while (p != io_regions) {
4409 p--;
4410 release_region(FDCS->address + p->offset, p->size);
4411 }
4412}
4413
4414#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4415
4416static int floppy_request_regions(int fdc)
4417{
4418 const struct io_region *p;
4419
4420 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004421 if (!request_region(FDCS->address + p->offset,
4422 p->size, "floppy")) {
4423 DPRINT("Floppy io-port 0x%04lx in use\n",
4424 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004425 floppy_release_allocated_regions(fdc, p);
4426 return -EBUSY;
4427 }
4428 }
4429 return 0;
4430}
4431
4432static void floppy_release_regions(int fdc)
4433{
4434 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4435}
4436
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437static int floppy_grab_irq_and_dma(void)
4438{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004439 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004441
4442 /*
4443 * We might have scheduled a free_irq(), wait it to
4444 * drain first:
4445 */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004446 flush_workqueue(floppy_wq);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004447
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 if (fd_request_irq()) {
4449 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4450 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004451 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 return -1;
4453 }
4454 if (fd_request_dma()) {
4455 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4456 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004457 if (can_use_virtual_dma & 2)
4458 use_virtual_dma = can_use_virtual_dma = 1;
4459 if (!(can_use_virtual_dma & 1)) {
4460 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004461 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004462 return -1;
4463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 }
4465
4466 for (fdc = 0; fdc < N_FDC; fdc++) {
4467 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004468 if (floppy_request_regions(fdc))
4469 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 }
4471 }
4472 for (fdc = 0; fdc < N_FDC; fdc++) {
4473 if (FDCS->address != -1) {
4474 reset_fdc_info(1);
4475 fd_outb(FDCS->dor, FD_DOR);
4476 }
4477 }
4478 fdc = 0;
4479 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4480
4481 for (fdc = 0; fdc < N_FDC; fdc++)
4482 if (FDCS->address != -1)
4483 fd_outb(FDCS->dor, FD_DOR);
4484 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004485 * The driver will try and free resources and relies on us
4486 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 */
4488 fdc = 0;
4489 irqdma_allocated = 1;
4490 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004491cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 fd_free_irq();
4493 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004494 while (--fdc >= 0)
4495 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004496 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 return -1;
4498}
4499
4500static void floppy_release_irq_and_dma(void)
4501{
4502 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503#ifndef __sparc__
4504 int drive;
4505#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 long tmpsize;
4507 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004509 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004511
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 if (irqdma_allocated) {
4513 fd_disable_dma();
4514 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004515 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 irqdma_allocated = 0;
4517 }
4518 set_dor(0, ~0, 8);
4519#if N_FDC > 1
4520 set_dor(1, ~8, 0);
4521#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522
4523 if (floppy_track_buffer && max_buffer_sectors) {
4524 tmpsize = max_buffer_sectors * 1024;
4525 tmpaddr = (unsigned long)floppy_track_buffer;
4526 floppy_track_buffer = NULL;
4527 max_buffer_sectors = 0;
4528 buffer_min = buffer_max = -1;
4529 fd_dma_mem_free(tmpaddr, tmpsize);
4530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531#ifndef __sparc__
4532 for (drive = 0; drive < N_FDC * 4; drive++)
4533 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004534 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535#endif
4536
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004537 if (delayed_work_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004538 pr_info("floppy timer still active:%s\n", timeout_message);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004539 if (delayed_work_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004540 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004541 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004542 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 old_fdc = fdc;
4544 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004545 if (FDCS->address != -1)
4546 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 fdc = old_fdc;
4548}
4549
4550#ifdef MODULE
4551
4552static char *floppy;
4553
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554static void __init parse_floppy_cfg_string(char *cfg)
4555{
4556 char *ptr;
4557
4558 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004559 ptr = cfg;
4560 while (*cfg && *cfg != ' ' && *cfg != '\t')
4561 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 if (*cfg) {
4563 *cfg = '\0';
4564 cfg++;
4565 }
4566 if (*ptr)
4567 floppy_setup(ptr);
4568 }
4569}
4570
Jon Schindler7afea3b2008-04-29 00:59:21 -07004571static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572{
4573 if (floppy)
4574 parse_floppy_cfg_string(floppy);
4575 return floppy_init();
4576}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004577module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578
Jon Schindler7afea3b2008-04-29 00:59:21 -07004579static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580{
4581 int drive;
4582
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4584 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004585 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004587 destroy_workqueue(floppy_wq);
4588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 for (drive = 0; drive < N_DRIVE; drive++) {
4590 del_timer_sync(&motor_off_timer[drive]);
4591
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004592 if (floppy_available(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004594 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4595 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 }
Jens Axboe48821182010-09-22 09:32:36 +02004597 blk_cleanup_queue(disks[drive]->queue);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004598
4599 /*
4600 * These disks have not called add_disk(). Don't put down
4601 * queue reference in put_disk().
4602 */
4603 if (!(allowed_drive_mask & (1 << drive)) ||
4604 fdc_state[FDC(drive)].version == FDC_NONE)
4605 disks[drive]->queue = NULL;
4606
Vivek Goyald017bf62010-11-06 08:16:05 -04004607 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004610 cancel_delayed_work_sync(&fd_timeout);
4611 cancel_delayed_work_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004613 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 floppy_release_irq_and_dma();
4615
4616 /* eject disk, if any */
4617 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618}
Joe Perches48c8cee2010-03-10 15:20:45 -08004619
Jon Schindler7afea3b2008-04-29 00:59:21 -07004620module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621
4622module_param(floppy, charp, 0);
4623module_param(FLOPPY_IRQ, int, 0);
4624module_param(FLOPPY_DMA, int, 0);
4625MODULE_AUTHOR("Alain L. Knaff");
4626MODULE_SUPPORTED_DEVICE("fd");
4627MODULE_LICENSE("GPL");
4628
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004629/* This doesn't actually get used other than for module information */
4630static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004631 {"PNP0700", 0},
4632 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004633};
Joe Perches48c8cee2010-03-10 15:20:45 -08004634
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004635MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4636
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637#else
4638
4639__setup("floppy=", floppy_setup);
4640module_init(floppy_init)
4641#endif
4642
4643MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);