blob: a7d6347aaa7913b2a029014a95a2558d8360597e [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;
Linus Torvaldsdab058f2012-07-03 15:51:22 -0700675 __cancel_delayed_work(&fd_timeout);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200676
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700677 if (drive < 0 || drive >= N_DRIVE) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200678 delay = 20UL * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 drive = 0;
680 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200681 delay = UDP->timeout;
682
683 queue_delayed_work(floppy_wq, &fd_timeout, delay);
Joe Perchesa81ee542010-03-10 15:20:46 -0800684 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800685 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 timeout_message = message;
687}
688
Joe Perches73507e62010-03-10 15:21:03 -0800689static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
691 unsigned long flags;
692
693 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800694 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 spin_unlock_irqrestore(&floppy_lock, flags);
696}
697
Joe Perches48c8cee2010-03-10 15:20:45 -0800698#define INFBOUND(a, b) (a) = max_t(int, a, b)
699#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701/*
702 * Bottom half floppy driver.
703 * ==========================
704 *
705 * This part of the file contains the code talking directly to the hardware,
706 * and also the main service loop (seek-configure-spinup-command)
707 */
708
709/*
710 * disk change.
711 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
712 * and the last_checked date.
713 *
714 * last_checked is the date of the last check which showed 'no disk change'
715 * FD_DISK_CHANGE is set under two conditions:
716 * 1. The floppy has been changed after some i/o to that floppy already
717 * took place.
718 * 2. No floppy disk is in the drive. This is done in order to ensure that
719 * requests are quickly flushed in case there is no disk in the drive. It
720 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
721 * the drive.
722 *
723 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
724 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
725 * each seek. If a disk is present, the disk change line should also be
726 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
727 * change line is set, this means either that no disk is in the drive, or
728 * that it has been removed since the last seek.
729 *
730 * This means that we really have a third possibility too:
731 * The floppy has been changed after the last seek.
732 */
733
734static int disk_change(int drive)
735{
736 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700737
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800738 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 DPRINT("WARNING disk change called early\n");
740 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
741 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
742 DPRINT("probing disk change on unselected drive\n");
743 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
744 (unsigned int)FDCS->dor);
745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Joe Perches87f530d2010-03-10 15:20:54 -0800747 debug_dcl(UDP->flags,
748 "checking disk change line for drive %d\n", drive);
749 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
750 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
751 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
752
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800754 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800756 set_bit(FD_VERIFY_BIT, &UDRS->flags);
757 /* verify write protection */
758
759 if (UDRS->maxblock) /* mark it changed */
760 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 /* invalidate its geometry */
763 if (UDRS->keep_data >= 0) {
764 if ((UDP->flags & FTD_MSG) &&
765 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800766 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 current_type[drive] = NULL;
768 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
769 }
770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return 1;
772 } else {
773 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800774 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776 return 0;
777}
778
779static inline int is_selected(int dor, int unit)
780{
781 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
782}
783
Joe Perches57584c52010-03-10 15:21:00 -0800784static bool is_ready_state(int status)
785{
786 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
787 return state == STATUS_READY;
788}
789
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790static int set_dor(int fdc, char mask, char data)
791{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700792 unsigned char unit;
793 unsigned char drive;
794 unsigned char newdor;
795 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 if (FDCS->address == -1)
798 return -1;
799
800 olddor = FDCS->dor;
801 newdor = (olddor & mask) | data;
802 if (newdor != olddor) {
803 unit = olddor & 0x3;
804 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
805 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800806 debug_dcl(UDP->flags,
807 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 disk_change(drive);
809 }
810 FDCS->dor = newdor;
811 fd_outb(newdor, FD_DOR);
812
813 unit = newdor & 0x3;
814 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
815 drive = REVDRIVE(fdc, unit);
816 UDRS->select_date = jiffies;
817 }
818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return olddor;
820}
821
822static void twaddle(void)
823{
824 if (DP->select_delay)
825 return;
826 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
827 fd_outb(FDCS->dor, FD_DOR);
828 DRS->select_date = jiffies;
829}
830
Joe Perches57584c52010-03-10 15:21:00 -0800831/*
832 * Reset all driver information about the current fdc.
833 * This is needed after a reset, and after a raw command.
834 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835static void reset_fdc_info(int mode)
836{
837 int drive;
838
839 FDCS->spec1 = FDCS->spec2 = -1;
840 FDCS->need_configure = 1;
841 FDCS->perp_mode = 1;
842 FDCS->rawcmd = 0;
843 for (drive = 0; drive < N_DRIVE; drive++)
844 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
845 UDRS->track = NEED_2_RECAL;
846}
847
848/* selects the fdc and drive, and enables the fdc's input/dma. */
849static void set_fdc(int drive)
850{
851 if (drive >= 0 && drive < N_DRIVE) {
852 fdc = FDC(drive);
853 current_drive = drive;
854 }
855 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800856 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 return;
858 }
859 set_dor(fdc, ~0, 8);
860#if N_FDC > 1
861 set_dor(1 - fdc, ~8, 0);
862#endif
863 if (FDCS->rawcmd == 2)
864 reset_fdc_info(1);
865 if (fd_inb(FD_STATUS) != STATUS_READY)
866 FDCS->reset = 1;
867}
868
869/* locks the driver */
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200870static int lock_fdc(int drive, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200872 if (WARN(atomic_read(&usage_count) == 0,
873 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200876 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
877 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 command_status = FD_COMMAND_NONE;
880
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200881 reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 set_fdc(drive);
883 return 0;
884}
885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200887static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 if (!test_bit(0, &fdc_busy))
890 DPRINT("FDC access conflict!\n");
891
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200892 raw_cmd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 command_status = FD_COMMAND_NONE;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200894 __cancel_delayed_work(&fd_timeout);
895 do_floppy = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 cont = NULL;
897 clear_bit(0, &fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 wake_up(&fdc_wait);
899}
900
901/* switches the motor off after a given timeout */
902static void motor_off_callback(unsigned long nr)
903{
904 unsigned char mask = ~(0x10 << UNIT(nr));
905
906 set_dor(FDC(nr), mask, 0);
907}
908
909/* schedules motor off */
910static void floppy_off(unsigned int drive)
911{
912 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700913 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 if (!(FDCS->dor & (0x10 << UNIT(drive))))
916 return;
917
918 del_timer(motor_off_timer + drive);
919
920 /* make spindle stop in a position which minimizes spinup time
921 * next time */
922 if (UDP->rps) {
923 delta = jiffies - UDRS->first_read_date + HZ -
924 UDP->spindown_offset;
925 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
926 motor_off_timer[drive].expires =
927 jiffies + UDP->spindown - delta;
928 }
929 add_timer(motor_off_timer + drive);
930}
931
932/*
933 * cycle through all N_DRIVE floppy drives, for disk change testing.
934 * stopping at current drive. This is done before any long operation, to
935 * be sure to have up to date disk change information.
936 */
937static void scandrives(void)
938{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700939 int i;
940 int drive;
941 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 if (DP->select_delay)
944 return;
945
946 saved_drive = current_drive;
947 for (i = 0; i < N_DRIVE; i++) {
948 drive = (saved_drive + i + 1) % N_DRIVE;
949 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
950 continue; /* skip closed drives */
951 set_fdc(drive);
952 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
953 (0x10 << UNIT(drive))))
954 /* switch the motor off again, if it was off to
955 * begin with */
956 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
957 }
958 set_fdc(saved_drive);
959}
960
961static void empty(void)
962{
963}
964
David Howells65f27f32006-11-22 14:55:48 +0000965static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
Joe Perches48c8cee2010-03-10 15:20:45 -0800967static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200969 WARN_ON(work_pending(&floppy_work));
970
David Howells65f27f32006-11-22 14:55:48 +0000971 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200972 queue_work(floppy_wq, &floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973}
974
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200975static DECLARE_DELAYED_WORK(fd_timer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977static void cancel_activity(void)
978{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 do_floppy = NULL;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200980 cancel_delayed_work_sync(&fd_timer);
981 cancel_work_sync(&floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982}
983
984/* this function makes sure that the disk stays in the drive during the
985 * transfer */
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200986static void fd_watchdog(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
Joe Perches87f530d2010-03-10 15:20:54 -0800988 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 if (disk_change(current_drive)) {
991 DPRINT("disk removed during i/o\n");
992 cancel_activity();
993 cont->done(0);
994 reset_fdc();
995 } else {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200996 cancel_delayed_work(&fd_timer);
997 PREPARE_DELAYED_WORK(&fd_timer, fd_watchdog);
998 queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 }
1000}
1001
1002static void main_command_interrupt(void)
1003{
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001004 cancel_delayed_work(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 cont->interrupt();
1006}
1007
1008/* waits for a delay (spinup or select) to pass */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001009static int fd_wait_for_completion(unsigned long expires, work_func_t function)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010{
1011 if (FDCS->reset) {
1012 reset_fdc(); /* do the reset during sleep to win time
1013 * if we don't need to sleep, it's a good
1014 * occasion anyways */
1015 return 1;
1016 }
1017
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001018 if (time_before(jiffies, expires)) {
1019 cancel_delayed_work(&fd_timer);
1020 PREPARE_DELAYED_WORK(&fd_timer, function);
1021 queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 return 1;
1023 }
1024 return 0;
1025}
1026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027static void setup_DMA(void)
1028{
1029 unsigned long f;
1030
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (raw_cmd->length == 0) {
1032 int i;
1033
Joe Perchesb46df352010-03-10 15:20:46 -08001034 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001036 pr_cont("%x,", raw_cmd->cmd[i]);
1037 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 cont->done(0);
1039 FDCS->reset = 1;
1040 return;
1041 }
1042 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001043 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 cont->done(0);
1045 FDCS->reset = 1;
1046 return;
1047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 f = claim_dma_lock();
1049 fd_disable_dma();
1050#ifdef fd_dma_setup
1051 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1052 (raw_cmd->flags & FD_RAW_READ) ?
1053 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1054 release_dma_lock(f);
1055 cont->done(0);
1056 FDCS->reset = 1;
1057 return;
1058 }
1059 release_dma_lock(f);
1060#else
1061 fd_clear_dma_ff();
1062 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1063 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1064 DMA_MODE_READ : DMA_MODE_WRITE);
1065 fd_set_dma_addr(raw_cmd->kernel_data);
1066 fd_set_dma_count(raw_cmd->length);
1067 virtual_dma_port = FDCS->address;
1068 fd_enable_dma();
1069 release_dma_lock(f);
1070#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071}
1072
1073static void show_floppy(void);
1074
1075/* waits until the fdc becomes ready */
1076static int wait_til_ready(void)
1077{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001078 int status;
1079 int counter;
1080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 if (FDCS->reset)
1082 return -1;
1083 for (counter = 0; counter < 10000; counter++) {
1084 status = fd_inb(FD_STATUS);
1085 if (status & STATUS_READY)
1086 return status;
1087 }
Joe Perches29f1c782010-03-10 15:21:00 -08001088 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1090 show_floppy();
1091 }
1092 FDCS->reset = 1;
1093 return -1;
1094}
1095
1096/* sends a command byte to the fdc */
1097static int output_byte(char byte)
1098{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001099 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001101 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001103
1104 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 output_log[output_log_pos].data = byte;
1107 output_log[output_log_pos].status = status;
1108 output_log[output_log_pos].jiffies = jiffies;
1109 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return 0;
1111 }
1112 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001113 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1115 byte, fdc, status);
1116 show_floppy();
1117 }
1118 return -1;
1119}
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121/* gets the response from the fdc */
1122static int result(void)
1123{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001124 int i;
1125 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001128 status = wait_til_ready();
1129 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 break;
1131 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1132 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 resultjiffies = jiffies;
1134 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 return i;
1136 }
1137 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1138 reply_buffer[i] = fd_inb(FD_DATA);
1139 else
1140 break;
1141 }
Joe Perches29f1c782010-03-10 15:21:00 -08001142 if (initialized) {
1143 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1144 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 show_floppy();
1146 }
1147 FDCS->reset = 1;
1148 return -1;
1149}
1150
1151#define MORE_OUTPUT -2
1152/* does the fdc need more output? */
1153static int need_more_output(void)
1154{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001155 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001156
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001157 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001159
1160 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 return result();
1164}
1165
1166/* Set perpendicular mode as required, based on data rate, if supported.
1167 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1168 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001169static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170{
1171 unsigned char perp_mode;
1172
1173 if (raw_cmd->rate & 0x40) {
1174 switch (raw_cmd->rate & 3) {
1175 case 0:
1176 perp_mode = 2;
1177 break;
1178 case 3:
1179 perp_mode = 3;
1180 break;
1181 default:
1182 DPRINT("Invalid data rate for perpendicular mode!\n");
1183 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001184 FDCS->reset = 1;
1185 /*
1186 * convenient way to return to
1187 * redo without too much hassle
1188 * (deep stack et al.)
1189 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 return;
1191 }
1192 } else
1193 perp_mode = 0;
1194
1195 if (FDCS->perp_mode == perp_mode)
1196 return;
1197 if (FDCS->version >= FDC_82077_ORIG) {
1198 output_byte(FD_PERPENDICULAR);
1199 output_byte(perp_mode);
1200 FDCS->perp_mode = perp_mode;
1201 } else if (perp_mode) {
1202 DPRINT("perpendicular mode not supported by this FDC.\n");
1203 }
1204} /* perpendicular_mode */
1205
1206static int fifo_depth = 0xa;
1207static int no_fifo;
1208
1209static int fdc_configure(void)
1210{
1211 /* Turn on FIFO */
1212 output_byte(FD_CONFIGURE);
1213 if (need_more_output() != MORE_OUTPUT)
1214 return 0;
1215 output_byte(0);
1216 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1217 output_byte(0); /* pre-compensation from track
1218 0 upwards */
1219 return 1;
1220}
1221
1222#define NOMINAL_DTR 500
1223
1224/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1225 * head load time, and DMA disable flag to values needed by floppy.
1226 *
1227 * The value "dtr" is the data transfer rate in Kbps. It is needed
1228 * to account for the data rate-based scaling done by the 82072 and 82077
1229 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1230 * 8272a).
1231 *
1232 * Note that changing the data transfer rate has a (probably deleterious)
1233 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1234 * fdc_specify is called again after each data transfer rate
1235 * change.
1236 *
1237 * srt: 1000 to 16000 in microseconds
1238 * hut: 16 to 240 milliseconds
1239 * hlt: 2 to 254 milliseconds
1240 *
1241 * These values are rounded up to the next highest available delay time.
1242 */
1243static void fdc_specify(void)
1244{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001245 unsigned char spec1;
1246 unsigned char spec2;
1247 unsigned long srt;
1248 unsigned long hlt;
1249 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 unsigned long dtr = NOMINAL_DTR;
1251 unsigned long scale_dtr = NOMINAL_DTR;
1252 int hlt_max_code = 0x7f;
1253 int hut_max_code = 0xf;
1254
1255 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1256 fdc_configure();
1257 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 }
1259
1260 switch (raw_cmd->rate & 0x03) {
1261 case 3:
1262 dtr = 1000;
1263 break;
1264 case 1:
1265 dtr = 300;
1266 if (FDCS->version >= FDC_82078) {
1267 /* chose the default rate table, not the one
1268 * where 1 = 2 Mbps */
1269 output_byte(FD_DRIVESPEC);
1270 if (need_more_output() == MORE_OUTPUT) {
1271 output_byte(UNIT(current_drive));
1272 output_byte(0xc0);
1273 }
1274 }
1275 break;
1276 case 2:
1277 dtr = 250;
1278 break;
1279 }
1280
1281 if (FDCS->version >= FDC_82072) {
1282 scale_dtr = dtr;
1283 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1284 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1285 }
1286
1287 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001288 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001289 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 SUPBOUND(srt, 0xf);
1293 INFBOUND(srt, 0);
1294
Julia Lawall061837b2008-09-22 14:57:16 -07001295 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 if (hlt < 0x01)
1297 hlt = 0x01;
1298 else if (hlt > 0x7f)
1299 hlt = hlt_max_code;
1300
Julia Lawall061837b2008-09-22 14:57:16 -07001301 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (hut < 0x1)
1303 hut = 0x1;
1304 else if (hut > 0xf)
1305 hut = hut_max_code;
1306
1307 spec1 = (srt << 4) | hut;
1308 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1309
1310 /* If these parameters did not change, just return with success */
1311 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1312 /* Go ahead and set spec1 and spec2 */
1313 output_byte(FD_SPECIFY);
1314 output_byte(FDCS->spec1 = spec1);
1315 output_byte(FDCS->spec2 = spec2);
1316 }
1317} /* fdc_specify */
1318
1319/* Set the FDC's data transfer rate on behalf of the specified drive.
1320 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1321 * of the specify command (i.e. using the fdc_specify function).
1322 */
1323static int fdc_dtr(void)
1324{
1325 /* If data rate not already set to desired value, set it. */
1326 if ((raw_cmd->rate & 3) == FDCS->dtr)
1327 return 0;
1328
1329 /* Set dtr */
1330 fd_outb(raw_cmd->rate & 3, FD_DCR);
1331
1332 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1333 * need a stabilization period of several milliseconds to be
1334 * enforced after data rate changes before R/W operations.
1335 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1336 */
1337 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001338 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001339 (work_func_t)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340} /* fdc_dtr */
1341
1342static void tell_sector(void)
1343{
Joe Perchesb46df352010-03-10 15:20:46 -08001344 pr_cont(": track %d, head %d, sector %d, size %d",
1345 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346} /* tell_sector */
1347
Joe Perchesb46df352010-03-10 15:20:46 -08001348static void print_errors(void)
1349{
1350 DPRINT("");
1351 if (ST0 & ST0_ECE) {
1352 pr_cont("Recalibrate failed!");
1353 } else if (ST2 & ST2_CRC) {
1354 pr_cont("data CRC error");
1355 tell_sector();
1356 } else if (ST1 & ST1_CRC) {
1357 pr_cont("CRC error");
1358 tell_sector();
1359 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1360 (ST2 & ST2_MAM)) {
1361 if (!probing) {
1362 pr_cont("sector not found");
1363 tell_sector();
1364 } else
1365 pr_cont("probe failed...");
1366 } else if (ST2 & ST2_WC) { /* seek error */
1367 pr_cont("wrong cylinder");
1368 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1369 pr_cont("bad cylinder");
1370 } else {
1371 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1372 ST0, ST1, ST2);
1373 tell_sector();
1374 }
1375 pr_cont("\n");
1376}
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378/*
1379 * OK, this error interpreting routine is called after a
1380 * DMA read/write has succeeded
1381 * or failed, so we check the results, and copy any buffers.
1382 * hhb: Added better error reporting.
1383 * ak: Made this into a separate routine.
1384 */
1385static int interpret_errors(void)
1386{
1387 char bad;
1388
1389 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001390 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 FDCS->reset = 1;
1392 return 1;
1393 }
1394
1395 /* check IC to find cause of interrupt */
1396 switch (ST0 & ST0_INTR) {
1397 case 0x40: /* error occurred during command execution */
1398 if (ST1 & ST1_EOC)
1399 return 0; /* occurs with pseudo-DMA */
1400 bad = 1;
1401 if (ST1 & ST1_WP) {
1402 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001403 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 cont->done(0);
1405 bad = 2;
1406 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001407 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 } else if (ST1 & ST1_OR) {
1409 if (DP->flags & FTD_MSG)
1410 DPRINT("Over/Underrun - retrying\n");
1411 bad = 0;
1412 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001413 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 }
1415 if (ST2 & ST2_WC || ST2 & ST2_BC)
1416 /* wrong cylinder => recal */
1417 DRS->track = NEED_2_RECAL;
1418 return bad;
1419 case 0x80: /* invalid command given */
1420 DPRINT("Invalid FDC command given!\n");
1421 cont->done(0);
1422 return 2;
1423 case 0xc0:
1424 DPRINT("Abnormal termination caused by polling\n");
1425 cont->error();
1426 return 2;
1427 default: /* (0) Normal command termination */
1428 return 0;
1429 }
1430}
1431
1432/*
1433 * This routine is called when everything should be correctly set up
1434 * for the transfer (i.e. floppy motor is on, the correct floppy is
1435 * selected, and the head is sitting on the right track).
1436 */
1437static void setup_rw_floppy(void)
1438{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001439 int i;
1440 int r;
1441 int flags;
1442 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 unsigned long ready_date;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001444 work_func_t function;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
1446 flags = raw_cmd->flags;
1447 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1448 flags |= FD_RAW_INTR;
1449
1450 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1451 ready_date = DRS->spinup_date + DP->spinup;
1452 /* If spinup will take a long time, rerun scandrives
1453 * again just before spinup completion. Beware that
1454 * after scandrives, we must again wait for selection.
1455 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001456 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 ready_date -= DP->select_delay;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001458 function = (work_func_t)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001460 function = (work_func_t)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
1462 /* wait until the floppy is spinning fast enough */
1463 if (fd_wait_for_completion(ready_date, function))
1464 return;
1465 }
1466 dflags = DRS->flags;
1467
1468 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1469 setup_DMA();
1470
1471 if (flags & FD_RAW_INTR)
1472 do_floppy = main_command_interrupt;
1473
1474 r = 0;
1475 for (i = 0; i < raw_cmd->cmd_count; i++)
1476 r |= output_byte(raw_cmd->cmd[i]);
1477
Joe Perchesded28632010-03-10 15:21:09 -08001478 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
1480 if (r) {
1481 cont->error();
1482 reset_fdc();
1483 return;
1484 }
1485
1486 if (!(flags & FD_RAW_INTR)) {
1487 inr = result();
1488 cont->interrupt();
1489 } else if (flags & FD_RAW_NEED_DISK)
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001490 fd_watchdog(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491}
1492
1493static int blind_seek;
1494
1495/*
1496 * This is the routine called after every seek (or recalibrate) interrupt
1497 * from the floppy controller.
1498 */
1499static void seek_interrupt(void)
1500{
Joe Perchesded28632010-03-10 15:21:09 -08001501 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1503 DPRINT("seek failed\n");
1504 DRS->track = NEED_2_RECAL;
1505 cont->error();
1506 cont->redo();
1507 return;
1508 }
1509 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001510 debug_dcl(DP->flags,
1511 "clearing NEWCHANGE flag because of effective seek\n");
1512 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001513 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1514 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 DRS->select_date = jiffies;
1516 }
1517 DRS->track = ST1;
1518 floppy_ready();
1519}
1520
1521static void check_wp(void)
1522{
Joe Perchese0298532010-03-10 15:20:55 -08001523 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1524 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 output_byte(FD_GETSTATUS);
1526 output_byte(UNIT(current_drive));
1527 if (result() != 1) {
1528 FDCS->reset = 1;
1529 return;
1530 }
Joe Perchese0298532010-03-10 15:20:55 -08001531 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1532 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001533 debug_dcl(DP->flags,
1534 "checking whether disk is write protected\n");
1535 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001537 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 else
Joe Perchese0298532010-03-10 15:20:55 -08001539 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 }
1541}
1542
1543static void seek_floppy(void)
1544{
1545 int track;
1546
1547 blind_seek = 0;
1548
Joe Perchesded28632010-03-10 15:21:09 -08001549 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Joe Perchese0298532010-03-10 15:20:55 -08001551 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1553 /* the media changed flag should be cleared after the seek.
1554 * If it isn't, this means that there is really no disk in
1555 * the drive.
1556 */
Joe Perchese0298532010-03-10 15:20:55 -08001557 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 cont->done(0);
1559 cont->redo();
1560 return;
1561 }
1562 if (DRS->track <= NEED_1_RECAL) {
1563 recalibrate_floppy();
1564 return;
Joe Perchese0298532010-03-10 15:20:55 -08001565 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1567 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1568 /* we seek to clear the media-changed condition. Does anybody
1569 * know a more elegant way, which works on all drives? */
1570 if (raw_cmd->track)
1571 track = raw_cmd->track - 1;
1572 else {
1573 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1574 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1575 blind_seek = 1;
1576 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1577 }
1578 track = 1;
1579 }
1580 } else {
1581 check_wp();
1582 if (raw_cmd->track != DRS->track &&
1583 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1584 track = raw_cmd->track;
1585 else {
1586 setup_rw_floppy();
1587 return;
1588 }
1589 }
1590
1591 do_floppy = seek_interrupt;
1592 output_byte(FD_SEEK);
1593 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001594 if (output_byte(track) < 0) {
1595 reset_fdc();
1596 return;
1597 }
Joe Perchesded28632010-03-10 15:21:09 -08001598 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599}
1600
1601static void recal_interrupt(void)
1602{
Joe Perchesded28632010-03-10 15:21:09 -08001603 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 if (inr != 2)
1605 FDCS->reset = 1;
1606 else if (ST0 & ST0_ECE) {
1607 switch (DRS->track) {
1608 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001609 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 /* after a second recalibrate, we still haven't
1611 * reached track 0. Probably no drive. Raise an
1612 * error, as failing immediately might upset
1613 * computers possessed by the Devil :-) */
1614 cont->error();
1615 cont->redo();
1616 return;
1617 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001618 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 /* If we already did a recalibrate,
1620 * and we are not at track 0, this
1621 * means we have moved. (The only way
1622 * not to move at recalibration is to
1623 * be already at track 0.) Clear the
1624 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001625 debug_dcl(DP->flags,
1626 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
Joe Perchese0298532010-03-10 15:20:55 -08001628 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 DRS->select_date = jiffies;
1630 /* fall through */
1631 default:
Joe Perchesded28632010-03-10 15:21:09 -08001632 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 /* Recalibrate moves the head by at
1634 * most 80 steps. If after one
1635 * recalibrate we don't have reached
1636 * track 0, this might mean that we
1637 * started beyond track 80. Try
1638 * again. */
1639 DRS->track = NEED_1_RECAL;
1640 break;
1641 }
1642 } else
1643 DRS->track = ST1;
1644 floppy_ready();
1645}
1646
1647static void print_result(char *message, int inr)
1648{
1649 int i;
1650
1651 DPRINT("%s ", message);
1652 if (inr >= 0)
1653 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001654 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1655 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656}
1657
1658/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001659irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 int do_print;
1662 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001663 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
1665 lasthandler = handler;
1666 interruptjiffies = jiffies;
1667
1668 f = claim_dma_lock();
1669 fd_disable_dma();
1670 release_dma_lock(f);
1671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 do_floppy = NULL;
1673 if (fdc >= N_FDC || FDCS->address == -1) {
1674 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001675 pr_info("DOR0=%x\n", fdc_state[0].dor);
1676 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001677 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001678 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 return IRQ_NONE;
1680 }
1681
1682 FDCS->reset = 0;
1683 /* We have to clear the reset flag here, because apparently on boxes
1684 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1685 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1686 * emission of the SENSEI's.
1687 * It is OK to emit floppy commands because we are in an interrupt
1688 * handler here, and thus we have to fear no interference of other
1689 * activity.
1690 */
1691
Joe Perches29f1c782010-03-10 15:21:00 -08001692 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694 inr = result();
1695 if (do_print)
1696 print_result("unexpected interrupt", inr);
1697 if (inr == 0) {
1698 int max_sensei = 4;
1699 do {
1700 output_byte(FD_SENSEI);
1701 inr = result();
1702 if (do_print)
1703 print_result("sensei", inr);
1704 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001705 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1706 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 }
1708 if (!handler) {
1709 FDCS->reset = 1;
1710 return IRQ_NONE;
1711 }
1712 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001713 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
1715 /* FIXME! Was it really for us? */
1716 return IRQ_HANDLED;
1717}
1718
1719static void recalibrate_floppy(void)
1720{
Joe Perchesded28632010-03-10 15:21:09 -08001721 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 do_floppy = recal_interrupt;
1723 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001724 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001725 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726}
1727
1728/*
1729 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1730 */
1731static void reset_interrupt(void)
1732{
Joe Perchesded28632010-03-10 15:21:09 -08001733 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 result(); /* get the status ready for set_fdc */
1735 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001736 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 cont->error(); /* a reset just after a reset. BAD! */
1738 }
1739 cont->redo();
1740}
1741
1742/*
1743 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1744 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1745 */
1746static void reset_fdc(void)
1747{
1748 unsigned long flags;
1749
1750 do_floppy = reset_interrupt;
1751 FDCS->reset = 0;
1752 reset_fdc_info(0);
1753
1754 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1755 /* Irrelevant for systems with true DMA (i386). */
1756
1757 flags = claim_dma_lock();
1758 fd_disable_dma();
1759 release_dma_lock(flags);
1760
1761 if (FDCS->version >= FDC_82072A)
1762 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1763 else {
1764 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1765 udelay(FD_RESET_DELAY);
1766 fd_outb(FDCS->dor, FD_DOR);
1767 }
1768}
1769
1770static void show_floppy(void)
1771{
1772 int i;
1773
Joe Perchesb46df352010-03-10 15:20:46 -08001774 pr_info("\n");
1775 pr_info("floppy driver state\n");
1776 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001777 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001778 jiffies, interruptjiffies, jiffies - interruptjiffies,
1779 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
Joe Perchesb46df352010-03-10 15:20:46 -08001781 pr_info("timeout_message=%s\n", timeout_message);
1782 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001784 pr_info("%2x %2x %lu\n",
1785 output_log[(i + output_log_pos) % OLOGSIZE].data,
1786 output_log[(i + output_log_pos) % OLOGSIZE].status,
1787 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1788 pr_info("last result at %lu\n", resultjiffies);
1789 pr_info("last redo_fd_request at %lu\n", lastredo);
1790 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1791 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
Joe Perchesb46df352010-03-10 15:20:46 -08001793 pr_info("status=%x\n", fd_inb(FD_STATUS));
1794 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001796 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001797 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001798 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001799 if (delayed_work_pending(&fd_timer))
1800 pr_info("delayed work.function=%p expires=%ld\n",
1801 fd_timer.work.func,
1802 fd_timer.timer.expires - jiffies);
1803 if (delayed_work_pending(&fd_timeout))
1804 pr_info("timer_function=%p expires=%ld\n",
1805 fd_timeout.work.func,
1806 fd_timeout.timer.expires - jiffies);
1807
Joe Perchesb46df352010-03-10 15:20:46 -08001808 pr_info("cont=%p\n", cont);
1809 pr_info("current_req=%p\n", current_req);
1810 pr_info("command_status=%d\n", command_status);
1811 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812}
1813
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001814static void floppy_shutdown(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815{
1816 unsigned long flags;
1817
Joe Perches29f1c782010-03-10 15:21:00 -08001818 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 show_floppy();
1820 cancel_activity();
1821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 flags = claim_dma_lock();
1823 fd_disable_dma();
1824 release_dma_lock(flags);
1825
1826 /* avoid dma going to a random drive after shutdown */
1827
Joe Perches29f1c782010-03-10 15:21:00 -08001828 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 DPRINT("floppy timeout called\n");
1830 FDCS->reset = 1;
1831 if (cont) {
1832 cont->done(0);
1833 cont->redo(); /* this will recall reset when needed */
1834 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001835 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 process_fd_request();
1837 }
Joe Perches275176b2010-03-10 15:21:06 -08001838 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839}
1840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001842static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001844 int mask;
1845 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847 mask = 0xfc;
1848 data = UNIT(current_drive);
1849 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1850 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1851 set_debugt();
1852 /* no read since this drive is running */
1853 DRS->first_read_date = 0;
1854 /* note motor start time if motor is not yet running */
1855 DRS->spinup_date = jiffies;
1856 data |= (0x10 << UNIT(current_drive));
1857 }
1858 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1859 mask &= ~(0x10 << UNIT(current_drive));
1860
1861 /* starts motor and selects floppy */
1862 del_timer(motor_off_timer + current_drive);
1863 set_dor(fdc, mask, data);
1864
1865 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001866 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001867 (work_func_t)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868}
1869
1870static void floppy_ready(void)
1871{
Joe Perches045f9832010-03-10 15:20:47 -08001872 if (FDCS->reset) {
1873 reset_fdc();
1874 return;
1875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (start_motor(floppy_ready))
1877 return;
1878 if (fdc_dtr())
1879 return;
1880
Joe Perches87f530d2010-03-10 15:20:54 -08001881 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1883 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001884 twaddle(); /* this clears the dcl on certain
1885 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
1887#ifdef fd_chose_dma_mode
1888 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1889 unsigned long flags = claim_dma_lock();
1890 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1891 release_dma_lock(flags);
1892 }
1893#endif
1894
1895 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1896 perpendicular_mode();
1897 fdc_specify(); /* must be done here because of hut, hlt ... */
1898 seek_floppy();
1899 } else {
1900 if ((raw_cmd->flags & FD_RAW_READ) ||
1901 (raw_cmd->flags & FD_RAW_WRITE))
1902 fdc_specify();
1903 setup_rw_floppy();
1904 }
1905}
1906
1907static void floppy_start(void)
1908{
Joe Perches73507e62010-03-10 15:21:03 -08001909 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
1911 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001912 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001913 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 floppy_ready();
1915}
1916
1917/*
1918 * ========================================================================
1919 * here ends the bottom half. Exported routines are:
1920 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1921 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1922 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1923 * and set_dor.
1924 * ========================================================================
1925 */
1926/*
1927 * General purpose continuations.
1928 * ==============================
1929 */
1930
1931static void do_wakeup(void)
1932{
Joe Perches73507e62010-03-10 15:21:03 -08001933 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 cont = NULL;
1935 command_status += 2;
1936 wake_up(&command_done);
1937}
1938
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001939static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 .interrupt = empty,
1941 .redo = do_wakeup,
1942 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001943 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944};
1945
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001946static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 .interrupt = empty,
1948 .redo = process_fd_request,
1949 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001950 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951};
1952
Joe Perches74f63f42010-03-10 15:20:58 -08001953static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954{
1955 int ret;
1956
1957 schedule_bh(handler);
1958
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001959 if (interruptible)
1960 wait_event_interruptible(command_done, command_status >= 2);
1961 else
1962 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
1964 if (command_status < 2) {
1965 cancel_activity();
1966 cont = &intr_cont;
1967 reset_fdc();
1968 return -EINTR;
1969 }
1970
1971 if (FDCS->reset)
1972 command_status = FD_COMMAND_ERROR;
1973 if (command_status == FD_COMMAND_OKAY)
1974 ret = 0;
1975 else
1976 ret = -EIO;
1977 command_status = FD_COMMAND_NONE;
1978 return ret;
1979}
1980
1981static void generic_done(int result)
1982{
1983 command_status = result;
1984 cont = &wakeup_cont;
1985}
1986
1987static void generic_success(void)
1988{
1989 cont->done(1);
1990}
1991
1992static void generic_failure(void)
1993{
1994 cont->done(0);
1995}
1996
1997static void success_and_wakeup(void)
1998{
1999 generic_success();
2000 cont->redo();
2001}
2002
2003/*
2004 * formatting and rw support.
2005 * ==========================
2006 */
2007
2008static int next_valid_format(void)
2009{
2010 int probed_format;
2011
2012 probed_format = DRS->probed_format;
2013 while (1) {
2014 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2015 DRS->probed_format = 0;
2016 return 1;
2017 }
2018 if (floppy_type[DP->autodetect[probed_format]].sect) {
2019 DRS->probed_format = probed_format;
2020 return 0;
2021 }
2022 probed_format++;
2023 }
2024}
2025
2026static void bad_flp_intr(void)
2027{
2028 int err_count;
2029
2030 if (probing) {
2031 DRS->probed_format++;
2032 if (!next_valid_format())
2033 return;
2034 }
2035 err_count = ++(*errors);
2036 INFBOUND(DRWE->badness, err_count);
2037 if (err_count > DP->max_errors.abort)
2038 cont->done(0);
2039 if (err_count > DP->max_errors.reset)
2040 FDCS->reset = 1;
2041 else if (err_count > DP->max_errors.recal)
2042 DRS->track = NEED_2_RECAL;
2043}
2044
2045static void set_floppy(int drive)
2046{
2047 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002048
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 if (type)
2050 _floppy = floppy_type + type;
2051 else
2052 _floppy = current_type[drive];
2053}
2054
2055/*
2056 * formatting support.
2057 * ===================
2058 */
2059static void format_interrupt(void)
2060{
2061 switch (interpret_errors()) {
2062 case 1:
2063 cont->error();
2064 case 2:
2065 break;
2066 case 0:
2067 cont->done(1);
2068 }
2069 cont->redo();
2070}
2071
Joe Perches48c8cee2010-03-10 15:20:45 -08002072#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075static void setup_format_params(int track)
2076{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002077 int n;
2078 int il;
2079 int count;
2080 int head_shift;
2081 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 struct fparm {
2083 unsigned char track, head, sect, size;
2084 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
2086 raw_cmd = &default_raw_cmd;
2087 raw_cmd->track = track;
2088
Joe Perches48c8cee2010-03-10 15:20:45 -08002089 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2090 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 raw_cmd->rate = _floppy->rate & 0x43;
2092 raw_cmd->cmd_count = NR_F;
2093 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2094 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2095 F_SIZECODE = FD_SIZECODE(_floppy);
2096 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2097 F_GAP = _floppy->fmt_gap;
2098 F_FILL = FD_FILL_BYTE;
2099
2100 raw_cmd->kernel_data = floppy_track_buffer;
2101 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2102
2103 /* allow for about 30ms for data transport per track */
2104 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2105
2106 /* a ``cylinder'' is two tracks plus a little stepping time */
2107 track_shift = 2 * head_shift + 3;
2108
2109 /* position of logical sector 1 on this track */
2110 n = (track_shift * format_req.track + head_shift * format_req.head)
2111 % F_SECT_PER_TRACK;
2112
2113 /* determine interleave */
2114 il = 1;
2115 if (_floppy->fmt_gap < 0x22)
2116 il++;
2117
2118 /* initialize field */
2119 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2120 here[count].track = format_req.track;
2121 here[count].head = format_req.head;
2122 here[count].sect = 0;
2123 here[count].size = F_SIZECODE;
2124 }
2125 /* place logical sectors */
2126 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2127 here[n].sect = count;
2128 n = (n + il) % F_SECT_PER_TRACK;
2129 if (here[n].sect) { /* sector busy, find next free sector */
2130 ++n;
2131 if (n >= F_SECT_PER_TRACK) {
2132 n -= F_SECT_PER_TRACK;
2133 while (here[n].sect)
2134 ++n;
2135 }
2136 }
2137 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002138 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002140 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 }
2142}
2143
2144static void redo_format(void)
2145{
2146 buffer_track = -1;
2147 setup_format_params(format_req.track << STRETCH(_floppy));
2148 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002149 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150}
2151
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002152static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 .interrupt = format_interrupt,
2154 .redo = redo_format,
2155 .error = bad_flp_intr,
2156 .done = generic_done
2157};
2158
2159static int do_format(int drive, struct format_descr *tmp_format_req)
2160{
2161 int ret;
2162
Joe Perches74f63f42010-03-10 15:20:58 -08002163 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002164 return -EINTR;
2165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 set_floppy(drive);
2167 if (!_floppy ||
2168 _floppy->track > DP->tracks ||
2169 tmp_format_req->track >= _floppy->track ||
2170 tmp_format_req->head >= _floppy->head ||
2171 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2172 !_floppy->fmt_gap) {
2173 process_fd_request();
2174 return -EINVAL;
2175 }
2176 format_req = *tmp_format_req;
2177 format_errors = 0;
2178 cont = &format_cont;
2179 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002180 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002181 if (ret == -EINTR)
2182 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 process_fd_request();
2184 return ret;
2185}
2186
2187/*
2188 * Buffer read/write and support
2189 * =============================
2190 */
2191
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002192static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193{
2194 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002195 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
2197 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002198 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002199 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002200 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
2203 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002204 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 current_req = NULL;
2206}
2207
2208/* new request_done. Can handle physical sectors which are smaller than a
2209 * logical buffer */
2210static void request_done(int uptodate)
2211{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 struct request *req = current_req;
Jens Axboe48821182010-09-22 09:32:36 +02002213 struct request_queue *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 unsigned long flags;
2215 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002216 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
2218 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002219 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2220 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002223 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 return;
2225 }
2226
Jens Axboe48821182010-09-22 09:32:36 +02002227 q = req->q;
2228
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 if (uptodate) {
2230 /* maintain values for invalidation on geometry
2231 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002232 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 INFBOUND(DRS->maxblock, block);
2234 if (block > _floppy->sect)
2235 DRS->maxtrack = 1;
2236
2237 /* unlock chained buffers */
2238 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002239 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 spin_unlock_irqrestore(q->queue_lock, flags);
2241 } else {
2242 if (rq_data_dir(req) == WRITE) {
2243 /* record write error information */
2244 DRWE->write_errors++;
2245 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002246 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 DRWE->first_error_generation = DRS->generation;
2248 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002249 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 DRWE->last_error_generation = DRS->generation;
2251 }
2252 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002253 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 spin_unlock_irqrestore(q->queue_lock, flags);
2255 }
2256}
2257
2258/* Interrupt handler evaluating the result of the r/w operation */
2259static void rw_interrupt(void)
2260{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002261 int eoc;
2262 int ssize;
2263 int heads;
2264 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
2266 if (R_HEAD >= 2) {
2267 /* some Toshiba floppy controllers occasionnally seem to
2268 * return bogus interrupts after read/write operations, which
2269 * can be recognized by a bad head number (>= 2) */
2270 return;
2271 }
2272
2273 if (!DRS->first_read_date)
2274 DRS->first_read_date = jiffies;
2275
2276 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002277 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278
2279 if (ST1 & ST1_EOC)
2280 eoc = 1;
2281 else
2282 eoc = 0;
2283
2284 if (COMMAND & 0x80)
2285 heads = 2;
2286 else
2287 heads = 1;
2288
2289 nr_sectors = (((R_TRACK - TRACK) * heads +
2290 R_HEAD - HEAD) * SECT_PER_TRACK +
2291 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2292
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002294 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 DPRINT("long rw: %x instead of %lx\n",
2296 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002297 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2298 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2299 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2300 pr_info("heads=%d eoc=%d\n", heads, eoc);
2301 pr_info("spt=%d st=%d ss=%d\n",
2302 SECT_PER_TRACK, fsector_t, ssize);
2303 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
2306 nr_sectors -= in_sector_offset;
2307 INFBOUND(nr_sectors, 0);
2308 SUPBOUND(current_count_sectors, nr_sectors);
2309
2310 switch (interpret_errors()) {
2311 case 2:
2312 cont->redo();
2313 return;
2314 case 1:
2315 if (!current_count_sectors) {
2316 cont->error();
2317 cont->redo();
2318 return;
2319 }
2320 break;
2321 case 0:
2322 if (!current_count_sectors) {
2323 cont->redo();
2324 return;
2325 }
2326 current_type[current_drive] = _floppy;
2327 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2328 break;
2329 }
2330
2331 if (probing) {
2332 if (DP->flags & FTD_MSG)
2333 DPRINT("Auto-detected floppy type %s in fd%d\n",
2334 _floppy->name, current_drive);
2335 current_type[current_drive] = _floppy;
2336 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2337 probing = 0;
2338 }
2339
2340 if (CT(COMMAND) != FD_READ ||
2341 raw_cmd->kernel_data == current_req->buffer) {
2342 /* transfer directly from buffer */
2343 cont->done(1);
2344 } else if (CT(COMMAND) == FD_READ) {
2345 buffer_track = raw_cmd->track;
2346 buffer_drive = current_drive;
2347 INFBOUND(buffer_max, nr_sectors + fsector_t);
2348 }
2349 cont->redo();
2350}
2351
2352/* Compute maximal contiguous buffer size. */
2353static int buffer_chain_size(void)
2354{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002356 int size;
2357 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 char *base;
2359
2360 base = bio_data(current_req->bio);
2361 size = 0;
2362
NeilBrown5705f702007-09-25 12:35:59 +02002363 rq_for_each_segment(bv, current_req, iter) {
2364 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2365 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
NeilBrown5705f702007-09-25 12:35:59 +02002367 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 }
2369
2370 return size >> 9;
2371}
2372
2373/* Compute the maximal transfer size */
2374static int transfer_size(int ssize, int max_sector, int max_size)
2375{
2376 SUPBOUND(max_sector, fsector_t + max_size);
2377
2378 /* alignment */
2379 max_sector -= (max_sector % _floppy->sect) % ssize;
2380
2381 /* transfer size, beginning not aligned */
2382 current_count_sectors = max_sector - fsector_t;
2383
2384 return max_sector;
2385}
2386
2387/*
2388 * Move data from/to the track buffer to/from the buffer cache.
2389 */
2390static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2391{
2392 int remaining; /* number of transferred 512-byte sectors */
2393 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002394 char *buffer;
2395 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002396 int size;
2397 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
2399 max_sector = transfer_size(ssize,
2400 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002401 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
2403 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002404 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002406 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
2408 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002409 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002411 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2412 pr_info("remaining=%d\n", remaining >> 9);
2413 pr_info("current_req->nr_sectors=%u\n",
2414 blk_rq_sectors(current_req));
2415 pr_info("current_req->current_nr_sectors=%u\n",
2416 blk_rq_cur_sectors(current_req));
2417 pr_info("max_sector=%d\n", max_sector);
2418 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
2421 buffer_max = max(max_sector, buffer_max);
2422
2423 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2424
Tejun Heo1011c1b2009-05-07 22:24:45 +09002425 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
NeilBrown5705f702007-09-25 12:35:59 +02002427 rq_for_each_segment(bv, current_req, iter) {
2428 if (!remaining)
2429 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
NeilBrown5705f702007-09-25 12:35:59 +02002431 size = bv->bv_len;
2432 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
NeilBrown5705f702007-09-25 12:35:59 +02002434 buffer = page_address(bv->bv_page) + bv->bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002435 if (dma_buffer + size >
2436 floppy_track_buffer + (max_buffer_sectors << 10) ||
2437 dma_buffer < floppy_track_buffer) {
2438 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002439 (int)((floppy_track_buffer - dma_buffer) >> 9));
2440 pr_info("fsector_t=%d buffer_min=%d\n",
2441 fsector_t, buffer_min);
2442 pr_info("current_count_sectors=%ld\n",
2443 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002445 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002446 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002447 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002448 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 }
NeilBrown5705f702007-09-25 12:35:59 +02002450 if (((unsigned long)buffer) % 512)
2451 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002452
NeilBrown5705f702007-09-25 12:35:59 +02002453 if (CT(COMMAND) == FD_READ)
2454 memcpy(buffer, dma_buffer, size);
2455 else
2456 memcpy(dma_buffer, buffer, size);
2457
2458 remaining -= size;
2459 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 if (remaining) {
2462 if (remaining > 0)
2463 max_sector -= remaining >> 9;
2464 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466}
2467
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468/* work around a bug in pseudo DMA
2469 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2470 * sending data. Hence we need a different way to signal the
2471 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2472 * does not work with MT, hence we can only transfer one head at
2473 * a time
2474 */
2475static void virtualdmabug_workaround(void)
2476{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002477 int hard_sectors;
2478 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480 if (CT(COMMAND) == FD_WRITE) {
2481 COMMAND &= ~0x80; /* switch off multiple track mode */
2482
2483 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2484 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002486 pr_info("too many sectors %d > %d\n",
2487 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 return;
2489 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002490 SECT_PER_TRACK = end_sector;
2491 /* make sure SECT_PER_TRACK
2492 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 }
2494}
2495
2496/*
2497 * Formulate a read/write request.
2498 * this routine decides where to load the data (directly to buffer, or to
2499 * tmp floppy area), how much data to load (the size of the buffer, the whole
2500 * track, or a single sector)
2501 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2502 * allocation on the fly, it should be done here. No other part should need
2503 * modification.
2504 */
2505
2506static int make_raw_rw_request(void)
2507{
2508 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002509 int max_sector;
2510 int max_size;
2511 int tracksize;
2512 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002514 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516
2517 set_fdc((long)current_req->rq_disk->private_data);
2518
2519 raw_cmd = &default_raw_cmd;
Fengguang Wu2fb2ca62012-07-28 19:45:59 +08002520 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 raw_cmd->cmd_count = NR_RW;
2522 if (rq_data_dir(current_req) == READ) {
2523 raw_cmd->flags |= FD_RAW_READ;
2524 COMMAND = FM_MODE(_floppy, FD_READ);
2525 } else if (rq_data_dir(current_req) == WRITE) {
2526 raw_cmd->flags |= FD_RAW_WRITE;
2527 COMMAND = FM_MODE(_floppy, FD_WRITE);
2528 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002529 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 return 0;
2531 }
2532
2533 max_sector = _floppy->sect * _floppy->head;
2534
Tejun Heo83096eb2009-05-07 22:24:39 +09002535 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2536 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002538 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 current_count_sectors = 1;
2540 return 1;
2541 } else
2542 return 0;
2543 }
2544 HEAD = fsector_t / _floppy->sect;
2545
Keith Wansbrough9e491842008-09-22 14:57:17 -07002546 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002547 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2548 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 max_sector = _floppy->sect;
2550
2551 /* 2M disks have phantom sectors on the first track */
2552 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2553 max_sector = 2 * _floppy->sect / 3;
2554 if (fsector_t >= max_sector) {
2555 current_count_sectors =
2556 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002557 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 return 1;
2559 }
2560 SIZECODE = 2;
2561 } else
2562 SIZECODE = FD_SIZECODE(_floppy);
2563 raw_cmd->rate = _floppy->rate & 0x43;
2564 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2565 raw_cmd->rate = 1;
2566
2567 if (SIZECODE)
2568 SIZECODE2 = 0xff;
2569 else
2570 SIZECODE2 = 0x80;
2571 raw_cmd->track = TRACK << STRETCH(_floppy);
2572 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2573 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002574 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2576 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002577 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
2579 /* tracksize describes the size which can be filled up with sectors
2580 * of size ssize.
2581 */
2582 tracksize = _floppy->sect - _floppy->sect % ssize;
2583 if (tracksize < _floppy->sect) {
2584 SECT_PER_TRACK++;
2585 if (tracksize <= fsector_t % _floppy->sect)
2586 SECTOR--;
2587
2588 /* if we are beyond tracksize, fill up using smaller sectors */
2589 while (tracksize <= fsector_t % _floppy->sect) {
2590 while (tracksize + ssize > _floppy->sect) {
2591 SIZECODE--;
2592 ssize >>= 1;
2593 }
2594 SECTOR++;
2595 SECT_PER_TRACK++;
2596 tracksize += ssize;
2597 }
2598 max_sector = HEAD * _floppy->sect + tracksize;
2599 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2600 max_sector = _floppy->sect;
2601 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2602 /* for virtual DMA bug workaround */
2603 max_sector = _floppy->sect;
2604 }
2605
2606 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2607 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002608 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 if ((raw_cmd->track == buffer_track) &&
2610 (current_drive == buffer_drive) &&
2611 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2612 /* data already in track buffer */
2613 if (CT(COMMAND) == FD_READ) {
2614 copy_buffer(1, max_sector, buffer_max);
2615 return 1;
2616 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002617 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002619 unsigned int sectors;
2620
2621 sectors = fsector_t + blk_rq_sectors(current_req);
2622 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 max_size = ssize + ssize;
2624 else
2625 max_size = ssize;
2626 }
2627 raw_cmd->flags &= ~FD_RAW_WRITE;
2628 raw_cmd->flags |= FD_RAW_READ;
2629 COMMAND = FM_MODE(_floppy, FD_READ);
2630 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2631 unsigned long dma_limit;
2632 int direct, indirect;
2633
2634 indirect =
2635 transfer_size(ssize, max_sector,
2636 max_buffer_sectors * 2) - fsector_t;
2637
2638 /*
2639 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2640 * on a 64 bit machine!
2641 */
2642 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002643 dma_limit = (MAX_DMA_ADDRESS -
2644 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002645 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 /* 64 kb boundaries */
2648 if (CROSS_64KB(current_req->buffer, max_size << 9))
2649 max_size = (K_64 -
2650 ((unsigned long)current_req->buffer) %
2651 K_64) >> 9;
2652 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2653 /*
2654 * We try to read tracks, but if we get too many errors, we
2655 * go back to reading just one sector at a time.
2656 *
2657 * This means we should be able to read a sector even if there
2658 * are other bad sectors on this track.
2659 */
2660 if (!direct ||
2661 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002662 *errors < DP->max_errors.read_track &&
2663 ((!probing ||
2664 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002665 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 } else {
2667 raw_cmd->kernel_data = current_req->buffer;
2668 raw_cmd->length = current_count_sectors << 9;
2669 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002670 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002671 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 indirect, direct, fsector_t);
2673 return 0;
2674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 virtualdmabug_workaround();
2676 return 2;
2677 }
2678 }
2679
2680 if (CT(COMMAND) == FD_READ)
2681 max_size = max_sector; /* unbounded */
2682
2683 /* claim buffer track if needed */
2684 if (buffer_track != raw_cmd->track || /* bad track */
2685 buffer_drive != current_drive || /* bad drive */
2686 fsector_t > buffer_max ||
2687 fsector_t < buffer_min ||
2688 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002689 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002691 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2692 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 buffer_track = -1;
2694 buffer_drive = current_drive;
2695 buffer_max = buffer_min = aligned_sector_t;
2696 }
2697 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002698 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
2700 if (CT(COMMAND) == FD_WRITE) {
2701 /* copy write buffer to track buffer.
2702 * if we get here, we know that the write
2703 * is either aligned or the data already in the buffer
2704 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 if (in_sector_offset && buffer_track == -1)
2706 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 buffer_track = raw_cmd->track;
2708 buffer_drive = current_drive;
2709 copy_buffer(ssize, max_sector,
2710 2 * max_buffer_sectors + buffer_min);
2711 } else
2712 transfer_size(ssize, max_sector,
2713 2 * max_buffer_sectors + buffer_min -
2714 aligned_sector_t);
2715
2716 /* round up current_count_sectors to get dma xfer size */
2717 raw_cmd->length = in_sector_offset + current_count_sectors;
2718 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2719 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 if ((raw_cmd->length < current_count_sectors << 9) ||
2721 (raw_cmd->kernel_data != current_req->buffer &&
2722 CT(COMMAND) == FD_WRITE &&
2723 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2724 aligned_sector_t < buffer_min)) ||
2725 raw_cmd->length % (128 << SIZECODE) ||
2726 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2727 DPRINT("fractionary current count b=%lx s=%lx\n",
2728 raw_cmd->length, current_count_sectors);
2729 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002730 pr_info("addr=%d, length=%ld\n",
2731 (int)((raw_cmd->kernel_data -
2732 floppy_track_buffer) >> 9),
2733 current_count_sectors);
2734 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2735 fsector_t, aligned_sector_t, max_sector, max_size);
2736 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2737 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2738 COMMAND, SECTOR, HEAD, TRACK);
2739 pr_info("buffer drive=%d\n", buffer_drive);
2740 pr_info("buffer track=%d\n", buffer_track);
2741 pr_info("buffer_min=%d\n", buffer_min);
2742 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 return 0;
2744 }
2745
2746 if (raw_cmd->kernel_data != current_req->buffer) {
2747 if (raw_cmd->kernel_data < floppy_track_buffer ||
2748 current_count_sectors < 0 ||
2749 raw_cmd->length < 0 ||
2750 raw_cmd->kernel_data + raw_cmd->length >
2751 floppy_track_buffer + (max_buffer_sectors << 10)) {
2752 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002753 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2754 fsector_t, buffer_min, raw_cmd->length >> 9);
2755 pr_info("current_count_sectors=%ld\n",
2756 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002758 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002760 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 return 0;
2762 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002763 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002764 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 DPRINT("buffer overrun in direct transfer\n");
2766 return 0;
2767 } else if (raw_cmd->length < current_count_sectors << 9) {
2768 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002769 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2770 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 }
2772 if (raw_cmd->length == 0) {
2773 DPRINT("zero dma transfer attempted from make_raw_request\n");
2774 return 0;
2775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
2777 virtualdmabug_workaround();
2778 return 2;
2779}
2780
Jens Axboe48821182010-09-22 09:32:36 +02002781/*
2782 * Round-robin between our available drives, doing one request from each
2783 */
2784static int set_next_request(void)
2785{
2786 struct request_queue *q;
2787 int old_pos = fdc_queue;
2788
2789 do {
2790 q = disks[fdc_queue]->queue;
2791 if (++fdc_queue == N_DRIVE)
2792 fdc_queue = 0;
2793 if (q) {
2794 current_req = blk_fetch_request(q);
2795 if (current_req)
2796 break;
2797 }
2798 } while (fdc_queue != old_pos);
2799
2800 return current_req != NULL;
2801}
2802
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803static void redo_fd_request(void)
2804{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 int drive;
2806 int tmp;
2807
2808 lastredo = jiffies;
2809 if (current_drive < N_DRIVE)
2810 floppy_off(current_drive);
2811
Joe Perches0da31322010-03-10 15:21:03 -08002812do_request:
2813 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002814 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815
Jens Axboe48821182010-09-22 09:32:36 +02002816 spin_lock_irq(&floppy_lock);
2817 pending = set_next_request();
2818 spin_unlock_irq(&floppy_lock);
Jens Axboe48821182010-09-22 09:32:36 +02002819 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002820 do_floppy = NULL;
2821 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 }
Joe Perches0da31322010-03-10 15:21:03 -08002825 drive = (long)current_req->rq_disk->private_data;
2826 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002827 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002828
2829 set_floppy(drive);
2830 raw_cmd = &default_raw_cmd;
2831 raw_cmd->flags = 0;
2832 if (start_motor(redo_fd_request))
2833 return;
2834
2835 disk_change(current_drive);
2836 if (test_bit(current_drive, &fake_change) ||
2837 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2838 DPRINT("disk absent or changed during operation\n");
2839 request_done(0);
2840 goto do_request;
2841 }
2842 if (!_floppy) { /* Autodetection */
2843 if (!probing) {
2844 DRS->probed_format = 0;
2845 if (next_valid_format()) {
2846 DPRINT("no autodetectable formats\n");
2847 _floppy = NULL;
2848 request_done(0);
2849 goto do_request;
2850 }
2851 }
2852 probing = 1;
2853 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2854 } else
2855 probing = 0;
2856 errors = &(current_req->errors);
2857 tmp = make_raw_rw_request();
2858 if (tmp < 2) {
2859 request_done(tmp);
2860 goto do_request;
2861 }
2862
2863 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2864 twaddle();
2865 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002866 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002867 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868}
2869
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002870static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 .interrupt = rw_interrupt,
2872 .redo = redo_fd_request,
2873 .error = bad_flp_intr,
2874 .done = request_done
2875};
2876
2877static void process_fd_request(void)
2878{
2879 cont = &rw_cont;
2880 schedule_bh(redo_fd_request);
2881}
2882
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002883static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884{
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002885 if (WARN(max_buffer_sectors == 0,
2886 "VFS: %s called on non-open device\n", __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002889 if (WARN(atomic_read(&usage_count) == 0,
2890 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%x\n",
2891 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
2892 current_req->cmd_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 return;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002894
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002895 if (test_and_set_bit(0, &fdc_busy)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 /* fdc busy, this new request will be treated when the
2897 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002898 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 return;
2900 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002901 command_status = FD_COMMAND_NONE;
2902 __reschedule_timeout(MAXTIMEOUT, "fd_request");
2903 set_fdc(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002905 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906}
2907
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002908static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 .interrupt = success_and_wakeup,
2910 .redo = floppy_ready,
2911 .error = generic_failure,
2912 .done = generic_done
2913};
2914
Joe Perches74f63f42010-03-10 15:20:58 -08002915static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 /* no auto-sense, just clear dcl */
2918 raw_cmd = &default_raw_cmd;
2919 raw_cmd->flags = flag;
2920 raw_cmd->track = 0;
2921 raw_cmd->cmd_count = 0;
2922 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002923 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002924 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002925
2926 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927}
2928
2929/*
2930 * User triggered reset
2931 * ====================
2932 */
2933
2934static void reset_intr(void)
2935{
Joe Perchesb46df352010-03-10 15:20:46 -08002936 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937}
2938
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002939static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 .interrupt = reset_intr,
2941 .redo = success_and_wakeup,
2942 .error = generic_failure,
2943 .done = generic_done
2944};
2945
Joe Perches74f63f42010-03-10 15:20:58 -08002946static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947{
2948 int ret;
2949
Joe Perches52a0d612010-03-10 15:20:53 -08002950 if (lock_fdc(drive, interruptible))
2951 return -EINTR;
2952
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 if (arg == FD_RESET_ALWAYS)
2954 FDCS->reset = 1;
2955 if (FDCS->reset) {
2956 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002957 ret = wait_til_done(reset_fdc, interruptible);
2958 if (ret == -EINTR)
2959 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 }
2961 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002962 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963}
2964
2965/*
2966 * Misc Ioctl's and support
2967 * ========================
2968 */
2969static inline int fd_copyout(void __user *param, const void *address,
2970 unsigned long size)
2971{
2972 return copy_to_user(param, address, size) ? -EFAULT : 0;
2973}
2974
Joe Perches48c8cee2010-03-10 15:20:45 -08002975static inline int fd_copyin(void __user *param, void *address,
2976 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977{
2978 return copy_from_user(address, param, size) ? -EFAULT : 0;
2979}
2980
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02002981static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982{
2983 struct floppy_struct *floppy;
2984
2985 if (type)
2986 floppy = floppy_type + type;
2987 else {
2988 if (UDP->native_format)
2989 floppy = floppy_type + UDP->native_format;
2990 else
2991 return "(null)";
2992 }
2993 if (floppy->name)
2994 return floppy->name;
2995 else
2996 return "(null)";
2997}
2998
2999/* raw commands */
3000static void raw_cmd_done(int flag)
3001{
3002 int i;
3003
3004 if (!flag) {
3005 raw_cmd->flags |= FD_RAW_FAILURE;
3006 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3007 } else {
3008 raw_cmd->reply_count = inr;
3009 if (raw_cmd->reply_count > MAX_REPLIES)
3010 raw_cmd->reply_count = 0;
3011 for (i = 0; i < raw_cmd->reply_count; i++)
3012 raw_cmd->reply[i] = reply_buffer[i];
3013
3014 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3015 unsigned long flags;
3016 flags = claim_dma_lock();
3017 raw_cmd->length = fd_get_dma_residue();
3018 release_dma_lock(flags);
3019 }
3020
3021 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3022 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3023 raw_cmd->flags |= FD_RAW_FAILURE;
3024
3025 if (disk_change(current_drive))
3026 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3027 else
3028 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3029 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3030 motor_off_callback(current_drive);
3031
3032 if (raw_cmd->next &&
3033 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3034 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3035 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3036 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3037 raw_cmd = raw_cmd->next;
3038 return;
3039 }
3040 }
3041 generic_done(flag);
3042}
3043
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003044static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 .interrupt = success_and_wakeup,
3046 .redo = floppy_start,
3047 .error = generic_failure,
3048 .done = raw_cmd_done
3049};
3050
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003051static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 struct floppy_raw_cmd *ptr)
3053{
3054 int ret;
3055
3056 while (ptr) {
Joe Perchesce2f11f2010-03-10 15:21:08 -08003057 ret = copy_to_user(param, ptr, sizeof(*ptr));
Joe Perches86b12b42010-03-10 15:20:56 -08003058 if (ret)
3059 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 param += sizeof(struct floppy_raw_cmd);
3061 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003062 if (ptr->length >= 0 &&
3063 ptr->length <= ptr->buffer_length) {
3064 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003065 ret = fd_copyout(ptr->data, ptr->kernel_data,
3066 length);
3067 if (ret)
3068 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 }
3071 ptr = ptr->next;
3072 }
Joe Perches7f252712010-03-10 15:21:08 -08003073
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 return 0;
3075}
3076
3077static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3078{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003079 struct floppy_raw_cmd *next;
3080 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081
3082 this = *ptr;
3083 *ptr = NULL;
3084 while (this) {
3085 if (this->buffer_length) {
3086 fd_dma_mem_free((unsigned long)this->kernel_data,
3087 this->buffer_length);
3088 this->buffer_length = 0;
3089 }
3090 next = this->next;
3091 kfree(this);
3092 this = next;
3093 }
3094}
3095
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003096static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 struct floppy_raw_cmd **rcmd)
3098{
3099 struct floppy_raw_cmd *ptr;
3100 int ret;
3101 int i;
3102
3103 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003104
3105loop:
3106 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3107 if (!ptr)
3108 return -ENOMEM;
3109 *rcmd = ptr;
3110 ret = copy_from_user(ptr, param, sizeof(*ptr));
3111 if (ret)
3112 return -EFAULT;
3113 ptr->next = NULL;
3114 ptr->buffer_length = 0;
3115 param += sizeof(struct floppy_raw_cmd);
3116 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 /* the command may now also take up the space
3118 * initially intended for the reply & the
3119 * reply count. Needed for long 82078 commands
3120 * such as RESTORE, which takes ... 17 command
3121 * bytes. Murphy's law #137: When you reserve
3122 * 16 bytes for a structure, you'll one day
3123 * discover that you really need 17...
3124 */
Joe Perches7f252712010-03-10 15:21:08 -08003125 return -EINVAL;
3126
3127 for (i = 0; i < 16; i++)
3128 ptr->reply[i] = 0;
3129 ptr->resultcode = 0;
3130 ptr->kernel_data = NULL;
3131
3132 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3133 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003135 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3136 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3137 if (!ptr->kernel_data)
3138 return -ENOMEM;
3139 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 }
Joe Perches7f252712010-03-10 15:21:08 -08003141 if (ptr->flags & FD_RAW_WRITE) {
3142 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3143 if (ret)
3144 return ret;
3145 }
3146
3147 if (ptr->flags & FD_RAW_MORE) {
3148 rcmd = &(ptr->next);
3149 ptr->rate &= 0x43;
3150 goto loop;
3151 }
3152
3153 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154}
3155
3156static int raw_cmd_ioctl(int cmd, void __user *param)
3157{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003159 int drive;
3160 int ret2;
3161 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
3163 if (FDCS->rawcmd <= 1)
3164 FDCS->rawcmd = 1;
3165 for (drive = 0; drive < N_DRIVE; drive++) {
3166 if (FDC(drive) != fdc)
3167 continue;
3168 if (drive == current_drive) {
3169 if (UDRS->fd_ref > 1) {
3170 FDCS->rawcmd = 2;
3171 break;
3172 }
3173 } else if (UDRS->fd_ref) {
3174 FDCS->rawcmd = 2;
3175 break;
3176 }
3177 }
3178
3179 if (FDCS->reset)
3180 return -EIO;
3181
3182 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3183 if (ret) {
3184 raw_cmd_free(&my_raw_cmd);
3185 return ret;
3186 }
3187
3188 raw_cmd = my_raw_cmd;
3189 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003190 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003191 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
3193 if (ret != -EINTR && FDCS->reset)
3194 ret = -EIO;
3195
3196 DRS->track = NO_TRACK;
3197
3198 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3199 if (!ret)
3200 ret = ret2;
3201 raw_cmd_free(&my_raw_cmd);
3202 return ret;
3203}
3204
3205static int invalidate_drive(struct block_device *bdev)
3206{
3207 /* invalidate the buffer track to force a reread */
3208 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3209 process_fd_request();
3210 check_disk_change(bdev);
3211 return 0;
3212}
3213
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003214static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 int drive, int type, struct block_device *bdev)
3216{
3217 int cnt;
3218
3219 /* sanity checking for parameters. */
3220 if (g->sect <= 0 ||
3221 g->head <= 0 ||
3222 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3223 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003224 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 return -EINVAL;
3226 if (type) {
3227 if (!capable(CAP_SYS_ADMIN))
3228 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003229 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003230 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003231 mutex_unlock(&open_lock);
3232 return -EINTR;
3233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 floppy_type[type] = *g;
3235 floppy_type[type].name = "user format";
3236 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3237 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3238 floppy_type[type].size + 1;
3239 process_fd_request();
3240 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3241 struct block_device *bdev = opened_bdev[cnt];
3242 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3243 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003244 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003246 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 } else {
3248 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003249
Joe Perches74f63f42010-03-10 15:20:58 -08003250 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003251 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003252 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 /* notice a disk change immediately, else
3254 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003255 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003256 return -EINTR;
3257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 oldStretch = g->stretch;
3259 user_params[drive] = *g;
3260 if (buffer_drive == drive)
3261 SUPBOUND(buffer_max, user_params[drive].sect);
3262 current_type[drive] = &user_params[drive];
3263 floppy_sizes[drive] = user_params[drive].size;
3264 if (cmd == FDDEFPRM)
3265 DRS->keep_data = -1;
3266 else
3267 DRS->keep_data = 1;
3268 /* invalidation. Invalidate only when needed, i.e.
3269 * when there are already sectors in the buffer cache
3270 * whose number will change. This is useful, because
3271 * mtools often changes the geometry of the disk after
3272 * looking at the boot block */
3273 if (DRS->maxblock > user_params[drive].sect ||
3274 DRS->maxtrack ||
3275 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003276 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 invalidate_drive(bdev);
3278 else
3279 process_fd_request();
3280 }
3281 return 0;
3282}
3283
3284/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003285static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 FDCLRPRM,
3287 FDSETPRM,
3288 FDDEFPRM,
3289 FDGETPRM,
3290 FDMSGON,
3291 FDMSGOFF,
3292 FDFMTBEG,
3293 FDFMTTRK,
3294 FDFMTEND,
3295 FDSETEMSGTRESH,
3296 FDFLUSH,
3297 FDSETMAXERRS,
3298 FDGETMAXERRS,
3299 FDGETDRVTYP,
3300 FDSETDRVPRM,
3301 FDGETDRVPRM,
3302 FDGETDRVSTAT,
3303 FDPOLLDRVSTAT,
3304 FDRESET,
3305 FDGETFDCSTAT,
3306 FDWERRORCLR,
3307 FDWERRORGET,
3308 FDRAWCMD,
3309 FDEJECT,
3310 FDTWADDLE
3311};
3312
Stephen Hemminger21af5442010-06-15 13:21:11 +02003313static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314{
3315 int i;
3316
3317 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3318 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3319 *size = _IOC_SIZE(*cmd);
3320 *cmd = ioctl_table[i];
3321 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003322 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 return -EFAULT;
3324 }
3325 return 0;
3326 }
3327 }
3328 return -EINVAL;
3329}
3330
3331static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3332{
3333 if (type)
3334 *g = &floppy_type[type];
3335 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003336 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003337 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003338 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003339 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 process_fd_request();
3341 *g = current_type[drive];
3342 }
3343 if (!*g)
3344 return -ENODEV;
3345 return 0;
3346}
3347
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003348static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3349{
3350 int drive = (long)bdev->bd_disk->private_data;
3351 int type = ITYPE(drive_state[drive].fd_device);
3352 struct floppy_struct *g;
3353 int ret;
3354
3355 ret = get_floppy_geometry(drive, type, &g);
3356 if (ret)
3357 return ret;
3358
3359 geo->heads = g->head;
3360 geo->sectors = g->sect;
3361 geo->cylinders = g->track;
3362 return 0;
3363}
3364
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003365static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 unsigned long param)
3367{
Al Viroa4af9b42008-03-02 09:27:55 -05003368 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003369 int type = ITYPE(UDRS->fd_device);
3370 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 int ret;
3372 int size;
3373 union inparam {
3374 struct floppy_struct g; /* geometry */
3375 struct format_descr f;
3376 struct floppy_max_errors max_errors;
3377 struct floppy_drive_params dp;
3378 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003379 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380
3381 /* convert compatibility eject ioctls into floppy eject ioctl.
3382 * We do this in order to provide a means to eject floppy disks before
3383 * installing the new fdutils package */
3384 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003385 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 DPRINT("obsolete eject ioctl\n");
3387 DPRINT("please use floppycontrol --eject\n");
3388 cmd = FDEJECT;
3389 }
3390
Joe Perchesa81ee542010-03-10 15:20:46 -08003391 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 return -EINVAL;
3393
Joe Perchesa81ee542010-03-10 15:20:46 -08003394 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003395 ret = normalize_ioctl(&cmd, &size);
3396 if (ret)
3397 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003398
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003400 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3402 return -EPERM;
3403
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003404 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3405 return -EINVAL;
3406
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003408 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003409 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3410 ret = fd_copyin((void __user *)param, &inparam, size);
3411 if (ret)
3412 return ret;
3413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414
Joe Perchesda273652010-03-10 15:20:52 -08003415 switch (cmd) {
3416 case FDEJECT:
3417 if (UDRS->fd_ref != 1)
3418 /* somebody else has this drive open */
3419 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003420 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003421 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422
Joe Perchesda273652010-03-10 15:20:52 -08003423 /* do the actual eject. Fails on
3424 * non-Sparc architectures */
3425 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426
Joe Perchese0298532010-03-10 15:20:55 -08003427 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3428 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003429 process_fd_request();
3430 return ret;
3431 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003432 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003433 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003434 current_type[drive] = NULL;
3435 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3436 UDRS->keep_data = 0;
3437 return invalidate_drive(bdev);
3438 case FDSETPRM:
3439 case FDDEFPRM:
3440 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3441 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003442 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003443 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003444 if (ret)
3445 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003446 break;
3447 case FDMSGON:
3448 UDP->flags |= FTD_MSG;
3449 return 0;
3450 case FDMSGOFF:
3451 UDP->flags &= ~FTD_MSG;
3452 return 0;
3453 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003454 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003455 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003456 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003457 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003458 ret = UDRS->flags;
3459 process_fd_request();
3460 if (ret & FD_VERIFY)
3461 return -ENODEV;
3462 if (!(ret & FD_DISK_WRITABLE))
3463 return -EROFS;
3464 return 0;
3465 case FDFMTTRK:
3466 if (UDRS->fd_ref != 1)
3467 return -EBUSY;
3468 return do_format(drive, &inparam.f);
3469 case FDFMTEND:
3470 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003471 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003472 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003473 return invalidate_drive(bdev);
3474 case FDSETEMSGTRESH:
3475 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3476 return 0;
3477 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003478 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003479 break;
3480 case FDSETMAXERRS:
3481 UDP->max_errors = inparam.max_errors;
3482 break;
3483 case FDGETDRVTYP:
3484 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003485 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003486 break;
3487 case FDSETDRVPRM:
3488 *UDP = inparam.dp;
3489 break;
3490 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003491 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003492 break;
3493 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003494 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003495 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003496 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003497 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003498 process_fd_request();
3499 /* fall through */
3500 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003501 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003502 break;
3503 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003504 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003505 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003506 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003507 break;
3508 case FDWERRORCLR:
3509 memset(UDRWE, 0, sizeof(*UDRWE));
3510 return 0;
3511 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003512 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003513 break;
3514 case FDRAWCMD:
3515 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003517 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003518 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003519 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003520 i = raw_cmd_ioctl(cmd, (void __user *)param);
3521 if (i == -EINTR)
3522 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003523 process_fd_request();
3524 return i;
3525 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003526 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003527 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003528 twaddle();
3529 process_fd_request();
3530 return 0;
3531 default:
3532 return -EINVAL;
3533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534
3535 if (_IOC_DIR(cmd) & _IOC_READ)
3536 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003537
3538 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539}
3540
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003541static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3542 unsigned int cmd, unsigned long param)
3543{
3544 int ret;
3545
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003546 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003547 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003548 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003549
3550 return ret;
3551}
3552
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553static void __init config_types(void)
3554{
Joe Perchesb46df352010-03-10 15:20:46 -08003555 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 int drive;
3557
3558 /* read drive info out of physical CMOS */
3559 drive = 0;
3560 if (!UDP->cmos)
3561 UDP->cmos = FLOPPY0_TYPE;
3562 drive = 1;
3563 if (!UDP->cmos && FLOPPY1_TYPE)
3564 UDP->cmos = FLOPPY1_TYPE;
3565
Jesper Juhl06f748c2007-10-16 23:30:57 -07003566 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567
3568 for (drive = 0; drive < N_DRIVE; drive++) {
3569 unsigned int type = UDP->cmos;
3570 struct floppy_drive_params *params;
3571 const char *name = NULL;
3572 static char temparea[32];
3573
Tobias Klauser945f3902006-01-08 01:05:11 -08003574 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 params = &default_drive_params[type].params;
3576 if (type) {
3577 name = default_drive_params[type].name;
3578 allowed_drive_mask |= 1 << drive;
3579 } else
3580 allowed_drive_mask &= ~(1 << drive);
3581 } else {
3582 params = &default_drive_params[0].params;
3583 sprintf(temparea, "unknown type %d (usb?)", type);
3584 name = temparea;
3585 }
3586 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003587 const char *prepend;
3588 if (!has_drive) {
3589 prepend = "";
3590 has_drive = true;
3591 pr_info("Floppy drive(s):");
3592 } else {
3593 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 }
Joe Perchesb46df352010-03-10 15:20:46 -08003595
3596 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 }
3598 *UDP = *params;
3599 }
Joe Perchesb46df352010-03-10 15:20:46 -08003600
3601 if (has_drive)
3602 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603}
3604
Al Viroa4af9b42008-03-02 09:27:55 -05003605static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606{
Al Viroa4af9b42008-03-02 09:27:55 -05003607 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003609 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003610 mutex_lock(&open_lock);
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003611 if (!UDRS->fd_ref--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 DPRINT("floppy_release with fd_ref == 0");
3613 UDRS->fd_ref = 0;
3614 }
3615 if (!UDRS->fd_ref)
3616 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003617 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003618 mutex_unlock(&floppy_mutex);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003619
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 return 0;
3621}
3622
3623/*
3624 * floppy_open check for aliasing (/dev/fd0 can be the same as
3625 * /dev/PS0 etc), and disallows simultaneous access to the same
3626 * drive with different device numbers.
3627 */
Al Viroa4af9b42008-03-02 09:27:55 -05003628static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629{
Al Viroa4af9b42008-03-02 09:27:55 -05003630 int drive = (long)bdev->bd_disk->private_data;
3631 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 int try;
3633 int res = -EBUSY;
3634 char *tmp;
3635
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003636 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003637 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003639 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 goto out2;
3641
3642 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003643 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3644 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 }
3646
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003647 UDRS->fd_ref++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648
Al Viroa4af9b42008-03-02 09:27:55 -05003649 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650
3651 res = -ENXIO;
3652
3653 if (!floppy_track_buffer) {
3654 /* if opening an ED drive, reserve a big buffer,
3655 * else reserve a small one */
3656 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3657 try = 64; /* Only 48 actually useful */
3658 else
3659 try = 32; /* Only 24 actually useful */
3660
3661 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3662 if (!tmp && !floppy_track_buffer) {
3663 try >>= 1; /* buffer only one side */
3664 INFBOUND(try, 16);
3665 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3666 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003667 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 if (!tmp && !floppy_track_buffer) {
3670 DPRINT("Unable to allocate DMA memory\n");
3671 goto out;
3672 }
3673 if (floppy_track_buffer) {
3674 if (tmp)
3675 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3676 } else {
3677 buffer_min = buffer_max = -1;
3678 floppy_track_buffer = tmp;
3679 max_buffer_sectors = try;
3680 }
3681 }
3682
Al Viroa4af9b42008-03-02 09:27:55 -05003683 new_dev = MINOR(bdev->bd_dev);
3684 UDRS->fd_device = new_dev;
3685 set_capacity(disks[drive], floppy_sizes[new_dev]);
3686 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 if (buffer_drive == drive)
3688 buffer_track = -1;
3689 }
3690
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 if (UFDCS->rawcmd == 1)
3692 UFDCS->rawcmd = 2;
3693
Al Viroa4af9b42008-03-02 09:27:55 -05003694 if (!(mode & FMODE_NDELAY)) {
3695 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003697 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003698 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 goto out;
3700 }
3701 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003702 if ((mode & FMODE_WRITE) &&
3703 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 goto out;
3705 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003706 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003707 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 return 0;
3709out:
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003710 UDRS->fd_ref--;
3711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 if (!UDRS->fd_ref)
3713 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003715 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003716 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 return res;
3718}
3719
3720/*
3721 * Check if the disk has been changed or if a change has been faked.
3722 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003723static unsigned int floppy_check_events(struct gendisk *disk,
3724 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725{
3726 int drive = (long)disk->private_data;
3727
Joe Perchese0298532010-03-10 15:20:55 -08003728 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3729 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003730 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003732 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003733 lock_fdc(drive, false);
3734 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 }
3737
Joe Perchese0298532010-03-10 15:20:55 -08003738 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3739 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003741 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003742 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 return 0;
3744}
3745
3746/*
3747 * This implements "read block 0" for floppy_revalidate().
3748 * Needed for format autodetection, checking whether there is
3749 * a disk in the drive, and whether that disk is writable.
3750 */
3751
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003752static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755}
3756
3757static int __floppy_read_block_0(struct block_device *bdev)
3758{
3759 struct bio bio;
3760 struct bio_vec bio_vec;
3761 struct completion complete;
3762 struct page *page;
3763 size_t size;
3764
3765 page = alloc_page(GFP_NOIO);
3766 if (!page) {
3767 process_fd_request();
3768 return -ENOMEM;
3769 }
3770
3771 size = bdev->bd_block_size;
3772 if (!size)
3773 size = 1024;
3774
3775 bio_init(&bio);
3776 bio.bi_io_vec = &bio_vec;
3777 bio_vec.bv_page = page;
3778 bio_vec.bv_len = size;
3779 bio_vec.bv_offset = 0;
3780 bio.bi_vcnt = 1;
3781 bio.bi_idx = 0;
3782 bio.bi_size = size;
3783 bio.bi_bdev = bdev;
3784 bio.bi_sector = 0;
Muthu Kumar9354f1b2012-03-05 14:59:16 -08003785 bio.bi_flags = (1 << BIO_QUIET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 init_completion(&complete);
3787 bio.bi_private = &complete;
3788 bio.bi_end_io = floppy_rb0_complete;
3789
3790 submit_bio(READ, &bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 process_fd_request();
3792 wait_for_completion(&complete);
3793
3794 __free_page(page);
3795
3796 return 0;
3797}
3798
3799/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3800 * the bootblock (block 0). "Autodetection" is also needed to check whether
3801 * there is a disk in the drive at all... Thus we also do it for fixed
3802 * geometry formats */
3803static int floppy_revalidate(struct gendisk *disk)
3804{
3805 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 int cf;
3807 int res = 0;
3808
Joe Perchese0298532010-03-10 15:20:55 -08003809 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3810 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003811 test_bit(drive, &fake_change) ||
3812 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003813 if (WARN(atomic_read(&usage_count) == 0,
3814 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003816
Joe Perches74f63f42010-03-10 15:20:58 -08003817 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003818 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3819 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003820 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 process_fd_request(); /*already done by another thread */
3822 return 0;
3823 }
3824 UDRS->maxblock = 0;
3825 UDRS->maxtrack = 0;
3826 if (buffer_drive == drive)
3827 buffer_track = -1;
3828 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003829 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 if (cf)
3831 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003832 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 /* auto-sensing */
3834 res = __floppy_read_block_0(opened_bdev[drive]);
3835 } else {
3836 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003837 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 process_fd_request();
3839 }
3840 }
3841 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3842 return res;
3843}
3844
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003845static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003846 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003847 .open = floppy_open,
3848 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003849 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003850 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003851 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003852 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855/*
3856 * Floppy Driver initialization
3857 * =============================
3858 */
3859
3860/* Determine the floppy disk controller type */
3861/* This routine was written by David C. Niemi */
3862static char __init get_fdc_version(void)
3863{
3864 int r;
3865
3866 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3867 if (FDCS->reset)
3868 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003869 r = result();
3870 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 return FDC_NONE; /* No FDC present ??? */
3872 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003873 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3875 }
3876 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003877 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3878 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 return FDC_UNKNOWN;
3880 }
3881
3882 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003883 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3885 }
3886
3887 output_byte(FD_PERPENDICULAR);
3888 if (need_more_output() == MORE_OUTPUT) {
3889 output_byte(0);
3890 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003891 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 return FDC_82072A; /* 82072A as found on Sparcs. */
3893 }
3894
3895 output_byte(FD_UNLOCK);
3896 r = result();
3897 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003898 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003899 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 * LOCK/UNLOCK */
3901 }
3902 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003903 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3904 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 return FDC_UNKNOWN;
3906 }
3907 output_byte(FD_PARTID);
3908 r = result();
3909 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003910 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3911 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 return FDC_UNKNOWN;
3913 }
3914 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003915 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 return FDC_82077; /* Revised 82077AA passes all the tests */
3917 }
3918 switch (reply_buffer[0] >> 5) {
3919 case 0x0:
3920 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003921 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 return FDC_82078;
3923 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003924 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 return FDC_82078;
3926 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003927 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 return FDC_S82078B;
3929 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003930 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 return FDC_87306;
3932 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003933 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3934 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 return FDC_82078_UNKN;
3936 }
3937} /* get_fdc_version */
3938
3939/* lilo configuration */
3940
3941static void __init floppy_set_flags(int *ints, int param, int param2)
3942{
3943 int i;
3944
3945 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3946 if (param)
3947 default_drive_params[i].params.flags |= param2;
3948 else
3949 default_drive_params[i].params.flags &= ~param2;
3950 }
3951 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
3952}
3953
3954static void __init daring(int *ints, int param, int param2)
3955{
3956 int i;
3957
3958 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3959 if (param) {
3960 default_drive_params[i].params.select_delay = 0;
3961 default_drive_params[i].params.flags |=
3962 FD_SILENT_DCL_CLEAR;
3963 } else {
3964 default_drive_params[i].params.select_delay =
3965 2 * HZ / 100;
3966 default_drive_params[i].params.flags &=
3967 ~FD_SILENT_DCL_CLEAR;
3968 }
3969 }
3970 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
3971}
3972
3973static void __init set_cmos(int *ints, int dummy, int dummy2)
3974{
3975 int current_drive = 0;
3976
3977 if (ints[0] != 2) {
3978 DPRINT("wrong number of parameters for CMOS\n");
3979 return;
3980 }
3981 current_drive = ints[1];
3982 if (current_drive < 0 || current_drive >= 8) {
3983 DPRINT("bad drive for set_cmos\n");
3984 return;
3985 }
3986#if N_FDC > 1
3987 if (current_drive >= 4 && !FDC2)
3988 FDC2 = 0x370;
3989#endif
3990 DP->cmos = ints[2];
3991 DPRINT("setting CMOS code to %d\n", ints[2]);
3992}
3993
3994static struct param_table {
3995 const char *name;
3996 void (*fn) (int *ints, int param, int param2);
3997 int *var;
3998 int def_param;
3999 int param2;
4000} config_params[] __initdata = {
4001 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4002 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4003 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4004 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4005 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4006 {"daring", daring, NULL, 1, 0},
4007#if N_FDC > 1
4008 {"two_fdc", NULL, &FDC2, 0x370, 0},
4009 {"one_fdc", NULL, &FDC2, 0, 0},
4010#endif
4011 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4012 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4013 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4014 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4015 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4016 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4017 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4018 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4019 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4020 {"nofifo", NULL, &no_fifo, 0x20, 0},
4021 {"usefifo", NULL, &no_fifo, 0, 0},
4022 {"cmos", set_cmos, NULL, 0, 0},
4023 {"slow", NULL, &slow_floppy, 1, 0},
4024 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4025 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4026 {"L40SX", NULL, &print_unex, 0, 0}
4027
4028 EXTRA_FLOPPY_PARAMS
4029};
4030
4031static int __init floppy_setup(char *str)
4032{
4033 int i;
4034 int param;
4035 int ints[11];
4036
4037 str = get_options(str, ARRAY_SIZE(ints), ints);
4038 if (str) {
4039 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4040 if (strcmp(str, config_params[i].name) == 0) {
4041 if (ints[0])
4042 param = ints[1];
4043 else
4044 param = config_params[i].def_param;
4045 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004046 config_params[i].fn(ints, param,
4047 config_params[i].
4048 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 if (config_params[i].var) {
4050 DPRINT("%s=%d\n", str, param);
4051 *config_params[i].var = param;
4052 }
4053 return 1;
4054 }
4055 }
4056 }
4057 if (str) {
4058 DPRINT("unknown floppy option [%s]\n", str);
4059
4060 DPRINT("allowed options are:");
4061 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004062 pr_cont(" %s", config_params[i].name);
4063 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 } else
4065 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004066 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 return 0;
4068}
4069
4070static int have_no_fdc = -ENODEV;
4071
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004072static ssize_t floppy_cmos_show(struct device *dev,
4073 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004074{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004075 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004076 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004077
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004078 drive = p->id;
4079 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004080}
Joe Perches48c8cee2010-03-10 15:20:45 -08004081
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004082static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004083
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084static void floppy_device_release(struct device *dev)
4085{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086}
4087
Frans Popc90cd332009-07-25 22:24:54 +02004088static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004089{
4090 int fdc;
4091
4092 for (fdc = 0; fdc < N_FDC; fdc++)
4093 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004094 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004095
4096 return 0;
4097}
4098
Alexey Dobriyan47145212009-12-14 18:00:08 -08004099static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004100 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004101 .restore = floppy_resume,
4102};
4103
4104static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004105 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004106 .name = "floppy",
4107 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004108 },
4109};
4110
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004111static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112
4113static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4114{
4115 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4116 if (drive >= N_DRIVE ||
4117 !(allowed_drive_mask & (1 << drive)) ||
4118 fdc_state[FDC(drive)].version == FDC_NONE)
4119 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004120 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 return NULL;
4122 *part = 0;
4123 return get_disk(disks[drive]);
4124}
4125
Andi Kleen0cc15d032012-07-02 17:27:04 -07004126static int __init do_floppy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127{
4128 int i, unit, drive;
4129 int err, dr;
4130
Stephen Hemminger285203c2010-06-15 13:21:11 +02004131 set_debugt();
4132 interruptjiffies = resultjiffies = jiffies;
4133
Kumar Gala68e1ee62008-09-22 14:41:31 -07004134#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004135 if (check_legacy_ioport(FDC1))
4136 return -ENODEV;
4137#endif
4138
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 raw_cmd = NULL;
4140
4141 for (dr = 0; dr < N_DRIVE; dr++) {
4142 disks[dr] = alloc_disk(1);
4143 if (!disks[dr]) {
4144 err = -ENOMEM;
4145 goto out_put_disk;
4146 }
4147
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004148 floppy_wq = alloc_ordered_workqueue("floppy", 0);
4149 if (!floppy_wq) {
4150 err = -ENOMEM;
4151 goto out_put_disk;
4152 }
4153
Jens Axboe48821182010-09-22 09:32:36 +02004154 disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4155 if (!disks[dr]->queue) {
4156 err = -ENOMEM;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004157 goto out_destroy_workq;
Jens Axboe48821182010-09-22 09:32:36 +02004158 }
4159
4160 blk_queue_max_hw_sectors(disks[dr]->queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 disks[dr]->major = FLOPPY_MAJOR;
4162 disks[dr]->first_minor = TOMINOR(dr);
4163 disks[dr]->fops = &floppy_fops;
4164 sprintf(disks[dr]->disk_name, "fd%d", dr);
4165
4166 init_timer(&motor_off_timer[dr]);
4167 motor_off_timer[dr].data = dr;
4168 motor_off_timer[dr].function = motor_off_callback;
4169 }
4170
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 err = register_blkdev(FLOPPY_MAJOR, "fd");
4172 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004173 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004175 err = platform_driver_register(&floppy_driver);
4176 if (err)
4177 goto out_unreg_blkdev;
4178
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4180 floppy_find, NULL, NULL);
4181
4182 for (i = 0; i < 256; i++)
4183 if (ITYPE(i))
4184 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4185 else
4186 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4187
Joe Perches73507e62010-03-10 15:21:03 -08004188 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 config_types();
4190
4191 for (i = 0; i < N_FDC; i++) {
4192 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004193 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 FDCS->dtr = -1;
4195 FDCS->dor = 0x4;
4196#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004197 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198#ifdef __mc68000__
4199 if (MACH_IS_SUN3X)
4200#endif
4201 FDCS->version = FDC_82072A;
4202#endif
4203 }
4204
4205 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 fdc_state[0].address = FDC1;
4207 if (fdc_state[0].address == -1) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004208 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 err = -ENODEV;
4210 goto out_unreg_region;
4211 }
4212#if N_FDC > 1
4213 fdc_state[1].address = FDC2;
4214#endif
4215
4216 fdc = 0; /* reset fdc in case of unexpected interrupt */
4217 err = floppy_grab_irq_and_dma();
4218 if (err) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004219 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 err = -EBUSY;
4221 goto out_unreg_region;
4222 }
4223
4224 /* initialise drive state */
4225 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004226 memset(UDRS, 0, sizeof(*UDRS));
4227 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004228 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4229 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4230 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 UDRS->fd_device = -1;
4232 floppy_track_buffer = NULL;
4233 max_buffer_sectors = 0;
4234 }
4235 /*
4236 * Small 10 msec delay to let through any interrupt that
4237 * initialization might have triggered, to not
4238 * confuse detection:
4239 */
4240 msleep(10);
4241
4242 for (i = 0; i < N_FDC; i++) {
4243 fdc = i;
4244 FDCS->driver_version = FD_DRIVER_VERSION;
4245 for (unit = 0; unit < 4; unit++)
4246 FDCS->track[unit] = 0;
4247 if (FDCS->address == -1)
4248 continue;
4249 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004250 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004252 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 FDCS->address = -1;
4254 FDCS->version = FDC_NONE;
4255 continue;
4256 }
4257 /* Try to determine the floppy controller type */
4258 FDCS->version = get_fdc_version();
4259 if (FDCS->version == FDC_NONE) {
4260 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004261 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 FDCS->address = -1;
4263 continue;
4264 }
4265 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4266 can_use_virtual_dma = 0;
4267
4268 have_no_fdc = 0;
4269 /* Not all FDCs seem to be able to handle the version command
4270 * properly, so force a reset for the standard FDC clones,
4271 * to avoid interrupt garbage.
4272 */
Joe Perches74f63f42010-03-10 15:20:58 -08004273 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 }
4275 fdc = 0;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004276 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004278 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 if (have_no_fdc) {
4280 DPRINT("no floppy controllers found\n");
4281 err = have_no_fdc;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004282 goto out_release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 }
4284
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 for (drive = 0; drive < N_DRIVE; drive++) {
4286 if (!(allowed_drive_mask & (1 << drive)))
4287 continue;
4288 if (fdc_state[FDC(drive)].version == FDC_NONE)
4289 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004290
4291 floppy_device[drive].name = floppy_device_name;
4292 floppy_device[drive].id = drive;
4293 floppy_device[drive].dev.release = floppy_device_release;
4294
4295 err = platform_device_register(&floppy_device[drive]);
4296 if (err)
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004297 goto out_release_dma;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004298
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004299 err = device_create_file(&floppy_device[drive].dev,
4300 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004301 if (err)
4302 goto out_unreg_platform_dev;
4303
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 /* to be cleaned up... */
4305 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004307 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 add_disk(disks[drive]);
4309 }
4310
4311 return 0;
4312
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004313out_unreg_platform_dev:
4314 platform_device_unregister(&floppy_device[drive]);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004315out_release_dma:
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004316 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 floppy_release_irq_and_dma();
4318out_unreg_region:
4319 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004320 platform_driver_unregister(&floppy_driver);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004321out_destroy_workq:
4322 destroy_workqueue(floppy_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323out_unreg_blkdev:
4324 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325out_put_disk:
4326 while (dr--) {
Carsten Emde6c4867f2011-09-21 10:22:11 +02004327 del_timer_sync(&motor_off_timer[dr]);
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004328 if (disks[dr]->queue) {
Jens Axboe48821182010-09-22 09:32:36 +02004329 blk_cleanup_queue(disks[dr]->queue);
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004330 /*
4331 * put_disk() is not paired with add_disk() and
4332 * will put queue reference one extra time. fix it.
4333 */
4334 disks[dr]->queue = NULL;
4335 }
Linus Torvaldsc093ee42010-11-05 17:45:59 -07004336 put_disk(disks[dr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 }
4338 return err;
4339}
4340
Andi Kleen0cc15d032012-07-02 17:27:04 -07004341#ifndef MODULE
4342static __init void floppy_async_init(void *data, async_cookie_t cookie)
4343{
4344 do_floppy_init();
4345}
4346#endif
4347
4348static int __init floppy_init(void)
4349{
4350#ifdef MODULE
4351 return do_floppy_init();
4352#else
4353 /* Don't hold up the bootup by the floppy initialization */
4354 async_schedule(floppy_async_init, NULL);
4355 return 0;
4356#endif
4357}
4358
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004359static const struct io_region {
4360 int offset;
4361 int size;
4362} io_regions[] = {
4363 { 2, 1 },
4364 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4365 { 4, 2 },
4366 /* address + 6 is reserved, and may be taken by IDE.
4367 * Unfortunately, Adaptec doesn't know this :-(, */
4368 { 7, 1 },
4369};
4370
4371static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4372{
4373 while (p != io_regions) {
4374 p--;
4375 release_region(FDCS->address + p->offset, p->size);
4376 }
4377}
4378
4379#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4380
4381static int floppy_request_regions(int fdc)
4382{
4383 const struct io_region *p;
4384
4385 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004386 if (!request_region(FDCS->address + p->offset,
4387 p->size, "floppy")) {
4388 DPRINT("Floppy io-port 0x%04lx in use\n",
4389 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004390 floppy_release_allocated_regions(fdc, p);
4391 return -EBUSY;
4392 }
4393 }
4394 return 0;
4395}
4396
4397static void floppy_release_regions(int fdc)
4398{
4399 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4400}
4401
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402static int floppy_grab_irq_and_dma(void)
4403{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004404 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004406
4407 /*
4408 * We might have scheduled a free_irq(), wait it to
4409 * drain first:
4410 */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004411 flush_workqueue(floppy_wq);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004412
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 if (fd_request_irq()) {
4414 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4415 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004416 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 return -1;
4418 }
4419 if (fd_request_dma()) {
4420 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4421 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004422 if (can_use_virtual_dma & 2)
4423 use_virtual_dma = can_use_virtual_dma = 1;
4424 if (!(can_use_virtual_dma & 1)) {
4425 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004426 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004427 return -1;
4428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 }
4430
4431 for (fdc = 0; fdc < N_FDC; fdc++) {
4432 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004433 if (floppy_request_regions(fdc))
4434 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 }
4436 }
4437 for (fdc = 0; fdc < N_FDC; fdc++) {
4438 if (FDCS->address != -1) {
4439 reset_fdc_info(1);
4440 fd_outb(FDCS->dor, FD_DOR);
4441 }
4442 }
4443 fdc = 0;
4444 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4445
4446 for (fdc = 0; fdc < N_FDC; fdc++)
4447 if (FDCS->address != -1)
4448 fd_outb(FDCS->dor, FD_DOR);
4449 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004450 * The driver will try and free resources and relies on us
4451 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 */
4453 fdc = 0;
4454 irqdma_allocated = 1;
4455 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004456cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 fd_free_irq();
4458 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004459 while (--fdc >= 0)
4460 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004461 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 return -1;
4463}
4464
4465static void floppy_release_irq_and_dma(void)
4466{
4467 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468#ifndef __sparc__
4469 int drive;
4470#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 long tmpsize;
4472 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004474 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004476
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 if (irqdma_allocated) {
4478 fd_disable_dma();
4479 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004480 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 irqdma_allocated = 0;
4482 }
4483 set_dor(0, ~0, 8);
4484#if N_FDC > 1
4485 set_dor(1, ~8, 0);
4486#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487
4488 if (floppy_track_buffer && max_buffer_sectors) {
4489 tmpsize = max_buffer_sectors * 1024;
4490 tmpaddr = (unsigned long)floppy_track_buffer;
4491 floppy_track_buffer = NULL;
4492 max_buffer_sectors = 0;
4493 buffer_min = buffer_max = -1;
4494 fd_dma_mem_free(tmpaddr, tmpsize);
4495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496#ifndef __sparc__
4497 for (drive = 0; drive < N_FDC * 4; drive++)
4498 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004499 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500#endif
4501
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004502 if (delayed_work_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004503 pr_info("floppy timer still active:%s\n", timeout_message);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004504 if (delayed_work_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004505 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004506 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004507 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 old_fdc = fdc;
4509 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004510 if (FDCS->address != -1)
4511 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 fdc = old_fdc;
4513}
4514
4515#ifdef MODULE
4516
4517static char *floppy;
4518
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519static void __init parse_floppy_cfg_string(char *cfg)
4520{
4521 char *ptr;
4522
4523 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004524 ptr = cfg;
4525 while (*cfg && *cfg != ' ' && *cfg != '\t')
4526 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 if (*cfg) {
4528 *cfg = '\0';
4529 cfg++;
4530 }
4531 if (*ptr)
4532 floppy_setup(ptr);
4533 }
4534}
4535
Jon Schindler7afea3b2008-04-29 00:59:21 -07004536static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537{
4538 if (floppy)
4539 parse_floppy_cfg_string(floppy);
4540 return floppy_init();
4541}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004542module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543
Jon Schindler7afea3b2008-04-29 00:59:21 -07004544static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545{
4546 int drive;
4547
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4549 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004550 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
4552 for (drive = 0; drive < N_DRIVE; drive++) {
4553 del_timer_sync(&motor_off_timer[drive]);
4554
4555 if ((allowed_drive_mask & (1 << drive)) &&
4556 fdc_state[FDC(drive)].version != FDC_NONE) {
4557 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004558 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4559 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 }
Jens Axboe48821182010-09-22 09:32:36 +02004561 blk_cleanup_queue(disks[drive]->queue);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004562
4563 /*
4564 * These disks have not called add_disk(). Don't put down
4565 * queue reference in put_disk().
4566 */
4567 if (!(allowed_drive_mask & (1 << drive)) ||
4568 fdc_state[FDC(drive)].version == FDC_NONE)
4569 disks[drive]->queue = NULL;
4570
Vivek Goyald017bf62010-11-06 08:16:05 -04004571 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004574 cancel_delayed_work_sync(&fd_timeout);
4575 cancel_delayed_work_sync(&fd_timer);
4576 destroy_workqueue(floppy_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004578 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 floppy_release_irq_and_dma();
4580
4581 /* eject disk, if any */
4582 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583}
Joe Perches48c8cee2010-03-10 15:20:45 -08004584
Jon Schindler7afea3b2008-04-29 00:59:21 -07004585module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586
4587module_param(floppy, charp, 0);
4588module_param(FLOPPY_IRQ, int, 0);
4589module_param(FLOPPY_DMA, int, 0);
4590MODULE_AUTHOR("Alain L. Knaff");
4591MODULE_SUPPORTED_DEVICE("fd");
4592MODULE_LICENSE("GPL");
4593
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004594/* This doesn't actually get used other than for module information */
4595static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004596 {"PNP0700", 0},
4597 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004598};
Joe Perches48c8cee2010-03-10 15:20:45 -08004599
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004600MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4601
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602#else
4603
4604__setup("floppy=", floppy_setup);
4605module_init(floppy_init)
4606#endif
4607
4608MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);