blob: 000abe2f105c60f06d5fac31a2a4889cddd22b15 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/block/floppy.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1993, 1994 Alain Knaff
6 * Copyright (C) 1998 Alan Cox
7 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009/*
10 * 02.12.91 - Changed to static variables to indicate need for reset
11 * and recalibrate. This makes some things easier (output_byte reset
12 * checking etc), and means less interrupt jumping in case of errors,
13 * so the code is hopefully easier to understand.
14 */
15
16/*
17 * This file is certainly a mess. I've tried my best to get it working,
18 * but I don't like programming floppies, and I have only one anyway.
19 * Urgel. I should check for more errors, and do more graceful error
20 * recovery. Seems there are problems with several drives. I've tried to
21 * correct them. No promises.
22 */
23
24/*
25 * As with hd.c, all routines within this file can (and will) be called
26 * by interrupts, so extreme caution is needed. A hardware interrupt
27 * handler may not sleep, or a kernel panic will happen. Thus I cannot
28 * call "floppy-on" directly, but have to set a special timer interrupt
29 * etc.
30 */
31
32/*
33 * 28.02.92 - made track-buffering routines, based on the routines written
34 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
35 */
36
37/*
38 * Automatic floppy-detection and formatting written by Werner Almesberger
39 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
40 * the floppy-change signal detection.
41 */
42
43/*
44 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
45 * FDC data overrun bug, added some preliminary stuff for vertical
46 * recording support.
47 *
48 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
49 *
50 * TODO: Errors are still not counted properly.
51 */
52
53/* 1992/9/20
54 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
55 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
56 * Christoph H. Hochst\"atter.
57 * I have fixed the shift values to the ones I always use. Maybe a new
58 * ioctl() should be created to be able to modify them.
59 * There is a bug in the driver that makes it impossible to format a
60 * floppy as the first thing after bootup.
61 */
62
63/*
64 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
65 * this helped the floppy driver as well. Much cleaner, and still seems to
66 * work.
67 */
68
69/* 1994/6/24 --bbroad-- added the floppy table entries and made
70 * minor modifications to allow 2.88 floppies to be run.
71 */
72
73/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
74 * disk types.
75 */
76
77/*
78 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
79 * format bug fixes, but unfortunately some new bugs too...
80 */
81
82/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
83 * errors to allow safe writing by specialized programs.
84 */
85
86/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
87 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
88 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
89 * drives are "upside-down").
90 */
91
92/*
93 * 1995/8/26 -- Andreas Busse -- added Mips support.
94 */
95
96/*
97 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
98 * features to asm/floppy.h.
99 */
100
101/*
James Nelsonb88b0982005-11-08 16:52:12 +0100102 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
103 */
104
105/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
107 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
108 * use of '0' for NULL.
109 */
110
111/*
112 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
113 * failures.
114 */
115
116/*
117 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
118 */
119
120/*
121 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
122 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
123 * being used to store jiffies, which are unsigned longs).
124 */
125
126/*
127 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
128 * - get rid of check_region
129 * - s/suser/capable/
130 */
131
132/*
133 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
134 * floppy controller (lingering task on list after module is gone... boom.)
135 */
136
137/*
138 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
139 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
140 * requires many non-obvious changes in arch dependent code.
141 */
142
143/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
144 * Better audit of register_blkdev.
145 */
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147#undef FLOPPY_SILENT_DCL_CLEAR
148
149#define REALLY_SLOW_IO
150
151#define DEBUGT 2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Joe Perches891eda82010-03-10 15:21:05 -0800153#define DPRINT(format, args...) \
154 pr_info("floppy%d: " format, current_drive, ##args)
155
156#define DCL_DEBUG /* debug disk change line */
Joe Perches87f530d2010-03-10 15:20:54 -0800157#ifdef DCL_DEBUG
158#define debug_dcl(test, fmt, args...) \
159 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
160#else
161#define debug_dcl(test, fmt, args...) \
162 do { if (0) DPRINT(fmt, ##args); } while (0)
163#endif
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165/* do print messages for unexpected interrupts */
166static int print_unex = 1;
167#include <linux/module.h>
168#include <linux/sched.h>
169#include <linux/fs.h>
170#include <linux/kernel.h>
171#include <linux/timer.h>
172#include <linux/workqueue.h>
173#define FDPATCHES
174#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#include <linux/fd.h>
176#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#include <linux/errno.h>
178#include <linux/slab.h>
179#include <linux/mm.h>
180#include <linux/bio.h>
181#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800182#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#include <linux/fcntl.h>
184#include <linux/delay.h>
185#include <linux/mc146818rtc.h> /* CMOS defines */
186#include <linux/ioport.h>
187#include <linux/interrupt.h>
188#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100189#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700190#include <linux/mod_devicetable.h>
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800191#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800192#include <linux/io.h>
193#include <linux/uaccess.h>
Andi Kleen0cc15d032012-07-02 17:27:04 -0700194#include <linux/async.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/*
197 * PS/2 floppies have much slower step rates than regular floppies.
198 * It's been recommended that take about 1/4 of the default speed
199 * in some more extreme cases.
200 */
Arnd Bergmann2a48fc02010-06-02 14:28:52 +0200201static DEFINE_MUTEX(floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static int slow_floppy;
203
204#include <asm/dma.h>
205#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207static int FLOPPY_IRQ = 6;
208static int FLOPPY_DMA = 2;
209static int can_use_virtual_dma = 2;
210/* =======
211 * can use virtual DMA:
212 * 0 = use of virtual DMA disallowed by config
213 * 1 = use of virtual DMA prescribed by config
214 * 2 = no virtual DMA preference configured. By default try hard DMA,
215 * but fall back on virtual DMA when not enough memory available
216 */
217
218static int use_virtual_dma;
219/* =======
220 * use virtual DMA
221 * 0 using hard DMA
222 * 1 using virtual DMA
223 * This variable is set to virtual when a DMA mem problem arises, and
224 * reset back in floppy_grab_irq_and_dma.
225 * It is not safe to reset it in other circumstances, because the floppy
226 * driver may have several buffers in use at once, and we do currently not
227 * record each buffers capabilities
228 */
229
230static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100233irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236#define K_64 0x10000 /* 64KB */
237
238/* the following is the mask of allowed drives. By default units 2 and
239 * 3 of both floppy controllers are disabled, because switching on the
240 * motor of these drives causes system hangs on some PCI computers. drive
241 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
242 * a drive is allowed.
243 *
244 * NOTE: This must come before we include the arch floppy header because
245 * some ports reference this variable from there. -DaveM
246 */
247
248static int allowed_drive_mask = 0x33;
249
250#include <asm/floppy.h>
251
252static int irqdma_allocated;
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254#include <linux/blkdev.h>
255#include <linux/blkpg.h>
256#include <linux/cdrom.h> /* for the compatibility eject ioctl */
257#include <linux/completion.h>
258
259static struct request *current_req;
Joe Perches48c8cee2010-03-10 15:20:45 -0800260static void do_fd_request(struct request_queue *q);
Jens Axboe48821182010-09-22 09:32:36 +0200261static int set_next_request(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263#ifndef fd_get_dma_residue
264#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
265#endif
266
267/* Dma Memory related stuff */
268
269#ifndef fd_dma_mem_free
270#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
271#endif
272
273#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800274#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275#endif
276
277static inline void fallback_on_nodma_alloc(char **addr, size_t l)
278{
279#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
280 if (*addr)
281 return; /* we have the memory */
282 if (can_use_virtual_dma != 2)
283 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800284 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 *addr = (char *)nodma_mem_alloc(l);
286#else
287 return;
288#endif
289}
290
291/* End dma memory related stuff */
292
293static unsigned long fake_change;
Joe Perches29f1c782010-03-10 15:21:00 -0800294static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Joe Perches48c8cee2010-03-10 15:20:45 -0800296#define ITYPE(x) (((x) >> 2) & 0x1f)
297#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
298#define UNIT(x) ((x) & 0x03) /* drive on fdc */
299#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700300 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Joe Perches48c8cee2010-03-10 15:20:45 -0800303#define DP (&drive_params[current_drive])
304#define DRS (&drive_state[current_drive])
305#define DRWE (&write_errors[current_drive])
306#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Joe Perches48c8cee2010-03-10 15:20:45 -0800308#define UDP (&drive_params[drive])
309#define UDRS (&drive_state[drive])
310#define UDRWE (&write_errors[drive])
311#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Joe Perches48c8cee2010-03-10 15:20:45 -0800313#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
314#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800317#define COMMAND (raw_cmd->cmd[0])
318#define DR_SELECT (raw_cmd->cmd[1])
319#define TRACK (raw_cmd->cmd[2])
320#define HEAD (raw_cmd->cmd[3])
321#define SECTOR (raw_cmd->cmd[4])
322#define SIZECODE (raw_cmd->cmd[5])
323#define SECT_PER_TRACK (raw_cmd->cmd[6])
324#define GAP (raw_cmd->cmd[7])
325#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326#define NR_RW 9
327
328/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800329#define F_SIZECODE (raw_cmd->cmd[2])
330#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
331#define F_GAP (raw_cmd->cmd[4])
332#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333#define NR_F 6
334
335/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800336 * Maximum disk size (in kilobytes).
337 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 * [Now it is rather a minimum]
339 */
340#define MAX_DISK_SIZE 4 /* 3984 */
341
342/*
343 * globals used by 'result()'
344 */
345#define MAX_REPLIES 16
346static unsigned char reply_buffer[MAX_REPLIES];
Joe Perches891eda82010-03-10 15:21:05 -0800347static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800348#define ST0 (reply_buffer[0])
349#define ST1 (reply_buffer[1])
350#define ST2 (reply_buffer[2])
351#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
352#define R_TRACK (reply_buffer[3])
353#define R_HEAD (reply_buffer[4])
354#define R_SECTOR (reply_buffer[5])
355#define R_SIZECODE (reply_buffer[6])
356
357#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359/*
360 * this struct defines the different floppy drive types.
361 */
362static struct {
363 struct floppy_drive_params params;
364 const char *name; /* name printed while booting */
365} default_drive_params[] = {
366/* NOTE: the time values in jiffies should be in msec!
367 CMOS drive type
368 | Maximum data rate supported by drive type
369 | | Head load time, msec
370 | | | Head unload time, msec (not used)
371 | | | | Step rate interval, usec
372 | | | | | Time needed for spinup time (jiffies)
373 | | | | | | Timeout for spinning down (jiffies)
374 | | | | | | | Spindown offset (where disk stops)
375 | | | | | | | | Select delay
376 | | | | | | | | | RPS
377 | | | | | | | | | | Max number of tracks
378 | | | | | | | | | | | Interrupt timeout
379 | | | | | | | | | | | | Max nonintlv. sectors
380 | | | | | | | | | | | | | -Max Errors- flags */
381{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
382 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
383
384{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
385 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
386
387{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
388 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
389
390{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
391 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
392
393{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
394 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
395
396{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
397 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
398
399{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
400 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
401/* | --autodetected formats--- | | |
402 * read_track | | Name printed when booting
403 * | Native format
404 * Frequency of disk change checks */
405};
406
407static struct floppy_drive_params drive_params[N_DRIVE];
408static struct floppy_drive_struct drive_state[N_DRIVE];
409static struct floppy_write_errors write_errors[N_DRIVE];
410static struct timer_list motor_off_timer[N_DRIVE];
411static struct gendisk *disks[N_DRIVE];
412static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800413static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
Jens Axboe48821182010-09-22 09:32:36 +0200415static int fdc_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
417/*
418 * This struct defines the different floppy types.
419 *
420 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
421 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
422 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
423 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
424 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
425 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
426 * side 0 is on physical side 0 (but with the misnamed sector IDs).
427 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700428 * 'options'.
429 *
430 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
431 * The LSB (bit 2) is flipped. For most disks, the first sector
432 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
433 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
434 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
435 *
436 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 */
438/*
439 Size
440 | Sectors per track
441 | | Head
442 | | | Tracks
443 | | | | Stretch
444 | | | | | Gap 1 size
445 | | | | | | Data rate, | 0x40 for perp
446 | | | | | | | Spec1 (stepping rate, head unload
447 | | | | | | | | /fmt gap (gap2) */
448static struct floppy_struct floppy_type[32] = {
449 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
450 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
451 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
452 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
453 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
454 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
455 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
456 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
457 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
458 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
459
460 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
461 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
462 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
463 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
464 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
465 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
466 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
467 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
468 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
469 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
470
471 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
472 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
473 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
474 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
475 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
476 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
477 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
478 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
479 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
483 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
484};
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486#define SECTSIZE (_FD_SECTSIZE(*floppy))
487
488/* Auto-detection: Disk type used until the next media change occurs. */
489static struct floppy_struct *current_type[N_DRIVE];
490
491/*
492 * User-provided type information. current_type points to
493 * the respective entry of this array.
494 */
495static struct floppy_struct user_params[N_DRIVE];
496
497static sector_t floppy_sizes[256];
498
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200499static char floppy_device_name[] = "floppy";
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501/*
502 * The driver is trying to determine the correct media format
503 * while probing is set. rw_interrupt() clears it after a
504 * successful access.
505 */
506static int probing;
507
508/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800509#define FD_COMMAND_NONE -1
510#define FD_COMMAND_ERROR 2
511#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513static volatile int command_status = FD_COMMAND_NONE;
514static unsigned long fdc_busy;
515static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
516static DECLARE_WAIT_QUEUE_HEAD(command_done);
517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518/* Errors during formatting are counted here. */
519static int format_errors;
520
521/* Format request descriptor. */
522static struct format_descr format_req;
523
524/*
525 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
526 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
527 * H is head unload time (1=16ms, 2=32ms, etc)
528 */
529
530/*
531 * Track buffer
532 * Because these are written to by the DMA controller, they must
533 * not contain a 64k byte boundary crossing, or data will be
534 * corrupted/lost.
535 */
536static char *floppy_track_buffer;
537static int max_buffer_sectors;
538
539static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700540typedef void (*done_f)(int);
Stephen Hemminger3b06c212010-07-20 20:09:00 -0600541static const struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800542 void (*interrupt)(void);
543 /* this is called after the interrupt of the
544 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700545 void (*redo)(void); /* this is called to retry the operation */
546 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 done_f done; /* this is called to say if the operation has
548 * succeeded/failed */
549} *cont;
550
551static void floppy_ready(void);
552static void floppy_start(void);
553static void process_fd_request(void);
554static void recalibrate_floppy(void);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200555static void floppy_shutdown(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800557static int floppy_request_regions(int);
558static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559static int floppy_grab_irq_and_dma(void);
560static void floppy_release_irq_and_dma(void);
561
562/*
563 * The "reset" variable should be tested whenever an interrupt is scheduled,
564 * after the commands have been sent. This is to ensure that the driver doesn't
565 * get wedged when the interrupt doesn't come because of a failed command.
566 * reset doesn't need to be tested before sending commands, because
567 * output_byte is automatically disabled when reset is set.
568 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569static void reset_fdc(void);
570
571/*
572 * These are global variables, as that's the easiest way to give
573 * information to interrupts. They are the data used for the current
574 * request.
575 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800576#define NO_TRACK -1
577#define NEED_1_RECAL -2
578#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200580static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582/* buffer related variables */
583static int buffer_track = -1;
584static int buffer_drive = -1;
585static int buffer_min = -1;
586static int buffer_max = -1;
587
588/* fdc related variables, should end up in a struct */
589static struct floppy_fdc_state fdc_state[N_FDC];
590static int fdc; /* current fdc */
591
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200592static struct workqueue_struct *floppy_wq;
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594static struct floppy_struct *_floppy = floppy_type;
595static unsigned char current_drive;
596static long current_count_sectors;
597static unsigned char fsector_t; /* sector in track */
598static unsigned char in_sector_offset; /* offset within physical sector,
599 * expressed in units of 512 bytes */
600
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100601static inline bool drive_no_geom(int drive)
602{
603 return !current_type[drive] && !ITYPE(UDRS->fd_device);
604}
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606#ifndef fd_eject
607static inline int fd_eject(int drive)
608{
609 return -EINVAL;
610}
611#endif
612
613/*
614 * Debugging
615 * =========
616 */
617#ifdef DEBUGT
618static long unsigned debugtimer;
619
620static inline void set_debugt(void)
621{
622 debugtimer = jiffies;
623}
624
Joe Perchesded28632010-03-10 15:21:09 -0800625static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
627 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800628 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629}
630#else
631static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800632static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633#endif /* DEBUGT */
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200636static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637static const char *timeout_message;
638
Joe Perches275176b2010-03-10 15:21:06 -0800639static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
641 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800642 if (test_bit(0, &fdc_busy) && command_status < 2 &&
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200643 !delayed_work_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800644 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
646}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Joe Perches48c8cee2010-03-10 15:20:45 -0800648static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650#define OLOGSIZE 20
651
Joe Perches48c8cee2010-03-10 15:20:45 -0800652static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653static unsigned long interruptjiffies;
654static unsigned long resultjiffies;
655static int resultsize;
656static unsigned long lastredo;
657
658static struct output_log {
659 unsigned char data;
660 unsigned char status;
661 unsigned long jiffies;
662} output_log[OLOGSIZE];
663
664static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666#define current_reqD -1
667#define MAXTIMEOUT -2
668
Joe Perches73507e62010-03-10 15:21:03 -0800669static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200671 unsigned long delay;
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (drive == current_reqD)
674 drive = current_drive;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200675
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700676 if (drive < 0 || drive >= N_DRIVE) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200677 delay = 20UL * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 drive = 0;
679 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200680 delay = UDP->timeout;
681
Tejun Heoe7c2f962012-08-21 13:18:24 -0700682 mod_delayed_work(floppy_wq, &fd_timeout, delay);
Joe Perchesa81ee542010-03-10 15:20:46 -0800683 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800684 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 timeout_message = message;
686}
687
Joe Perches73507e62010-03-10 15:21:03 -0800688static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
690 unsigned long flags;
691
692 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800693 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 spin_unlock_irqrestore(&floppy_lock, flags);
695}
696
Joe Perches48c8cee2010-03-10 15:20:45 -0800697#define INFBOUND(a, b) (a) = max_t(int, a, b)
698#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700/*
701 * Bottom half floppy driver.
702 * ==========================
703 *
704 * This part of the file contains the code talking directly to the hardware,
705 * and also the main service loop (seek-configure-spinup-command)
706 */
707
708/*
709 * disk change.
710 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
711 * and the last_checked date.
712 *
713 * last_checked is the date of the last check which showed 'no disk change'
714 * FD_DISK_CHANGE is set under two conditions:
715 * 1. The floppy has been changed after some i/o to that floppy already
716 * took place.
717 * 2. No floppy disk is in the drive. This is done in order to ensure that
718 * requests are quickly flushed in case there is no disk in the drive. It
719 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
720 * the drive.
721 *
722 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
723 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
724 * each seek. If a disk is present, the disk change line should also be
725 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
726 * change line is set, this means either that no disk is in the drive, or
727 * that it has been removed since the last seek.
728 *
729 * This means that we really have a third possibility too:
730 * The floppy has been changed after the last seek.
731 */
732
733static int disk_change(int drive)
734{
735 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700736
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800737 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 DPRINT("WARNING disk change called early\n");
739 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
740 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
741 DPRINT("probing disk change on unselected drive\n");
742 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
743 (unsigned int)FDCS->dor);
744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Joe Perches87f530d2010-03-10 15:20:54 -0800746 debug_dcl(UDP->flags,
747 "checking disk change line for drive %d\n", drive);
748 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
749 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
750 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800753 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800755 set_bit(FD_VERIFY_BIT, &UDRS->flags);
756 /* verify write protection */
757
758 if (UDRS->maxblock) /* mark it changed */
759 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
761 /* invalidate its geometry */
762 if (UDRS->keep_data >= 0) {
763 if ((UDP->flags & FTD_MSG) &&
764 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800765 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 current_type[drive] = NULL;
767 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
768 }
769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return 1;
771 } else {
772 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800773 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
775 return 0;
776}
777
778static inline int is_selected(int dor, int unit)
779{
780 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
781}
782
Joe Perches57584c52010-03-10 15:21:00 -0800783static bool is_ready_state(int status)
784{
785 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
786 return state == STATUS_READY;
787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789static int set_dor(int fdc, char mask, char data)
790{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700791 unsigned char unit;
792 unsigned char drive;
793 unsigned char newdor;
794 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 if (FDCS->address == -1)
797 return -1;
798
799 olddor = FDCS->dor;
800 newdor = (olddor & mask) | data;
801 if (newdor != olddor) {
802 unit = olddor & 0x3;
803 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
804 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800805 debug_dcl(UDP->flags,
806 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 disk_change(drive);
808 }
809 FDCS->dor = newdor;
810 fd_outb(newdor, FD_DOR);
811
812 unit = newdor & 0x3;
813 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
814 drive = REVDRIVE(fdc, unit);
815 UDRS->select_date = jiffies;
816 }
817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 return olddor;
819}
820
821static void twaddle(void)
822{
823 if (DP->select_delay)
824 return;
825 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
826 fd_outb(FDCS->dor, FD_DOR);
827 DRS->select_date = jiffies;
828}
829
Joe Perches57584c52010-03-10 15:21:00 -0800830/*
831 * Reset all driver information about the current fdc.
832 * This is needed after a reset, and after a raw command.
833 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834static void reset_fdc_info(int mode)
835{
836 int drive;
837
838 FDCS->spec1 = FDCS->spec2 = -1;
839 FDCS->need_configure = 1;
840 FDCS->perp_mode = 1;
841 FDCS->rawcmd = 0;
842 for (drive = 0; drive < N_DRIVE; drive++)
843 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
844 UDRS->track = NEED_2_RECAL;
845}
846
847/* selects the fdc and drive, and enables the fdc's input/dma. */
848static void set_fdc(int drive)
849{
850 if (drive >= 0 && drive < N_DRIVE) {
851 fdc = FDC(drive);
852 current_drive = drive;
853 }
854 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800855 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return;
857 }
858 set_dor(fdc, ~0, 8);
859#if N_FDC > 1
860 set_dor(1 - fdc, ~8, 0);
861#endif
862 if (FDCS->rawcmd == 2)
863 reset_fdc_info(1);
864 if (fd_inb(FD_STATUS) != STATUS_READY)
865 FDCS->reset = 1;
866}
867
868/* locks the driver */
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200869static int lock_fdc(int drive, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200871 if (WARN(atomic_read(&usage_count) == 0,
872 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200875 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
876 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 command_status = FD_COMMAND_NONE;
879
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200880 reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 set_fdc(drive);
882 return 0;
883}
884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200886static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if (!test_bit(0, &fdc_busy))
889 DPRINT("FDC access conflict!\n");
890
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200891 raw_cmd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 command_status = FD_COMMAND_NONE;
Tejun Heo136b5722012-08-21 13:18:24 -0700893 cancel_delayed_work(&fd_timeout);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200894 do_floppy = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 cont = NULL;
896 clear_bit(0, &fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 wake_up(&fdc_wait);
898}
899
900/* switches the motor off after a given timeout */
901static void motor_off_callback(unsigned long nr)
902{
903 unsigned char mask = ~(0x10 << UNIT(nr));
904
905 set_dor(FDC(nr), mask, 0);
906}
907
908/* schedules motor off */
909static void floppy_off(unsigned int drive)
910{
911 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700912 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 if (!(FDCS->dor & (0x10 << UNIT(drive))))
915 return;
916
917 del_timer(motor_off_timer + drive);
918
919 /* make spindle stop in a position which minimizes spinup time
920 * next time */
921 if (UDP->rps) {
922 delta = jiffies - UDRS->first_read_date + HZ -
923 UDP->spindown_offset;
924 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
925 motor_off_timer[drive].expires =
926 jiffies + UDP->spindown - delta;
927 }
928 add_timer(motor_off_timer + drive);
929}
930
931/*
932 * cycle through all N_DRIVE floppy drives, for disk change testing.
933 * stopping at current drive. This is done before any long operation, to
934 * be sure to have up to date disk change information.
935 */
936static void scandrives(void)
937{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700938 int i;
939 int drive;
940 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 if (DP->select_delay)
943 return;
944
945 saved_drive = current_drive;
946 for (i = 0; i < N_DRIVE; i++) {
947 drive = (saved_drive + i + 1) % N_DRIVE;
948 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
949 continue; /* skip closed drives */
950 set_fdc(drive);
951 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
952 (0x10 << UNIT(drive))))
953 /* switch the motor off again, if it was off to
954 * begin with */
955 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
956 }
957 set_fdc(saved_drive);
958}
959
960static void empty(void)
961{
962}
963
David Howells65f27f32006-11-22 14:55:48 +0000964static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Joe Perches48c8cee2010-03-10 15:20:45 -0800966static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200968 WARN_ON(work_pending(&floppy_work));
969
David Howells65f27f32006-11-22 14:55:48 +0000970 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200971 queue_work(floppy_wq, &floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972}
973
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200974static DECLARE_DELAYED_WORK(fd_timer, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976static void cancel_activity(void)
977{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 do_floppy = NULL;
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200979 cancel_delayed_work_sync(&fd_timer);
980 cancel_work_sync(&floppy_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981}
982
983/* this function makes sure that the disk stays in the drive during the
984 * transfer */
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200985static void fd_watchdog(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
Joe Perches87f530d2010-03-10 15:20:54 -0800987 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 if (disk_change(current_drive)) {
990 DPRINT("disk removed during i/o\n");
991 cancel_activity();
992 cont->done(0);
993 reset_fdc();
994 } else {
Jiri Kosina070ad7e2012-05-18 13:50:25 +0200995 cancel_delayed_work(&fd_timer);
996 PREPARE_DELAYED_WORK(&fd_timer, fd_watchdog);
997 queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 }
999}
1000
1001static void main_command_interrupt(void)
1002{
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001003 cancel_delayed_work(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 cont->interrupt();
1005}
1006
1007/* waits for a delay (spinup or select) to pass */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001008static int fd_wait_for_completion(unsigned long expires, work_func_t function)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{
1010 if (FDCS->reset) {
1011 reset_fdc(); /* do the reset during sleep to win time
1012 * if we don't need to sleep, it's a good
1013 * occasion anyways */
1014 return 1;
1015 }
1016
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001017 if (time_before(jiffies, expires)) {
1018 cancel_delayed_work(&fd_timer);
1019 PREPARE_DELAYED_WORK(&fd_timer, function);
1020 queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return 1;
1022 }
1023 return 0;
1024}
1025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026static void setup_DMA(void)
1027{
1028 unsigned long f;
1029
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if (raw_cmd->length == 0) {
1031 int i;
1032
Joe Perchesb46df352010-03-10 15:20:46 -08001033 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001035 pr_cont("%x,", raw_cmd->cmd[i]);
1036 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 cont->done(0);
1038 FDCS->reset = 1;
1039 return;
1040 }
1041 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001042 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 cont->done(0);
1044 FDCS->reset = 1;
1045 return;
1046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 f = claim_dma_lock();
1048 fd_disable_dma();
1049#ifdef fd_dma_setup
1050 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1051 (raw_cmd->flags & FD_RAW_READ) ?
1052 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1053 release_dma_lock(f);
1054 cont->done(0);
1055 FDCS->reset = 1;
1056 return;
1057 }
1058 release_dma_lock(f);
1059#else
1060 fd_clear_dma_ff();
1061 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1062 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1063 DMA_MODE_READ : DMA_MODE_WRITE);
1064 fd_set_dma_addr(raw_cmd->kernel_data);
1065 fd_set_dma_count(raw_cmd->length);
1066 virtual_dma_port = FDCS->address;
1067 fd_enable_dma();
1068 release_dma_lock(f);
1069#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070}
1071
1072static void show_floppy(void);
1073
1074/* waits until the fdc becomes ready */
1075static int wait_til_ready(void)
1076{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001077 int status;
1078 int counter;
1079
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (FDCS->reset)
1081 return -1;
1082 for (counter = 0; counter < 10000; counter++) {
1083 status = fd_inb(FD_STATUS);
1084 if (status & STATUS_READY)
1085 return status;
1086 }
Joe Perches29f1c782010-03-10 15:21:00 -08001087 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1089 show_floppy();
1090 }
1091 FDCS->reset = 1;
1092 return -1;
1093}
1094
1095/* sends a command byte to the fdc */
1096static int output_byte(char byte)
1097{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001098 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001100 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001102
1103 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 output_log[output_log_pos].data = byte;
1106 output_log[output_log_pos].status = status;
1107 output_log[output_log_pos].jiffies = jiffies;
1108 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 return 0;
1110 }
1111 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001112 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1114 byte, fdc, status);
1115 show_floppy();
1116 }
1117 return -1;
1118}
1119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120/* gets the response from the fdc */
1121static int result(void)
1122{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001123 int i;
1124 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001127 status = wait_til_ready();
1128 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 break;
1130 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1131 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 resultjiffies = jiffies;
1133 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 return i;
1135 }
1136 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1137 reply_buffer[i] = fd_inb(FD_DATA);
1138 else
1139 break;
1140 }
Joe Perches29f1c782010-03-10 15:21:00 -08001141 if (initialized) {
1142 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1143 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 show_floppy();
1145 }
1146 FDCS->reset = 1;
1147 return -1;
1148}
1149
1150#define MORE_OUTPUT -2
1151/* does the fdc need more output? */
1152static int need_more_output(void)
1153{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001154 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001155
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001156 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001158
1159 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 return result();
1163}
1164
1165/* Set perpendicular mode as required, based on data rate, if supported.
1166 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1167 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001168static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169{
1170 unsigned char perp_mode;
1171
1172 if (raw_cmd->rate & 0x40) {
1173 switch (raw_cmd->rate & 3) {
1174 case 0:
1175 perp_mode = 2;
1176 break;
1177 case 3:
1178 perp_mode = 3;
1179 break;
1180 default:
1181 DPRINT("Invalid data rate for perpendicular mode!\n");
1182 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001183 FDCS->reset = 1;
1184 /*
1185 * convenient way to return to
1186 * redo without too much hassle
1187 * (deep stack et al.)
1188 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 return;
1190 }
1191 } else
1192 perp_mode = 0;
1193
1194 if (FDCS->perp_mode == perp_mode)
1195 return;
1196 if (FDCS->version >= FDC_82077_ORIG) {
1197 output_byte(FD_PERPENDICULAR);
1198 output_byte(perp_mode);
1199 FDCS->perp_mode = perp_mode;
1200 } else if (perp_mode) {
1201 DPRINT("perpendicular mode not supported by this FDC.\n");
1202 }
1203} /* perpendicular_mode */
1204
1205static int fifo_depth = 0xa;
1206static int no_fifo;
1207
1208static int fdc_configure(void)
1209{
1210 /* Turn on FIFO */
1211 output_byte(FD_CONFIGURE);
1212 if (need_more_output() != MORE_OUTPUT)
1213 return 0;
1214 output_byte(0);
1215 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1216 output_byte(0); /* pre-compensation from track
1217 0 upwards */
1218 return 1;
1219}
1220
1221#define NOMINAL_DTR 500
1222
1223/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1224 * head load time, and DMA disable flag to values needed by floppy.
1225 *
1226 * The value "dtr" is the data transfer rate in Kbps. It is needed
1227 * to account for the data rate-based scaling done by the 82072 and 82077
1228 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1229 * 8272a).
1230 *
1231 * Note that changing the data transfer rate has a (probably deleterious)
1232 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1233 * fdc_specify is called again after each data transfer rate
1234 * change.
1235 *
1236 * srt: 1000 to 16000 in microseconds
1237 * hut: 16 to 240 milliseconds
1238 * hlt: 2 to 254 milliseconds
1239 *
1240 * These values are rounded up to the next highest available delay time.
1241 */
1242static void fdc_specify(void)
1243{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001244 unsigned char spec1;
1245 unsigned char spec2;
1246 unsigned long srt;
1247 unsigned long hlt;
1248 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 unsigned long dtr = NOMINAL_DTR;
1250 unsigned long scale_dtr = NOMINAL_DTR;
1251 int hlt_max_code = 0x7f;
1252 int hut_max_code = 0xf;
1253
1254 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1255 fdc_configure();
1256 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 }
1258
1259 switch (raw_cmd->rate & 0x03) {
1260 case 3:
1261 dtr = 1000;
1262 break;
1263 case 1:
1264 dtr = 300;
1265 if (FDCS->version >= FDC_82078) {
1266 /* chose the default rate table, not the one
1267 * where 1 = 2 Mbps */
1268 output_byte(FD_DRIVESPEC);
1269 if (need_more_output() == MORE_OUTPUT) {
1270 output_byte(UNIT(current_drive));
1271 output_byte(0xc0);
1272 }
1273 }
1274 break;
1275 case 2:
1276 dtr = 250;
1277 break;
1278 }
1279
1280 if (FDCS->version >= FDC_82072) {
1281 scale_dtr = dtr;
1282 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1283 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1284 }
1285
1286 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001287 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001288 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001290
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 SUPBOUND(srt, 0xf);
1292 INFBOUND(srt, 0);
1293
Julia Lawall061837b2008-09-22 14:57:16 -07001294 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 if (hlt < 0x01)
1296 hlt = 0x01;
1297 else if (hlt > 0x7f)
1298 hlt = hlt_max_code;
1299
Julia Lawall061837b2008-09-22 14:57:16 -07001300 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 if (hut < 0x1)
1302 hut = 0x1;
1303 else if (hut > 0xf)
1304 hut = hut_max_code;
1305
1306 spec1 = (srt << 4) | hut;
1307 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1308
1309 /* If these parameters did not change, just return with success */
1310 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1311 /* Go ahead and set spec1 and spec2 */
1312 output_byte(FD_SPECIFY);
1313 output_byte(FDCS->spec1 = spec1);
1314 output_byte(FDCS->spec2 = spec2);
1315 }
1316} /* fdc_specify */
1317
1318/* Set the FDC's data transfer rate on behalf of the specified drive.
1319 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1320 * of the specify command (i.e. using the fdc_specify function).
1321 */
1322static int fdc_dtr(void)
1323{
1324 /* If data rate not already set to desired value, set it. */
1325 if ((raw_cmd->rate & 3) == FDCS->dtr)
1326 return 0;
1327
1328 /* Set dtr */
1329 fd_outb(raw_cmd->rate & 3, FD_DCR);
1330
1331 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1332 * need a stabilization period of several milliseconds to be
1333 * enforced after data rate changes before R/W operations.
1334 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1335 */
1336 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001337 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001338 (work_func_t)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339} /* fdc_dtr */
1340
1341static void tell_sector(void)
1342{
Joe Perchesb46df352010-03-10 15:20:46 -08001343 pr_cont(": track %d, head %d, sector %d, size %d",
1344 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345} /* tell_sector */
1346
Joe Perchesb46df352010-03-10 15:20:46 -08001347static void print_errors(void)
1348{
1349 DPRINT("");
1350 if (ST0 & ST0_ECE) {
1351 pr_cont("Recalibrate failed!");
1352 } else if (ST2 & ST2_CRC) {
1353 pr_cont("data CRC error");
1354 tell_sector();
1355 } else if (ST1 & ST1_CRC) {
1356 pr_cont("CRC error");
1357 tell_sector();
1358 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1359 (ST2 & ST2_MAM)) {
1360 if (!probing) {
1361 pr_cont("sector not found");
1362 tell_sector();
1363 } else
1364 pr_cont("probe failed...");
1365 } else if (ST2 & ST2_WC) { /* seek error */
1366 pr_cont("wrong cylinder");
1367 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1368 pr_cont("bad cylinder");
1369 } else {
1370 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1371 ST0, ST1, ST2);
1372 tell_sector();
1373 }
1374 pr_cont("\n");
1375}
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377/*
1378 * OK, this error interpreting routine is called after a
1379 * DMA read/write has succeeded
1380 * or failed, so we check the results, and copy any buffers.
1381 * hhb: Added better error reporting.
1382 * ak: Made this into a separate routine.
1383 */
1384static int interpret_errors(void)
1385{
1386 char bad;
1387
1388 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001389 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 FDCS->reset = 1;
1391 return 1;
1392 }
1393
1394 /* check IC to find cause of interrupt */
1395 switch (ST0 & ST0_INTR) {
1396 case 0x40: /* error occurred during command execution */
1397 if (ST1 & ST1_EOC)
1398 return 0; /* occurs with pseudo-DMA */
1399 bad = 1;
1400 if (ST1 & ST1_WP) {
1401 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001402 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 cont->done(0);
1404 bad = 2;
1405 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001406 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 } else if (ST1 & ST1_OR) {
1408 if (DP->flags & FTD_MSG)
1409 DPRINT("Over/Underrun - retrying\n");
1410 bad = 0;
1411 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001412 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 }
1414 if (ST2 & ST2_WC || ST2 & ST2_BC)
1415 /* wrong cylinder => recal */
1416 DRS->track = NEED_2_RECAL;
1417 return bad;
1418 case 0x80: /* invalid command given */
1419 DPRINT("Invalid FDC command given!\n");
1420 cont->done(0);
1421 return 2;
1422 case 0xc0:
1423 DPRINT("Abnormal termination caused by polling\n");
1424 cont->error();
1425 return 2;
1426 default: /* (0) Normal command termination */
1427 return 0;
1428 }
1429}
1430
1431/*
1432 * This routine is called when everything should be correctly set up
1433 * for the transfer (i.e. floppy motor is on, the correct floppy is
1434 * selected, and the head is sitting on the right track).
1435 */
1436static void setup_rw_floppy(void)
1437{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001438 int i;
1439 int r;
1440 int flags;
1441 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 unsigned long ready_date;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001443 work_func_t function;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
1445 flags = raw_cmd->flags;
1446 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1447 flags |= FD_RAW_INTR;
1448
1449 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1450 ready_date = DRS->spinup_date + DP->spinup;
1451 /* If spinup will take a long time, rerun scandrives
1452 * again just before spinup completion. Beware that
1453 * after scandrives, we must again wait for selection.
1454 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001455 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 ready_date -= DP->select_delay;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001457 function = (work_func_t)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 } else
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001459 function = (work_func_t)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
1461 /* wait until the floppy is spinning fast enough */
1462 if (fd_wait_for_completion(ready_date, function))
1463 return;
1464 }
1465 dflags = DRS->flags;
1466
1467 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1468 setup_DMA();
1469
1470 if (flags & FD_RAW_INTR)
1471 do_floppy = main_command_interrupt;
1472
1473 r = 0;
1474 for (i = 0; i < raw_cmd->cmd_count; i++)
1475 r |= output_byte(raw_cmd->cmd[i]);
1476
Joe Perchesded28632010-03-10 15:21:09 -08001477 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
1479 if (r) {
1480 cont->error();
1481 reset_fdc();
1482 return;
1483 }
1484
1485 if (!(flags & FD_RAW_INTR)) {
1486 inr = result();
1487 cont->interrupt();
1488 } else if (flags & FD_RAW_NEED_DISK)
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001489 fd_watchdog(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490}
1491
1492static int blind_seek;
1493
1494/*
1495 * This is the routine called after every seek (or recalibrate) interrupt
1496 * from the floppy controller.
1497 */
1498static void seek_interrupt(void)
1499{
Joe Perchesded28632010-03-10 15:21:09 -08001500 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1502 DPRINT("seek failed\n");
1503 DRS->track = NEED_2_RECAL;
1504 cont->error();
1505 cont->redo();
1506 return;
1507 }
1508 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001509 debug_dcl(DP->flags,
1510 "clearing NEWCHANGE flag because of effective seek\n");
1511 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001512 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1513 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 DRS->select_date = jiffies;
1515 }
1516 DRS->track = ST1;
1517 floppy_ready();
1518}
1519
1520static void check_wp(void)
1521{
Joe Perchese0298532010-03-10 15:20:55 -08001522 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1523 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 output_byte(FD_GETSTATUS);
1525 output_byte(UNIT(current_drive));
1526 if (result() != 1) {
1527 FDCS->reset = 1;
1528 return;
1529 }
Joe Perchese0298532010-03-10 15:20:55 -08001530 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1531 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001532 debug_dcl(DP->flags,
1533 "checking whether disk is write protected\n");
1534 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001536 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 else
Joe Perchese0298532010-03-10 15:20:55 -08001538 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 }
1540}
1541
1542static void seek_floppy(void)
1543{
1544 int track;
1545
1546 blind_seek = 0;
1547
Joe Perchesded28632010-03-10 15:21:09 -08001548 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Joe Perchese0298532010-03-10 15:20:55 -08001550 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1552 /* the media changed flag should be cleared after the seek.
1553 * If it isn't, this means that there is really no disk in
1554 * the drive.
1555 */
Joe Perchese0298532010-03-10 15:20:55 -08001556 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 cont->done(0);
1558 cont->redo();
1559 return;
1560 }
1561 if (DRS->track <= NEED_1_RECAL) {
1562 recalibrate_floppy();
1563 return;
Joe Perchese0298532010-03-10 15:20:55 -08001564 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1566 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1567 /* we seek to clear the media-changed condition. Does anybody
1568 * know a more elegant way, which works on all drives? */
1569 if (raw_cmd->track)
1570 track = raw_cmd->track - 1;
1571 else {
1572 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1573 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1574 blind_seek = 1;
1575 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1576 }
1577 track = 1;
1578 }
1579 } else {
1580 check_wp();
1581 if (raw_cmd->track != DRS->track &&
1582 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1583 track = raw_cmd->track;
1584 else {
1585 setup_rw_floppy();
1586 return;
1587 }
1588 }
1589
1590 do_floppy = seek_interrupt;
1591 output_byte(FD_SEEK);
1592 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001593 if (output_byte(track) < 0) {
1594 reset_fdc();
1595 return;
1596 }
Joe Perchesded28632010-03-10 15:21:09 -08001597 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598}
1599
1600static void recal_interrupt(void)
1601{
Joe Perchesded28632010-03-10 15:21:09 -08001602 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 if (inr != 2)
1604 FDCS->reset = 1;
1605 else if (ST0 & ST0_ECE) {
1606 switch (DRS->track) {
1607 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001608 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 /* after a second recalibrate, we still haven't
1610 * reached track 0. Probably no drive. Raise an
1611 * error, as failing immediately might upset
1612 * computers possessed by the Devil :-) */
1613 cont->error();
1614 cont->redo();
1615 return;
1616 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001617 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 /* If we already did a recalibrate,
1619 * and we are not at track 0, this
1620 * means we have moved. (The only way
1621 * not to move at recalibration is to
1622 * be already at track 0.) Clear the
1623 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001624 debug_dcl(DP->flags,
1625 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Joe Perchese0298532010-03-10 15:20:55 -08001627 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 DRS->select_date = jiffies;
1629 /* fall through */
1630 default:
Joe Perchesded28632010-03-10 15:21:09 -08001631 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 /* Recalibrate moves the head by at
1633 * most 80 steps. If after one
1634 * recalibrate we don't have reached
1635 * track 0, this might mean that we
1636 * started beyond track 80. Try
1637 * again. */
1638 DRS->track = NEED_1_RECAL;
1639 break;
1640 }
1641 } else
1642 DRS->track = ST1;
1643 floppy_ready();
1644}
1645
1646static void print_result(char *message, int inr)
1647{
1648 int i;
1649
1650 DPRINT("%s ", message);
1651 if (inr >= 0)
1652 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001653 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1654 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655}
1656
1657/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001658irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 int do_print;
1661 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001662 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
1664 lasthandler = handler;
1665 interruptjiffies = jiffies;
1666
1667 f = claim_dma_lock();
1668 fd_disable_dma();
1669 release_dma_lock(f);
1670
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 do_floppy = NULL;
1672 if (fdc >= N_FDC || FDCS->address == -1) {
1673 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001674 pr_info("DOR0=%x\n", fdc_state[0].dor);
1675 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001676 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001677 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 return IRQ_NONE;
1679 }
1680
1681 FDCS->reset = 0;
1682 /* We have to clear the reset flag here, because apparently on boxes
1683 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1684 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1685 * emission of the SENSEI's.
1686 * It is OK to emit floppy commands because we are in an interrupt
1687 * handler here, and thus we have to fear no interference of other
1688 * activity.
1689 */
1690
Joe Perches29f1c782010-03-10 15:21:00 -08001691 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 inr = result();
1694 if (do_print)
1695 print_result("unexpected interrupt", inr);
1696 if (inr == 0) {
1697 int max_sensei = 4;
1698 do {
1699 output_byte(FD_SENSEI);
1700 inr = result();
1701 if (do_print)
1702 print_result("sensei", inr);
1703 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001704 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1705 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 }
1707 if (!handler) {
1708 FDCS->reset = 1;
1709 return IRQ_NONE;
1710 }
1711 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001712 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
1714 /* FIXME! Was it really for us? */
1715 return IRQ_HANDLED;
1716}
1717
1718static void recalibrate_floppy(void)
1719{
Joe Perchesded28632010-03-10 15:21:09 -08001720 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 do_floppy = recal_interrupt;
1722 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001723 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001724 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725}
1726
1727/*
1728 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1729 */
1730static void reset_interrupt(void)
1731{
Joe Perchesded28632010-03-10 15:21:09 -08001732 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 result(); /* get the status ready for set_fdc */
1734 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001735 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 cont->error(); /* a reset just after a reset. BAD! */
1737 }
1738 cont->redo();
1739}
1740
1741/*
1742 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1743 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1744 */
1745static void reset_fdc(void)
1746{
1747 unsigned long flags;
1748
1749 do_floppy = reset_interrupt;
1750 FDCS->reset = 0;
1751 reset_fdc_info(0);
1752
1753 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1754 /* Irrelevant for systems with true DMA (i386). */
1755
1756 flags = claim_dma_lock();
1757 fd_disable_dma();
1758 release_dma_lock(flags);
1759
1760 if (FDCS->version >= FDC_82072A)
1761 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1762 else {
1763 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1764 udelay(FD_RESET_DELAY);
1765 fd_outb(FDCS->dor, FD_DOR);
1766 }
1767}
1768
1769static void show_floppy(void)
1770{
1771 int i;
1772
Joe Perchesb46df352010-03-10 15:20:46 -08001773 pr_info("\n");
1774 pr_info("floppy driver state\n");
1775 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001776 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001777 jiffies, interruptjiffies, jiffies - interruptjiffies,
1778 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Joe Perchesb46df352010-03-10 15:20:46 -08001780 pr_info("timeout_message=%s\n", timeout_message);
1781 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001783 pr_info("%2x %2x %lu\n",
1784 output_log[(i + output_log_pos) % OLOGSIZE].data,
1785 output_log[(i + output_log_pos) % OLOGSIZE].status,
1786 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1787 pr_info("last result at %lu\n", resultjiffies);
1788 pr_info("last redo_fd_request at %lu\n", lastredo);
1789 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1790 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Joe Perchesb46df352010-03-10 15:20:46 -08001792 pr_info("status=%x\n", fd_inb(FD_STATUS));
1793 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001795 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001796 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001797 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001798 if (delayed_work_pending(&fd_timer))
1799 pr_info("delayed work.function=%p expires=%ld\n",
1800 fd_timer.work.func,
1801 fd_timer.timer.expires - jiffies);
1802 if (delayed_work_pending(&fd_timeout))
1803 pr_info("timer_function=%p expires=%ld\n",
1804 fd_timeout.work.func,
1805 fd_timeout.timer.expires - jiffies);
1806
Joe Perchesb46df352010-03-10 15:20:46 -08001807 pr_info("cont=%p\n", cont);
1808 pr_info("current_req=%p\n", current_req);
1809 pr_info("command_status=%d\n", command_status);
1810 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811}
1812
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001813static void floppy_shutdown(struct work_struct *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814{
1815 unsigned long flags;
1816
Joe Perches29f1c782010-03-10 15:21:00 -08001817 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 show_floppy();
1819 cancel_activity();
1820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 flags = claim_dma_lock();
1822 fd_disable_dma();
1823 release_dma_lock(flags);
1824
1825 /* avoid dma going to a random drive after shutdown */
1826
Joe Perches29f1c782010-03-10 15:21:00 -08001827 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 DPRINT("floppy timeout called\n");
1829 FDCS->reset = 1;
1830 if (cont) {
1831 cont->done(0);
1832 cont->redo(); /* this will recall reset when needed */
1833 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001834 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 process_fd_request();
1836 }
Joe Perches275176b2010-03-10 15:21:06 -08001837 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838}
1839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001841static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001843 int mask;
1844 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 mask = 0xfc;
1847 data = UNIT(current_drive);
1848 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1849 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1850 set_debugt();
1851 /* no read since this drive is running */
1852 DRS->first_read_date = 0;
1853 /* note motor start time if motor is not yet running */
1854 DRS->spinup_date = jiffies;
1855 data |= (0x10 << UNIT(current_drive));
1856 }
1857 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1858 mask &= ~(0x10 << UNIT(current_drive));
1859
1860 /* starts motor and selects floppy */
1861 del_timer(motor_off_timer + current_drive);
1862 set_dor(fdc, mask, data);
1863
1864 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001865 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
Jiri Kosina070ad7e2012-05-18 13:50:25 +02001866 (work_func_t)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867}
1868
1869static void floppy_ready(void)
1870{
Joe Perches045f9832010-03-10 15:20:47 -08001871 if (FDCS->reset) {
1872 reset_fdc();
1873 return;
1874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 if (start_motor(floppy_ready))
1876 return;
1877 if (fdc_dtr())
1878 return;
1879
Joe Perches87f530d2010-03-10 15:20:54 -08001880 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1882 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001883 twaddle(); /* this clears the dcl on certain
1884 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885
1886#ifdef fd_chose_dma_mode
1887 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1888 unsigned long flags = claim_dma_lock();
1889 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1890 release_dma_lock(flags);
1891 }
1892#endif
1893
1894 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1895 perpendicular_mode();
1896 fdc_specify(); /* must be done here because of hut, hlt ... */
1897 seek_floppy();
1898 } else {
1899 if ((raw_cmd->flags & FD_RAW_READ) ||
1900 (raw_cmd->flags & FD_RAW_WRITE))
1901 fdc_specify();
1902 setup_rw_floppy();
1903 }
1904}
1905
1906static void floppy_start(void)
1907{
Joe Perches73507e62010-03-10 15:21:03 -08001908 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
1910 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001911 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001912 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 floppy_ready();
1914}
1915
1916/*
1917 * ========================================================================
1918 * here ends the bottom half. Exported routines are:
1919 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1920 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1921 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1922 * and set_dor.
1923 * ========================================================================
1924 */
1925/*
1926 * General purpose continuations.
1927 * ==============================
1928 */
1929
1930static void do_wakeup(void)
1931{
Joe Perches73507e62010-03-10 15:21:03 -08001932 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 cont = NULL;
1934 command_status += 2;
1935 wake_up(&command_done);
1936}
1937
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001938static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 .interrupt = empty,
1940 .redo = do_wakeup,
1941 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001942 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943};
1944
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001945static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 .interrupt = empty,
1947 .redo = process_fd_request,
1948 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001949 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950};
1951
Joe Perches74f63f42010-03-10 15:20:58 -08001952static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953{
1954 int ret;
1955
1956 schedule_bh(handler);
1957
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001958 if (interruptible)
1959 wait_event_interruptible(command_done, command_status >= 2);
1960 else
1961 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962
1963 if (command_status < 2) {
1964 cancel_activity();
1965 cont = &intr_cont;
1966 reset_fdc();
1967 return -EINTR;
1968 }
1969
1970 if (FDCS->reset)
1971 command_status = FD_COMMAND_ERROR;
1972 if (command_status == FD_COMMAND_OKAY)
1973 ret = 0;
1974 else
1975 ret = -EIO;
1976 command_status = FD_COMMAND_NONE;
1977 return ret;
1978}
1979
1980static void generic_done(int result)
1981{
1982 command_status = result;
1983 cont = &wakeup_cont;
1984}
1985
1986static void generic_success(void)
1987{
1988 cont->done(1);
1989}
1990
1991static void generic_failure(void)
1992{
1993 cont->done(0);
1994}
1995
1996static void success_and_wakeup(void)
1997{
1998 generic_success();
1999 cont->redo();
2000}
2001
2002/*
2003 * formatting and rw support.
2004 * ==========================
2005 */
2006
2007static int next_valid_format(void)
2008{
2009 int probed_format;
2010
2011 probed_format = DRS->probed_format;
2012 while (1) {
2013 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2014 DRS->probed_format = 0;
2015 return 1;
2016 }
2017 if (floppy_type[DP->autodetect[probed_format]].sect) {
2018 DRS->probed_format = probed_format;
2019 return 0;
2020 }
2021 probed_format++;
2022 }
2023}
2024
2025static void bad_flp_intr(void)
2026{
2027 int err_count;
2028
2029 if (probing) {
2030 DRS->probed_format++;
2031 if (!next_valid_format())
2032 return;
2033 }
2034 err_count = ++(*errors);
2035 INFBOUND(DRWE->badness, err_count);
2036 if (err_count > DP->max_errors.abort)
2037 cont->done(0);
2038 if (err_count > DP->max_errors.reset)
2039 FDCS->reset = 1;
2040 else if (err_count > DP->max_errors.recal)
2041 DRS->track = NEED_2_RECAL;
2042}
2043
2044static void set_floppy(int drive)
2045{
2046 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 if (type)
2049 _floppy = floppy_type + type;
2050 else
2051 _floppy = current_type[drive];
2052}
2053
2054/*
2055 * formatting support.
2056 * ===================
2057 */
2058static void format_interrupt(void)
2059{
2060 switch (interpret_errors()) {
2061 case 1:
2062 cont->error();
2063 case 2:
2064 break;
2065 case 0:
2066 cont->done(1);
2067 }
2068 cont->redo();
2069}
2070
Joe Perches48c8cee2010-03-10 15:20:45 -08002071#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002073
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074static void setup_format_params(int track)
2075{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002076 int n;
2077 int il;
2078 int count;
2079 int head_shift;
2080 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 struct fparm {
2082 unsigned char track, head, sect, size;
2083 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
2085 raw_cmd = &default_raw_cmd;
2086 raw_cmd->track = track;
2087
Joe Perches48c8cee2010-03-10 15:20:45 -08002088 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2089 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 raw_cmd->rate = _floppy->rate & 0x43;
2091 raw_cmd->cmd_count = NR_F;
2092 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2093 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2094 F_SIZECODE = FD_SIZECODE(_floppy);
2095 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2096 F_GAP = _floppy->fmt_gap;
2097 F_FILL = FD_FILL_BYTE;
2098
2099 raw_cmd->kernel_data = floppy_track_buffer;
2100 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2101
2102 /* allow for about 30ms for data transport per track */
2103 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2104
2105 /* a ``cylinder'' is two tracks plus a little stepping time */
2106 track_shift = 2 * head_shift + 3;
2107
2108 /* position of logical sector 1 on this track */
2109 n = (track_shift * format_req.track + head_shift * format_req.head)
2110 % F_SECT_PER_TRACK;
2111
2112 /* determine interleave */
2113 il = 1;
2114 if (_floppy->fmt_gap < 0x22)
2115 il++;
2116
2117 /* initialize field */
2118 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2119 here[count].track = format_req.track;
2120 here[count].head = format_req.head;
2121 here[count].sect = 0;
2122 here[count].size = F_SIZECODE;
2123 }
2124 /* place logical sectors */
2125 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2126 here[n].sect = count;
2127 n = (n + il) % F_SECT_PER_TRACK;
2128 if (here[n].sect) { /* sector busy, find next free sector */
2129 ++n;
2130 if (n >= F_SECT_PER_TRACK) {
2131 n -= F_SECT_PER_TRACK;
2132 while (here[n].sect)
2133 ++n;
2134 }
2135 }
2136 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002137 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002139 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 }
2141}
2142
2143static void redo_format(void)
2144{
2145 buffer_track = -1;
2146 setup_format_params(format_req.track << STRETCH(_floppy));
2147 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002148 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149}
2150
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002151static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 .interrupt = format_interrupt,
2153 .redo = redo_format,
2154 .error = bad_flp_intr,
2155 .done = generic_done
2156};
2157
2158static int do_format(int drive, struct format_descr *tmp_format_req)
2159{
2160 int ret;
2161
Joe Perches74f63f42010-03-10 15:20:58 -08002162 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002163 return -EINTR;
2164
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 set_floppy(drive);
2166 if (!_floppy ||
2167 _floppy->track > DP->tracks ||
2168 tmp_format_req->track >= _floppy->track ||
2169 tmp_format_req->head >= _floppy->head ||
2170 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2171 !_floppy->fmt_gap) {
2172 process_fd_request();
2173 return -EINVAL;
2174 }
2175 format_req = *tmp_format_req;
2176 format_errors = 0;
2177 cont = &format_cont;
2178 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002179 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002180 if (ret == -EINTR)
2181 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 process_fd_request();
2183 return ret;
2184}
2185
2186/*
2187 * Buffer read/write and support
2188 * =============================
2189 */
2190
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002191static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{
2193 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002194 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
2196 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002197 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002198 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002199 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
2202 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002203 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 current_req = NULL;
2205}
2206
2207/* new request_done. Can handle physical sectors which are smaller than a
2208 * logical buffer */
2209static void request_done(int uptodate)
2210{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 struct request *req = current_req;
Jens Axboe48821182010-09-22 09:32:36 +02002212 struct request_queue *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 unsigned long flags;
2214 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002215 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
2217 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002218 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2219 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
2221 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002222 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 return;
2224 }
2225
Jens Axboe48821182010-09-22 09:32:36 +02002226 q = req->q;
2227
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 if (uptodate) {
2229 /* maintain values for invalidation on geometry
2230 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002231 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 INFBOUND(DRS->maxblock, block);
2233 if (block > _floppy->sect)
2234 DRS->maxtrack = 1;
2235
2236 /* unlock chained buffers */
2237 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002238 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 spin_unlock_irqrestore(q->queue_lock, flags);
2240 } else {
2241 if (rq_data_dir(req) == WRITE) {
2242 /* record write error information */
2243 DRWE->write_errors++;
2244 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002245 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 DRWE->first_error_generation = DRS->generation;
2247 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002248 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 DRWE->last_error_generation = DRS->generation;
2250 }
2251 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002252 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 spin_unlock_irqrestore(q->queue_lock, flags);
2254 }
2255}
2256
2257/* Interrupt handler evaluating the result of the r/w operation */
2258static void rw_interrupt(void)
2259{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002260 int eoc;
2261 int ssize;
2262 int heads;
2263 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
2265 if (R_HEAD >= 2) {
2266 /* some Toshiba floppy controllers occasionnally seem to
2267 * return bogus interrupts after read/write operations, which
2268 * can be recognized by a bad head number (>= 2) */
2269 return;
2270 }
2271
2272 if (!DRS->first_read_date)
2273 DRS->first_read_date = jiffies;
2274
2275 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002276 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277
2278 if (ST1 & ST1_EOC)
2279 eoc = 1;
2280 else
2281 eoc = 0;
2282
2283 if (COMMAND & 0x80)
2284 heads = 2;
2285 else
2286 heads = 1;
2287
2288 nr_sectors = (((R_TRACK - TRACK) * heads +
2289 R_HEAD - HEAD) * SECT_PER_TRACK +
2290 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2291
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002293 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 DPRINT("long rw: %x instead of %lx\n",
2295 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002296 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2297 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2298 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2299 pr_info("heads=%d eoc=%d\n", heads, eoc);
2300 pr_info("spt=%d st=%d ss=%d\n",
2301 SECT_PER_TRACK, fsector_t, ssize);
2302 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
2305 nr_sectors -= in_sector_offset;
2306 INFBOUND(nr_sectors, 0);
2307 SUPBOUND(current_count_sectors, nr_sectors);
2308
2309 switch (interpret_errors()) {
2310 case 2:
2311 cont->redo();
2312 return;
2313 case 1:
2314 if (!current_count_sectors) {
2315 cont->error();
2316 cont->redo();
2317 return;
2318 }
2319 break;
2320 case 0:
2321 if (!current_count_sectors) {
2322 cont->redo();
2323 return;
2324 }
2325 current_type[current_drive] = _floppy;
2326 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2327 break;
2328 }
2329
2330 if (probing) {
2331 if (DP->flags & FTD_MSG)
2332 DPRINT("Auto-detected floppy type %s in fd%d\n",
2333 _floppy->name, current_drive);
2334 current_type[current_drive] = _floppy;
2335 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2336 probing = 0;
2337 }
2338
2339 if (CT(COMMAND) != FD_READ ||
2340 raw_cmd->kernel_data == current_req->buffer) {
2341 /* transfer directly from buffer */
2342 cont->done(1);
2343 } else if (CT(COMMAND) == FD_READ) {
2344 buffer_track = raw_cmd->track;
2345 buffer_drive = current_drive;
2346 INFBOUND(buffer_max, nr_sectors + fsector_t);
2347 }
2348 cont->redo();
2349}
2350
2351/* Compute maximal contiguous buffer size. */
2352static int buffer_chain_size(void)
2353{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002355 int size;
2356 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 char *base;
2358
2359 base = bio_data(current_req->bio);
2360 size = 0;
2361
NeilBrown5705f702007-09-25 12:35:59 +02002362 rq_for_each_segment(bv, current_req, iter) {
2363 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2364 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
NeilBrown5705f702007-09-25 12:35:59 +02002366 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 }
2368
2369 return size >> 9;
2370}
2371
2372/* Compute the maximal transfer size */
2373static int transfer_size(int ssize, int max_sector, int max_size)
2374{
2375 SUPBOUND(max_sector, fsector_t + max_size);
2376
2377 /* alignment */
2378 max_sector -= (max_sector % _floppy->sect) % ssize;
2379
2380 /* transfer size, beginning not aligned */
2381 current_count_sectors = max_sector - fsector_t;
2382
2383 return max_sector;
2384}
2385
2386/*
2387 * Move data from/to the track buffer to/from the buffer cache.
2388 */
2389static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2390{
2391 int remaining; /* number of transferred 512-byte sectors */
2392 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002393 char *buffer;
2394 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002395 int size;
2396 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398 max_sector = transfer_size(ssize,
2399 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002400 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
2402 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002403 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002405 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
2407 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002408 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002410 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2411 pr_info("remaining=%d\n", remaining >> 9);
2412 pr_info("current_req->nr_sectors=%u\n",
2413 blk_rq_sectors(current_req));
2414 pr_info("current_req->current_nr_sectors=%u\n",
2415 blk_rq_cur_sectors(current_req));
2416 pr_info("max_sector=%d\n", max_sector);
2417 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420 buffer_max = max(max_sector, buffer_max);
2421
2422 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2423
Tejun Heo1011c1b2009-05-07 22:24:45 +09002424 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
NeilBrown5705f702007-09-25 12:35:59 +02002426 rq_for_each_segment(bv, current_req, iter) {
2427 if (!remaining)
2428 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
NeilBrown5705f702007-09-25 12:35:59 +02002430 size = bv->bv_len;
2431 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
NeilBrown5705f702007-09-25 12:35:59 +02002433 buffer = page_address(bv->bv_page) + bv->bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002434 if (dma_buffer + size >
2435 floppy_track_buffer + (max_buffer_sectors << 10) ||
2436 dma_buffer < floppy_track_buffer) {
2437 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002438 (int)((floppy_track_buffer - dma_buffer) >> 9));
2439 pr_info("fsector_t=%d buffer_min=%d\n",
2440 fsector_t, buffer_min);
2441 pr_info("current_count_sectors=%ld\n",
2442 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002444 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002445 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002446 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002447 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
NeilBrown5705f702007-09-25 12:35:59 +02002449 if (((unsigned long)buffer) % 512)
2450 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002451
NeilBrown5705f702007-09-25 12:35:59 +02002452 if (CT(COMMAND) == FD_READ)
2453 memcpy(buffer, dma_buffer, size);
2454 else
2455 memcpy(dma_buffer, buffer, size);
2456
2457 remaining -= size;
2458 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 if (remaining) {
2461 if (remaining > 0)
2462 max_sector -= remaining >> 9;
2463 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465}
2466
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467/* work around a bug in pseudo DMA
2468 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2469 * sending data. Hence we need a different way to signal the
2470 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2471 * does not work with MT, hence we can only transfer one head at
2472 * a time
2473 */
2474static void virtualdmabug_workaround(void)
2475{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002476 int hard_sectors;
2477 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479 if (CT(COMMAND) == FD_WRITE) {
2480 COMMAND &= ~0x80; /* switch off multiple track mode */
2481
2482 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2483 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002485 pr_info("too many sectors %d > %d\n",
2486 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 return;
2488 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002489 SECT_PER_TRACK = end_sector;
2490 /* make sure SECT_PER_TRACK
2491 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 }
2493}
2494
2495/*
2496 * Formulate a read/write request.
2497 * this routine decides where to load the data (directly to buffer, or to
2498 * tmp floppy area), how much data to load (the size of the buffer, the whole
2499 * track, or a single sector)
2500 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2501 * allocation on the fly, it should be done here. No other part should need
2502 * modification.
2503 */
2504
2505static int make_raw_rw_request(void)
2506{
2507 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002508 int max_sector;
2509 int max_size;
2510 int tracksize;
2511 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002513 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 set_fdc((long)current_req->rq_disk->private_data);
2517
2518 raw_cmd = &default_raw_cmd;
Fengguang Wu2fb2ca62012-07-28 19:45:59 +08002519 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 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,
Jens Axboe59533162013-05-23 12:25:08 +02002889 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%llx\n",
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002890 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
Jens Axboe59533162013-05-23 12:25:08 +02002891 (unsigned long long) 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 Virodb2a1442013-05-05 21:52:57 -04003604static void 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618}
3619
3620/*
3621 * floppy_open check for aliasing (/dev/fd0 can be the same as
3622 * /dev/PS0 etc), and disallows simultaneous access to the same
3623 * drive with different device numbers.
3624 */
Al Viroa4af9b42008-03-02 09:27:55 -05003625static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626{
Al Viroa4af9b42008-03-02 09:27:55 -05003627 int drive = (long)bdev->bd_disk->private_data;
3628 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 int try;
3630 int res = -EBUSY;
3631 char *tmp;
3632
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003633 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003634 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003636 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 goto out2;
3638
3639 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003640 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3641 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 }
3643
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003644 UDRS->fd_ref++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645
Al Viroa4af9b42008-03-02 09:27:55 -05003646 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
3648 res = -ENXIO;
3649
3650 if (!floppy_track_buffer) {
3651 /* if opening an ED drive, reserve a big buffer,
3652 * else reserve a small one */
3653 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3654 try = 64; /* Only 48 actually useful */
3655 else
3656 try = 32; /* Only 24 actually useful */
3657
3658 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3659 if (!tmp && !floppy_track_buffer) {
3660 try >>= 1; /* buffer only one side */
3661 INFBOUND(try, 16);
3662 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3663 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003664 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 if (!tmp && !floppy_track_buffer) {
3667 DPRINT("Unable to allocate DMA memory\n");
3668 goto out;
3669 }
3670 if (floppy_track_buffer) {
3671 if (tmp)
3672 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3673 } else {
3674 buffer_min = buffer_max = -1;
3675 floppy_track_buffer = tmp;
3676 max_buffer_sectors = try;
3677 }
3678 }
3679
Al Viroa4af9b42008-03-02 09:27:55 -05003680 new_dev = MINOR(bdev->bd_dev);
3681 UDRS->fd_device = new_dev;
3682 set_capacity(disks[drive], floppy_sizes[new_dev]);
3683 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 if (buffer_drive == drive)
3685 buffer_track = -1;
3686 }
3687
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 if (UFDCS->rawcmd == 1)
3689 UFDCS->rawcmd = 2;
3690
Al Viroa4af9b42008-03-02 09:27:55 -05003691 if (!(mode & FMODE_NDELAY)) {
3692 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003694 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003695 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 goto out;
3697 }
3698 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003699 if ((mode & FMODE_WRITE) &&
3700 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 goto out;
3702 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003703 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003704 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 return 0;
3706out:
Jiri Kosinabfa10b82012-05-18 13:50:28 +02003707 UDRS->fd_ref--;
3708
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 if (!UDRS->fd_ref)
3710 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003712 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003713 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 return res;
3715}
3716
3717/*
3718 * Check if the disk has been changed or if a change has been faked.
3719 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003720static unsigned int floppy_check_events(struct gendisk *disk,
3721 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722{
3723 int drive = (long)disk->private_data;
3724
Joe Perchese0298532010-03-10 15:20:55 -08003725 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3726 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003727 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003729 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003730 lock_fdc(drive, false);
3731 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 }
3734
Joe Perchese0298532010-03-10 15:20:55 -08003735 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3736 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003738 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003739 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 return 0;
3741}
3742
3743/*
3744 * This implements "read block 0" for floppy_revalidate().
3745 * Needed for format autodetection, checking whether there is
3746 * a disk in the drive, and whether that disk is writable.
3747 */
3748
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003749static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752}
3753
3754static int __floppy_read_block_0(struct block_device *bdev)
3755{
3756 struct bio bio;
3757 struct bio_vec bio_vec;
3758 struct completion complete;
3759 struct page *page;
3760 size_t size;
3761
3762 page = alloc_page(GFP_NOIO);
3763 if (!page) {
3764 process_fd_request();
3765 return -ENOMEM;
3766 }
3767
3768 size = bdev->bd_block_size;
3769 if (!size)
3770 size = 1024;
3771
3772 bio_init(&bio);
3773 bio.bi_io_vec = &bio_vec;
3774 bio_vec.bv_page = page;
3775 bio_vec.bv_len = size;
3776 bio_vec.bv_offset = 0;
3777 bio.bi_vcnt = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 bio.bi_size = size;
3779 bio.bi_bdev = bdev;
3780 bio.bi_sector = 0;
Muthu Kumar9354f1b2012-03-05 14:59:16 -08003781 bio.bi_flags = (1 << BIO_QUIET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 init_completion(&complete);
3783 bio.bi_private = &complete;
3784 bio.bi_end_io = floppy_rb0_complete;
3785
3786 submit_bio(READ, &bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 process_fd_request();
3788 wait_for_completion(&complete);
3789
3790 __free_page(page);
3791
3792 return 0;
3793}
3794
3795/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3796 * the bootblock (block 0). "Autodetection" is also needed to check whether
3797 * there is a disk in the drive at all... Thus we also do it for fixed
3798 * geometry formats */
3799static int floppy_revalidate(struct gendisk *disk)
3800{
3801 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 int cf;
3803 int res = 0;
3804
Joe Perchese0298532010-03-10 15:20:55 -08003805 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3806 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003807 test_bit(drive, &fake_change) ||
3808 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003809 if (WARN(atomic_read(&usage_count) == 0,
3810 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003812
Joe Perches74f63f42010-03-10 15:20:58 -08003813 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003814 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3815 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003816 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 process_fd_request(); /*already done by another thread */
3818 return 0;
3819 }
3820 UDRS->maxblock = 0;
3821 UDRS->maxtrack = 0;
3822 if (buffer_drive == drive)
3823 buffer_track = -1;
3824 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003825 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 if (cf)
3827 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003828 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 /* auto-sensing */
3830 res = __floppy_read_block_0(opened_bdev[drive]);
3831 } else {
3832 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003833 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 process_fd_request();
3835 }
3836 }
3837 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3838 return res;
3839}
3840
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003841static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003842 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003843 .open = floppy_open,
3844 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003845 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003846 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003847 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003848 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851/*
3852 * Floppy Driver initialization
3853 * =============================
3854 */
3855
3856/* Determine the floppy disk controller type */
3857/* This routine was written by David C. Niemi */
3858static char __init get_fdc_version(void)
3859{
3860 int r;
3861
3862 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3863 if (FDCS->reset)
3864 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003865 r = result();
3866 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 return FDC_NONE; /* No FDC present ??? */
3868 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003869 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3871 }
3872 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003873 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3874 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 return FDC_UNKNOWN;
3876 }
3877
3878 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003879 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3881 }
3882
3883 output_byte(FD_PERPENDICULAR);
3884 if (need_more_output() == MORE_OUTPUT) {
3885 output_byte(0);
3886 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003887 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 return FDC_82072A; /* 82072A as found on Sparcs. */
3889 }
3890
3891 output_byte(FD_UNLOCK);
3892 r = result();
3893 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003894 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003895 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 * LOCK/UNLOCK */
3897 }
3898 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003899 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3900 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 return FDC_UNKNOWN;
3902 }
3903 output_byte(FD_PARTID);
3904 r = result();
3905 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003906 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3907 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 return FDC_UNKNOWN;
3909 }
3910 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003911 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 return FDC_82077; /* Revised 82077AA passes all the tests */
3913 }
3914 switch (reply_buffer[0] >> 5) {
3915 case 0x0:
3916 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003917 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 return FDC_82078;
3919 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003920 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 return FDC_82078;
3922 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003923 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 return FDC_S82078B;
3925 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003926 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 return FDC_87306;
3928 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003929 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3930 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 return FDC_82078_UNKN;
3932 }
3933} /* get_fdc_version */
3934
3935/* lilo configuration */
3936
3937static void __init floppy_set_flags(int *ints, int param, int param2)
3938{
3939 int i;
3940
3941 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3942 if (param)
3943 default_drive_params[i].params.flags |= param2;
3944 else
3945 default_drive_params[i].params.flags &= ~param2;
3946 }
3947 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
3948}
3949
3950static void __init daring(int *ints, int param, int param2)
3951{
3952 int i;
3953
3954 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3955 if (param) {
3956 default_drive_params[i].params.select_delay = 0;
3957 default_drive_params[i].params.flags |=
3958 FD_SILENT_DCL_CLEAR;
3959 } else {
3960 default_drive_params[i].params.select_delay =
3961 2 * HZ / 100;
3962 default_drive_params[i].params.flags &=
3963 ~FD_SILENT_DCL_CLEAR;
3964 }
3965 }
3966 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
3967}
3968
3969static void __init set_cmos(int *ints, int dummy, int dummy2)
3970{
3971 int current_drive = 0;
3972
3973 if (ints[0] != 2) {
3974 DPRINT("wrong number of parameters for CMOS\n");
3975 return;
3976 }
3977 current_drive = ints[1];
3978 if (current_drive < 0 || current_drive >= 8) {
3979 DPRINT("bad drive for set_cmos\n");
3980 return;
3981 }
3982#if N_FDC > 1
3983 if (current_drive >= 4 && !FDC2)
3984 FDC2 = 0x370;
3985#endif
3986 DP->cmos = ints[2];
3987 DPRINT("setting CMOS code to %d\n", ints[2]);
3988}
3989
3990static struct param_table {
3991 const char *name;
3992 void (*fn) (int *ints, int param, int param2);
3993 int *var;
3994 int def_param;
3995 int param2;
3996} config_params[] __initdata = {
3997 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
3998 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
3999 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4000 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4001 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4002 {"daring", daring, NULL, 1, 0},
4003#if N_FDC > 1
4004 {"two_fdc", NULL, &FDC2, 0x370, 0},
4005 {"one_fdc", NULL, &FDC2, 0, 0},
4006#endif
4007 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4008 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4009 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4010 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4011 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4012 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4013 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4014 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4015 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4016 {"nofifo", NULL, &no_fifo, 0x20, 0},
4017 {"usefifo", NULL, &no_fifo, 0, 0},
4018 {"cmos", set_cmos, NULL, 0, 0},
4019 {"slow", NULL, &slow_floppy, 1, 0},
4020 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4021 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4022 {"L40SX", NULL, &print_unex, 0, 0}
4023
4024 EXTRA_FLOPPY_PARAMS
4025};
4026
4027static int __init floppy_setup(char *str)
4028{
4029 int i;
4030 int param;
4031 int ints[11];
4032
4033 str = get_options(str, ARRAY_SIZE(ints), ints);
4034 if (str) {
4035 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4036 if (strcmp(str, config_params[i].name) == 0) {
4037 if (ints[0])
4038 param = ints[1];
4039 else
4040 param = config_params[i].def_param;
4041 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004042 config_params[i].fn(ints, param,
4043 config_params[i].
4044 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 if (config_params[i].var) {
4046 DPRINT("%s=%d\n", str, param);
4047 *config_params[i].var = param;
4048 }
4049 return 1;
4050 }
4051 }
4052 }
4053 if (str) {
4054 DPRINT("unknown floppy option [%s]\n", str);
4055
4056 DPRINT("allowed options are:");
4057 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004058 pr_cont(" %s", config_params[i].name);
4059 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 } else
4061 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004062 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 return 0;
4064}
4065
4066static int have_no_fdc = -ENODEV;
4067
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004068static ssize_t floppy_cmos_show(struct device *dev,
4069 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004070{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004071 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004072 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004073
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004074 drive = p->id;
4075 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004076}
Joe Perches48c8cee2010-03-10 15:20:45 -08004077
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004078static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004079
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080static void floppy_device_release(struct device *dev)
4081{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082}
4083
Frans Popc90cd332009-07-25 22:24:54 +02004084static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004085{
4086 int fdc;
4087
4088 for (fdc = 0; fdc < N_FDC; fdc++)
4089 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004090 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004091
4092 return 0;
4093}
4094
Alexey Dobriyan47145212009-12-14 18:00:08 -08004095static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004096 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004097 .restore = floppy_resume,
4098};
4099
4100static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004101 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004102 .name = "floppy",
4103 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004104 },
4105};
4106
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004107static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004109static bool floppy_available(int drive)
4110{
4111 if (!(allowed_drive_mask & (1 << drive)))
4112 return false;
4113 if (fdc_state[FDC(drive)].version == FDC_NONE)
4114 return false;
4115 return true;
4116}
4117
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4119{
4120 int drive = (*part & 3) | ((*part & 0x80) >> 5);
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004121 if (drive >= N_DRIVE || !floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004123 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 return NULL;
4125 *part = 0;
4126 return get_disk(disks[drive]);
4127}
4128
Andi Kleen0cc15d032012-07-02 17:27:04 -07004129static int __init do_floppy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130{
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004131 int i, unit, drive, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132
Stephen Hemminger285203c2010-06-15 13:21:11 +02004133 set_debugt();
4134 interruptjiffies = resultjiffies = jiffies;
4135
Kumar Gala68e1ee62008-09-22 14:41:31 -07004136#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004137 if (check_legacy_ioport(FDC1))
4138 return -ENODEV;
4139#endif
4140
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 raw_cmd = NULL;
4142
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004143 floppy_wq = alloc_ordered_workqueue("floppy", 0);
4144 if (!floppy_wq)
4145 return -ENOMEM;
4146
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004147 for (drive = 0; drive < N_DRIVE; drive++) {
4148 disks[drive] = alloc_disk(1);
4149 if (!disks[drive]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 err = -ENOMEM;
4151 goto out_put_disk;
4152 }
4153
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004154 disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4155 if (!disks[drive]->queue) {
Jens Axboe48821182010-09-22 09:32:36 +02004156 err = -ENOMEM;
Herton Ronaldo Krzesinskib54e1f82012-08-27 20:56:51 -03004157 goto out_put_disk;
Jens Axboe48821182010-09-22 09:32:36 +02004158 }
4159
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004160 blk_queue_max_hw_sectors(disks[drive]->queue, 64);
4161 disks[drive]->major = FLOPPY_MAJOR;
4162 disks[drive]->first_minor = TOMINOR(drive);
4163 disks[drive]->fops = &floppy_fops;
4164 sprintf(disks[drive]->disk_name, "fd%d", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004166 init_timer(&motor_off_timer[drive]);
4167 motor_off_timer[drive].data = drive;
4168 motor_off_timer[drive].function = motor_off_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 }
4170
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 err = register_blkdev(FLOPPY_MAJOR, "fd");
4172 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004173 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004175 err = platform_driver_register(&floppy_driver);
4176 if (err)
4177 goto out_unreg_blkdev;
4178
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4180 floppy_find, NULL, NULL);
4181
4182 for (i = 0; i < 256; i++)
4183 if (ITYPE(i))
4184 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4185 else
4186 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4187
Joe Perches73507e62010-03-10 15:21:03 -08004188 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 config_types();
4190
4191 for (i = 0; i < N_FDC; i++) {
4192 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004193 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 FDCS->dtr = -1;
4195 FDCS->dor = 0x4;
4196#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004197 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198#ifdef __mc68000__
4199 if (MACH_IS_SUN3X)
4200#endif
4201 FDCS->version = FDC_82072A;
4202#endif
4203 }
4204
4205 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 fdc_state[0].address = FDC1;
4207 if (fdc_state[0].address == -1) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004208 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 err = -ENODEV;
4210 goto out_unreg_region;
4211 }
4212#if N_FDC > 1
4213 fdc_state[1].address = FDC2;
4214#endif
4215
4216 fdc = 0; /* reset fdc in case of unexpected interrupt */
4217 err = floppy_grab_irq_and_dma();
4218 if (err) {
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004219 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 err = -EBUSY;
4221 goto out_unreg_region;
4222 }
4223
4224 /* initialise drive state */
4225 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004226 memset(UDRS, 0, sizeof(*UDRS));
4227 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004228 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4229 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4230 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 UDRS->fd_device = -1;
4232 floppy_track_buffer = NULL;
4233 max_buffer_sectors = 0;
4234 }
4235 /*
4236 * Small 10 msec delay to let through any interrupt that
4237 * initialization might have triggered, to not
4238 * confuse detection:
4239 */
4240 msleep(10);
4241
4242 for (i = 0; i < N_FDC; i++) {
4243 fdc = i;
4244 FDCS->driver_version = FD_DRIVER_VERSION;
4245 for (unit = 0; unit < 4; unit++)
4246 FDCS->track[unit] = 0;
4247 if (FDCS->address == -1)
4248 continue;
4249 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004250 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004252 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 FDCS->address = -1;
4254 FDCS->version = FDC_NONE;
4255 continue;
4256 }
4257 /* Try to determine the floppy controller type */
4258 FDCS->version = get_fdc_version();
4259 if (FDCS->version == FDC_NONE) {
4260 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004261 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 FDCS->address = -1;
4263 continue;
4264 }
4265 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4266 can_use_virtual_dma = 0;
4267
4268 have_no_fdc = 0;
4269 /* Not all FDCs seem to be able to handle the version command
4270 * properly, so force a reset for the standard FDC clones,
4271 * to avoid interrupt garbage.
4272 */
Joe Perches74f63f42010-03-10 15:20:58 -08004273 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 }
4275 fdc = 0;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004276 cancel_delayed_work(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004278 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 if (have_no_fdc) {
4280 DPRINT("no floppy controllers found\n");
4281 err = have_no_fdc;
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004282 goto out_release_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 }
4284
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 for (drive = 0; drive < N_DRIVE; drive++) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004286 if (!floppy_available(drive))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004288
4289 floppy_device[drive].name = floppy_device_name;
4290 floppy_device[drive].id = drive;
4291 floppy_device[drive].dev.release = floppy_device_release;
4292
4293 err = platform_device_register(&floppy_device[drive]);
4294 if (err)
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004295 goto out_remove_drives;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004296
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004297 err = device_create_file(&floppy_device[drive].dev,
4298 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004299 if (err)
4300 goto out_unreg_platform_dev;
4301
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 /* to be cleaned up... */
4303 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004305 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 add_disk(disks[drive]);
4307 }
4308
4309 return 0;
4310
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004311out_unreg_platform_dev:
4312 platform_device_unregister(&floppy_device[drive]);
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004313out_remove_drives:
4314 while (drive--) {
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004315 if (floppy_available(drive)) {
Herton Ronaldo Krzesinskid60e7ec2012-08-27 20:56:54 -03004316 del_gendisk(disks[drive]);
4317 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4318 platform_device_unregister(&floppy_device[drive]);
4319 }
4320 }
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004321out_release_dma:
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004322 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 floppy_release_irq_and_dma();
4324out_unreg_region:
4325 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004326 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327out_unreg_blkdev:
4328 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329out_put_disk:
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004330 destroy_workqueue(floppy_wq);
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004331 for (drive = 0; drive < N_DRIVE; drive++) {
4332 if (!disks[drive])
4333 break;
4334 if (disks[drive]->queue) {
4335 del_timer_sync(&motor_off_timer[drive]);
4336 blk_cleanup_queue(disks[drive]->queue);
4337 disks[drive]->queue = NULL;
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004338 }
Herton Ronaldo Krzesinski1a4ae432012-10-30 08:36:07 +01004339 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 }
4341 return err;
4342}
4343
Andi Kleen0cc15d032012-07-02 17:27:04 -07004344#ifndef MODULE
4345static __init void floppy_async_init(void *data, async_cookie_t cookie)
4346{
4347 do_floppy_init();
4348}
4349#endif
4350
4351static int __init floppy_init(void)
4352{
4353#ifdef MODULE
4354 return do_floppy_init();
4355#else
4356 /* Don't hold up the bootup by the floppy initialization */
4357 async_schedule(floppy_async_init, NULL);
4358 return 0;
4359#endif
4360}
4361
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004362static const struct io_region {
4363 int offset;
4364 int size;
4365} io_regions[] = {
4366 { 2, 1 },
4367 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4368 { 4, 2 },
4369 /* address + 6 is reserved, and may be taken by IDE.
4370 * Unfortunately, Adaptec doesn't know this :-(, */
4371 { 7, 1 },
4372};
4373
4374static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4375{
4376 while (p != io_regions) {
4377 p--;
4378 release_region(FDCS->address + p->offset, p->size);
4379 }
4380}
4381
4382#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4383
4384static int floppy_request_regions(int fdc)
4385{
4386 const struct io_region *p;
4387
4388 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004389 if (!request_region(FDCS->address + p->offset,
4390 p->size, "floppy")) {
4391 DPRINT("Floppy io-port 0x%04lx in use\n",
4392 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004393 floppy_release_allocated_regions(fdc, p);
4394 return -EBUSY;
4395 }
4396 }
4397 return 0;
4398}
4399
4400static void floppy_release_regions(int fdc)
4401{
4402 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4403}
4404
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405static int floppy_grab_irq_and_dma(void)
4406{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004407 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004409
4410 /*
4411 * We might have scheduled a free_irq(), wait it to
4412 * drain first:
4413 */
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004414 flush_workqueue(floppy_wq);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004415
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 if (fd_request_irq()) {
4417 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4418 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004419 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 return -1;
4421 }
4422 if (fd_request_dma()) {
4423 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4424 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004425 if (can_use_virtual_dma & 2)
4426 use_virtual_dma = can_use_virtual_dma = 1;
4427 if (!(can_use_virtual_dma & 1)) {
4428 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004429 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004430 return -1;
4431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 }
4433
4434 for (fdc = 0; fdc < N_FDC; fdc++) {
4435 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004436 if (floppy_request_regions(fdc))
4437 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 }
4439 }
4440 for (fdc = 0; fdc < N_FDC; fdc++) {
4441 if (FDCS->address != -1) {
4442 reset_fdc_info(1);
4443 fd_outb(FDCS->dor, FD_DOR);
4444 }
4445 }
4446 fdc = 0;
4447 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4448
4449 for (fdc = 0; fdc < N_FDC; fdc++)
4450 if (FDCS->address != -1)
4451 fd_outb(FDCS->dor, FD_DOR);
4452 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004453 * The driver will try and free resources and relies on us
4454 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 */
4456 fdc = 0;
4457 irqdma_allocated = 1;
4458 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004459cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 fd_free_irq();
4461 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004462 while (--fdc >= 0)
4463 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004464 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 return -1;
4466}
4467
4468static void floppy_release_irq_and_dma(void)
4469{
4470 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471#ifndef __sparc__
4472 int drive;
4473#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 long tmpsize;
4475 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004477 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004479
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 if (irqdma_allocated) {
4481 fd_disable_dma();
4482 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004483 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 irqdma_allocated = 0;
4485 }
4486 set_dor(0, ~0, 8);
4487#if N_FDC > 1
4488 set_dor(1, ~8, 0);
4489#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
4491 if (floppy_track_buffer && max_buffer_sectors) {
4492 tmpsize = max_buffer_sectors * 1024;
4493 tmpaddr = (unsigned long)floppy_track_buffer;
4494 floppy_track_buffer = NULL;
4495 max_buffer_sectors = 0;
4496 buffer_min = buffer_max = -1;
4497 fd_dma_mem_free(tmpaddr, tmpsize);
4498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499#ifndef __sparc__
4500 for (drive = 0; drive < N_FDC * 4; drive++)
4501 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004502 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503#endif
4504
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004505 if (delayed_work_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004506 pr_info("floppy timer still active:%s\n", timeout_message);
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004507 if (delayed_work_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004508 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004509 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004510 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 old_fdc = fdc;
4512 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004513 if (FDCS->address != -1)
4514 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 fdc = old_fdc;
4516}
4517
4518#ifdef MODULE
4519
4520static char *floppy;
4521
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522static void __init parse_floppy_cfg_string(char *cfg)
4523{
4524 char *ptr;
4525
4526 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004527 ptr = cfg;
4528 while (*cfg && *cfg != ' ' && *cfg != '\t')
4529 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 if (*cfg) {
4531 *cfg = '\0';
4532 cfg++;
4533 }
4534 if (*ptr)
4535 floppy_setup(ptr);
4536 }
4537}
4538
Jon Schindler7afea3b2008-04-29 00:59:21 -07004539static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540{
4541 if (floppy)
4542 parse_floppy_cfg_string(floppy);
4543 return floppy_init();
4544}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004545module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546
Jon Schindler7afea3b2008-04-29 00:59:21 -07004547static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548{
4549 int drive;
4550
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4552 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004553 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554
Jiri Kosinaeac7cc52012-11-06 11:47:13 +01004555 destroy_workqueue(floppy_wq);
4556
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 for (drive = 0; drive < N_DRIVE; drive++) {
4558 del_timer_sync(&motor_off_timer[drive]);
4559
Herton Ronaldo Krzesinski8d3ab4e2012-08-27 20:56:55 -03004560 if (floppy_available(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004562 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4563 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 }
Jens Axboe48821182010-09-22 09:32:36 +02004565 blk_cleanup_queue(disks[drive]->queue);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004566
4567 /*
4568 * These disks have not called add_disk(). Don't put down
4569 * queue reference in put_disk().
4570 */
4571 if (!(allowed_drive_mask & (1 << drive)) ||
4572 fdc_state[FDC(drive)].version == FDC_NONE)
4573 disks[drive]->queue = NULL;
4574
Vivek Goyald017bf62010-11-06 08:16:05 -04004575 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577
Jiri Kosina070ad7e2012-05-18 13:50:25 +02004578 cancel_delayed_work_sync(&fd_timeout);
4579 cancel_delayed_work_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004581 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 floppy_release_irq_and_dma();
4583
4584 /* eject disk, if any */
4585 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586}
Joe Perches48c8cee2010-03-10 15:20:45 -08004587
Jon Schindler7afea3b2008-04-29 00:59:21 -07004588module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589
4590module_param(floppy, charp, 0);
4591module_param(FLOPPY_IRQ, int, 0);
4592module_param(FLOPPY_DMA, int, 0);
4593MODULE_AUTHOR("Alain L. Knaff");
4594MODULE_SUPPORTED_DEVICE("fd");
4595MODULE_LICENSE("GPL");
4596
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004597/* This doesn't actually get used other than for module information */
4598static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004599 {"PNP0700", 0},
4600 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004601};
Joe Perches48c8cee2010-03-10 15:20:45 -08004602
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004603MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4604
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605#else
4606
4607__setup("floppy=", floppy_setup);
4608module_init(floppy_init)
4609#endif
4610
4611MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);