blob: cce7df367b793d111ef875bd5cd30a6f5e08782c [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195/*
196 * PS/2 floppies have much slower step rates than regular floppies.
197 * It's been recommended that take about 1/4 of the default speed
198 * in some more extreme cases.
199 */
Arnd Bergmann2a48fc02010-06-02 14:28:52 +0200200static DEFINE_MUTEX(floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201static int slow_floppy;
202
203#include <asm/dma.h>
204#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206static int FLOPPY_IRQ = 6;
207static int FLOPPY_DMA = 2;
208static int can_use_virtual_dma = 2;
209/* =======
210 * can use virtual DMA:
211 * 0 = use of virtual DMA disallowed by config
212 * 1 = use of virtual DMA prescribed by config
213 * 2 = no virtual DMA preference configured. By default try hard DMA,
214 * but fall back on virtual DMA when not enough memory available
215 */
216
217static int use_virtual_dma;
218/* =======
219 * use virtual DMA
220 * 0 using hard DMA
221 * 1 using virtual DMA
222 * This variable is set to virtual when a DMA mem problem arises, and
223 * reset back in floppy_grab_irq_and_dma.
224 * It is not safe to reset it in other circumstances, because the floppy
225 * driver may have several buffers in use at once, and we do currently not
226 * record each buffers capabilities
227 */
228
229static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100232irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235#define K_64 0x10000 /* 64KB */
236
237/* the following is the mask of allowed drives. By default units 2 and
238 * 3 of both floppy controllers are disabled, because switching on the
239 * motor of these drives causes system hangs on some PCI computers. drive
240 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
241 * a drive is allowed.
242 *
243 * NOTE: This must come before we include the arch floppy header because
244 * some ports reference this variable from there. -DaveM
245 */
246
247static int allowed_drive_mask = 0x33;
248
249#include <asm/floppy.h>
250
251static int irqdma_allocated;
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253#include <linux/blkdev.h>
254#include <linux/blkpg.h>
255#include <linux/cdrom.h> /* for the compatibility eject ioctl */
256#include <linux/completion.h>
257
258static struct request *current_req;
Joe Perches48c8cee2010-03-10 15:20:45 -0800259static void do_fd_request(struct request_queue *q);
Jens Axboe48821182010-09-22 09:32:36 +0200260static int set_next_request(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262#ifndef fd_get_dma_residue
263#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
264#endif
265
266/* Dma Memory related stuff */
267
268#ifndef fd_dma_mem_free
269#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
270#endif
271
272#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800273#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274#endif
275
276static inline void fallback_on_nodma_alloc(char **addr, size_t l)
277{
278#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
279 if (*addr)
280 return; /* we have the memory */
281 if (can_use_virtual_dma != 2)
282 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800283 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 *addr = (char *)nodma_mem_alloc(l);
285#else
286 return;
287#endif
288}
289
290/* End dma memory related stuff */
291
292static unsigned long fake_change;
Joe Perches29f1c782010-03-10 15:21:00 -0800293static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Joe Perches48c8cee2010-03-10 15:20:45 -0800295#define ITYPE(x) (((x) >> 2) & 0x1f)
296#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
297#define UNIT(x) ((x) & 0x03) /* drive on fdc */
298#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700299 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Joe Perches48c8cee2010-03-10 15:20:45 -0800302#define DP (&drive_params[current_drive])
303#define DRS (&drive_state[current_drive])
304#define DRWE (&write_errors[current_drive])
305#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Joe Perches48c8cee2010-03-10 15:20:45 -0800307#define UDP (&drive_params[drive])
308#define UDRS (&drive_state[drive])
309#define UDRWE (&write_errors[drive])
310#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Joe Perches48c8cee2010-03-10 15:20:45 -0800312#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
313#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800316#define COMMAND (raw_cmd->cmd[0])
317#define DR_SELECT (raw_cmd->cmd[1])
318#define TRACK (raw_cmd->cmd[2])
319#define HEAD (raw_cmd->cmd[3])
320#define SECTOR (raw_cmd->cmd[4])
321#define SIZECODE (raw_cmd->cmd[5])
322#define SECT_PER_TRACK (raw_cmd->cmd[6])
323#define GAP (raw_cmd->cmd[7])
324#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325#define NR_RW 9
326
327/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800328#define F_SIZECODE (raw_cmd->cmd[2])
329#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
330#define F_GAP (raw_cmd->cmd[4])
331#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332#define NR_F 6
333
334/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800335 * Maximum disk size (in kilobytes).
336 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 * [Now it is rather a minimum]
338 */
339#define MAX_DISK_SIZE 4 /* 3984 */
340
341/*
342 * globals used by 'result()'
343 */
344#define MAX_REPLIES 16
345static unsigned char reply_buffer[MAX_REPLIES];
Joe Perches891eda82010-03-10 15:21:05 -0800346static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800347#define ST0 (reply_buffer[0])
348#define ST1 (reply_buffer[1])
349#define ST2 (reply_buffer[2])
350#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
351#define R_TRACK (reply_buffer[3])
352#define R_HEAD (reply_buffer[4])
353#define R_SECTOR (reply_buffer[5])
354#define R_SIZECODE (reply_buffer[6])
355
356#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358/*
359 * this struct defines the different floppy drive types.
360 */
361static struct {
362 struct floppy_drive_params params;
363 const char *name; /* name printed while booting */
364} default_drive_params[] = {
365/* NOTE: the time values in jiffies should be in msec!
366 CMOS drive type
367 | Maximum data rate supported by drive type
368 | | Head load time, msec
369 | | | Head unload time, msec (not used)
370 | | | | Step rate interval, usec
371 | | | | | Time needed for spinup time (jiffies)
372 | | | | | | Timeout for spinning down (jiffies)
373 | | | | | | | Spindown offset (where disk stops)
374 | | | | | | | | Select delay
375 | | | | | | | | | RPS
376 | | | | | | | | | | Max number of tracks
377 | | | | | | | | | | | Interrupt timeout
378 | | | | | | | | | | | | Max nonintlv. sectors
379 | | | | | | | | | | | | | -Max Errors- flags */
380{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
381 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
382
383{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
384 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
385
386{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
387 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
388
389{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
390 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
391
392{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
393 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
394
395{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
396 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
397
398{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
399 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
400/* | --autodetected formats--- | | |
401 * read_track | | Name printed when booting
402 * | Native format
403 * Frequency of disk change checks */
404};
405
406static struct floppy_drive_params drive_params[N_DRIVE];
407static struct floppy_drive_struct drive_state[N_DRIVE];
408static struct floppy_write_errors write_errors[N_DRIVE];
409static struct timer_list motor_off_timer[N_DRIVE];
410static struct gendisk *disks[N_DRIVE];
411static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800412static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
Jens Axboe48821182010-09-22 09:32:36 +0200414static int fdc_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416/*
417 * This struct defines the different floppy types.
418 *
419 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
420 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
421 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
422 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
423 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
424 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
425 * side 0 is on physical side 0 (but with the misnamed sector IDs).
426 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700427 * 'options'.
428 *
429 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
430 * The LSB (bit 2) is flipped. For most disks, the first sector
431 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
432 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
433 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
434 *
435 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 */
437/*
438 Size
439 | Sectors per track
440 | | Head
441 | | | Tracks
442 | | | | Stretch
443 | | | | | Gap 1 size
444 | | | | | | Data rate, | 0x40 for perp
445 | | | | | | | Spec1 (stepping rate, head unload
446 | | | | | | | | /fmt gap (gap2) */
447static struct floppy_struct floppy_type[32] = {
448 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
449 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
450 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
451 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
452 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
453 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
454 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
455 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
456 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
457 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
458
459 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
460 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
461 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
462 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
463 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
464 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
465 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
466 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
467 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
468 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
469
470 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
471 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
472 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
473 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
474 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
475 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
476 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
477 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
478 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
482 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
483};
484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485#define SECTSIZE (_FD_SECTSIZE(*floppy))
486
487/* Auto-detection: Disk type used until the next media change occurs. */
488static struct floppy_struct *current_type[N_DRIVE];
489
490/*
491 * User-provided type information. current_type points to
492 * the respective entry of this array.
493 */
494static struct floppy_struct user_params[N_DRIVE];
495
496static sector_t floppy_sizes[256];
497
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200498static char floppy_device_name[] = "floppy";
499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500/*
501 * The driver is trying to determine the correct media format
502 * while probing is set. rw_interrupt() clears it after a
503 * successful access.
504 */
505static int probing;
506
507/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800508#define FD_COMMAND_NONE -1
509#define FD_COMMAND_ERROR 2
510#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512static volatile int command_status = FD_COMMAND_NONE;
513static unsigned long fdc_busy;
514static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
515static DECLARE_WAIT_QUEUE_HEAD(command_done);
516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517/* Errors during formatting are counted here. */
518static int format_errors;
519
520/* Format request descriptor. */
521static struct format_descr format_req;
522
523/*
524 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
525 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
526 * H is head unload time (1=16ms, 2=32ms, etc)
527 */
528
529/*
530 * Track buffer
531 * Because these are written to by the DMA controller, they must
532 * not contain a 64k byte boundary crossing, or data will be
533 * corrupted/lost.
534 */
535static char *floppy_track_buffer;
536static int max_buffer_sectors;
537
538static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700539typedef void (*done_f)(int);
Stephen Hemminger3b06c212010-07-20 20:09:00 -0600540static const struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800541 void (*interrupt)(void);
542 /* this is called after the interrupt of the
543 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700544 void (*redo)(void); /* this is called to retry the operation */
545 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 done_f done; /* this is called to say if the operation has
547 * succeeded/failed */
548} *cont;
549
550static void floppy_ready(void);
551static void floppy_start(void);
552static void process_fd_request(void);
553static void recalibrate_floppy(void);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200554static void floppy_shutdown(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800556static int floppy_request_regions(int);
557static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558static int floppy_grab_irq_and_dma(void);
559static void floppy_release_irq_and_dma(void);
560
561/*
562 * The "reset" variable should be tested whenever an interrupt is scheduled,
563 * after the commands have been sent. This is to ensure that the driver doesn't
564 * get wedged when the interrupt doesn't come because of a failed command.
565 * reset doesn't need to be tested before sending commands, because
566 * output_byte is automatically disabled when reset is set.
567 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568static void reset_fdc(void);
569
570/*
571 * These are global variables, as that's the easiest way to give
572 * information to interrupts. They are the data used for the current
573 * request.
574 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800575#define NO_TRACK -1
576#define NEED_1_RECAL -2
577#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200579static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581/* buffer related variables */
582static int buffer_track = -1;
583static int buffer_drive = -1;
584static int buffer_min = -1;
585static int buffer_max = -1;
586
587/* fdc related variables, should end up in a struct */
588static struct floppy_fdc_state fdc_state[N_FDC];
589static int fdc; /* current fdc */
590
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200591static struct workqueue_struct *floppy_wq;
592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593static struct floppy_struct *_floppy = floppy_type;
594static unsigned char current_drive;
595static long current_count_sectors;
596static unsigned char fsector_t; /* sector in track */
597static unsigned char in_sector_offset; /* offset within physical sector,
598 * expressed in units of 512 bytes */
599
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100600static inline bool drive_no_geom(int drive)
601{
602 return !current_type[drive] && !ITYPE(UDRS->fd_device);
603}
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605#ifndef fd_eject
606static inline int fd_eject(int drive)
607{
608 return -EINVAL;
609}
610#endif
611
612/*
613 * Debugging
614 * =========
615 */
616#ifdef DEBUGT
617static long unsigned debugtimer;
618
619static inline void set_debugt(void)
620{
621 debugtimer = jiffies;
622}
623
Joe Perchesded28632010-03-10 15:21:09 -0800624static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800627 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628}
629#else
630static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800631static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632#endif /* DEBUGT */
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200635static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636static const char *timeout_message;
637
Joe Perches275176b2010-03-10 15:21:06 -0800638static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
640 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800641 if (test_bit(0, &fdc_busy) && command_status < 2 &&
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200642 !delayed_work_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800643 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
645}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Joe Perches48c8cee2010-03-10 15:20:45 -0800647static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649#define OLOGSIZE 20
650
Joe Perches48c8cee2010-03-10 15:20:45 -0800651static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652static unsigned long interruptjiffies;
653static unsigned long resultjiffies;
654static int resultsize;
655static unsigned long lastredo;
656
657static struct output_log {
658 unsigned char data;
659 unsigned char status;
660 unsigned long jiffies;
661} output_log[OLOGSIZE];
662
663static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665#define current_reqD -1
666#define MAXTIMEOUT -2
667
Joe Perches73507e62010-03-10 15:21:03 -0800668static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200670 unsigned long delay;
671
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if (drive == current_reqD)
673 drive = current_drive;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200674
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700675 if (drive < 0 || drive >= N_DRIVE) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200676 delay = 20UL * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 drive = 0;
678 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200679 delay = UDP->timeout;
680
681 queue_delayed_work(floppy_wq, &fd_timeout, delay);
Joe Perchesa81ee542010-03-10 15:20:46 -0800682 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800683 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 timeout_message = message;
685}
686
Joe Perches73507e62010-03-10 15:21:03 -0800687static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 unsigned long flags;
690
691 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800692 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 spin_unlock_irqrestore(&floppy_lock, flags);
694}
695
Joe Perches48c8cee2010-03-10 15:20:45 -0800696#define INFBOUND(a, b) (a) = max_t(int, a, b)
697#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699/*
700 * Bottom half floppy driver.
701 * ==========================
702 *
703 * This part of the file contains the code talking directly to the hardware,
704 * and also the main service loop (seek-configure-spinup-command)
705 */
706
707/*
708 * disk change.
709 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
710 * and the last_checked date.
711 *
712 * last_checked is the date of the last check which showed 'no disk change'
713 * FD_DISK_CHANGE is set under two conditions:
714 * 1. The floppy has been changed after some i/o to that floppy already
715 * took place.
716 * 2. No floppy disk is in the drive. This is done in order to ensure that
717 * requests are quickly flushed in case there is no disk in the drive. It
718 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
719 * the drive.
720 *
721 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
722 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
723 * each seek. If a disk is present, the disk change line should also be
724 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
725 * change line is set, this means either that no disk is in the drive, or
726 * that it has been removed since the last seek.
727 *
728 * This means that we really have a third possibility too:
729 * The floppy has been changed after the last seek.
730 */
731
732static int disk_change(int drive)
733{
734 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700735
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800736 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 DPRINT("WARNING disk change called early\n");
738 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
739 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
740 DPRINT("probing disk change on unselected drive\n");
741 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
742 (unsigned int)FDCS->dor);
743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Joe Perches87f530d2010-03-10 15:20:54 -0800745 debug_dcl(UDP->flags,
746 "checking disk change line for drive %d\n", drive);
747 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
748 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
749 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800752 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800754 set_bit(FD_VERIFY_BIT, &UDRS->flags);
755 /* verify write protection */
756
757 if (UDRS->maxblock) /* mark it changed */
758 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
760 /* invalidate its geometry */
761 if (UDRS->keep_data >= 0) {
762 if ((UDP->flags & FTD_MSG) &&
763 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800764 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 current_type[drive] = NULL;
766 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
767 }
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return 1;
770 } else {
771 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800772 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
774 return 0;
775}
776
777static inline int is_selected(int dor, int unit)
778{
779 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
780}
781
Joe Perches57584c52010-03-10 15:21:00 -0800782static bool is_ready_state(int status)
783{
784 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
785 return state == STATUS_READY;
786}
787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788static int set_dor(int fdc, char mask, char data)
789{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700790 unsigned char unit;
791 unsigned char drive;
792 unsigned char newdor;
793 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 if (FDCS->address == -1)
796 return -1;
797
798 olddor = FDCS->dor;
799 newdor = (olddor & mask) | data;
800 if (newdor != olddor) {
801 unit = olddor & 0x3;
802 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
803 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800804 debug_dcl(UDP->flags,
805 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 disk_change(drive);
807 }
808 FDCS->dor = newdor;
809 fd_outb(newdor, FD_DOR);
810
811 unit = newdor & 0x3;
812 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
813 drive = REVDRIVE(fdc, unit);
814 UDRS->select_date = jiffies;
815 }
816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 return olddor;
818}
819
820static void twaddle(void)
821{
822 if (DP->select_delay)
823 return;
824 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
825 fd_outb(FDCS->dor, FD_DOR);
826 DRS->select_date = jiffies;
827}
828
Joe Perches57584c52010-03-10 15:21:00 -0800829/*
830 * Reset all driver information about the current fdc.
831 * This is needed after a reset, and after a raw command.
832 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833static void reset_fdc_info(int mode)
834{
835 int drive;
836
837 FDCS->spec1 = FDCS->spec2 = -1;
838 FDCS->need_configure = 1;
839 FDCS->perp_mode = 1;
840 FDCS->rawcmd = 0;
841 for (drive = 0; drive < N_DRIVE; drive++)
842 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
843 UDRS->track = NEED_2_RECAL;
844}
845
846/* selects the fdc and drive, and enables the fdc's input/dma. */
847static void set_fdc(int drive)
848{
849 if (drive >= 0 && drive < N_DRIVE) {
850 fdc = FDC(drive);
851 current_drive = drive;
852 }
853 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800854 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 return;
856 }
857 set_dor(fdc, ~0, 8);
858#if N_FDC > 1
859 set_dor(1 - fdc, ~8, 0);
860#endif
861 if (FDCS->rawcmd == 2)
862 reset_fdc_info(1);
863 if (fd_inb(FD_STATUS) != STATUS_READY)
864 FDCS->reset = 1;
865}
866
867/* locks the driver */
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200868static int lock_fdc(int drive, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200870 if (WARN(atomic_read(&usage_count) == 0,
871 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200874 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
875 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 command_status = FD_COMMAND_NONE;
878
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200879 reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 set_fdc(drive);
881 return 0;
882}
883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200885static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 if (!test_bit(0, &fdc_busy))
888 DPRINT("FDC access conflict!\n");
889
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200890 raw_cmd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 command_status = FD_COMMAND_NONE;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200892 __cancel_delayed_work(&fd_timeout);
893 do_floppy = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 cont = NULL;
895 clear_bit(0, &fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 wake_up(&fdc_wait);
897}
898
899/* switches the motor off after a given timeout */
900static void motor_off_callback(unsigned long nr)
901{
902 unsigned char mask = ~(0x10 << UNIT(nr));
903
904 set_dor(FDC(nr), mask, 0);
905}
906
907/* schedules motor off */
908static void floppy_off(unsigned int drive)
909{
910 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700911 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
913 if (!(FDCS->dor & (0x10 << UNIT(drive))))
914 return;
915
916 del_timer(motor_off_timer + drive);
917
918 /* make spindle stop in a position which minimizes spinup time
919 * next time */
920 if (UDP->rps) {
921 delta = jiffies - UDRS->first_read_date + HZ -
922 UDP->spindown_offset;
923 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
924 motor_off_timer[drive].expires =
925 jiffies + UDP->spindown - delta;
926 }
927 add_timer(motor_off_timer + drive);
928}
929
930/*
931 * cycle through all N_DRIVE floppy drives, for disk change testing.
932 * stopping at current drive. This is done before any long operation, to
933 * be sure to have up to date disk change information.
934 */
935static void scandrives(void)
936{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700937 int i;
938 int drive;
939 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 if (DP->select_delay)
942 return;
943
944 saved_drive = current_drive;
945 for (i = 0; i < N_DRIVE; i++) {
946 drive = (saved_drive + i + 1) % N_DRIVE;
947 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
948 continue; /* skip closed drives */
949 set_fdc(drive);
950 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
951 (0x10 << UNIT(drive))))
952 /* switch the motor off again, if it was off to
953 * begin with */
954 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
955 }
956 set_fdc(saved_drive);
957}
958
959static void empty(void)
960{
961}
962
David Howells65f27f32006-11-22 14:55:48 +0000963static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Joe Perches48c8cee2010-03-10 15:20:45 -0800965static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200967 WARN_ON(work_pending(&floppy_work));
968
David Howells65f27f32006-11-22 14:55:48 +0000969 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200970 queue_work(floppy_wq, &floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971}
972
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200973static DECLARE_DELAYED_WORK(fd_timer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975static void cancel_activity(void)
976{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 do_floppy = NULL;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200978 cancel_delayed_work_sync(&fd_timer);
979 cancel_work_sync(&floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
982/* this function makes sure that the disk stays in the drive during the
983 * transfer */
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200984static void fd_watchdog(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985{
Joe Perches87f530d2010-03-10 15:20:54 -0800986 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 if (disk_change(current_drive)) {
989 DPRINT("disk removed during i/o\n");
990 cancel_activity();
991 cont->done(0);
992 reset_fdc();
993 } else {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200994 cancel_delayed_work(&fd_timer);
995 PREPARE_DELAYED_WORK(&fd_timer, fd_watchdog);
996 queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 }
998}
999
1000static void main_command_interrupt(void)
1001{
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001002 cancel_delayed_work(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 cont->interrupt();
1004}
1005
1006/* waits for a delay (spinup or select) to pass */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001007static int fd_wait_for_completion(unsigned long expires, work_func_t function)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
1009 if (FDCS->reset) {
1010 reset_fdc(); /* do the reset during sleep to win time
1011 * if we don't need to sleep, it's a good
1012 * occasion anyways */
1013 return 1;
1014 }
1015
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001016 if (time_before(jiffies, expires)) {
1017 cancel_delayed_work(&fd_timer);
1018 PREPARE_DELAYED_WORK(&fd_timer, function);
1019 queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return 1;
1021 }
1022 return 0;
1023}
1024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025static void setup_DMA(void)
1026{
1027 unsigned long f;
1028
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (raw_cmd->length == 0) {
1030 int i;
1031
Joe Perchesb46df352010-03-10 15:20:46 -08001032 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001034 pr_cont("%x,", raw_cmd->cmd[i]);
1035 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 cont->done(0);
1037 FDCS->reset = 1;
1038 return;
1039 }
1040 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001041 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 cont->done(0);
1043 FDCS->reset = 1;
1044 return;
1045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 f = claim_dma_lock();
1047 fd_disable_dma();
1048#ifdef fd_dma_setup
1049 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1050 (raw_cmd->flags & FD_RAW_READ) ?
1051 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1052 release_dma_lock(f);
1053 cont->done(0);
1054 FDCS->reset = 1;
1055 return;
1056 }
1057 release_dma_lock(f);
1058#else
1059 fd_clear_dma_ff();
1060 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1061 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1062 DMA_MODE_READ : DMA_MODE_WRITE);
1063 fd_set_dma_addr(raw_cmd->kernel_data);
1064 fd_set_dma_count(raw_cmd->length);
1065 virtual_dma_port = FDCS->address;
1066 fd_enable_dma();
1067 release_dma_lock(f);
1068#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069}
1070
1071static void show_floppy(void);
1072
1073/* waits until the fdc becomes ready */
1074static int wait_til_ready(void)
1075{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001076 int status;
1077 int counter;
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if (FDCS->reset)
1080 return -1;
1081 for (counter = 0; counter < 10000; counter++) {
1082 status = fd_inb(FD_STATUS);
1083 if (status & STATUS_READY)
1084 return status;
1085 }
Joe Perches29f1c782010-03-10 15:21:00 -08001086 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1088 show_floppy();
1089 }
1090 FDCS->reset = 1;
1091 return -1;
1092}
1093
1094/* sends a command byte to the fdc */
1095static int output_byte(char byte)
1096{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001097 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001099 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001101
1102 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 output_log[output_log_pos].data = byte;
1105 output_log[output_log_pos].status = status;
1106 output_log[output_log_pos].jiffies = jiffies;
1107 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return 0;
1109 }
1110 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001111 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1113 byte, fdc, status);
1114 show_floppy();
1115 }
1116 return -1;
1117}
1118
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119/* gets the response from the fdc */
1120static int result(void)
1121{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001122 int i;
1123 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
1125 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001126 status = wait_til_ready();
1127 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 break;
1129 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1130 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 resultjiffies = jiffies;
1132 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return i;
1134 }
1135 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1136 reply_buffer[i] = fd_inb(FD_DATA);
1137 else
1138 break;
1139 }
Joe Perches29f1c782010-03-10 15:21:00 -08001140 if (initialized) {
1141 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1142 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 show_floppy();
1144 }
1145 FDCS->reset = 1;
1146 return -1;
1147}
1148
1149#define MORE_OUTPUT -2
1150/* does the fdc need more output? */
1151static int need_more_output(void)
1152{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001153 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001154
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001155 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001157
1158 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 return result();
1162}
1163
1164/* Set perpendicular mode as required, based on data rate, if supported.
1165 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1166 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001167static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168{
1169 unsigned char perp_mode;
1170
1171 if (raw_cmd->rate & 0x40) {
1172 switch (raw_cmd->rate & 3) {
1173 case 0:
1174 perp_mode = 2;
1175 break;
1176 case 3:
1177 perp_mode = 3;
1178 break;
1179 default:
1180 DPRINT("Invalid data rate for perpendicular mode!\n");
1181 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001182 FDCS->reset = 1;
1183 /*
1184 * convenient way to return to
1185 * redo without too much hassle
1186 * (deep stack et al.)
1187 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 return;
1189 }
1190 } else
1191 perp_mode = 0;
1192
1193 if (FDCS->perp_mode == perp_mode)
1194 return;
1195 if (FDCS->version >= FDC_82077_ORIG) {
1196 output_byte(FD_PERPENDICULAR);
1197 output_byte(perp_mode);
1198 FDCS->perp_mode = perp_mode;
1199 } else if (perp_mode) {
1200 DPRINT("perpendicular mode not supported by this FDC.\n");
1201 }
1202} /* perpendicular_mode */
1203
1204static int fifo_depth = 0xa;
1205static int no_fifo;
1206
1207static int fdc_configure(void)
1208{
1209 /* Turn on FIFO */
1210 output_byte(FD_CONFIGURE);
1211 if (need_more_output() != MORE_OUTPUT)
1212 return 0;
1213 output_byte(0);
1214 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1215 output_byte(0); /* pre-compensation from track
1216 0 upwards */
1217 return 1;
1218}
1219
1220#define NOMINAL_DTR 500
1221
1222/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1223 * head load time, and DMA disable flag to values needed by floppy.
1224 *
1225 * The value "dtr" is the data transfer rate in Kbps. It is needed
1226 * to account for the data rate-based scaling done by the 82072 and 82077
1227 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1228 * 8272a).
1229 *
1230 * Note that changing the data transfer rate has a (probably deleterious)
1231 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1232 * fdc_specify is called again after each data transfer rate
1233 * change.
1234 *
1235 * srt: 1000 to 16000 in microseconds
1236 * hut: 16 to 240 milliseconds
1237 * hlt: 2 to 254 milliseconds
1238 *
1239 * These values are rounded up to the next highest available delay time.
1240 */
1241static void fdc_specify(void)
1242{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001243 unsigned char spec1;
1244 unsigned char spec2;
1245 unsigned long srt;
1246 unsigned long hlt;
1247 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 unsigned long dtr = NOMINAL_DTR;
1249 unsigned long scale_dtr = NOMINAL_DTR;
1250 int hlt_max_code = 0x7f;
1251 int hut_max_code = 0xf;
1252
1253 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1254 fdc_configure();
1255 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 }
1257
1258 switch (raw_cmd->rate & 0x03) {
1259 case 3:
1260 dtr = 1000;
1261 break;
1262 case 1:
1263 dtr = 300;
1264 if (FDCS->version >= FDC_82078) {
1265 /* chose the default rate table, not the one
1266 * where 1 = 2 Mbps */
1267 output_byte(FD_DRIVESPEC);
1268 if (need_more_output() == MORE_OUTPUT) {
1269 output_byte(UNIT(current_drive));
1270 output_byte(0xc0);
1271 }
1272 }
1273 break;
1274 case 2:
1275 dtr = 250;
1276 break;
1277 }
1278
1279 if (FDCS->version >= FDC_82072) {
1280 scale_dtr = dtr;
1281 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1282 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1283 }
1284
1285 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001286 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001287 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 SUPBOUND(srt, 0xf);
1291 INFBOUND(srt, 0);
1292
Julia Lawall061837b2008-09-22 14:57:16 -07001293 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (hlt < 0x01)
1295 hlt = 0x01;
1296 else if (hlt > 0x7f)
1297 hlt = hlt_max_code;
1298
Julia Lawall061837b2008-09-22 14:57:16 -07001299 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (hut < 0x1)
1301 hut = 0x1;
1302 else if (hut > 0xf)
1303 hut = hut_max_code;
1304
1305 spec1 = (srt << 4) | hut;
1306 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1307
1308 /* If these parameters did not change, just return with success */
1309 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1310 /* Go ahead and set spec1 and spec2 */
1311 output_byte(FD_SPECIFY);
1312 output_byte(FDCS->spec1 = spec1);
1313 output_byte(FDCS->spec2 = spec2);
1314 }
1315} /* fdc_specify */
1316
1317/* Set the FDC's data transfer rate on behalf of the specified drive.
1318 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1319 * of the specify command (i.e. using the fdc_specify function).
1320 */
1321static int fdc_dtr(void)
1322{
1323 /* If data rate not already set to desired value, set it. */
1324 if ((raw_cmd->rate & 3) == FDCS->dtr)
1325 return 0;
1326
1327 /* Set dtr */
1328 fd_outb(raw_cmd->rate & 3, FD_DCR);
1329
1330 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1331 * need a stabilization period of several milliseconds to be
1332 * enforced after data rate changes before R/W operations.
1333 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1334 */
1335 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001336 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001337 (work_func_t)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338} /* fdc_dtr */
1339
1340static void tell_sector(void)
1341{
Joe Perchesb46df352010-03-10 15:20:46 -08001342 pr_cont(": track %d, head %d, sector %d, size %d",
1343 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344} /* tell_sector */
1345
Joe Perchesb46df352010-03-10 15:20:46 -08001346static void print_errors(void)
1347{
1348 DPRINT("");
1349 if (ST0 & ST0_ECE) {
1350 pr_cont("Recalibrate failed!");
1351 } else if (ST2 & ST2_CRC) {
1352 pr_cont("data CRC error");
1353 tell_sector();
1354 } else if (ST1 & ST1_CRC) {
1355 pr_cont("CRC error");
1356 tell_sector();
1357 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1358 (ST2 & ST2_MAM)) {
1359 if (!probing) {
1360 pr_cont("sector not found");
1361 tell_sector();
1362 } else
1363 pr_cont("probe failed...");
1364 } else if (ST2 & ST2_WC) { /* seek error */
1365 pr_cont("wrong cylinder");
1366 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1367 pr_cont("bad cylinder");
1368 } else {
1369 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1370 ST0, ST1, ST2);
1371 tell_sector();
1372 }
1373 pr_cont("\n");
1374}
1375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376/*
1377 * OK, this error interpreting routine is called after a
1378 * DMA read/write has succeeded
1379 * or failed, so we check the results, and copy any buffers.
1380 * hhb: Added better error reporting.
1381 * ak: Made this into a separate routine.
1382 */
1383static int interpret_errors(void)
1384{
1385 char bad;
1386
1387 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001388 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 FDCS->reset = 1;
1390 return 1;
1391 }
1392
1393 /* check IC to find cause of interrupt */
1394 switch (ST0 & ST0_INTR) {
1395 case 0x40: /* error occurred during command execution */
1396 if (ST1 & ST1_EOC)
1397 return 0; /* occurs with pseudo-DMA */
1398 bad = 1;
1399 if (ST1 & ST1_WP) {
1400 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001401 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 cont->done(0);
1403 bad = 2;
1404 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001405 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 } else if (ST1 & ST1_OR) {
1407 if (DP->flags & FTD_MSG)
1408 DPRINT("Over/Underrun - retrying\n");
1409 bad = 0;
1410 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001411 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413 if (ST2 & ST2_WC || ST2 & ST2_BC)
1414 /* wrong cylinder => recal */
1415 DRS->track = NEED_2_RECAL;
1416 return bad;
1417 case 0x80: /* invalid command given */
1418 DPRINT("Invalid FDC command given!\n");
1419 cont->done(0);
1420 return 2;
1421 case 0xc0:
1422 DPRINT("Abnormal termination caused by polling\n");
1423 cont->error();
1424 return 2;
1425 default: /* (0) Normal command termination */
1426 return 0;
1427 }
1428}
1429
1430/*
1431 * This routine is called when everything should be correctly set up
1432 * for the transfer (i.e. floppy motor is on, the correct floppy is
1433 * selected, and the head is sitting on the right track).
1434 */
1435static void setup_rw_floppy(void)
1436{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001437 int i;
1438 int r;
1439 int flags;
1440 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 unsigned long ready_date;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001442 work_func_t function;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
1444 flags = raw_cmd->flags;
1445 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1446 flags |= FD_RAW_INTR;
1447
1448 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1449 ready_date = DRS->spinup_date + DP->spinup;
1450 /* If spinup will take a long time, rerun scandrives
1451 * again just before spinup completion. Beware that
1452 * after scandrives, we must again wait for selection.
1453 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001454 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 ready_date -= DP->select_delay;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001456 function = (work_func_t)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001458 function = (work_func_t)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
1460 /* wait until the floppy is spinning fast enough */
1461 if (fd_wait_for_completion(ready_date, function))
1462 return;
1463 }
1464 dflags = DRS->flags;
1465
1466 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1467 setup_DMA();
1468
1469 if (flags & FD_RAW_INTR)
1470 do_floppy = main_command_interrupt;
1471
1472 r = 0;
1473 for (i = 0; i < raw_cmd->cmd_count; i++)
1474 r |= output_byte(raw_cmd->cmd[i]);
1475
Joe Perchesded28632010-03-10 15:21:09 -08001476 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
1478 if (r) {
1479 cont->error();
1480 reset_fdc();
1481 return;
1482 }
1483
1484 if (!(flags & FD_RAW_INTR)) {
1485 inr = result();
1486 cont->interrupt();
1487 } else if (flags & FD_RAW_NEED_DISK)
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001488 fd_watchdog(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489}
1490
1491static int blind_seek;
1492
1493/*
1494 * This is the routine called after every seek (or recalibrate) interrupt
1495 * from the floppy controller.
1496 */
1497static void seek_interrupt(void)
1498{
Joe Perchesded28632010-03-10 15:21:09 -08001499 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1501 DPRINT("seek failed\n");
1502 DRS->track = NEED_2_RECAL;
1503 cont->error();
1504 cont->redo();
1505 return;
1506 }
1507 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001508 debug_dcl(DP->flags,
1509 "clearing NEWCHANGE flag because of effective seek\n");
1510 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001511 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1512 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 DRS->select_date = jiffies;
1514 }
1515 DRS->track = ST1;
1516 floppy_ready();
1517}
1518
1519static void check_wp(void)
1520{
Joe Perchese0298532010-03-10 15:20:55 -08001521 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1522 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 output_byte(FD_GETSTATUS);
1524 output_byte(UNIT(current_drive));
1525 if (result() != 1) {
1526 FDCS->reset = 1;
1527 return;
1528 }
Joe Perchese0298532010-03-10 15:20:55 -08001529 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1530 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001531 debug_dcl(DP->flags,
1532 "checking whether disk is write protected\n");
1533 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001535 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 else
Joe Perchese0298532010-03-10 15:20:55 -08001537 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 }
1539}
1540
1541static void seek_floppy(void)
1542{
1543 int track;
1544
1545 blind_seek = 0;
1546
Joe Perchesded28632010-03-10 15:21:09 -08001547 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
Joe Perchese0298532010-03-10 15:20:55 -08001549 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1551 /* the media changed flag should be cleared after the seek.
1552 * If it isn't, this means that there is really no disk in
1553 * the drive.
1554 */
Joe Perchese0298532010-03-10 15:20:55 -08001555 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 cont->done(0);
1557 cont->redo();
1558 return;
1559 }
1560 if (DRS->track <= NEED_1_RECAL) {
1561 recalibrate_floppy();
1562 return;
Joe Perchese0298532010-03-10 15:20:55 -08001563 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1565 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1566 /* we seek to clear the media-changed condition. Does anybody
1567 * know a more elegant way, which works on all drives? */
1568 if (raw_cmd->track)
1569 track = raw_cmd->track - 1;
1570 else {
1571 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1572 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1573 blind_seek = 1;
1574 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1575 }
1576 track = 1;
1577 }
1578 } else {
1579 check_wp();
1580 if (raw_cmd->track != DRS->track &&
1581 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1582 track = raw_cmd->track;
1583 else {
1584 setup_rw_floppy();
1585 return;
1586 }
1587 }
1588
1589 do_floppy = seek_interrupt;
1590 output_byte(FD_SEEK);
1591 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001592 if (output_byte(track) < 0) {
1593 reset_fdc();
1594 return;
1595 }
Joe Perchesded28632010-03-10 15:21:09 -08001596 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597}
1598
1599static void recal_interrupt(void)
1600{
Joe Perchesded28632010-03-10 15:21:09 -08001601 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 if (inr != 2)
1603 FDCS->reset = 1;
1604 else if (ST0 & ST0_ECE) {
1605 switch (DRS->track) {
1606 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001607 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 /* after a second recalibrate, we still haven't
1609 * reached track 0. Probably no drive. Raise an
1610 * error, as failing immediately might upset
1611 * computers possessed by the Devil :-) */
1612 cont->error();
1613 cont->redo();
1614 return;
1615 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001616 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 /* If we already did a recalibrate,
1618 * and we are not at track 0, this
1619 * means we have moved. (The only way
1620 * not to move at recalibration is to
1621 * be already at track 0.) Clear the
1622 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001623 debug_dcl(DP->flags,
1624 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Joe Perchese0298532010-03-10 15:20:55 -08001626 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 DRS->select_date = jiffies;
1628 /* fall through */
1629 default:
Joe Perchesded28632010-03-10 15:21:09 -08001630 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 /* Recalibrate moves the head by at
1632 * most 80 steps. If after one
1633 * recalibrate we don't have reached
1634 * track 0, this might mean that we
1635 * started beyond track 80. Try
1636 * again. */
1637 DRS->track = NEED_1_RECAL;
1638 break;
1639 }
1640 } else
1641 DRS->track = ST1;
1642 floppy_ready();
1643}
1644
1645static void print_result(char *message, int inr)
1646{
1647 int i;
1648
1649 DPRINT("%s ", message);
1650 if (inr >= 0)
1651 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001652 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1653 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654}
1655
1656/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001657irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 int do_print;
1660 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001661 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
1663 lasthandler = handler;
1664 interruptjiffies = jiffies;
1665
1666 f = claim_dma_lock();
1667 fd_disable_dma();
1668 release_dma_lock(f);
1669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 do_floppy = NULL;
1671 if (fdc >= N_FDC || FDCS->address == -1) {
1672 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001673 pr_info("DOR0=%x\n", fdc_state[0].dor);
1674 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001675 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001676 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 return IRQ_NONE;
1678 }
1679
1680 FDCS->reset = 0;
1681 /* We have to clear the reset flag here, because apparently on boxes
1682 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1683 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1684 * emission of the SENSEI's.
1685 * It is OK to emit floppy commands because we are in an interrupt
1686 * handler here, and thus we have to fear no interference of other
1687 * activity.
1688 */
1689
Joe Perches29f1c782010-03-10 15:21:00 -08001690 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692 inr = result();
1693 if (do_print)
1694 print_result("unexpected interrupt", inr);
1695 if (inr == 0) {
1696 int max_sensei = 4;
1697 do {
1698 output_byte(FD_SENSEI);
1699 inr = result();
1700 if (do_print)
1701 print_result("sensei", inr);
1702 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001703 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1704 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 }
1706 if (!handler) {
1707 FDCS->reset = 1;
1708 return IRQ_NONE;
1709 }
1710 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001711 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
1713 /* FIXME! Was it really for us? */
1714 return IRQ_HANDLED;
1715}
1716
1717static void recalibrate_floppy(void)
1718{
Joe Perchesded28632010-03-10 15:21:09 -08001719 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 do_floppy = recal_interrupt;
1721 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001722 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001723 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724}
1725
1726/*
1727 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1728 */
1729static void reset_interrupt(void)
1730{
Joe Perchesded28632010-03-10 15:21:09 -08001731 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 result(); /* get the status ready for set_fdc */
1733 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001734 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 cont->error(); /* a reset just after a reset. BAD! */
1736 }
1737 cont->redo();
1738}
1739
1740/*
1741 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1742 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1743 */
1744static void reset_fdc(void)
1745{
1746 unsigned long flags;
1747
1748 do_floppy = reset_interrupt;
1749 FDCS->reset = 0;
1750 reset_fdc_info(0);
1751
1752 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1753 /* Irrelevant for systems with true DMA (i386). */
1754
1755 flags = claim_dma_lock();
1756 fd_disable_dma();
1757 release_dma_lock(flags);
1758
1759 if (FDCS->version >= FDC_82072A)
1760 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1761 else {
1762 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1763 udelay(FD_RESET_DELAY);
1764 fd_outb(FDCS->dor, FD_DOR);
1765 }
1766}
1767
1768static void show_floppy(void)
1769{
1770 int i;
1771
Joe Perchesb46df352010-03-10 15:20:46 -08001772 pr_info("\n");
1773 pr_info("floppy driver state\n");
1774 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001775 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001776 jiffies, interruptjiffies, jiffies - interruptjiffies,
1777 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
Joe Perchesb46df352010-03-10 15:20:46 -08001779 pr_info("timeout_message=%s\n", timeout_message);
1780 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001782 pr_info("%2x %2x %lu\n",
1783 output_log[(i + output_log_pos) % OLOGSIZE].data,
1784 output_log[(i + output_log_pos) % OLOGSIZE].status,
1785 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1786 pr_info("last result at %lu\n", resultjiffies);
1787 pr_info("last redo_fd_request at %lu\n", lastredo);
1788 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1789 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Joe Perchesb46df352010-03-10 15:20:46 -08001791 pr_info("status=%x\n", fd_inb(FD_STATUS));
1792 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001794 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001795 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001796 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001797 if (delayed_work_pending(&fd_timer))
1798 pr_info("delayed work.function=%p expires=%ld\n",
1799 fd_timer.work.func,
1800 fd_timer.timer.expires - jiffies);
1801 if (delayed_work_pending(&fd_timeout))
1802 pr_info("timer_function=%p expires=%ld\n",
1803 fd_timeout.work.func,
1804 fd_timeout.timer.expires - jiffies);
1805
Joe Perchesb46df352010-03-10 15:20:46 -08001806 pr_info("cont=%p\n", cont);
1807 pr_info("current_req=%p\n", current_req);
1808 pr_info("command_status=%d\n", command_status);
1809 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810}
1811
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001812static void floppy_shutdown(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813{
1814 unsigned long flags;
1815
Joe Perches29f1c782010-03-10 15:21:00 -08001816 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 show_floppy();
1818 cancel_activity();
1819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 flags = claim_dma_lock();
1821 fd_disable_dma();
1822 release_dma_lock(flags);
1823
1824 /* avoid dma going to a random drive after shutdown */
1825
Joe Perches29f1c782010-03-10 15:21:00 -08001826 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 DPRINT("floppy timeout called\n");
1828 FDCS->reset = 1;
1829 if (cont) {
1830 cont->done(0);
1831 cont->redo(); /* this will recall reset when needed */
1832 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001833 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 process_fd_request();
1835 }
Joe Perches275176b2010-03-10 15:21:06 -08001836 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837}
1838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001840static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001842 int mask;
1843 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
1845 mask = 0xfc;
1846 data = UNIT(current_drive);
1847 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1848 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1849 set_debugt();
1850 /* no read since this drive is running */
1851 DRS->first_read_date = 0;
1852 /* note motor start time if motor is not yet running */
1853 DRS->spinup_date = jiffies;
1854 data |= (0x10 << UNIT(current_drive));
1855 }
1856 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1857 mask &= ~(0x10 << UNIT(current_drive));
1858
1859 /* starts motor and selects floppy */
1860 del_timer(motor_off_timer + current_drive);
1861 set_dor(fdc, mask, data);
1862
1863 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001864 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001865 (work_func_t)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
1867
1868static void floppy_ready(void)
1869{
Joe Perches045f9832010-03-10 15:20:47 -08001870 if (FDCS->reset) {
1871 reset_fdc();
1872 return;
1873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (start_motor(floppy_ready))
1875 return;
1876 if (fdc_dtr())
1877 return;
1878
Joe Perches87f530d2010-03-10 15:20:54 -08001879 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1881 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001882 twaddle(); /* this clears the dcl on certain
1883 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
1885#ifdef fd_chose_dma_mode
1886 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1887 unsigned long flags = claim_dma_lock();
1888 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1889 release_dma_lock(flags);
1890 }
1891#endif
1892
1893 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1894 perpendicular_mode();
1895 fdc_specify(); /* must be done here because of hut, hlt ... */
1896 seek_floppy();
1897 } else {
1898 if ((raw_cmd->flags & FD_RAW_READ) ||
1899 (raw_cmd->flags & FD_RAW_WRITE))
1900 fdc_specify();
1901 setup_rw_floppy();
1902 }
1903}
1904
1905static void floppy_start(void)
1906{
Joe Perches73507e62010-03-10 15:21:03 -08001907 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
1909 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001910 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001911 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 floppy_ready();
1913}
1914
1915/*
1916 * ========================================================================
1917 * here ends the bottom half. Exported routines are:
1918 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1919 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1920 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1921 * and set_dor.
1922 * ========================================================================
1923 */
1924/*
1925 * General purpose continuations.
1926 * ==============================
1927 */
1928
1929static void do_wakeup(void)
1930{
Joe Perches73507e62010-03-10 15:21:03 -08001931 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 cont = NULL;
1933 command_status += 2;
1934 wake_up(&command_done);
1935}
1936
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001937static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 .interrupt = empty,
1939 .redo = do_wakeup,
1940 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001941 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942};
1943
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001944static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 .interrupt = empty,
1946 .redo = process_fd_request,
1947 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001948 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949};
1950
Joe Perches74f63f42010-03-10 15:20:58 -08001951static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952{
1953 int ret;
1954
1955 schedule_bh(handler);
1956
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001957 if (interruptible)
1958 wait_event_interruptible(command_done, command_status >= 2);
1959 else
1960 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961
1962 if (command_status < 2) {
1963 cancel_activity();
1964 cont = &intr_cont;
1965 reset_fdc();
1966 return -EINTR;
1967 }
1968
1969 if (FDCS->reset)
1970 command_status = FD_COMMAND_ERROR;
1971 if (command_status == FD_COMMAND_OKAY)
1972 ret = 0;
1973 else
1974 ret = -EIO;
1975 command_status = FD_COMMAND_NONE;
1976 return ret;
1977}
1978
1979static void generic_done(int result)
1980{
1981 command_status = result;
1982 cont = &wakeup_cont;
1983}
1984
1985static void generic_success(void)
1986{
1987 cont->done(1);
1988}
1989
1990static void generic_failure(void)
1991{
1992 cont->done(0);
1993}
1994
1995static void success_and_wakeup(void)
1996{
1997 generic_success();
1998 cont->redo();
1999}
2000
2001/*
2002 * formatting and rw support.
2003 * ==========================
2004 */
2005
2006static int next_valid_format(void)
2007{
2008 int probed_format;
2009
2010 probed_format = DRS->probed_format;
2011 while (1) {
2012 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2013 DRS->probed_format = 0;
2014 return 1;
2015 }
2016 if (floppy_type[DP->autodetect[probed_format]].sect) {
2017 DRS->probed_format = probed_format;
2018 return 0;
2019 }
2020 probed_format++;
2021 }
2022}
2023
2024static void bad_flp_intr(void)
2025{
2026 int err_count;
2027
2028 if (probing) {
2029 DRS->probed_format++;
2030 if (!next_valid_format())
2031 return;
2032 }
2033 err_count = ++(*errors);
2034 INFBOUND(DRWE->badness, err_count);
2035 if (err_count > DP->max_errors.abort)
2036 cont->done(0);
2037 if (err_count > DP->max_errors.reset)
2038 FDCS->reset = 1;
2039 else if (err_count > DP->max_errors.recal)
2040 DRS->track = NEED_2_RECAL;
2041}
2042
2043static void set_floppy(int drive)
2044{
2045 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002046
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 if (type)
2048 _floppy = floppy_type + type;
2049 else
2050 _floppy = current_type[drive];
2051}
2052
2053/*
2054 * formatting support.
2055 * ===================
2056 */
2057static void format_interrupt(void)
2058{
2059 switch (interpret_errors()) {
2060 case 1:
2061 cont->error();
2062 case 2:
2063 break;
2064 case 0:
2065 cont->done(1);
2066 }
2067 cont->redo();
2068}
2069
Joe Perches48c8cee2010-03-10 15:20:45 -08002070#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002072
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073static void setup_format_params(int track)
2074{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002075 int n;
2076 int il;
2077 int count;
2078 int head_shift;
2079 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 struct fparm {
2081 unsigned char track, head, sect, size;
2082 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084 raw_cmd = &default_raw_cmd;
2085 raw_cmd->track = track;
2086
Joe Perches48c8cee2010-03-10 15:20:45 -08002087 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2088 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 raw_cmd->rate = _floppy->rate & 0x43;
2090 raw_cmd->cmd_count = NR_F;
2091 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2092 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2093 F_SIZECODE = FD_SIZECODE(_floppy);
2094 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2095 F_GAP = _floppy->fmt_gap;
2096 F_FILL = FD_FILL_BYTE;
2097
2098 raw_cmd->kernel_data = floppy_track_buffer;
2099 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2100
2101 /* allow for about 30ms for data transport per track */
2102 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2103
2104 /* a ``cylinder'' is two tracks plus a little stepping time */
2105 track_shift = 2 * head_shift + 3;
2106
2107 /* position of logical sector 1 on this track */
2108 n = (track_shift * format_req.track + head_shift * format_req.head)
2109 % F_SECT_PER_TRACK;
2110
2111 /* determine interleave */
2112 il = 1;
2113 if (_floppy->fmt_gap < 0x22)
2114 il++;
2115
2116 /* initialize field */
2117 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2118 here[count].track = format_req.track;
2119 here[count].head = format_req.head;
2120 here[count].sect = 0;
2121 here[count].size = F_SIZECODE;
2122 }
2123 /* place logical sectors */
2124 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2125 here[n].sect = count;
2126 n = (n + il) % F_SECT_PER_TRACK;
2127 if (here[n].sect) { /* sector busy, find next free sector */
2128 ++n;
2129 if (n >= F_SECT_PER_TRACK) {
2130 n -= F_SECT_PER_TRACK;
2131 while (here[n].sect)
2132 ++n;
2133 }
2134 }
2135 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002136 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002138 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 }
2140}
2141
2142static void redo_format(void)
2143{
2144 buffer_track = -1;
2145 setup_format_params(format_req.track << STRETCH(_floppy));
2146 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002147 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148}
2149
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002150static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 .interrupt = format_interrupt,
2152 .redo = redo_format,
2153 .error = bad_flp_intr,
2154 .done = generic_done
2155};
2156
2157static int do_format(int drive, struct format_descr *tmp_format_req)
2158{
2159 int ret;
2160
Joe Perches74f63f42010-03-10 15:20:58 -08002161 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002162 return -EINTR;
2163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 set_floppy(drive);
2165 if (!_floppy ||
2166 _floppy->track > DP->tracks ||
2167 tmp_format_req->track >= _floppy->track ||
2168 tmp_format_req->head >= _floppy->head ||
2169 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2170 !_floppy->fmt_gap) {
2171 process_fd_request();
2172 return -EINVAL;
2173 }
2174 format_req = *tmp_format_req;
2175 format_errors = 0;
2176 cont = &format_cont;
2177 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002178 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002179 if (ret == -EINTR)
2180 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 process_fd_request();
2182 return ret;
2183}
2184
2185/*
2186 * Buffer read/write and support
2187 * =============================
2188 */
2189
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002190static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191{
2192 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002193 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194
2195 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002196 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002197 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002198 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
2201 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002202 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 current_req = NULL;
2204}
2205
2206/* new request_done. Can handle physical sectors which are smaller than a
2207 * logical buffer */
2208static void request_done(int uptodate)
2209{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 struct request *req = current_req;
Jens Axboe48821182010-09-22 09:32:36 +02002211 struct request_queue *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 unsigned long flags;
2213 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002214 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
2216 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002217 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2218 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
2220 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002221 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 return;
2223 }
2224
Jens Axboe48821182010-09-22 09:32:36 +02002225 q = req->q;
2226
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 if (uptodate) {
2228 /* maintain values for invalidation on geometry
2229 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002230 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 INFBOUND(DRS->maxblock, block);
2232 if (block > _floppy->sect)
2233 DRS->maxtrack = 1;
2234
2235 /* unlock chained buffers */
2236 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002237 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 spin_unlock_irqrestore(q->queue_lock, flags);
2239 } else {
2240 if (rq_data_dir(req) == WRITE) {
2241 /* record write error information */
2242 DRWE->write_errors++;
2243 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002244 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 DRWE->first_error_generation = DRS->generation;
2246 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002247 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 DRWE->last_error_generation = DRS->generation;
2249 }
2250 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002251 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 spin_unlock_irqrestore(q->queue_lock, flags);
2253 }
2254}
2255
2256/* Interrupt handler evaluating the result of the r/w operation */
2257static void rw_interrupt(void)
2258{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002259 int eoc;
2260 int ssize;
2261 int heads;
2262 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
2264 if (R_HEAD >= 2) {
2265 /* some Toshiba floppy controllers occasionnally seem to
2266 * return bogus interrupts after read/write operations, which
2267 * can be recognized by a bad head number (>= 2) */
2268 return;
2269 }
2270
2271 if (!DRS->first_read_date)
2272 DRS->first_read_date = jiffies;
2273
2274 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002275 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276
2277 if (ST1 & ST1_EOC)
2278 eoc = 1;
2279 else
2280 eoc = 0;
2281
2282 if (COMMAND & 0x80)
2283 heads = 2;
2284 else
2285 heads = 1;
2286
2287 nr_sectors = (((R_TRACK - TRACK) * heads +
2288 R_HEAD - HEAD) * SECT_PER_TRACK +
2289 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2290
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002292 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 DPRINT("long rw: %x instead of %lx\n",
2294 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002295 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2296 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2297 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2298 pr_info("heads=%d eoc=%d\n", heads, eoc);
2299 pr_info("spt=%d st=%d ss=%d\n",
2300 SECT_PER_TRACK, fsector_t, ssize);
2301 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
2304 nr_sectors -= in_sector_offset;
2305 INFBOUND(nr_sectors, 0);
2306 SUPBOUND(current_count_sectors, nr_sectors);
2307
2308 switch (interpret_errors()) {
2309 case 2:
2310 cont->redo();
2311 return;
2312 case 1:
2313 if (!current_count_sectors) {
2314 cont->error();
2315 cont->redo();
2316 return;
2317 }
2318 break;
2319 case 0:
2320 if (!current_count_sectors) {
2321 cont->redo();
2322 return;
2323 }
2324 current_type[current_drive] = _floppy;
2325 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2326 break;
2327 }
2328
2329 if (probing) {
2330 if (DP->flags & FTD_MSG)
2331 DPRINT("Auto-detected floppy type %s in fd%d\n",
2332 _floppy->name, current_drive);
2333 current_type[current_drive] = _floppy;
2334 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2335 probing = 0;
2336 }
2337
2338 if (CT(COMMAND) != FD_READ ||
2339 raw_cmd->kernel_data == current_req->buffer) {
2340 /* transfer directly from buffer */
2341 cont->done(1);
2342 } else if (CT(COMMAND) == FD_READ) {
2343 buffer_track = raw_cmd->track;
2344 buffer_drive = current_drive;
2345 INFBOUND(buffer_max, nr_sectors + fsector_t);
2346 }
2347 cont->redo();
2348}
2349
2350/* Compute maximal contiguous buffer size. */
2351static int buffer_chain_size(void)
2352{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002354 int size;
2355 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 char *base;
2357
2358 base = bio_data(current_req->bio);
2359 size = 0;
2360
NeilBrown5705f702007-09-25 12:35:59 +02002361 rq_for_each_segment(bv, current_req, iter) {
2362 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2363 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
NeilBrown5705f702007-09-25 12:35:59 +02002365 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 }
2367
2368 return size >> 9;
2369}
2370
2371/* Compute the maximal transfer size */
2372static int transfer_size(int ssize, int max_sector, int max_size)
2373{
2374 SUPBOUND(max_sector, fsector_t + max_size);
2375
2376 /* alignment */
2377 max_sector -= (max_sector % _floppy->sect) % ssize;
2378
2379 /* transfer size, beginning not aligned */
2380 current_count_sectors = max_sector - fsector_t;
2381
2382 return max_sector;
2383}
2384
2385/*
2386 * Move data from/to the track buffer to/from the buffer cache.
2387 */
2388static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2389{
2390 int remaining; /* number of transferred 512-byte sectors */
2391 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002392 char *buffer;
2393 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002394 int size;
2395 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396
2397 max_sector = transfer_size(ssize,
2398 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002399 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
2401 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002402 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002404 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
2406 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002407 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002409 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2410 pr_info("remaining=%d\n", remaining >> 9);
2411 pr_info("current_req->nr_sectors=%u\n",
2412 blk_rq_sectors(current_req));
2413 pr_info("current_req->current_nr_sectors=%u\n",
2414 blk_rq_cur_sectors(current_req));
2415 pr_info("max_sector=%d\n", max_sector);
2416 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
2419 buffer_max = max(max_sector, buffer_max);
2420
2421 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2422
Tejun Heo1011c1b2009-05-07 22:24:45 +09002423 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
NeilBrown5705f702007-09-25 12:35:59 +02002425 rq_for_each_segment(bv, current_req, iter) {
2426 if (!remaining)
2427 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
NeilBrown5705f702007-09-25 12:35:59 +02002429 size = bv->bv_len;
2430 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
NeilBrown5705f702007-09-25 12:35:59 +02002432 buffer = page_address(bv->bv_page) + bv->bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002433 if (dma_buffer + size >
2434 floppy_track_buffer + (max_buffer_sectors << 10) ||
2435 dma_buffer < floppy_track_buffer) {
2436 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002437 (int)((floppy_track_buffer - dma_buffer) >> 9));
2438 pr_info("fsector_t=%d buffer_min=%d\n",
2439 fsector_t, buffer_min);
2440 pr_info("current_count_sectors=%ld\n",
2441 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002443 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002444 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002445 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002446 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 }
NeilBrown5705f702007-09-25 12:35:59 +02002448 if (((unsigned long)buffer) % 512)
2449 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002450
NeilBrown5705f702007-09-25 12:35:59 +02002451 if (CT(COMMAND) == FD_READ)
2452 memcpy(buffer, dma_buffer, size);
2453 else
2454 memcpy(dma_buffer, buffer, size);
2455
2456 remaining -= size;
2457 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 if (remaining) {
2460 if (remaining > 0)
2461 max_sector -= remaining >> 9;
2462 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464}
2465
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466/* work around a bug in pseudo DMA
2467 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2468 * sending data. Hence we need a different way to signal the
2469 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2470 * does not work with MT, hence we can only transfer one head at
2471 * a time
2472 */
2473static void virtualdmabug_workaround(void)
2474{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002475 int hard_sectors;
2476 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
2478 if (CT(COMMAND) == FD_WRITE) {
2479 COMMAND &= ~0x80; /* switch off multiple track mode */
2480
2481 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2482 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002484 pr_info("too many sectors %d > %d\n",
2485 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 return;
2487 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002488 SECT_PER_TRACK = end_sector;
2489 /* make sure SECT_PER_TRACK
2490 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 }
2492}
2493
2494/*
2495 * Formulate a read/write request.
2496 * this routine decides where to load the data (directly to buffer, or to
2497 * tmp floppy area), how much data to load (the size of the buffer, the whole
2498 * track, or a single sector)
2499 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2500 * allocation on the fly, it should be done here. No other part should need
2501 * modification.
2502 */
2503
2504static int make_raw_rw_request(void)
2505{
2506 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002507 int max_sector;
2508 int max_size;
2509 int tracksize;
2510 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002512 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
2515 set_fdc((long)current_req->rq_disk->private_data);
2516
2517 raw_cmd = &default_raw_cmd;
2518 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2519 FD_RAW_NEED_SEEK;
2520 raw_cmd->cmd_count = NR_RW;
2521 if (rq_data_dir(current_req) == READ) {
2522 raw_cmd->flags |= FD_RAW_READ;
2523 COMMAND = FM_MODE(_floppy, FD_READ);
2524 } else if (rq_data_dir(current_req) == WRITE) {
2525 raw_cmd->flags |= FD_RAW_WRITE;
2526 COMMAND = FM_MODE(_floppy, FD_WRITE);
2527 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002528 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 return 0;
2530 }
2531
2532 max_sector = _floppy->sect * _floppy->head;
2533
Tejun Heo83096eb2009-05-07 22:24:39 +09002534 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2535 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002537 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 current_count_sectors = 1;
2539 return 1;
2540 } else
2541 return 0;
2542 }
2543 HEAD = fsector_t / _floppy->sect;
2544
Keith Wansbrough9e491842008-09-22 14:57:17 -07002545 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002546 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2547 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 max_sector = _floppy->sect;
2549
2550 /* 2M disks have phantom sectors on the first track */
2551 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2552 max_sector = 2 * _floppy->sect / 3;
2553 if (fsector_t >= max_sector) {
2554 current_count_sectors =
2555 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002556 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 return 1;
2558 }
2559 SIZECODE = 2;
2560 } else
2561 SIZECODE = FD_SIZECODE(_floppy);
2562 raw_cmd->rate = _floppy->rate & 0x43;
2563 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2564 raw_cmd->rate = 1;
2565
2566 if (SIZECODE)
2567 SIZECODE2 = 0xff;
2568 else
2569 SIZECODE2 = 0x80;
2570 raw_cmd->track = TRACK << STRETCH(_floppy);
2571 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2572 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002573 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2575 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002576 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
2578 /* tracksize describes the size which can be filled up with sectors
2579 * of size ssize.
2580 */
2581 tracksize = _floppy->sect - _floppy->sect % ssize;
2582 if (tracksize < _floppy->sect) {
2583 SECT_PER_TRACK++;
2584 if (tracksize <= fsector_t % _floppy->sect)
2585 SECTOR--;
2586
2587 /* if we are beyond tracksize, fill up using smaller sectors */
2588 while (tracksize <= fsector_t % _floppy->sect) {
2589 while (tracksize + ssize > _floppy->sect) {
2590 SIZECODE--;
2591 ssize >>= 1;
2592 }
2593 SECTOR++;
2594 SECT_PER_TRACK++;
2595 tracksize += ssize;
2596 }
2597 max_sector = HEAD * _floppy->sect + tracksize;
2598 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2599 max_sector = _floppy->sect;
2600 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2601 /* for virtual DMA bug workaround */
2602 max_sector = _floppy->sect;
2603 }
2604
2605 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2606 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002607 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 if ((raw_cmd->track == buffer_track) &&
2609 (current_drive == buffer_drive) &&
2610 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2611 /* data already in track buffer */
2612 if (CT(COMMAND) == FD_READ) {
2613 copy_buffer(1, max_sector, buffer_max);
2614 return 1;
2615 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002616 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002618 unsigned int sectors;
2619
2620 sectors = fsector_t + blk_rq_sectors(current_req);
2621 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 max_size = ssize + ssize;
2623 else
2624 max_size = ssize;
2625 }
2626 raw_cmd->flags &= ~FD_RAW_WRITE;
2627 raw_cmd->flags |= FD_RAW_READ;
2628 COMMAND = FM_MODE(_floppy, FD_READ);
2629 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2630 unsigned long dma_limit;
2631 int direct, indirect;
2632
2633 indirect =
2634 transfer_size(ssize, max_sector,
2635 max_buffer_sectors * 2) - fsector_t;
2636
2637 /*
2638 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2639 * on a 64 bit machine!
2640 */
2641 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002642 dma_limit = (MAX_DMA_ADDRESS -
2643 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002644 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 /* 64 kb boundaries */
2647 if (CROSS_64KB(current_req->buffer, max_size << 9))
2648 max_size = (K_64 -
2649 ((unsigned long)current_req->buffer) %
2650 K_64) >> 9;
2651 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2652 /*
2653 * We try to read tracks, but if we get too many errors, we
2654 * go back to reading just one sector at a time.
2655 *
2656 * This means we should be able to read a sector even if there
2657 * are other bad sectors on this track.
2658 */
2659 if (!direct ||
2660 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002661 *errors < DP->max_errors.read_track &&
2662 ((!probing ||
2663 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002664 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 } else {
2666 raw_cmd->kernel_data = current_req->buffer;
2667 raw_cmd->length = current_count_sectors << 9;
2668 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002669 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002670 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 indirect, direct, fsector_t);
2672 return 0;
2673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 virtualdmabug_workaround();
2675 return 2;
2676 }
2677 }
2678
2679 if (CT(COMMAND) == FD_READ)
2680 max_size = max_sector; /* unbounded */
2681
2682 /* claim buffer track if needed */
2683 if (buffer_track != raw_cmd->track || /* bad track */
2684 buffer_drive != current_drive || /* bad drive */
2685 fsector_t > buffer_max ||
2686 fsector_t < buffer_min ||
2687 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002688 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002690 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2691 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 buffer_track = -1;
2693 buffer_drive = current_drive;
2694 buffer_max = buffer_min = aligned_sector_t;
2695 }
2696 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002697 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
2699 if (CT(COMMAND) == FD_WRITE) {
2700 /* copy write buffer to track buffer.
2701 * if we get here, we know that the write
2702 * is either aligned or the data already in the buffer
2703 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 if (in_sector_offset && buffer_track == -1)
2705 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 buffer_track = raw_cmd->track;
2707 buffer_drive = current_drive;
2708 copy_buffer(ssize, max_sector,
2709 2 * max_buffer_sectors + buffer_min);
2710 } else
2711 transfer_size(ssize, max_sector,
2712 2 * max_buffer_sectors + buffer_min -
2713 aligned_sector_t);
2714
2715 /* round up current_count_sectors to get dma xfer size */
2716 raw_cmd->length = in_sector_offset + current_count_sectors;
2717 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2718 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 if ((raw_cmd->length < current_count_sectors << 9) ||
2720 (raw_cmd->kernel_data != current_req->buffer &&
2721 CT(COMMAND) == FD_WRITE &&
2722 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2723 aligned_sector_t < buffer_min)) ||
2724 raw_cmd->length % (128 << SIZECODE) ||
2725 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2726 DPRINT("fractionary current count b=%lx s=%lx\n",
2727 raw_cmd->length, current_count_sectors);
2728 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002729 pr_info("addr=%d, length=%ld\n",
2730 (int)((raw_cmd->kernel_data -
2731 floppy_track_buffer) >> 9),
2732 current_count_sectors);
2733 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2734 fsector_t, aligned_sector_t, max_sector, max_size);
2735 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2736 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2737 COMMAND, SECTOR, HEAD, TRACK);
2738 pr_info("buffer drive=%d\n", buffer_drive);
2739 pr_info("buffer track=%d\n", buffer_track);
2740 pr_info("buffer_min=%d\n", buffer_min);
2741 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 return 0;
2743 }
2744
2745 if (raw_cmd->kernel_data != current_req->buffer) {
2746 if (raw_cmd->kernel_data < floppy_track_buffer ||
2747 current_count_sectors < 0 ||
2748 raw_cmd->length < 0 ||
2749 raw_cmd->kernel_data + raw_cmd->length >
2750 floppy_track_buffer + (max_buffer_sectors << 10)) {
2751 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002752 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2753 fsector_t, buffer_min, raw_cmd->length >> 9);
2754 pr_info("current_count_sectors=%ld\n",
2755 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002757 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002759 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 return 0;
2761 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002762 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002763 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 DPRINT("buffer overrun in direct transfer\n");
2765 return 0;
2766 } else if (raw_cmd->length < current_count_sectors << 9) {
2767 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002768 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2769 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 }
2771 if (raw_cmd->length == 0) {
2772 DPRINT("zero dma transfer attempted from make_raw_request\n");
2773 return 0;
2774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
2776 virtualdmabug_workaround();
2777 return 2;
2778}
2779
Jens Axboe48821182010-09-22 09:32:36 +02002780/*
2781 * Round-robin between our available drives, doing one request from each
2782 */
2783static int set_next_request(void)
2784{
2785 struct request_queue *q;
2786 int old_pos = fdc_queue;
2787
2788 do {
2789 q = disks[fdc_queue]->queue;
2790 if (++fdc_queue == N_DRIVE)
2791 fdc_queue = 0;
2792 if (q) {
2793 current_req = blk_fetch_request(q);
2794 if (current_req)
2795 break;
2796 }
2797 } while (fdc_queue != old_pos);
2798
2799 return current_req != NULL;
2800}
2801
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802static void redo_fd_request(void)
2803{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 int drive;
2805 int tmp;
2806
2807 lastredo = jiffies;
2808 if (current_drive < N_DRIVE)
2809 floppy_off(current_drive);
2810
Joe Perches0da31322010-03-10 15:21:03 -08002811do_request:
2812 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002813 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Jens Axboe48821182010-09-22 09:32:36 +02002815 spin_lock_irq(&floppy_lock);
2816 pending = set_next_request();
2817 spin_unlock_irq(&floppy_lock);
Jens Axboe48821182010-09-22 09:32:36 +02002818 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002819 do_floppy = NULL;
2820 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 }
Joe Perches0da31322010-03-10 15:21:03 -08002824 drive = (long)current_req->rq_disk->private_data;
2825 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002826 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002827
2828 set_floppy(drive);
2829 raw_cmd = &default_raw_cmd;
2830 raw_cmd->flags = 0;
2831 if (start_motor(redo_fd_request))
2832 return;
2833
2834 disk_change(current_drive);
2835 if (test_bit(current_drive, &fake_change) ||
2836 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2837 DPRINT("disk absent or changed during operation\n");
2838 request_done(0);
2839 goto do_request;
2840 }
2841 if (!_floppy) { /* Autodetection */
2842 if (!probing) {
2843 DRS->probed_format = 0;
2844 if (next_valid_format()) {
2845 DPRINT("no autodetectable formats\n");
2846 _floppy = NULL;
2847 request_done(0);
2848 goto do_request;
2849 }
2850 }
2851 probing = 1;
2852 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2853 } else
2854 probing = 0;
2855 errors = &(current_req->errors);
2856 tmp = make_raw_rw_request();
2857 if (tmp < 2) {
2858 request_done(tmp);
2859 goto do_request;
2860 }
2861
2862 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2863 twaddle();
2864 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002865 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002866 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867}
2868
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002869static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 .interrupt = rw_interrupt,
2871 .redo = redo_fd_request,
2872 .error = bad_flp_intr,
2873 .done = request_done
2874};
2875
2876static void process_fd_request(void)
2877{
2878 cont = &rw_cont;
2879 schedule_bh(redo_fd_request);
2880}
2881
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002882static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883{
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002884 if (WARN(max_buffer_sectors == 0,
2885 "VFS: %s called on non-open device\n", __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002888 if (WARN(atomic_read(&usage_count) == 0,
2889 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%x\n",
2890 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
2891 current_req->cmd_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 return;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002893
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002894 if (test_and_set_bit(0, &fdc_busy)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 /* fdc busy, this new request will be treated when the
2896 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002897 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 return;
2899 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02002900 command_status = FD_COMMAND_NONE;
2901 __reschedule_timeout(MAXTIMEOUT, "fd_request");
2902 set_fdc(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002904 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905}
2906
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002907static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 .interrupt = success_and_wakeup,
2909 .redo = floppy_ready,
2910 .error = generic_failure,
2911 .done = generic_done
2912};
2913
Joe Perches74f63f42010-03-10 15:20:58 -08002914static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 /* no auto-sense, just clear dcl */
2917 raw_cmd = &default_raw_cmd;
2918 raw_cmd->flags = flag;
2919 raw_cmd->track = 0;
2920 raw_cmd->cmd_count = 0;
2921 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002922 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002923 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002924
2925 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926}
2927
2928/*
2929 * User triggered reset
2930 * ====================
2931 */
2932
2933static void reset_intr(void)
2934{
Joe Perchesb46df352010-03-10 15:20:46 -08002935 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936}
2937
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002938static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 .interrupt = reset_intr,
2940 .redo = success_and_wakeup,
2941 .error = generic_failure,
2942 .done = generic_done
2943};
2944
Joe Perches74f63f42010-03-10 15:20:58 -08002945static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946{
2947 int ret;
2948
Joe Perches52a0d612010-03-10 15:20:53 -08002949 if (lock_fdc(drive, interruptible))
2950 return -EINTR;
2951
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 if (arg == FD_RESET_ALWAYS)
2953 FDCS->reset = 1;
2954 if (FDCS->reset) {
2955 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002956 ret = wait_til_done(reset_fdc, interruptible);
2957 if (ret == -EINTR)
2958 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 }
2960 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002961 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962}
2963
2964/*
2965 * Misc Ioctl's and support
2966 * ========================
2967 */
2968static inline int fd_copyout(void __user *param, const void *address,
2969 unsigned long size)
2970{
2971 return copy_to_user(param, address, size) ? -EFAULT : 0;
2972}
2973
Joe Perches48c8cee2010-03-10 15:20:45 -08002974static inline int fd_copyin(void __user *param, void *address,
2975 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976{
2977 return copy_from_user(address, param, size) ? -EFAULT : 0;
2978}
2979
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02002980static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981{
2982 struct floppy_struct *floppy;
2983
2984 if (type)
2985 floppy = floppy_type + type;
2986 else {
2987 if (UDP->native_format)
2988 floppy = floppy_type + UDP->native_format;
2989 else
2990 return "(null)";
2991 }
2992 if (floppy->name)
2993 return floppy->name;
2994 else
2995 return "(null)";
2996}
2997
2998/* raw commands */
2999static void raw_cmd_done(int flag)
3000{
3001 int i;
3002
3003 if (!flag) {
3004 raw_cmd->flags |= FD_RAW_FAILURE;
3005 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3006 } else {
3007 raw_cmd->reply_count = inr;
3008 if (raw_cmd->reply_count > MAX_REPLIES)
3009 raw_cmd->reply_count = 0;
3010 for (i = 0; i < raw_cmd->reply_count; i++)
3011 raw_cmd->reply[i] = reply_buffer[i];
3012
3013 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3014 unsigned long flags;
3015 flags = claim_dma_lock();
3016 raw_cmd->length = fd_get_dma_residue();
3017 release_dma_lock(flags);
3018 }
3019
3020 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3021 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3022 raw_cmd->flags |= FD_RAW_FAILURE;
3023
3024 if (disk_change(current_drive))
3025 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3026 else
3027 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3028 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3029 motor_off_callback(current_drive);
3030
3031 if (raw_cmd->next &&
3032 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3033 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3034 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3035 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3036 raw_cmd = raw_cmd->next;
3037 return;
3038 }
3039 }
3040 generic_done(flag);
3041}
3042
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003043static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 .interrupt = success_and_wakeup,
3045 .redo = floppy_start,
3046 .error = generic_failure,
3047 .done = raw_cmd_done
3048};
3049
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003050static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 struct floppy_raw_cmd *ptr)
3052{
3053 int ret;
3054
3055 while (ptr) {
Joe Perchesce2f11f2010-03-10 15:21:08 -08003056 ret = copy_to_user(param, ptr, sizeof(*ptr));
Joe Perches86b12b42010-03-10 15:20:56 -08003057 if (ret)
3058 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 param += sizeof(struct floppy_raw_cmd);
3060 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003061 if (ptr->length >= 0 &&
3062 ptr->length <= ptr->buffer_length) {
3063 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003064 ret = fd_copyout(ptr->data, ptr->kernel_data,
3065 length);
3066 if (ret)
3067 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 }
3070 ptr = ptr->next;
3071 }
Joe Perches7f252712010-03-10 15:21:08 -08003072
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 return 0;
3074}
3075
3076static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3077{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003078 struct floppy_raw_cmd *next;
3079 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
3081 this = *ptr;
3082 *ptr = NULL;
3083 while (this) {
3084 if (this->buffer_length) {
3085 fd_dma_mem_free((unsigned long)this->kernel_data,
3086 this->buffer_length);
3087 this->buffer_length = 0;
3088 }
3089 next = this->next;
3090 kfree(this);
3091 this = next;
3092 }
3093}
3094
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003095static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 struct floppy_raw_cmd **rcmd)
3097{
3098 struct floppy_raw_cmd *ptr;
3099 int ret;
3100 int i;
3101
3102 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003103
3104loop:
3105 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3106 if (!ptr)
3107 return -ENOMEM;
3108 *rcmd = ptr;
3109 ret = copy_from_user(ptr, param, sizeof(*ptr));
3110 if (ret)
3111 return -EFAULT;
3112 ptr->next = NULL;
3113 ptr->buffer_length = 0;
3114 param += sizeof(struct floppy_raw_cmd);
3115 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 /* the command may now also take up the space
3117 * initially intended for the reply & the
3118 * reply count. Needed for long 82078 commands
3119 * such as RESTORE, which takes ... 17 command
3120 * bytes. Murphy's law #137: When you reserve
3121 * 16 bytes for a structure, you'll one day
3122 * discover that you really need 17...
3123 */
Joe Perches7f252712010-03-10 15:21:08 -08003124 return -EINVAL;
3125
3126 for (i = 0; i < 16; i++)
3127 ptr->reply[i] = 0;
3128 ptr->resultcode = 0;
3129 ptr->kernel_data = NULL;
3130
3131 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3132 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003134 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3135 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3136 if (!ptr->kernel_data)
3137 return -ENOMEM;
3138 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 }
Joe Perches7f252712010-03-10 15:21:08 -08003140 if (ptr->flags & FD_RAW_WRITE) {
3141 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3142 if (ret)
3143 return ret;
3144 }
3145
3146 if (ptr->flags & FD_RAW_MORE) {
3147 rcmd = &(ptr->next);
3148 ptr->rate &= 0x43;
3149 goto loop;
3150 }
3151
3152 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153}
3154
3155static int raw_cmd_ioctl(int cmd, void __user *param)
3156{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003158 int drive;
3159 int ret2;
3160 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161
3162 if (FDCS->rawcmd <= 1)
3163 FDCS->rawcmd = 1;
3164 for (drive = 0; drive < N_DRIVE; drive++) {
3165 if (FDC(drive) != fdc)
3166 continue;
3167 if (drive == current_drive) {
3168 if (UDRS->fd_ref > 1) {
3169 FDCS->rawcmd = 2;
3170 break;
3171 }
3172 } else if (UDRS->fd_ref) {
3173 FDCS->rawcmd = 2;
3174 break;
3175 }
3176 }
3177
3178 if (FDCS->reset)
3179 return -EIO;
3180
3181 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3182 if (ret) {
3183 raw_cmd_free(&my_raw_cmd);
3184 return ret;
3185 }
3186
3187 raw_cmd = my_raw_cmd;
3188 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003189 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003190 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
3192 if (ret != -EINTR && FDCS->reset)
3193 ret = -EIO;
3194
3195 DRS->track = NO_TRACK;
3196
3197 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3198 if (!ret)
3199 ret = ret2;
3200 raw_cmd_free(&my_raw_cmd);
3201 return ret;
3202}
3203
3204static int invalidate_drive(struct block_device *bdev)
3205{
3206 /* invalidate the buffer track to force a reread */
3207 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3208 process_fd_request();
3209 check_disk_change(bdev);
3210 return 0;
3211}
3212
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003213static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 int drive, int type, struct block_device *bdev)
3215{
3216 int cnt;
3217
3218 /* sanity checking for parameters. */
3219 if (g->sect <= 0 ||
3220 g->head <= 0 ||
3221 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3222 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003223 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 return -EINVAL;
3225 if (type) {
3226 if (!capable(CAP_SYS_ADMIN))
3227 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003228 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003229 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003230 mutex_unlock(&open_lock);
3231 return -EINTR;
3232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 floppy_type[type] = *g;
3234 floppy_type[type].name = "user format";
3235 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3236 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3237 floppy_type[type].size + 1;
3238 process_fd_request();
3239 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3240 struct block_device *bdev = opened_bdev[cnt];
3241 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3242 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003243 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003245 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 } else {
3247 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003248
Joe Perches74f63f42010-03-10 15:20:58 -08003249 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003250 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003251 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 /* notice a disk change immediately, else
3253 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003254 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003255 return -EINTR;
3256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 oldStretch = g->stretch;
3258 user_params[drive] = *g;
3259 if (buffer_drive == drive)
3260 SUPBOUND(buffer_max, user_params[drive].sect);
3261 current_type[drive] = &user_params[drive];
3262 floppy_sizes[drive] = user_params[drive].size;
3263 if (cmd == FDDEFPRM)
3264 DRS->keep_data = -1;
3265 else
3266 DRS->keep_data = 1;
3267 /* invalidation. Invalidate only when needed, i.e.
3268 * when there are already sectors in the buffer cache
3269 * whose number will change. This is useful, because
3270 * mtools often changes the geometry of the disk after
3271 * looking at the boot block */
3272 if (DRS->maxblock > user_params[drive].sect ||
3273 DRS->maxtrack ||
3274 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003275 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 invalidate_drive(bdev);
3277 else
3278 process_fd_request();
3279 }
3280 return 0;
3281}
3282
3283/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003284static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 FDCLRPRM,
3286 FDSETPRM,
3287 FDDEFPRM,
3288 FDGETPRM,
3289 FDMSGON,
3290 FDMSGOFF,
3291 FDFMTBEG,
3292 FDFMTTRK,
3293 FDFMTEND,
3294 FDSETEMSGTRESH,
3295 FDFLUSH,
3296 FDSETMAXERRS,
3297 FDGETMAXERRS,
3298 FDGETDRVTYP,
3299 FDSETDRVPRM,
3300 FDGETDRVPRM,
3301 FDGETDRVSTAT,
3302 FDPOLLDRVSTAT,
3303 FDRESET,
3304 FDGETFDCSTAT,
3305 FDWERRORCLR,
3306 FDWERRORGET,
3307 FDRAWCMD,
3308 FDEJECT,
3309 FDTWADDLE
3310};
3311
Stephen Hemminger21af5442010-06-15 13:21:11 +02003312static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313{
3314 int i;
3315
3316 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3317 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3318 *size = _IOC_SIZE(*cmd);
3319 *cmd = ioctl_table[i];
3320 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003321 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 return -EFAULT;
3323 }
3324 return 0;
3325 }
3326 }
3327 return -EINVAL;
3328}
3329
3330static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3331{
3332 if (type)
3333 *g = &floppy_type[type];
3334 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003335 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003336 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003337 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003338 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 process_fd_request();
3340 *g = current_type[drive];
3341 }
3342 if (!*g)
3343 return -ENODEV;
3344 return 0;
3345}
3346
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003347static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3348{
3349 int drive = (long)bdev->bd_disk->private_data;
3350 int type = ITYPE(drive_state[drive].fd_device);
3351 struct floppy_struct *g;
3352 int ret;
3353
3354 ret = get_floppy_geometry(drive, type, &g);
3355 if (ret)
3356 return ret;
3357
3358 geo->heads = g->head;
3359 geo->sectors = g->sect;
3360 geo->cylinders = g->track;
3361 return 0;
3362}
3363
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003364static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 unsigned long param)
3366{
Al Viroa4af9b42008-03-02 09:27:55 -05003367 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003368 int type = ITYPE(UDRS->fd_device);
3369 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 int ret;
3371 int size;
3372 union inparam {
3373 struct floppy_struct g; /* geometry */
3374 struct format_descr f;
3375 struct floppy_max_errors max_errors;
3376 struct floppy_drive_params dp;
3377 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003378 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379
3380 /* convert compatibility eject ioctls into floppy eject ioctl.
3381 * We do this in order to provide a means to eject floppy disks before
3382 * installing the new fdutils package */
3383 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003384 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 DPRINT("obsolete eject ioctl\n");
3386 DPRINT("please use floppycontrol --eject\n");
3387 cmd = FDEJECT;
3388 }
3389
Joe Perchesa81ee542010-03-10 15:20:46 -08003390 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 return -EINVAL;
3392
Joe Perchesa81ee542010-03-10 15:20:46 -08003393 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003394 ret = normalize_ioctl(&cmd, &size);
3395 if (ret)
3396 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003397
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003399 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3401 return -EPERM;
3402
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003403 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3404 return -EINVAL;
3405
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003407 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003408 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3409 ret = fd_copyin((void __user *)param, &inparam, size);
3410 if (ret)
3411 return ret;
3412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413
Joe Perchesda273652010-03-10 15:20:52 -08003414 switch (cmd) {
3415 case FDEJECT:
3416 if (UDRS->fd_ref != 1)
3417 /* somebody else has this drive open */
3418 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003419 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003420 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
Joe Perchesda273652010-03-10 15:20:52 -08003422 /* do the actual eject. Fails on
3423 * non-Sparc architectures */
3424 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425
Joe Perchese0298532010-03-10 15:20:55 -08003426 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3427 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003428 process_fd_request();
3429 return ret;
3430 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003431 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003432 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003433 current_type[drive] = NULL;
3434 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3435 UDRS->keep_data = 0;
3436 return invalidate_drive(bdev);
3437 case FDSETPRM:
3438 case FDDEFPRM:
3439 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3440 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003441 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003442 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003443 if (ret)
3444 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003445 break;
3446 case FDMSGON:
3447 UDP->flags |= FTD_MSG;
3448 return 0;
3449 case FDMSGOFF:
3450 UDP->flags &= ~FTD_MSG;
3451 return 0;
3452 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003453 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003454 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003455 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003456 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003457 ret = UDRS->flags;
3458 process_fd_request();
3459 if (ret & FD_VERIFY)
3460 return -ENODEV;
3461 if (!(ret & FD_DISK_WRITABLE))
3462 return -EROFS;
3463 return 0;
3464 case FDFMTTRK:
3465 if (UDRS->fd_ref != 1)
3466 return -EBUSY;
3467 return do_format(drive, &inparam.f);
3468 case FDFMTEND:
3469 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003470 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003471 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003472 return invalidate_drive(bdev);
3473 case FDSETEMSGTRESH:
3474 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3475 return 0;
3476 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003477 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003478 break;
3479 case FDSETMAXERRS:
3480 UDP->max_errors = inparam.max_errors;
3481 break;
3482 case FDGETDRVTYP:
3483 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003484 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003485 break;
3486 case FDSETDRVPRM:
3487 *UDP = inparam.dp;
3488 break;
3489 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003490 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003491 break;
3492 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003493 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003494 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003495 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003496 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003497 process_fd_request();
3498 /* fall through */
3499 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003500 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003501 break;
3502 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003503 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003504 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003505 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003506 break;
3507 case FDWERRORCLR:
3508 memset(UDRWE, 0, sizeof(*UDRWE));
3509 return 0;
3510 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003511 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003512 break;
3513 case FDRAWCMD:
3514 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003516 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003517 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003518 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003519 i = raw_cmd_ioctl(cmd, (void __user *)param);
3520 if (i == -EINTR)
3521 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003522 process_fd_request();
3523 return i;
3524 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003525 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003526 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003527 twaddle();
3528 process_fd_request();
3529 return 0;
3530 default:
3531 return -EINVAL;
3532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534 if (_IOC_DIR(cmd) & _IOC_READ)
3535 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003536
3537 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538}
3539
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003540static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3541 unsigned int cmd, unsigned long param)
3542{
3543 int ret;
3544
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003545 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003546 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003547 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003548
3549 return ret;
3550}
3551
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552static void __init config_types(void)
3553{
Joe Perchesb46df352010-03-10 15:20:46 -08003554 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 int drive;
3556
3557 /* read drive info out of physical CMOS */
3558 drive = 0;
3559 if (!UDP->cmos)
3560 UDP->cmos = FLOPPY0_TYPE;
3561 drive = 1;
3562 if (!UDP->cmos && FLOPPY1_TYPE)
3563 UDP->cmos = FLOPPY1_TYPE;
3564
Jesper Juhl06f748c2007-10-16 23:30:57 -07003565 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
3567 for (drive = 0; drive < N_DRIVE; drive++) {
3568 unsigned int type = UDP->cmos;
3569 struct floppy_drive_params *params;
3570 const char *name = NULL;
3571 static char temparea[32];
3572
Tobias Klauser945f3902006-01-08 01:05:11 -08003573 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 params = &default_drive_params[type].params;
3575 if (type) {
3576 name = default_drive_params[type].name;
3577 allowed_drive_mask |= 1 << drive;
3578 } else
3579 allowed_drive_mask &= ~(1 << drive);
3580 } else {
3581 params = &default_drive_params[0].params;
3582 sprintf(temparea, "unknown type %d (usb?)", type);
3583 name = temparea;
3584 }
3585 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003586 const char *prepend;
3587 if (!has_drive) {
3588 prepend = "";
3589 has_drive = true;
3590 pr_info("Floppy drive(s):");
3591 } else {
3592 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 }
Joe Perchesb46df352010-03-10 15:20:46 -08003594
3595 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 }
3597 *UDP = *params;
3598 }
Joe Perchesb46df352010-03-10 15:20:46 -08003599
3600 if (has_drive)
3601 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602}
3603
Al Viroa4af9b42008-03-02 09:27:55 -05003604static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605{
Al Viroa4af9b42008-03-02 09:27:55 -05003606 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003608 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003609 mutex_lock(&open_lock);
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003610 if (!UDRS->fd_ref--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 DPRINT("floppy_release with fd_ref == 0");
3612 UDRS->fd_ref = 0;
3613 }
3614 if (!UDRS->fd_ref)
3615 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003616 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003617 mutex_unlock(&floppy_mutex);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003618
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 return 0;
3620}
3621
3622/*
3623 * floppy_open check for aliasing (/dev/fd0 can be the same as
3624 * /dev/PS0 etc), and disallows simultaneous access to the same
3625 * drive with different device numbers.
3626 */
Al Viroa4af9b42008-03-02 09:27:55 -05003627static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628{
Al Viroa4af9b42008-03-02 09:27:55 -05003629 int drive = (long)bdev->bd_disk->private_data;
3630 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 int try;
3632 int res = -EBUSY;
3633 char *tmp;
3634
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003635 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003636 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003638 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 goto out2;
3640
3641 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003642 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3643 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 }
3645
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003646 UDRS->fd_ref++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
Al Viroa4af9b42008-03-02 09:27:55 -05003648 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649
3650 res = -ENXIO;
3651
3652 if (!floppy_track_buffer) {
3653 /* if opening an ED drive, reserve a big buffer,
3654 * else reserve a small one */
3655 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3656 try = 64; /* Only 48 actually useful */
3657 else
3658 try = 32; /* Only 24 actually useful */
3659
3660 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3661 if (!tmp && !floppy_track_buffer) {
3662 try >>= 1; /* buffer only one side */
3663 INFBOUND(try, 16);
3664 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3665 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003666 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 if (!tmp && !floppy_track_buffer) {
3669 DPRINT("Unable to allocate DMA memory\n");
3670 goto out;
3671 }
3672 if (floppy_track_buffer) {
3673 if (tmp)
3674 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3675 } else {
3676 buffer_min = buffer_max = -1;
3677 floppy_track_buffer = tmp;
3678 max_buffer_sectors = try;
3679 }
3680 }
3681
Al Viroa4af9b42008-03-02 09:27:55 -05003682 new_dev = MINOR(bdev->bd_dev);
3683 UDRS->fd_device = new_dev;
3684 set_capacity(disks[drive], floppy_sizes[new_dev]);
3685 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 if (buffer_drive == drive)
3687 buffer_track = -1;
3688 }
3689
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 if (UFDCS->rawcmd == 1)
3691 UFDCS->rawcmd = 2;
3692
Al Viroa4af9b42008-03-02 09:27:55 -05003693 if (!(mode & FMODE_NDELAY)) {
3694 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003696 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003697 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 goto out;
3699 }
3700 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003701 if ((mode & FMODE_WRITE) &&
3702 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 goto out;
3704 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003705 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003706 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 return 0;
3708out:
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003709 UDRS->fd_ref--;
3710
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 if (!UDRS->fd_ref)
3712 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003714 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003715 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 return res;
3717}
3718
3719/*
3720 * Check if the disk has been changed or if a change has been faked.
3721 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003722static unsigned int floppy_check_events(struct gendisk *disk,
3723 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724{
3725 int drive = (long)disk->private_data;
3726
Joe Perchese0298532010-03-10 15:20:55 -08003727 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3728 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003729 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003731 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003732 lock_fdc(drive, false);
3733 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 }
3736
Joe Perchese0298532010-03-10 15:20:55 -08003737 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3738 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003740 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003741 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 return 0;
3743}
3744
3745/*
3746 * This implements "read block 0" for floppy_revalidate().
3747 * Needed for format autodetection, checking whether there is
3748 * a disk in the drive, and whether that disk is writable.
3749 */
3750
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003751static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754}
3755
3756static int __floppy_read_block_0(struct block_device *bdev)
3757{
3758 struct bio bio;
3759 struct bio_vec bio_vec;
3760 struct completion complete;
3761 struct page *page;
3762 size_t size;
3763
3764 page = alloc_page(GFP_NOIO);
3765 if (!page) {
3766 process_fd_request();
3767 return -ENOMEM;
3768 }
3769
3770 size = bdev->bd_block_size;
3771 if (!size)
3772 size = 1024;
3773
3774 bio_init(&bio);
3775 bio.bi_io_vec = &bio_vec;
3776 bio_vec.bv_page = page;
3777 bio_vec.bv_len = size;
3778 bio_vec.bv_offset = 0;
3779 bio.bi_vcnt = 1;
3780 bio.bi_idx = 0;
3781 bio.bi_size = size;
3782 bio.bi_bdev = bdev;
3783 bio.bi_sector = 0;
Muthu Kumar9354f1b2012-03-05 14:59:16 -08003784 bio.bi_flags = (1 << BIO_QUIET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 init_completion(&complete);
3786 bio.bi_private = &complete;
3787 bio.bi_end_io = floppy_rb0_complete;
3788
3789 submit_bio(READ, &bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 process_fd_request();
3791 wait_for_completion(&complete);
3792
3793 __free_page(page);
3794
3795 return 0;
3796}
3797
3798/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3799 * the bootblock (block 0). "Autodetection" is also needed to check whether
3800 * there is a disk in the drive at all... Thus we also do it for fixed
3801 * geometry formats */
3802static int floppy_revalidate(struct gendisk *disk)
3803{
3804 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 int cf;
3806 int res = 0;
3807
Joe Perchese0298532010-03-10 15:20:55 -08003808 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3809 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003810 test_bit(drive, &fake_change) ||
3811 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003812 if (WARN(atomic_read(&usage_count) == 0,
3813 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003815
Joe Perches74f63f42010-03-10 15:20:58 -08003816 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003817 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3818 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003819 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 process_fd_request(); /*already done by another thread */
3821 return 0;
3822 }
3823 UDRS->maxblock = 0;
3824 UDRS->maxtrack = 0;
3825 if (buffer_drive == drive)
3826 buffer_track = -1;
3827 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003828 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 if (cf)
3830 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003831 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 /* auto-sensing */
3833 res = __floppy_read_block_0(opened_bdev[drive]);
3834 } else {
3835 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003836 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 process_fd_request();
3838 }
3839 }
3840 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3841 return res;
3842}
3843
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003844static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003845 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003846 .open = floppy_open,
3847 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003848 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003849 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003850 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003851 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854/*
3855 * Floppy Driver initialization
3856 * =============================
3857 */
3858
3859/* Determine the floppy disk controller type */
3860/* This routine was written by David C. Niemi */
3861static char __init get_fdc_version(void)
3862{
3863 int r;
3864
3865 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3866 if (FDCS->reset)
3867 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003868 r = result();
3869 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 return FDC_NONE; /* No FDC present ??? */
3871 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003872 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3874 }
3875 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003876 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3877 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 return FDC_UNKNOWN;
3879 }
3880
3881 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003882 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3884 }
3885
3886 output_byte(FD_PERPENDICULAR);
3887 if (need_more_output() == MORE_OUTPUT) {
3888 output_byte(0);
3889 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003890 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 return FDC_82072A; /* 82072A as found on Sparcs. */
3892 }
3893
3894 output_byte(FD_UNLOCK);
3895 r = result();
3896 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003897 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003898 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 * LOCK/UNLOCK */
3900 }
3901 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003902 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3903 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 return FDC_UNKNOWN;
3905 }
3906 output_byte(FD_PARTID);
3907 r = result();
3908 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003909 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3910 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 return FDC_UNKNOWN;
3912 }
3913 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003914 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 return FDC_82077; /* Revised 82077AA passes all the tests */
3916 }
3917 switch (reply_buffer[0] >> 5) {
3918 case 0x0:
3919 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003920 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 return FDC_82078;
3922 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003923 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 return FDC_82078;
3925 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003926 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 return FDC_S82078B;
3928 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003929 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 return FDC_87306;
3931 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003932 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3933 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 return FDC_82078_UNKN;
3935 }
3936} /* get_fdc_version */
3937
3938/* lilo configuration */
3939
3940static void __init floppy_set_flags(int *ints, int param, int param2)
3941{
3942 int i;
3943
3944 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3945 if (param)
3946 default_drive_params[i].params.flags |= param2;
3947 else
3948 default_drive_params[i].params.flags &= ~param2;
3949 }
3950 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
3951}
3952
3953static void __init daring(int *ints, int param, int param2)
3954{
3955 int i;
3956
3957 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3958 if (param) {
3959 default_drive_params[i].params.select_delay = 0;
3960 default_drive_params[i].params.flags |=
3961 FD_SILENT_DCL_CLEAR;
3962 } else {
3963 default_drive_params[i].params.select_delay =
3964 2 * HZ / 100;
3965 default_drive_params[i].params.flags &=
3966 ~FD_SILENT_DCL_CLEAR;
3967 }
3968 }
3969 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
3970}
3971
3972static void __init set_cmos(int *ints, int dummy, int dummy2)
3973{
3974 int current_drive = 0;
3975
3976 if (ints[0] != 2) {
3977 DPRINT("wrong number of parameters for CMOS\n");
3978 return;
3979 }
3980 current_drive = ints[1];
3981 if (current_drive < 0 || current_drive >= 8) {
3982 DPRINT("bad drive for set_cmos\n");
3983 return;
3984 }
3985#if N_FDC > 1
3986 if (current_drive >= 4 && !FDC2)
3987 FDC2 = 0x370;
3988#endif
3989 DP->cmos = ints[2];
3990 DPRINT("setting CMOS code to %d\n", ints[2]);
3991}
3992
3993static struct param_table {
3994 const char *name;
3995 void (*fn) (int *ints, int param, int param2);
3996 int *var;
3997 int def_param;
3998 int param2;
3999} config_params[] __initdata = {
4000 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4001 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4002 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4003 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4004 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4005 {"daring", daring, NULL, 1, 0},
4006#if N_FDC > 1
4007 {"two_fdc", NULL, &FDC2, 0x370, 0},
4008 {"one_fdc", NULL, &FDC2, 0, 0},
4009#endif
4010 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4011 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4012 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4013 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4014 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4015 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4016 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4017 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4018 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4019 {"nofifo", NULL, &no_fifo, 0x20, 0},
4020 {"usefifo", NULL, &no_fifo, 0, 0},
4021 {"cmos", set_cmos, NULL, 0, 0},
4022 {"slow", NULL, &slow_floppy, 1, 0},
4023 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4024 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4025 {"L40SX", NULL, &print_unex, 0, 0}
4026
4027 EXTRA_FLOPPY_PARAMS
4028};
4029
4030static int __init floppy_setup(char *str)
4031{
4032 int i;
4033 int param;
4034 int ints[11];
4035
4036 str = get_options(str, ARRAY_SIZE(ints), ints);
4037 if (str) {
4038 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4039 if (strcmp(str, config_params[i].name) == 0) {
4040 if (ints[0])
4041 param = ints[1];
4042 else
4043 param = config_params[i].def_param;
4044 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004045 config_params[i].fn(ints, param,
4046 config_params[i].
4047 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 if (config_params[i].var) {
4049 DPRINT("%s=%d\n", str, param);
4050 *config_params[i].var = param;
4051 }
4052 return 1;
4053 }
4054 }
4055 }
4056 if (str) {
4057 DPRINT("unknown floppy option [%s]\n", str);
4058
4059 DPRINT("allowed options are:");
4060 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004061 pr_cont(" %s", config_params[i].name);
4062 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 } else
4064 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004065 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 return 0;
4067}
4068
4069static int have_no_fdc = -ENODEV;
4070
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004071static ssize_t floppy_cmos_show(struct device *dev,
4072 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004073{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004074 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004075 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004076
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004077 drive = p->id;
4078 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004079}
Joe Perches48c8cee2010-03-10 15:20:45 -08004080
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004081static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004082
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083static void floppy_device_release(struct device *dev)
4084{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085}
4086
Frans Popc90cd332009-07-25 22:24:54 +02004087static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004088{
4089 int fdc;
4090
4091 for (fdc = 0; fdc < N_FDC; fdc++)
4092 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004093 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004094
4095 return 0;
4096}
4097
Alexey Dobriyan47145212009-12-14 18:00:08 -08004098static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004099 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004100 .restore = floppy_resume,
4101};
4102
4103static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004104 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004105 .name = "floppy",
4106 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004107 },
4108};
4109
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004110static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
4112static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4113{
4114 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4115 if (drive >= N_DRIVE ||
4116 !(allowed_drive_mask & (1 << drive)) ||
4117 fdc_state[FDC(drive)].version == FDC_NONE)
4118 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004119 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 return NULL;
4121 *part = 0;
4122 return get_disk(disks[drive]);
4123}
4124
4125static int __init floppy_init(void)
4126{
4127 int i, unit, drive;
4128 int err, dr;
4129
Stephen Hemminger285203c2010-06-15 13:21:11 +02004130 set_debugt();
4131 interruptjiffies = resultjiffies = jiffies;
4132
Kumar Gala68e1ee62008-09-22 14:41:31 -07004133#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004134 if (check_legacy_ioport(FDC1))
4135 return -ENODEV;
4136#endif
4137
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 raw_cmd = NULL;
4139
4140 for (dr = 0; dr < N_DRIVE; dr++) {
4141 disks[dr] = alloc_disk(1);
4142 if (!disks[dr]) {
4143 err = -ENOMEM;
4144 goto out_put_disk;
4145 }
4146
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004147 floppy_wq = alloc_ordered_workqueue("floppy", 0);
4148 if (!floppy_wq) {
4149 err = -ENOMEM;
4150 goto out_put_disk;
4151 }
4152
Jens Axboe48821182010-09-22 09:32:36 +02004153 disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4154 if (!disks[dr]->queue) {
4155 err = -ENOMEM;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004156 goto out_destroy_workq;
Jens Axboe48821182010-09-22 09:32:36 +02004157 }
4158
4159 blk_queue_max_hw_sectors(disks[dr]->queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 disks[dr]->major = FLOPPY_MAJOR;
4161 disks[dr]->first_minor = TOMINOR(dr);
4162 disks[dr]->fops = &floppy_fops;
4163 sprintf(disks[dr]->disk_name, "fd%d", dr);
4164
4165 init_timer(&motor_off_timer[dr]);
4166 motor_off_timer[dr].data = dr;
4167 motor_off_timer[dr].function = motor_off_callback;
4168 }
4169
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 err = register_blkdev(FLOPPY_MAJOR, "fd");
4171 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004172 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004174 err = platform_driver_register(&floppy_driver);
4175 if (err)
4176 goto out_unreg_blkdev;
4177
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4179 floppy_find, NULL, NULL);
4180
4181 for (i = 0; i < 256; i++)
4182 if (ITYPE(i))
4183 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4184 else
4185 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4186
Joe Perches73507e62010-03-10 15:21:03 -08004187 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 config_types();
4189
4190 for (i = 0; i < N_FDC; i++) {
4191 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004192 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 FDCS->dtr = -1;
4194 FDCS->dor = 0x4;
4195#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004196 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197#ifdef __mc68000__
4198 if (MACH_IS_SUN3X)
4199#endif
4200 FDCS->version = FDC_82072A;
4201#endif
4202 }
4203
4204 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 fdc_state[0].address = FDC1;
4206 if (fdc_state[0].address == -1) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004207 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 err = -ENODEV;
4209 goto out_unreg_region;
4210 }
4211#if N_FDC > 1
4212 fdc_state[1].address = FDC2;
4213#endif
4214
4215 fdc = 0; /* reset fdc in case of unexpected interrupt */
4216 err = floppy_grab_irq_and_dma();
4217 if (err) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004218 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 err = -EBUSY;
4220 goto out_unreg_region;
4221 }
4222
4223 /* initialise drive state */
4224 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004225 memset(UDRS, 0, sizeof(*UDRS));
4226 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004227 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4228 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4229 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 UDRS->fd_device = -1;
4231 floppy_track_buffer = NULL;
4232 max_buffer_sectors = 0;
4233 }
4234 /*
4235 * Small 10 msec delay to let through any interrupt that
4236 * initialization might have triggered, to not
4237 * confuse detection:
4238 */
4239 msleep(10);
4240
4241 for (i = 0; i < N_FDC; i++) {
4242 fdc = i;
4243 FDCS->driver_version = FD_DRIVER_VERSION;
4244 for (unit = 0; unit < 4; unit++)
4245 FDCS->track[unit] = 0;
4246 if (FDCS->address == -1)
4247 continue;
4248 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004249 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004251 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 FDCS->address = -1;
4253 FDCS->version = FDC_NONE;
4254 continue;
4255 }
4256 /* Try to determine the floppy controller type */
4257 FDCS->version = get_fdc_version();
4258 if (FDCS->version == FDC_NONE) {
4259 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004260 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 FDCS->address = -1;
4262 continue;
4263 }
4264 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4265 can_use_virtual_dma = 0;
4266
4267 have_no_fdc = 0;
4268 /* Not all FDCs seem to be able to handle the version command
4269 * properly, so force a reset for the standard FDC clones,
4270 * to avoid interrupt garbage.
4271 */
Joe Perches74f63f42010-03-10 15:20:58 -08004272 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 }
4274 fdc = 0;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004275 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004277 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 if (have_no_fdc) {
4279 DPRINT("no floppy controllers found\n");
4280 err = have_no_fdc;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004281 goto out_release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 }
4283
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 for (drive = 0; drive < N_DRIVE; drive++) {
4285 if (!(allowed_drive_mask & (1 << drive)))
4286 continue;
4287 if (fdc_state[FDC(drive)].version == FDC_NONE)
4288 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004289
4290 floppy_device[drive].name = floppy_device_name;
4291 floppy_device[drive].id = drive;
4292 floppy_device[drive].dev.release = floppy_device_release;
4293
4294 err = platform_device_register(&floppy_device[drive]);
4295 if (err)
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004296 goto out_release_dma;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004297
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004298 err = device_create_file(&floppy_device[drive].dev,
4299 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004300 if (err)
4301 goto out_unreg_platform_dev;
4302
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 /* to be cleaned up... */
4304 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004306 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 add_disk(disks[drive]);
4308 }
4309
4310 return 0;
4311
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004312out_unreg_platform_dev:
4313 platform_device_unregister(&floppy_device[drive]);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004314out_release_dma:
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004315 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 floppy_release_irq_and_dma();
4317out_unreg_region:
4318 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004319 platform_driver_unregister(&floppy_driver);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004320out_destroy_workq:
4321 destroy_workqueue(floppy_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322out_unreg_blkdev:
4323 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324out_put_disk:
4325 while (dr--) {
Carsten Emde6c4867f2011-09-21 10:22:11 +02004326 del_timer_sync(&motor_off_timer[dr]);
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004327 if (disks[dr]->queue) {
Jens Axboe48821182010-09-22 09:32:36 +02004328 blk_cleanup_queue(disks[dr]->queue);
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004329 /*
4330 * put_disk() is not paired with add_disk() and
4331 * will put queue reference one extra time. fix it.
4332 */
4333 disks[dr]->queue = NULL;
4334 }
Linus Torvaldsc093ee42010-11-05 17:45:59 -07004335 put_disk(disks[dr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 }
4337 return err;
4338}
4339
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004340static const struct io_region {
4341 int offset;
4342 int size;
4343} io_regions[] = {
4344 { 2, 1 },
4345 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4346 { 4, 2 },
4347 /* address + 6 is reserved, and may be taken by IDE.
4348 * Unfortunately, Adaptec doesn't know this :-(, */
4349 { 7, 1 },
4350};
4351
4352static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4353{
4354 while (p != io_regions) {
4355 p--;
4356 release_region(FDCS->address + p->offset, p->size);
4357 }
4358}
4359
4360#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4361
4362static int floppy_request_regions(int fdc)
4363{
4364 const struct io_region *p;
4365
4366 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004367 if (!request_region(FDCS->address + p->offset,
4368 p->size, "floppy")) {
4369 DPRINT("Floppy io-port 0x%04lx in use\n",
4370 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004371 floppy_release_allocated_regions(fdc, p);
4372 return -EBUSY;
4373 }
4374 }
4375 return 0;
4376}
4377
4378static void floppy_release_regions(int fdc)
4379{
4380 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4381}
4382
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383static int floppy_grab_irq_and_dma(void)
4384{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004385 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004387
4388 /*
4389 * We might have scheduled a free_irq(), wait it to
4390 * drain first:
4391 */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004392 flush_workqueue(floppy_wq);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004393
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 if (fd_request_irq()) {
4395 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4396 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004397 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 return -1;
4399 }
4400 if (fd_request_dma()) {
4401 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4402 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004403 if (can_use_virtual_dma & 2)
4404 use_virtual_dma = can_use_virtual_dma = 1;
4405 if (!(can_use_virtual_dma & 1)) {
4406 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004407 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004408 return -1;
4409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 }
4411
4412 for (fdc = 0; fdc < N_FDC; fdc++) {
4413 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004414 if (floppy_request_regions(fdc))
4415 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 }
4417 }
4418 for (fdc = 0; fdc < N_FDC; fdc++) {
4419 if (FDCS->address != -1) {
4420 reset_fdc_info(1);
4421 fd_outb(FDCS->dor, FD_DOR);
4422 }
4423 }
4424 fdc = 0;
4425 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4426
4427 for (fdc = 0; fdc < N_FDC; fdc++)
4428 if (FDCS->address != -1)
4429 fd_outb(FDCS->dor, FD_DOR);
4430 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004431 * The driver will try and free resources and relies on us
4432 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 */
4434 fdc = 0;
4435 irqdma_allocated = 1;
4436 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004437cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 fd_free_irq();
4439 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004440 while (--fdc >= 0)
4441 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004442 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 return -1;
4444}
4445
4446static void floppy_release_irq_and_dma(void)
4447{
4448 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449#ifndef __sparc__
4450 int drive;
4451#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 long tmpsize;
4453 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004455 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 if (irqdma_allocated) {
4459 fd_disable_dma();
4460 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004461 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 irqdma_allocated = 0;
4463 }
4464 set_dor(0, ~0, 8);
4465#if N_FDC > 1
4466 set_dor(1, ~8, 0);
4467#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468
4469 if (floppy_track_buffer && max_buffer_sectors) {
4470 tmpsize = max_buffer_sectors * 1024;
4471 tmpaddr = (unsigned long)floppy_track_buffer;
4472 floppy_track_buffer = NULL;
4473 max_buffer_sectors = 0;
4474 buffer_min = buffer_max = -1;
4475 fd_dma_mem_free(tmpaddr, tmpsize);
4476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477#ifndef __sparc__
4478 for (drive = 0; drive < N_FDC * 4; drive++)
4479 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004480 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481#endif
4482
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004483 if (delayed_work_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004484 pr_info("floppy timer still active:%s\n", timeout_message);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004485 if (delayed_work_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004486 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004487 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004488 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 old_fdc = fdc;
4490 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004491 if (FDCS->address != -1)
4492 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 fdc = old_fdc;
4494}
4495
4496#ifdef MODULE
4497
4498static char *floppy;
4499
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500static void __init parse_floppy_cfg_string(char *cfg)
4501{
4502 char *ptr;
4503
4504 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004505 ptr = cfg;
4506 while (*cfg && *cfg != ' ' && *cfg != '\t')
4507 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 if (*cfg) {
4509 *cfg = '\0';
4510 cfg++;
4511 }
4512 if (*ptr)
4513 floppy_setup(ptr);
4514 }
4515}
4516
Jon Schindler7afea3b2008-04-29 00:59:21 -07004517static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518{
4519 if (floppy)
4520 parse_floppy_cfg_string(floppy);
4521 return floppy_init();
4522}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004523module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
Jon Schindler7afea3b2008-04-29 00:59:21 -07004525static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526{
4527 int drive;
4528
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4530 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004531 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
4533 for (drive = 0; drive < N_DRIVE; drive++) {
4534 del_timer_sync(&motor_off_timer[drive]);
4535
4536 if ((allowed_drive_mask & (1 << drive)) &&
4537 fdc_state[FDC(drive)].version != FDC_NONE) {
4538 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004539 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4540 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 }
Jens Axboe48821182010-09-22 09:32:36 +02004542 blk_cleanup_queue(disks[drive]->queue);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004543
4544 /*
4545 * These disks have not called add_disk(). Don't put down
4546 * queue reference in put_disk().
4547 */
4548 if (!(allowed_drive_mask & (1 << drive)) ||
4549 fdc_state[FDC(drive)].version == FDC_NONE)
4550 disks[drive]->queue = NULL;
4551
Vivek Goyald017bf62010-11-06 08:16:05 -04004552 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004555 cancel_delayed_work_sync(&fd_timeout);
4556 cancel_delayed_work_sync(&fd_timer);
4557 destroy_workqueue(floppy_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004559 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 floppy_release_irq_and_dma();
4561
4562 /* eject disk, if any */
4563 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564}
Joe Perches48c8cee2010-03-10 15:20:45 -08004565
Jon Schindler7afea3b2008-04-29 00:59:21 -07004566module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567
4568module_param(floppy, charp, 0);
4569module_param(FLOPPY_IRQ, int, 0);
4570module_param(FLOPPY_DMA, int, 0);
4571MODULE_AUTHOR("Alain L. Knaff");
4572MODULE_SUPPORTED_DEVICE("fd");
4573MODULE_LICENSE("GPL");
4574
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004575/* This doesn't actually get used other than for module information */
4576static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004577 {"PNP0700", 0},
4578 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004579};
Joe Perches48c8cee2010-03-10 15:20:45 -08004580
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004581MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4582
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583#else
4584
4585__setup("floppy=", floppy_setup);
4586module_init(floppy_init)
4587#endif
4588
4589MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);