blob: 665b32f598cb41072cf614c4cb4f60267101897b [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
147#define FLOPPY_SANITY_CHECK
148#undef FLOPPY_SILENT_DCL_CLEAR
149
150#define REALLY_SLOW_IO
151
152#define DEBUGT 2
Joe Perches48c8cee2010-03-10 15:20:45 -0800153#define DCL_DEBUG /* debug disk change line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Joe Perches87f530d2010-03-10 15:20:54 -0800155#ifdef DCL_DEBUG
156#define debug_dcl(test, fmt, args...) \
157 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
158#else
159#define debug_dcl(test, fmt, args...) \
160 do { if (0) DPRINT(fmt, ##args); } while (0)
161#endif
162
163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164/* do print messages for unexpected interrupts */
165static int print_unex = 1;
166#include <linux/module.h>
167#include <linux/sched.h>
168#include <linux/fs.h>
169#include <linux/kernel.h>
170#include <linux/timer.h>
171#include <linux/workqueue.h>
172#define FDPATCHES
173#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174#include <linux/fd.h>
175#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#include <linux/errno.h>
177#include <linux/slab.h>
178#include <linux/mm.h>
179#include <linux/bio.h>
180#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800181#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#include <linux/fcntl.h>
183#include <linux/delay.h>
184#include <linux/mc146818rtc.h> /* CMOS defines */
185#include <linux/ioport.h>
186#include <linux/interrupt.h>
187#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100188#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700189#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800191#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800192#include <linux/io.h>
193#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195/*
196 * PS/2 floppies have much slower step rates than regular floppies.
197 * It's been recommended that take about 1/4 of the default speed
198 * in some more extreme cases.
199 */
200static int slow_floppy;
201
202#include <asm/dma.h>
203#include <asm/irq.h>
204#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206static int FLOPPY_IRQ = 6;
207static int FLOPPY_DMA = 2;
208static int can_use_virtual_dma = 2;
209/* =======
210 * can use virtual DMA:
211 * 0 = use of virtual DMA disallowed by config
212 * 1 = use of virtual DMA prescribed by config
213 * 2 = no virtual DMA preference configured. By default try hard DMA,
214 * but fall back on virtual DMA when not enough memory available
215 */
216
217static int use_virtual_dma;
218/* =======
219 * use virtual DMA
220 * 0 using hard DMA
221 * 1 using virtual DMA
222 * This variable is set to virtual when a DMA mem problem arises, and
223 * reset back in floppy_grab_irq_and_dma.
224 * It is not safe to reset it in other circumstances, because the floppy
225 * driver may have several buffers in use at once, and we do currently not
226 * record each buffers capabilities
227 */
228
229static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100232irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235#define K_64 0x10000 /* 64KB */
236
237/* the following is the mask of allowed drives. By default units 2 and
238 * 3 of both floppy controllers are disabled, because switching on the
239 * motor of these drives causes system hangs on some PCI computers. drive
240 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
241 * a drive is allowed.
242 *
243 * NOTE: This must come before we include the arch floppy header because
244 * some ports reference this variable from there. -DaveM
245 */
246
247static int allowed_drive_mask = 0x33;
248
249#include <asm/floppy.h>
250
251static int irqdma_allocated;
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253#define DEVICE_NAME "floppy"
254
255#include <linux/blkdev.h>
256#include <linux/blkpg.h>
257#include <linux/cdrom.h> /* for the compatibility eject ioctl */
258#include <linux/completion.h>
259
260static struct request *current_req;
261static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800262static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264#ifndef fd_get_dma_residue
265#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
266#endif
267
268/* Dma Memory related stuff */
269
270#ifndef fd_dma_mem_free
271#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
272#endif
273
274#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800275#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276#endif
277
278static inline void fallback_on_nodma_alloc(char **addr, size_t l)
279{
280#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
281 if (*addr)
282 return; /* we have the memory */
283 if (can_use_virtual_dma != 2)
284 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800285 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 *addr = (char *)nodma_mem_alloc(l);
287#else
288 return;
289#endif
290}
291
292/* End dma memory related stuff */
293
294static unsigned long fake_change;
295static int initialising = 1;
296
Joe Perches48c8cee2010-03-10 15:20:45 -0800297#define ITYPE(x) (((x) >> 2) & 0x1f)
298#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
299#define UNIT(x) ((x) & 0x03) /* drive on fdc */
300#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700301 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Joe Perches48c8cee2010-03-10 15:20:45 -0800304#define DP (&drive_params[current_drive])
305#define DRS (&drive_state[current_drive])
306#define DRWE (&write_errors[current_drive])
307#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Joe Perches48c8cee2010-03-10 15:20:45 -0800309#define UDP (&drive_params[drive])
310#define UDRS (&drive_state[drive])
311#define UDRWE (&write_errors[drive])
312#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Joe Perches48c8cee2010-03-10 15:20:45 -0800314#define DPRINT(format, args...) \
Joe Perchesb46df352010-03-10 15:20:46 -0800315 pr_info(DEVICE_NAME "%d: " format, current_drive, ##args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Joe Perches48c8cee2010-03-10 15:20:45 -0800317#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
318#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
319
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800321#define COMMAND (raw_cmd->cmd[0])
322#define DR_SELECT (raw_cmd->cmd[1])
323#define TRACK (raw_cmd->cmd[2])
324#define HEAD (raw_cmd->cmd[3])
325#define SECTOR (raw_cmd->cmd[4])
326#define SIZECODE (raw_cmd->cmd[5])
327#define SECT_PER_TRACK (raw_cmd->cmd[6])
328#define GAP (raw_cmd->cmd[7])
329#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330#define NR_RW 9
331
332/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800333#define F_SIZECODE (raw_cmd->cmd[2])
334#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
335#define F_GAP (raw_cmd->cmd[4])
336#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337#define NR_F 6
338
339/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800340 * Maximum disk size (in kilobytes).
341 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 * [Now it is rather a minimum]
343 */
344#define MAX_DISK_SIZE 4 /* 3984 */
345
346/*
347 * globals used by 'result()'
348 */
349#define MAX_REPLIES 16
350static unsigned char reply_buffer[MAX_REPLIES];
351static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800352#define ST0 (reply_buffer[0])
353#define ST1 (reply_buffer[1])
354#define ST2 (reply_buffer[2])
355#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
356#define R_TRACK (reply_buffer[3])
357#define R_HEAD (reply_buffer[4])
358#define R_SECTOR (reply_buffer[5])
359#define R_SIZECODE (reply_buffer[6])
360
361#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363/*
364 * this struct defines the different floppy drive types.
365 */
366static struct {
367 struct floppy_drive_params params;
368 const char *name; /* name printed while booting */
369} default_drive_params[] = {
370/* NOTE: the time values in jiffies should be in msec!
371 CMOS drive type
372 | Maximum data rate supported by drive type
373 | | Head load time, msec
374 | | | Head unload time, msec (not used)
375 | | | | Step rate interval, usec
376 | | | | | Time needed for spinup time (jiffies)
377 | | | | | | Timeout for spinning down (jiffies)
378 | | | | | | | Spindown offset (where disk stops)
379 | | | | | | | | Select delay
380 | | | | | | | | | RPS
381 | | | | | | | | | | Max number of tracks
382 | | | | | | | | | | | Interrupt timeout
383 | | | | | | | | | | | | Max nonintlv. sectors
384 | | | | | | | | | | | | | -Max Errors- flags */
385{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
386 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
387
388{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
389 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
390
391{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
392 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
393
394{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
395 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
396
397{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
398 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
399
400{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
401 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
402
403{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
404 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
405/* | --autodetected formats--- | | |
406 * read_track | | Name printed when booting
407 * | Native format
408 * Frequency of disk change checks */
409};
410
411static struct floppy_drive_params drive_params[N_DRIVE];
412static struct floppy_drive_struct drive_state[N_DRIVE];
413static struct floppy_write_errors write_errors[N_DRIVE];
414static struct timer_list motor_off_timer[N_DRIVE];
415static struct gendisk *disks[N_DRIVE];
416static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800417static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
419
420/*
421 * This struct defines the different floppy types.
422 *
423 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
424 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
425 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
426 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
427 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
428 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
429 * side 0 is on physical side 0 (but with the misnamed sector IDs).
430 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700431 * 'options'.
432 *
433 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
434 * The LSB (bit 2) is flipped. For most disks, the first sector
435 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
436 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
437 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
438 *
439 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 */
441/*
442 Size
443 | Sectors per track
444 | | Head
445 | | | Tracks
446 | | | | Stretch
447 | | | | | Gap 1 size
448 | | | | | | Data rate, | 0x40 for perp
449 | | | | | | | Spec1 (stepping rate, head unload
450 | | | | | | | | /fmt gap (gap2) */
451static struct floppy_struct floppy_type[32] = {
452 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
453 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
454 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
455 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
456 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
457 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
458 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
459 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
460 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
461 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
462
463 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
464 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
465 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
466 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
467 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
468 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
469 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
470 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
471 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
472 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
473
474 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
475 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
476 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
477 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
478 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
479 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
480 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
481 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
482 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
486 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
487};
488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489#define SECTSIZE (_FD_SECTSIZE(*floppy))
490
491/* Auto-detection: Disk type used until the next media change occurs. */
492static struct floppy_struct *current_type[N_DRIVE];
493
494/*
495 * User-provided type information. current_type points to
496 * the respective entry of this array.
497 */
498static struct floppy_struct user_params[N_DRIVE];
499
500static sector_t floppy_sizes[256];
501
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200502static char floppy_device_name[] = "floppy";
503
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504/*
505 * The driver is trying to determine the correct media format
506 * while probing is set. rw_interrupt() clears it after a
507 * successful access.
508 */
509static int probing;
510
511/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800512#define FD_COMMAND_NONE -1
513#define FD_COMMAND_ERROR 2
514#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516static volatile int command_status = FD_COMMAND_NONE;
517static unsigned long fdc_busy;
518static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
519static DECLARE_WAIT_QUEUE_HEAD(command_done);
520
521#define NO_SIGNAL (!interruptible || !signal_pending(current))
Joe Perches48c8cee2010-03-10 15:20:45 -0800522#define CALL(x) if ((x) == -EINTR) return -EINTR
Joe Perches48c8cee2010-03-10 15:20:45 -0800523#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
524#define WAIT(x) _WAIT((x),interruptible)
525#define IWAIT(x) _WAIT((x),1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527/* Errors during formatting are counted here. */
528static int format_errors;
529
530/* Format request descriptor. */
531static struct format_descr format_req;
532
533/*
534 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
535 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
536 * H is head unload time (1=16ms, 2=32ms, etc)
537 */
538
539/*
540 * Track buffer
541 * Because these are written to by the DMA controller, they must
542 * not contain a 64k byte boundary crossing, or data will be
543 * corrupted/lost.
544 */
545static char *floppy_track_buffer;
546static int max_buffer_sectors;
547
548static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700549typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800551 void (*interrupt)(void);
552 /* this is called after the interrupt of the
553 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700554 void (*redo)(void); /* this is called to retry the operation */
555 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 done_f done; /* this is called to say if the operation has
557 * succeeded/failed */
558} *cont;
559
560static void floppy_ready(void);
561static void floppy_start(void);
562static void process_fd_request(void);
563static void recalibrate_floppy(void);
564static void floppy_shutdown(unsigned long);
565
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800566static int floppy_request_regions(int);
567static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568static int floppy_grab_irq_and_dma(void);
569static void floppy_release_irq_and_dma(void);
570
571/*
572 * The "reset" variable should be tested whenever an interrupt is scheduled,
573 * after the commands have been sent. This is to ensure that the driver doesn't
574 * get wedged when the interrupt doesn't come because of a failed command.
575 * reset doesn't need to be tested before sending commands, because
576 * output_byte is automatically disabled when reset is set.
577 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578static void reset_fdc(void);
579
580/*
581 * These are global variables, as that's the easiest way to give
582 * information to interrupts. They are the data used for the current
583 * request.
584 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800585#define NO_TRACK -1
586#define NEED_1_RECAL -2
587#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589static int usage_count;
590
591/* buffer related variables */
592static int buffer_track = -1;
593static int buffer_drive = -1;
594static int buffer_min = -1;
595static int buffer_max = -1;
596
597/* fdc related variables, should end up in a struct */
598static struct floppy_fdc_state fdc_state[N_FDC];
599static int fdc; /* current fdc */
600
601static struct floppy_struct *_floppy = floppy_type;
602static unsigned char current_drive;
603static long current_count_sectors;
604static unsigned char fsector_t; /* sector in track */
605static unsigned char in_sector_offset; /* offset within physical sector,
606 * expressed in units of 512 bytes */
607
608#ifndef fd_eject
609static inline int fd_eject(int drive)
610{
611 return -EINVAL;
612}
613#endif
614
615/*
616 * Debugging
617 * =========
618 */
619#ifdef DEBUGT
620static long unsigned debugtimer;
621
622static inline void set_debugt(void)
623{
624 debugtimer = jiffies;
625}
626
627static inline void debugt(const char *message)
628{
629 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800630 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632#else
633static inline void set_debugt(void) { }
634static inline void debugt(const char *message) { }
635#endif /* DEBUGT */
636
Joe Perchesa0a52d62010-03-10 15:20:52 -0800637typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700638static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640static const char *timeout_message;
641
642#ifdef FLOPPY_SANITY_CHECK
643static void is_alive(const char *message)
644{
645 /* this routine checks whether the floppy driver is "alive" */
646 if (test_bit(0, &fdc_busy) && command_status < 2
647 && !timer_pending(&fd_timeout)) {
648 DPRINT("timeout handler died: %s\n", message);
649 }
650}
651#endif
652
Joe Perches48c8cee2010-03-10 15:20:45 -0800653static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655#ifdef FLOPPY_SANITY_CHECK
656
657#define OLOGSIZE 20
658
Joe Perches48c8cee2010-03-10 15:20:45 -0800659static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660static unsigned long interruptjiffies;
661static unsigned long resultjiffies;
662static int resultsize;
663static unsigned long lastredo;
664
665static struct output_log {
666 unsigned char data;
667 unsigned char status;
668 unsigned long jiffies;
669} output_log[OLOGSIZE];
670
671static int output_log_pos;
672#endif
673
674#define current_reqD -1
675#define MAXTIMEOUT -2
676
677static void __reschedule_timeout(int drive, const char *message, int marg)
678{
679 if (drive == current_reqD)
680 drive = current_drive;
681 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700682 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 fd_timeout.expires = jiffies + 20UL * HZ;
684 drive = 0;
685 } else
686 fd_timeout.expires = jiffies + UDP->timeout;
687 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800688 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800689 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 timeout_message = message;
691}
692
693static void reschedule_timeout(int drive, const char *message, int marg)
694{
695 unsigned long flags;
696
697 spin_lock_irqsave(&floppy_lock, flags);
698 __reschedule_timeout(drive, message, marg);
699 spin_unlock_irqrestore(&floppy_lock, flags);
700}
701
Joe Perches48c8cee2010-03-10 15:20:45 -0800702#define INFBOUND(a, b) (a) = max_t(int, a, b)
703#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705/*
706 * Bottom half floppy driver.
707 * ==========================
708 *
709 * This part of the file contains the code talking directly to the hardware,
710 * and also the main service loop (seek-configure-spinup-command)
711 */
712
713/*
714 * disk change.
715 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
716 * and the last_checked date.
717 *
718 * last_checked is the date of the last check which showed 'no disk change'
719 * FD_DISK_CHANGE is set under two conditions:
720 * 1. The floppy has been changed after some i/o to that floppy already
721 * took place.
722 * 2. No floppy disk is in the drive. This is done in order to ensure that
723 * requests are quickly flushed in case there is no disk in the drive. It
724 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
725 * the drive.
726 *
727 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
728 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
729 * each seek. If a disk is present, the disk change line should also be
730 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
731 * change line is set, this means either that no disk is in the drive, or
732 * that it has been removed since the last seek.
733 *
734 * This means that we really have a third possibility too:
735 * The floppy has been changed after the last seek.
736 */
737
738static int disk_change(int drive)
739{
740 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800743 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 DPRINT("WARNING disk change called early\n");
745 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
746 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
747 DPRINT("probing disk change on unselected drive\n");
748 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
749 (unsigned int)FDCS->dor);
750 }
751#endif
752
Joe Perches87f530d2010-03-10 15:20:54 -0800753 debug_dcl(UDP->flags,
754 "checking disk change line for drive %d\n", drive);
755 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
756 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
757 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800760 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800762 set_bit(FD_VERIFY_BIT, &UDRS->flags);
763 /* verify write protection */
764
765 if (UDRS->maxblock) /* mark it changed */
766 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 /* invalidate its geometry */
769 if (UDRS->keep_data >= 0) {
770 if ((UDP->flags & FTD_MSG) &&
771 current_type[drive] != NULL)
772 DPRINT("Disk type is undefined after "
773 "disk change\n");
774 current_type[drive] = NULL;
775 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
776 }
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return 1;
779 } else {
780 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800781 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 }
783 return 0;
784}
785
786static inline int is_selected(int dor, int unit)
787{
788 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
789}
790
791static int set_dor(int fdc, char mask, char data)
792{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700793 unsigned char unit;
794 unsigned char drive;
795 unsigned char newdor;
796 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if (FDCS->address == -1)
799 return -1;
800
801 olddor = FDCS->dor;
802 newdor = (olddor & mask) | data;
803 if (newdor != olddor) {
804 unit = olddor & 0x3;
805 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
806 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800807 debug_dcl(UDP->flags,
808 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 disk_change(drive);
810 }
811 FDCS->dor = newdor;
812 fd_outb(newdor, FD_DOR);
813
814 unit = newdor & 0x3;
815 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
816 drive = REVDRIVE(fdc, unit);
817 UDRS->select_date = jiffies;
818 }
819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 return olddor;
821}
822
823static void twaddle(void)
824{
825 if (DP->select_delay)
826 return;
827 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
828 fd_outb(FDCS->dor, FD_DOR);
829 DRS->select_date = jiffies;
830}
831
832/* reset all driver information about the current fdc. This is needed after
833 * a reset, and after a raw command. */
834static 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 */
869static int _lock_fdc(int drive, int interruptible, int line)
870{
871 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800872 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 line);
874 return -1;
875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 if (test_and_set_bit(0, &fdc_busy)) {
878 DECLARE_WAITQUEUE(wait, current);
879 add_wait_queue(&fdc_wait, &wait);
880
881 for (;;) {
882 set_current_state(TASK_INTERRUPTIBLE);
883
884 if (!test_and_set_bit(0, &fdc_busy))
885 break;
886
887 schedule();
888
889 if (!NO_SIGNAL) {
890 remove_wait_queue(&fdc_wait, &wait);
891 return -EINTR;
892 }
893 }
894
895 set_current_state(TASK_RUNNING);
896 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700897 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 }
899 command_status = FD_COMMAND_NONE;
900
901 __reschedule_timeout(drive, "lock fdc", 0);
902 set_fdc(drive);
903 return 0;
904}
905
Joe Perches48c8cee2010-03-10 15:20:45 -0800906#define lock_fdc(drive, interruptible) \
907 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909/* unlocks the driver */
910static inline void unlock_fdc(void)
911{
912 unsigned long flags;
913
914 raw_cmd = NULL;
915 if (!test_bit(0, &fdc_busy))
916 DPRINT("FDC access conflict!\n");
917
918 if (do_floppy)
919 DPRINT("device interrupt still active at FDC release: %p!\n",
920 do_floppy);
921 command_status = FD_COMMAND_NONE;
922 spin_lock_irqsave(&floppy_lock, flags);
923 del_timer(&fd_timeout);
924 cont = NULL;
925 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900926 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 do_fd_request(floppy_queue);
928 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 wake_up(&fdc_wait);
930}
931
932/* switches the motor off after a given timeout */
933static void motor_off_callback(unsigned long nr)
934{
935 unsigned char mask = ~(0x10 << UNIT(nr));
936
937 set_dor(FDC(nr), mask, 0);
938}
939
940/* schedules motor off */
941static void floppy_off(unsigned int drive)
942{
943 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700944 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 if (!(FDCS->dor & (0x10 << UNIT(drive))))
947 return;
948
949 del_timer(motor_off_timer + drive);
950
951 /* make spindle stop in a position which minimizes spinup time
952 * next time */
953 if (UDP->rps) {
954 delta = jiffies - UDRS->first_read_date + HZ -
955 UDP->spindown_offset;
956 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
957 motor_off_timer[drive].expires =
958 jiffies + UDP->spindown - delta;
959 }
960 add_timer(motor_off_timer + drive);
961}
962
963/*
964 * cycle through all N_DRIVE floppy drives, for disk change testing.
965 * stopping at current drive. This is done before any long operation, to
966 * be sure to have up to date disk change information.
967 */
968static void scandrives(void)
969{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700970 int i;
971 int drive;
972 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 if (DP->select_delay)
975 return;
976
977 saved_drive = current_drive;
978 for (i = 0; i < N_DRIVE; i++) {
979 drive = (saved_drive + i + 1) % N_DRIVE;
980 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
981 continue; /* skip closed drives */
982 set_fdc(drive);
983 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
984 (0x10 << UNIT(drive))))
985 /* switch the motor off again, if it was off to
986 * begin with */
987 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
988 }
989 set_fdc(saved_drive);
990}
991
992static void empty(void)
993{
994}
995
David Howells65f27f32006-11-22 14:55:48 +0000996static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Joe Perches48c8cee2010-03-10 15:20:45 -0800998static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
David Howells65f27f32006-11-22 14:55:48 +00001000 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 schedule_work(&floppy_work);
1002}
1003
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001004static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
1006static void cancel_activity(void)
1007{
1008 unsigned long flags;
1009
1010 spin_lock_irqsave(&floppy_lock, flags);
1011 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001012 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 del_timer(&fd_timer);
1014 spin_unlock_irqrestore(&floppy_lock, flags);
1015}
1016
1017/* this function makes sure that the disk stays in the drive during the
1018 * transfer */
1019static void fd_watchdog(void)
1020{
Joe Perches87f530d2010-03-10 15:20:54 -08001021 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 if (disk_change(current_drive)) {
1024 DPRINT("disk removed during i/o\n");
1025 cancel_activity();
1026 cont->done(0);
1027 reset_fdc();
1028 } else {
1029 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001030 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 fd_timer.expires = jiffies + HZ / 10;
1032 add_timer(&fd_timer);
1033 }
1034}
1035
1036static void main_command_interrupt(void)
1037{
1038 del_timer(&fd_timer);
1039 cont->interrupt();
1040}
1041
1042/* waits for a delay (spinup or select) to pass */
1043static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1044{
1045 if (FDCS->reset) {
1046 reset_fdc(); /* do the reset during sleep to win time
1047 * if we don't need to sleep, it's a good
1048 * occasion anyways */
1049 return 1;
1050 }
1051
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001052 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 del_timer(&fd_timer);
1054 fd_timer.function = function;
1055 fd_timer.expires = delay;
1056 add_timer(&fd_timer);
1057 return 1;
1058 }
1059 return 0;
1060}
1061
1062static DEFINE_SPINLOCK(floppy_hlt_lock);
1063static int hlt_disabled;
1064static void floppy_disable_hlt(void)
1065{
1066 unsigned long flags;
1067
1068 spin_lock_irqsave(&floppy_hlt_lock, flags);
1069 if (!hlt_disabled) {
1070 hlt_disabled = 1;
1071#ifdef HAVE_DISABLE_HLT
1072 disable_hlt();
1073#endif
1074 }
1075 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1076}
1077
1078static void floppy_enable_hlt(void)
1079{
1080 unsigned long flags;
1081
1082 spin_lock_irqsave(&floppy_hlt_lock, flags);
1083 if (hlt_disabled) {
1084 hlt_disabled = 0;
1085#ifdef HAVE_DISABLE_HLT
1086 enable_hlt();
1087#endif
1088 }
1089 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1090}
1091
1092static void setup_DMA(void)
1093{
1094 unsigned long f;
1095
1096#ifdef FLOPPY_SANITY_CHECK
1097 if (raw_cmd->length == 0) {
1098 int i;
1099
Joe Perchesb46df352010-03-10 15:20:46 -08001100 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001102 pr_cont("%x,", raw_cmd->cmd[i]);
1103 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 cont->done(0);
1105 FDCS->reset = 1;
1106 return;
1107 }
1108 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001109 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 cont->done(0);
1111 FDCS->reset = 1;
1112 return;
1113 }
1114#endif
1115 f = claim_dma_lock();
1116 fd_disable_dma();
1117#ifdef fd_dma_setup
1118 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1119 (raw_cmd->flags & FD_RAW_READ) ?
1120 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1121 release_dma_lock(f);
1122 cont->done(0);
1123 FDCS->reset = 1;
1124 return;
1125 }
1126 release_dma_lock(f);
1127#else
1128 fd_clear_dma_ff();
1129 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1130 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1131 DMA_MODE_READ : DMA_MODE_WRITE);
1132 fd_set_dma_addr(raw_cmd->kernel_data);
1133 fd_set_dma_count(raw_cmd->length);
1134 virtual_dma_port = FDCS->address;
1135 fd_enable_dma();
1136 release_dma_lock(f);
1137#endif
1138 floppy_disable_hlt();
1139}
1140
1141static void show_floppy(void);
1142
1143/* waits until the fdc becomes ready */
1144static int wait_til_ready(void)
1145{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001146 int status;
1147 int counter;
1148
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 if (FDCS->reset)
1150 return -1;
1151 for (counter = 0; counter < 10000; counter++) {
1152 status = fd_inb(FD_STATUS);
1153 if (status & STATUS_READY)
1154 return status;
1155 }
1156 if (!initialising) {
1157 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1158 show_floppy();
1159 }
1160 FDCS->reset = 1;
1161 return -1;
1162}
1163
1164/* sends a command byte to the fdc */
1165static int output_byte(char byte)
1166{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001167 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001169 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 return -1;
1171 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1172 fd_outb(byte, FD_DATA);
1173#ifdef FLOPPY_SANITY_CHECK
1174 output_log[output_log_pos].data = byte;
1175 output_log[output_log_pos].status = status;
1176 output_log[output_log_pos].jiffies = jiffies;
1177 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1178#endif
1179 return 0;
1180 }
1181 FDCS->reset = 1;
1182 if (!initialising) {
1183 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1184 byte, fdc, status);
1185 show_floppy();
1186 }
1187 return -1;
1188}
1189
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190/* gets the response from the fdc */
1191static int result(void)
1192{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001193 int i;
1194 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
1196 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001197 status = wait_til_ready();
1198 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 break;
1200 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1201 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1202#ifdef FLOPPY_SANITY_CHECK
1203 resultjiffies = jiffies;
1204 resultsize = i;
1205#endif
1206 return i;
1207 }
1208 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1209 reply_buffer[i] = fd_inb(FD_DATA);
1210 else
1211 break;
1212 }
1213 if (!initialising) {
1214 DPRINT
1215 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1216 fdc, status, i);
1217 show_floppy();
1218 }
1219 FDCS->reset = 1;
1220 return -1;
1221}
1222
1223#define MORE_OUTPUT -2
1224/* does the fdc need more output? */
1225static int need_more_output(void)
1226{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001227 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001228
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001229 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 return -1;
1231 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1232 return MORE_OUTPUT;
1233 return result();
1234}
1235
1236/* Set perpendicular mode as required, based on data rate, if supported.
1237 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1238 */
1239static inline void perpendicular_mode(void)
1240{
1241 unsigned char perp_mode;
1242
1243 if (raw_cmd->rate & 0x40) {
1244 switch (raw_cmd->rate & 3) {
1245 case 0:
1246 perp_mode = 2;
1247 break;
1248 case 3:
1249 perp_mode = 3;
1250 break;
1251 default:
1252 DPRINT("Invalid data rate for perpendicular mode!\n");
1253 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001254 FDCS->reset = 1;
1255 /*
1256 * convenient way to return to
1257 * redo without too much hassle
1258 * (deep stack et al.)
1259 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 return;
1261 }
1262 } else
1263 perp_mode = 0;
1264
1265 if (FDCS->perp_mode == perp_mode)
1266 return;
1267 if (FDCS->version >= FDC_82077_ORIG) {
1268 output_byte(FD_PERPENDICULAR);
1269 output_byte(perp_mode);
1270 FDCS->perp_mode = perp_mode;
1271 } else if (perp_mode) {
1272 DPRINT("perpendicular mode not supported by this FDC.\n");
1273 }
1274} /* perpendicular_mode */
1275
1276static int fifo_depth = 0xa;
1277static int no_fifo;
1278
1279static int fdc_configure(void)
1280{
1281 /* Turn on FIFO */
1282 output_byte(FD_CONFIGURE);
1283 if (need_more_output() != MORE_OUTPUT)
1284 return 0;
1285 output_byte(0);
1286 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1287 output_byte(0); /* pre-compensation from track
1288 0 upwards */
1289 return 1;
1290}
1291
1292#define NOMINAL_DTR 500
1293
1294/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1295 * head load time, and DMA disable flag to values needed by floppy.
1296 *
1297 * The value "dtr" is the data transfer rate in Kbps. It is needed
1298 * to account for the data rate-based scaling done by the 82072 and 82077
1299 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1300 * 8272a).
1301 *
1302 * Note that changing the data transfer rate has a (probably deleterious)
1303 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1304 * fdc_specify is called again after each data transfer rate
1305 * change.
1306 *
1307 * srt: 1000 to 16000 in microseconds
1308 * hut: 16 to 240 milliseconds
1309 * hlt: 2 to 254 milliseconds
1310 *
1311 * These values are rounded up to the next highest available delay time.
1312 */
1313static void fdc_specify(void)
1314{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001315 unsigned char spec1;
1316 unsigned char spec2;
1317 unsigned long srt;
1318 unsigned long hlt;
1319 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 unsigned long dtr = NOMINAL_DTR;
1321 unsigned long scale_dtr = NOMINAL_DTR;
1322 int hlt_max_code = 0x7f;
1323 int hut_max_code = 0xf;
1324
1325 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1326 fdc_configure();
1327 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 }
1329
1330 switch (raw_cmd->rate & 0x03) {
1331 case 3:
1332 dtr = 1000;
1333 break;
1334 case 1:
1335 dtr = 300;
1336 if (FDCS->version >= FDC_82078) {
1337 /* chose the default rate table, not the one
1338 * where 1 = 2 Mbps */
1339 output_byte(FD_DRIVESPEC);
1340 if (need_more_output() == MORE_OUTPUT) {
1341 output_byte(UNIT(current_drive));
1342 output_byte(0xc0);
1343 }
1344 }
1345 break;
1346 case 2:
1347 dtr = 250;
1348 break;
1349 }
1350
1351 if (FDCS->version >= FDC_82072) {
1352 scale_dtr = dtr;
1353 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1354 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1355 }
1356
1357 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001358 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001359 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001361
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 SUPBOUND(srt, 0xf);
1363 INFBOUND(srt, 0);
1364
Julia Lawall061837b2008-09-22 14:57:16 -07001365 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (hlt < 0x01)
1367 hlt = 0x01;
1368 else if (hlt > 0x7f)
1369 hlt = hlt_max_code;
1370
Julia Lawall061837b2008-09-22 14:57:16 -07001371 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 if (hut < 0x1)
1373 hut = 0x1;
1374 else if (hut > 0xf)
1375 hut = hut_max_code;
1376
1377 spec1 = (srt << 4) | hut;
1378 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1379
1380 /* If these parameters did not change, just return with success */
1381 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1382 /* Go ahead and set spec1 and spec2 */
1383 output_byte(FD_SPECIFY);
1384 output_byte(FDCS->spec1 = spec1);
1385 output_byte(FDCS->spec2 = spec2);
1386 }
1387} /* fdc_specify */
1388
1389/* Set the FDC's data transfer rate on behalf of the specified drive.
1390 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1391 * of the specify command (i.e. using the fdc_specify function).
1392 */
1393static int fdc_dtr(void)
1394{
1395 /* If data rate not already set to desired value, set it. */
1396 if ((raw_cmd->rate & 3) == FDCS->dtr)
1397 return 0;
1398
1399 /* Set dtr */
1400 fd_outb(raw_cmd->rate & 3, FD_DCR);
1401
1402 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1403 * need a stabilization period of several milliseconds to be
1404 * enforced after data rate changes before R/W operations.
1405 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1406 */
1407 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001408 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1409 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410} /* fdc_dtr */
1411
1412static void tell_sector(void)
1413{
Joe Perchesb46df352010-03-10 15:20:46 -08001414 pr_cont(": track %d, head %d, sector %d, size %d",
1415 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416} /* tell_sector */
1417
Joe Perchesb46df352010-03-10 15:20:46 -08001418static void print_errors(void)
1419{
1420 DPRINT("");
1421 if (ST0 & ST0_ECE) {
1422 pr_cont("Recalibrate failed!");
1423 } else if (ST2 & ST2_CRC) {
1424 pr_cont("data CRC error");
1425 tell_sector();
1426 } else if (ST1 & ST1_CRC) {
1427 pr_cont("CRC error");
1428 tell_sector();
1429 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1430 (ST2 & ST2_MAM)) {
1431 if (!probing) {
1432 pr_cont("sector not found");
1433 tell_sector();
1434 } else
1435 pr_cont("probe failed...");
1436 } else if (ST2 & ST2_WC) { /* seek error */
1437 pr_cont("wrong cylinder");
1438 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1439 pr_cont("bad cylinder");
1440 } else {
1441 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1442 ST0, ST1, ST2);
1443 tell_sector();
1444 }
1445 pr_cont("\n");
1446}
1447
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448/*
1449 * OK, this error interpreting routine is called after a
1450 * DMA read/write has succeeded
1451 * or failed, so we check the results, and copy any buffers.
1452 * hhb: Added better error reporting.
1453 * ak: Made this into a separate routine.
1454 */
1455static int interpret_errors(void)
1456{
1457 char bad;
1458
1459 if (inr != 7) {
1460 DPRINT("-- FDC reply error");
1461 FDCS->reset = 1;
1462 return 1;
1463 }
1464
1465 /* check IC to find cause of interrupt */
1466 switch (ST0 & ST0_INTR) {
1467 case 0x40: /* error occurred during command execution */
1468 if (ST1 & ST1_EOC)
1469 return 0; /* occurs with pseudo-DMA */
1470 bad = 1;
1471 if (ST1 & ST1_WP) {
1472 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001473 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 cont->done(0);
1475 bad = 2;
1476 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001477 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 } else if (ST1 & ST1_OR) {
1479 if (DP->flags & FTD_MSG)
1480 DPRINT("Over/Underrun - retrying\n");
1481 bad = 0;
1482 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001483 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 }
1485 if (ST2 & ST2_WC || ST2 & ST2_BC)
1486 /* wrong cylinder => recal */
1487 DRS->track = NEED_2_RECAL;
1488 return bad;
1489 case 0x80: /* invalid command given */
1490 DPRINT("Invalid FDC command given!\n");
1491 cont->done(0);
1492 return 2;
1493 case 0xc0:
1494 DPRINT("Abnormal termination caused by polling\n");
1495 cont->error();
1496 return 2;
1497 default: /* (0) Normal command termination */
1498 return 0;
1499 }
1500}
1501
1502/*
1503 * This routine is called when everything should be correctly set up
1504 * for the transfer (i.e. floppy motor is on, the correct floppy is
1505 * selected, and the head is sitting on the right track).
1506 */
1507static void setup_rw_floppy(void)
1508{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001509 int i;
1510 int r;
1511 int flags;
1512 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 unsigned long ready_date;
1514 timeout_fn function;
1515
1516 flags = raw_cmd->flags;
1517 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1518 flags |= FD_RAW_INTR;
1519
1520 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1521 ready_date = DRS->spinup_date + DP->spinup;
1522 /* If spinup will take a long time, rerun scandrives
1523 * again just before spinup completion. Beware that
1524 * after scandrives, we must again wait for selection.
1525 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001526 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001528 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001530 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
1532 /* wait until the floppy is spinning fast enough */
1533 if (fd_wait_for_completion(ready_date, function))
1534 return;
1535 }
1536 dflags = DRS->flags;
1537
1538 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1539 setup_DMA();
1540
1541 if (flags & FD_RAW_INTR)
1542 do_floppy = main_command_interrupt;
1543
1544 r = 0;
1545 for (i = 0; i < raw_cmd->cmd_count; i++)
1546 r |= output_byte(raw_cmd->cmd[i]);
1547
1548 debugt("rw_command: ");
1549
1550 if (r) {
1551 cont->error();
1552 reset_fdc();
1553 return;
1554 }
1555
1556 if (!(flags & FD_RAW_INTR)) {
1557 inr = result();
1558 cont->interrupt();
1559 } else if (flags & FD_RAW_NEED_DISK)
1560 fd_watchdog();
1561}
1562
1563static int blind_seek;
1564
1565/*
1566 * This is the routine called after every seek (or recalibrate) interrupt
1567 * from the floppy controller.
1568 */
1569static void seek_interrupt(void)
1570{
1571 debugt("seek interrupt:");
1572 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1573 DPRINT("seek failed\n");
1574 DRS->track = NEED_2_RECAL;
1575 cont->error();
1576 cont->redo();
1577 return;
1578 }
1579 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001580 debug_dcl(DP->flags,
1581 "clearing NEWCHANGE flag because of effective seek\n");
1582 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001583 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1584 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 DRS->select_date = jiffies;
1586 }
1587 DRS->track = ST1;
1588 floppy_ready();
1589}
1590
1591static void check_wp(void)
1592{
Joe Perchese0298532010-03-10 15:20:55 -08001593 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1594 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 output_byte(FD_GETSTATUS);
1596 output_byte(UNIT(current_drive));
1597 if (result() != 1) {
1598 FDCS->reset = 1;
1599 return;
1600 }
Joe Perchese0298532010-03-10 15:20:55 -08001601 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1602 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001603 debug_dcl(DP->flags,
1604 "checking whether disk is write protected\n");
1605 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001607 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 else
Joe Perchese0298532010-03-10 15:20:55 -08001609 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 }
1611}
1612
1613static void seek_floppy(void)
1614{
1615 int track;
1616
1617 blind_seek = 0;
1618
Joe Perches87f530d2010-03-10 15:20:54 -08001619 debug_dcl(DP->flags, "calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
Joe Perchese0298532010-03-10 15:20:55 -08001621 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1623 /* the media changed flag should be cleared after the seek.
1624 * If it isn't, this means that there is really no disk in
1625 * the drive.
1626 */
Joe Perchese0298532010-03-10 15:20:55 -08001627 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 cont->done(0);
1629 cont->redo();
1630 return;
1631 }
1632 if (DRS->track <= NEED_1_RECAL) {
1633 recalibrate_floppy();
1634 return;
Joe Perchese0298532010-03-10 15:20:55 -08001635 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1637 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1638 /* we seek to clear the media-changed condition. Does anybody
1639 * know a more elegant way, which works on all drives? */
1640 if (raw_cmd->track)
1641 track = raw_cmd->track - 1;
1642 else {
1643 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1644 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1645 blind_seek = 1;
1646 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1647 }
1648 track = 1;
1649 }
1650 } else {
1651 check_wp();
1652 if (raw_cmd->track != DRS->track &&
1653 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1654 track = raw_cmd->track;
1655 else {
1656 setup_rw_floppy();
1657 return;
1658 }
1659 }
1660
1661 do_floppy = seek_interrupt;
1662 output_byte(FD_SEEK);
1663 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001664 if (output_byte(track) < 0) {
1665 reset_fdc();
1666 return;
1667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 debugt("seek command:");
1669}
1670
1671static void recal_interrupt(void)
1672{
1673 debugt("recal interrupt:");
1674 if (inr != 2)
1675 FDCS->reset = 1;
1676 else if (ST0 & ST0_ECE) {
1677 switch (DRS->track) {
1678 case NEED_1_RECAL:
1679 debugt("recal interrupt need 1 recal:");
1680 /* after a second recalibrate, we still haven't
1681 * reached track 0. Probably no drive. Raise an
1682 * error, as failing immediately might upset
1683 * computers possessed by the Devil :-) */
1684 cont->error();
1685 cont->redo();
1686 return;
1687 case NEED_2_RECAL:
1688 debugt("recal interrupt need 2 recal:");
1689 /* If we already did a recalibrate,
1690 * and we are not at track 0, this
1691 * means we have moved. (The only way
1692 * not to move at recalibration is to
1693 * be already at track 0.) Clear the
1694 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001695 debug_dcl(DP->flags,
1696 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
Joe Perchese0298532010-03-10 15:20:55 -08001698 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 DRS->select_date = jiffies;
1700 /* fall through */
1701 default:
1702 debugt("recal interrupt default:");
1703 /* Recalibrate moves the head by at
1704 * most 80 steps. If after one
1705 * recalibrate we don't have reached
1706 * track 0, this might mean that we
1707 * started beyond track 80. Try
1708 * again. */
1709 DRS->track = NEED_1_RECAL;
1710 break;
1711 }
1712 } else
1713 DRS->track = ST1;
1714 floppy_ready();
1715}
1716
1717static void print_result(char *message, int inr)
1718{
1719 int i;
1720
1721 DPRINT("%s ", message);
1722 if (inr >= 0)
1723 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001724 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1725 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726}
1727
1728/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001729irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 int do_print;
1732 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001733 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
1735 lasthandler = handler;
1736 interruptjiffies = jiffies;
1737
1738 f = claim_dma_lock();
1739 fd_disable_dma();
1740 release_dma_lock(f);
1741
1742 floppy_enable_hlt();
1743 do_floppy = NULL;
1744 if (fdc >= N_FDC || FDCS->address == -1) {
1745 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001746 pr_info("DOR0=%x\n", fdc_state[0].dor);
1747 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1748 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 is_alive("bizarre fdc");
1750 return IRQ_NONE;
1751 }
1752
1753 FDCS->reset = 0;
1754 /* We have to clear the reset flag here, because apparently on boxes
1755 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1756 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1757 * emission of the SENSEI's.
1758 * It is OK to emit floppy commands because we are in an interrupt
1759 * handler here, and thus we have to fear no interference of other
1760 * activity.
1761 */
1762
1763 do_print = !handler && print_unex && !initialising;
1764
1765 inr = result();
1766 if (do_print)
1767 print_result("unexpected interrupt", inr);
1768 if (inr == 0) {
1769 int max_sensei = 4;
1770 do {
1771 output_byte(FD_SENSEI);
1772 inr = result();
1773 if (do_print)
1774 print_result("sensei", inr);
1775 max_sensei--;
1776 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1777 && max_sensei);
1778 }
1779 if (!handler) {
1780 FDCS->reset = 1;
1781 return IRQ_NONE;
1782 }
1783 schedule_bh(handler);
1784 is_alive("normal interrupt end");
1785
1786 /* FIXME! Was it really for us? */
1787 return IRQ_HANDLED;
1788}
1789
1790static void recalibrate_floppy(void)
1791{
1792 debugt("recalibrate floppy:");
1793 do_floppy = recal_interrupt;
1794 output_byte(FD_RECALIBRATE);
Joe Perches2300f902010-03-10 15:20:49 -08001795 if (output_byte(UNIT(current_drive)) < 0) {
1796 reset_fdc();
1797 return;
1798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799}
1800
1801/*
1802 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1803 */
1804static void reset_interrupt(void)
1805{
1806 debugt("reset interrupt:");
1807 result(); /* get the status ready for set_fdc */
1808 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001809 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 cont->error(); /* a reset just after a reset. BAD! */
1811 }
1812 cont->redo();
1813}
1814
1815/*
1816 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1817 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1818 */
1819static void reset_fdc(void)
1820{
1821 unsigned long flags;
1822
1823 do_floppy = reset_interrupt;
1824 FDCS->reset = 0;
1825 reset_fdc_info(0);
1826
1827 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1828 /* Irrelevant for systems with true DMA (i386). */
1829
1830 flags = claim_dma_lock();
1831 fd_disable_dma();
1832 release_dma_lock(flags);
1833
1834 if (FDCS->version >= FDC_82072A)
1835 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1836 else {
1837 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1838 udelay(FD_RESET_DELAY);
1839 fd_outb(FDCS->dor, FD_DOR);
1840 }
1841}
1842
1843static void show_floppy(void)
1844{
1845 int i;
1846
Joe Perchesb46df352010-03-10 15:20:46 -08001847 pr_info("\n");
1848 pr_info("floppy driver state\n");
1849 pr_info("-------------------\n");
1850 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1851 jiffies, interruptjiffies, jiffies - interruptjiffies,
1852 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853
1854#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001855 pr_info("timeout_message=%s\n", timeout_message);
1856 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001858 pr_info("%2x %2x %lu\n",
1859 output_log[(i + output_log_pos) % OLOGSIZE].data,
1860 output_log[(i + output_log_pos) % OLOGSIZE].status,
1861 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1862 pr_info("last result at %lu\n", resultjiffies);
1863 pr_info("last redo_fd_request at %lu\n", lastredo);
1864 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1865 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866#endif
1867
Joe Perchesb46df352010-03-10 15:20:46 -08001868 pr_info("status=%x\n", fd_inb(FD_STATUS));
1869 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001871 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001872 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001873 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001875 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001877 pr_info("timer_function=%p\n", fd_timeout.function);
1878 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1879 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 }
Joe Perchesb46df352010-03-10 15:20:46 -08001881 pr_info("cont=%p\n", cont);
1882 pr_info("current_req=%p\n", current_req);
1883 pr_info("command_status=%d\n", command_status);
1884 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885}
1886
1887static void floppy_shutdown(unsigned long data)
1888{
1889 unsigned long flags;
1890
1891 if (!initialising)
1892 show_floppy();
1893 cancel_activity();
1894
1895 floppy_enable_hlt();
1896
1897 flags = claim_dma_lock();
1898 fd_disable_dma();
1899 release_dma_lock(flags);
1900
1901 /* avoid dma going to a random drive after shutdown */
1902
1903 if (!initialising)
1904 DPRINT("floppy timeout called\n");
1905 FDCS->reset = 1;
1906 if (cont) {
1907 cont->done(0);
1908 cont->redo(); /* this will recall reset when needed */
1909 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001910 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 process_fd_request();
1912 }
1913 is_alive("floppy shutdown");
1914}
1915
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001917static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001919 int mask;
1920 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922 mask = 0xfc;
1923 data = UNIT(current_drive);
1924 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1925 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1926 set_debugt();
1927 /* no read since this drive is running */
1928 DRS->first_read_date = 0;
1929 /* note motor start time if motor is not yet running */
1930 DRS->spinup_date = jiffies;
1931 data |= (0x10 << UNIT(current_drive));
1932 }
1933 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1934 mask &= ~(0x10 << UNIT(current_drive));
1935
1936 /* starts motor and selects floppy */
1937 del_timer(motor_off_timer + current_drive);
1938 set_dor(fdc, mask, data);
1939
1940 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001941 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1942 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943}
1944
1945static void floppy_ready(void)
1946{
Joe Perches045f9832010-03-10 15:20:47 -08001947 if (FDCS->reset) {
1948 reset_fdc();
1949 return;
1950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 if (start_motor(floppy_ready))
1952 return;
1953 if (fdc_dtr())
1954 return;
1955
Joe Perches87f530d2010-03-10 15:20:54 -08001956 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1958 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001959 twaddle(); /* this clears the dcl on certain
1960 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961
1962#ifdef fd_chose_dma_mode
1963 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1964 unsigned long flags = claim_dma_lock();
1965 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1966 release_dma_lock(flags);
1967 }
1968#endif
1969
1970 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1971 perpendicular_mode();
1972 fdc_specify(); /* must be done here because of hut, hlt ... */
1973 seek_floppy();
1974 } else {
1975 if ((raw_cmd->flags & FD_RAW_READ) ||
1976 (raw_cmd->flags & FD_RAW_WRITE))
1977 fdc_specify();
1978 setup_rw_floppy();
1979 }
1980}
1981
1982static void floppy_start(void)
1983{
1984 reschedule_timeout(current_reqD, "floppy start", 0);
1985
1986 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001987 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001988 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 floppy_ready();
1990}
1991
1992/*
1993 * ========================================================================
1994 * here ends the bottom half. Exported routines are:
1995 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1996 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1997 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1998 * and set_dor.
1999 * ========================================================================
2000 */
2001/*
2002 * General purpose continuations.
2003 * ==============================
2004 */
2005
2006static void do_wakeup(void)
2007{
2008 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2009 cont = NULL;
2010 command_status += 2;
2011 wake_up(&command_done);
2012}
2013
2014static struct cont_t wakeup_cont = {
2015 .interrupt = empty,
2016 .redo = do_wakeup,
2017 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002018 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019};
2020
2021static struct cont_t intr_cont = {
2022 .interrupt = empty,
2023 .redo = process_fd_request,
2024 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002025 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026};
2027
Jesper Juhl06f748c2007-10-16 23:30:57 -07002028static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029{
2030 int ret;
2031
2032 schedule_bh(handler);
2033
2034 if (command_status < 2 && NO_SIGNAL) {
2035 DECLARE_WAITQUEUE(wait, current);
2036
2037 add_wait_queue(&command_done, &wait);
2038 for (;;) {
2039 set_current_state(interruptible ?
2040 TASK_INTERRUPTIBLE :
2041 TASK_UNINTERRUPTIBLE);
2042
2043 if (command_status >= 2 || !NO_SIGNAL)
2044 break;
2045
2046 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 schedule();
2048 }
2049
2050 set_current_state(TASK_RUNNING);
2051 remove_wait_queue(&command_done, &wait);
2052 }
2053
2054 if (command_status < 2) {
2055 cancel_activity();
2056 cont = &intr_cont;
2057 reset_fdc();
2058 return -EINTR;
2059 }
2060
2061 if (FDCS->reset)
2062 command_status = FD_COMMAND_ERROR;
2063 if (command_status == FD_COMMAND_OKAY)
2064 ret = 0;
2065 else
2066 ret = -EIO;
2067 command_status = FD_COMMAND_NONE;
2068 return ret;
2069}
2070
2071static void generic_done(int result)
2072{
2073 command_status = result;
2074 cont = &wakeup_cont;
2075}
2076
2077static void generic_success(void)
2078{
2079 cont->done(1);
2080}
2081
2082static void generic_failure(void)
2083{
2084 cont->done(0);
2085}
2086
2087static void success_and_wakeup(void)
2088{
2089 generic_success();
2090 cont->redo();
2091}
2092
2093/*
2094 * formatting and rw support.
2095 * ==========================
2096 */
2097
2098static int next_valid_format(void)
2099{
2100 int probed_format;
2101
2102 probed_format = DRS->probed_format;
2103 while (1) {
2104 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2105 DRS->probed_format = 0;
2106 return 1;
2107 }
2108 if (floppy_type[DP->autodetect[probed_format]].sect) {
2109 DRS->probed_format = probed_format;
2110 return 0;
2111 }
2112 probed_format++;
2113 }
2114}
2115
2116static void bad_flp_intr(void)
2117{
2118 int err_count;
2119
2120 if (probing) {
2121 DRS->probed_format++;
2122 if (!next_valid_format())
2123 return;
2124 }
2125 err_count = ++(*errors);
2126 INFBOUND(DRWE->badness, err_count);
2127 if (err_count > DP->max_errors.abort)
2128 cont->done(0);
2129 if (err_count > DP->max_errors.reset)
2130 FDCS->reset = 1;
2131 else if (err_count > DP->max_errors.recal)
2132 DRS->track = NEED_2_RECAL;
2133}
2134
2135static void set_floppy(int drive)
2136{
2137 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002138
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 if (type)
2140 _floppy = floppy_type + type;
2141 else
2142 _floppy = current_type[drive];
2143}
2144
2145/*
2146 * formatting support.
2147 * ===================
2148 */
2149static void format_interrupt(void)
2150{
2151 switch (interpret_errors()) {
2152 case 1:
2153 cont->error();
2154 case 2:
2155 break;
2156 case 0:
2157 cont->done(1);
2158 }
2159 cont->redo();
2160}
2161
2162#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002163#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166static void setup_format_params(int track)
2167{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002168 int n;
2169 int il;
2170 int count;
2171 int head_shift;
2172 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 struct fparm {
2174 unsigned char track, head, sect, size;
2175 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
2177 raw_cmd = &default_raw_cmd;
2178 raw_cmd->track = track;
2179
Joe Perches48c8cee2010-03-10 15:20:45 -08002180 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2181 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 raw_cmd->rate = _floppy->rate & 0x43;
2183 raw_cmd->cmd_count = NR_F;
2184 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2185 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2186 F_SIZECODE = FD_SIZECODE(_floppy);
2187 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2188 F_GAP = _floppy->fmt_gap;
2189 F_FILL = FD_FILL_BYTE;
2190
2191 raw_cmd->kernel_data = floppy_track_buffer;
2192 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2193
2194 /* allow for about 30ms for data transport per track */
2195 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2196
2197 /* a ``cylinder'' is two tracks plus a little stepping time */
2198 track_shift = 2 * head_shift + 3;
2199
2200 /* position of logical sector 1 on this track */
2201 n = (track_shift * format_req.track + head_shift * format_req.head)
2202 % F_SECT_PER_TRACK;
2203
2204 /* determine interleave */
2205 il = 1;
2206 if (_floppy->fmt_gap < 0x22)
2207 il++;
2208
2209 /* initialize field */
2210 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2211 here[count].track = format_req.track;
2212 here[count].head = format_req.head;
2213 here[count].sect = 0;
2214 here[count].size = F_SIZECODE;
2215 }
2216 /* place logical sectors */
2217 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2218 here[n].sect = count;
2219 n = (n + il) % F_SECT_PER_TRACK;
2220 if (here[n].sect) { /* sector busy, find next free sector */
2221 ++n;
2222 if (n >= F_SECT_PER_TRACK) {
2223 n -= F_SECT_PER_TRACK;
2224 while (here[n].sect)
2225 ++n;
2226 }
2227 }
2228 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002229 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002231 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 }
2233}
2234
2235static void redo_format(void)
2236{
2237 buffer_track = -1;
2238 setup_format_params(format_req.track << STRETCH(_floppy));
2239 floppy_start();
2240 debugt("queue format request");
2241}
2242
2243static struct cont_t format_cont = {
2244 .interrupt = format_interrupt,
2245 .redo = redo_format,
2246 .error = bad_flp_intr,
2247 .done = generic_done
2248};
2249
2250static int do_format(int drive, struct format_descr *tmp_format_req)
2251{
2252 int ret;
2253
Joe Perches52a0d612010-03-10 15:20:53 -08002254 if (lock_fdc(drive, 1))
2255 return -EINTR;
2256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 set_floppy(drive);
2258 if (!_floppy ||
2259 _floppy->track > DP->tracks ||
2260 tmp_format_req->track >= _floppy->track ||
2261 tmp_format_req->head >= _floppy->head ||
2262 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2263 !_floppy->fmt_gap) {
2264 process_fd_request();
2265 return -EINVAL;
2266 }
2267 format_req = *tmp_format_req;
2268 format_errors = 0;
2269 cont = &format_cont;
2270 errors = &format_errors;
2271 IWAIT(redo_format);
2272 process_fd_request();
2273 return ret;
2274}
2275
2276/*
2277 * Buffer read/write and support
2278 * =============================
2279 */
2280
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002281static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282{
2283 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002284 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285
2286 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002287 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002288 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002289 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002293 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 current_req = NULL;
2295}
2296
2297/* new request_done. Can handle physical sectors which are smaller than a
2298 * logical buffer */
2299static void request_done(int uptodate)
2300{
2301 struct request_queue *q = floppy_queue;
2302 struct request *req = current_req;
2303 unsigned long flags;
2304 int block;
2305
2306 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002307 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
2309 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002310 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 return;
2312 }
2313
2314 if (uptodate) {
2315 /* maintain values for invalidation on geometry
2316 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002317 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 INFBOUND(DRS->maxblock, block);
2319 if (block > _floppy->sect)
2320 DRS->maxtrack = 1;
2321
2322 /* unlock chained buffers */
2323 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002324 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 spin_unlock_irqrestore(q->queue_lock, flags);
2326 } else {
2327 if (rq_data_dir(req) == WRITE) {
2328 /* record write error information */
2329 DRWE->write_errors++;
2330 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002331 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 DRWE->first_error_generation = DRS->generation;
2333 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002334 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 DRWE->last_error_generation = DRS->generation;
2336 }
2337 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002338 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 spin_unlock_irqrestore(q->queue_lock, flags);
2340 }
2341}
2342
2343/* Interrupt handler evaluating the result of the r/w operation */
2344static void rw_interrupt(void)
2345{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002346 int eoc;
2347 int ssize;
2348 int heads;
2349 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350
2351 if (R_HEAD >= 2) {
2352 /* some Toshiba floppy controllers occasionnally seem to
2353 * return bogus interrupts after read/write operations, which
2354 * can be recognized by a bad head number (>= 2) */
2355 return;
2356 }
2357
2358 if (!DRS->first_read_date)
2359 DRS->first_read_date = jiffies;
2360
2361 nr_sectors = 0;
2362 CODE2SIZE;
2363
2364 if (ST1 & ST1_EOC)
2365 eoc = 1;
2366 else
2367 eoc = 0;
2368
2369 if (COMMAND & 0x80)
2370 heads = 2;
2371 else
2372 heads = 1;
2373
2374 nr_sectors = (((R_TRACK - TRACK) * heads +
2375 R_HEAD - HEAD) * SECT_PER_TRACK +
2376 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2377
2378#ifdef FLOPPY_SANITY_CHECK
2379 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002380 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 DPRINT("long rw: %x instead of %lx\n",
2382 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002383 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2384 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2385 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2386 pr_info("heads=%d eoc=%d\n", heads, eoc);
2387 pr_info("spt=%d st=%d ss=%d\n",
2388 SECT_PER_TRACK, fsector_t, ssize);
2389 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 }
2391#endif
2392
2393 nr_sectors -= in_sector_offset;
2394 INFBOUND(nr_sectors, 0);
2395 SUPBOUND(current_count_sectors, nr_sectors);
2396
2397 switch (interpret_errors()) {
2398 case 2:
2399 cont->redo();
2400 return;
2401 case 1:
2402 if (!current_count_sectors) {
2403 cont->error();
2404 cont->redo();
2405 return;
2406 }
2407 break;
2408 case 0:
2409 if (!current_count_sectors) {
2410 cont->redo();
2411 return;
2412 }
2413 current_type[current_drive] = _floppy;
2414 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2415 break;
2416 }
2417
2418 if (probing) {
2419 if (DP->flags & FTD_MSG)
2420 DPRINT("Auto-detected floppy type %s in fd%d\n",
2421 _floppy->name, current_drive);
2422 current_type[current_drive] = _floppy;
2423 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2424 probing = 0;
2425 }
2426
2427 if (CT(COMMAND) != FD_READ ||
2428 raw_cmd->kernel_data == current_req->buffer) {
2429 /* transfer directly from buffer */
2430 cont->done(1);
2431 } else if (CT(COMMAND) == FD_READ) {
2432 buffer_track = raw_cmd->track;
2433 buffer_drive = current_drive;
2434 INFBOUND(buffer_max, nr_sectors + fsector_t);
2435 }
2436 cont->redo();
2437}
2438
2439/* Compute maximal contiguous buffer size. */
2440static int buffer_chain_size(void)
2441{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002443 int size;
2444 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 char *base;
2446
2447 base = bio_data(current_req->bio);
2448 size = 0;
2449
NeilBrown5705f702007-09-25 12:35:59 +02002450 rq_for_each_segment(bv, current_req, iter) {
2451 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2452 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453
NeilBrown5705f702007-09-25 12:35:59 +02002454 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 }
2456
2457 return size >> 9;
2458}
2459
2460/* Compute the maximal transfer size */
2461static int transfer_size(int ssize, int max_sector, int max_size)
2462{
2463 SUPBOUND(max_sector, fsector_t + max_size);
2464
2465 /* alignment */
2466 max_sector -= (max_sector % _floppy->sect) % ssize;
2467
2468 /* transfer size, beginning not aligned */
2469 current_count_sectors = max_sector - fsector_t;
2470
2471 return max_sector;
2472}
2473
2474/*
2475 * Move data from/to the track buffer to/from the buffer cache.
2476 */
2477static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2478{
2479 int remaining; /* number of transferred 512-byte sectors */
2480 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002481 char *buffer;
2482 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002483 int size;
2484 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
2486 max_sector = transfer_size(ssize,
2487 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002488 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002491 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002493 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494
2495 remaining = current_count_sectors << 9;
2496#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002497 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002499 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2500 pr_info("remaining=%d\n", remaining >> 9);
2501 pr_info("current_req->nr_sectors=%u\n",
2502 blk_rq_sectors(current_req));
2503 pr_info("current_req->current_nr_sectors=%u\n",
2504 blk_rq_cur_sectors(current_req));
2505 pr_info("max_sector=%d\n", max_sector);
2506 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 }
2508#endif
2509
2510 buffer_max = max(max_sector, buffer_max);
2511
2512 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2513
Tejun Heo1011c1b2009-05-07 22:24:45 +09002514 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
NeilBrown5705f702007-09-25 12:35:59 +02002516 rq_for_each_segment(bv, current_req, iter) {
2517 if (!remaining)
2518 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
NeilBrown5705f702007-09-25 12:35:59 +02002520 size = bv->bv_len;
2521 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
NeilBrown5705f702007-09-25 12:35:59 +02002523 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002525 if (dma_buffer + size >
2526 floppy_track_buffer + (max_buffer_sectors << 10) ||
2527 dma_buffer < floppy_track_buffer) {
2528 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002529 (int)((floppy_track_buffer - dma_buffer) >> 9));
2530 pr_info("fsector_t=%d buffer_min=%d\n",
2531 fsector_t, buffer_min);
2532 pr_info("current_count_sectors=%ld\n",
2533 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002535 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002536 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002537 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002538 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 }
NeilBrown5705f702007-09-25 12:35:59 +02002540 if (((unsigned long)buffer) % 512)
2541 DPRINT("%p buffer not aligned\n", buffer);
2542#endif
2543 if (CT(COMMAND) == FD_READ)
2544 memcpy(buffer, dma_buffer, size);
2545 else
2546 memcpy(dma_buffer, buffer, size);
2547
2548 remaining -= size;
2549 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 }
2551#ifdef FLOPPY_SANITY_CHECK
2552 if (remaining) {
2553 if (remaining > 0)
2554 max_sector -= remaining >> 9;
2555 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2556 }
2557#endif
2558}
2559
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560/* work around a bug in pseudo DMA
2561 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2562 * sending data. Hence we need a different way to signal the
2563 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2564 * does not work with MT, hence we can only transfer one head at
2565 * a time
2566 */
2567static void virtualdmabug_workaround(void)
2568{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002569 int hard_sectors;
2570 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
2572 if (CT(COMMAND) == FD_WRITE) {
2573 COMMAND &= ~0x80; /* switch off multiple track mode */
2574
2575 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2576 end_sector = SECTOR + hard_sectors - 1;
2577#ifdef FLOPPY_SANITY_CHECK
2578 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002579 pr_info("too many sectors %d > %d\n",
2580 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 return;
2582 }
2583#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002584 SECT_PER_TRACK = end_sector;
2585 /* make sure SECT_PER_TRACK
2586 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 }
2588}
2589
2590/*
2591 * Formulate a read/write request.
2592 * this routine decides where to load the data (directly to buffer, or to
2593 * tmp floppy area), how much data to load (the size of the buffer, the whole
2594 * track, or a single sector)
2595 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2596 * allocation on the fly, it should be done here. No other part should need
2597 * modification.
2598 */
2599
2600static int make_raw_rw_request(void)
2601{
2602 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002603 int max_sector;
2604 int max_size;
2605 int tracksize;
2606 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002609 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 return 0;
2611 }
2612
2613 set_fdc((long)current_req->rq_disk->private_data);
2614
2615 raw_cmd = &default_raw_cmd;
2616 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2617 FD_RAW_NEED_SEEK;
2618 raw_cmd->cmd_count = NR_RW;
2619 if (rq_data_dir(current_req) == READ) {
2620 raw_cmd->flags |= FD_RAW_READ;
2621 COMMAND = FM_MODE(_floppy, FD_READ);
2622 } else if (rq_data_dir(current_req) == WRITE) {
2623 raw_cmd->flags |= FD_RAW_WRITE;
2624 COMMAND = FM_MODE(_floppy, FD_WRITE);
2625 } else {
2626 DPRINT("make_raw_rw_request: unknown command\n");
2627 return 0;
2628 }
2629
2630 max_sector = _floppy->sect * _floppy->head;
2631
Tejun Heo83096eb2009-05-07 22:24:39 +09002632 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2633 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002635 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 current_count_sectors = 1;
2637 return 1;
2638 } else
2639 return 0;
2640 }
2641 HEAD = fsector_t / _floppy->sect;
2642
Keith Wansbrough9e491842008-09-22 14:57:17 -07002643 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002644 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2645 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 max_sector = _floppy->sect;
2647
2648 /* 2M disks have phantom sectors on the first track */
2649 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2650 max_sector = 2 * _floppy->sect / 3;
2651 if (fsector_t >= max_sector) {
2652 current_count_sectors =
2653 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002654 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return 1;
2656 }
2657 SIZECODE = 2;
2658 } else
2659 SIZECODE = FD_SIZECODE(_floppy);
2660 raw_cmd->rate = _floppy->rate & 0x43;
2661 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2662 raw_cmd->rate = 1;
2663
2664 if (SIZECODE)
2665 SIZECODE2 = 0xff;
2666 else
2667 SIZECODE2 = 0x80;
2668 raw_cmd->track = TRACK << STRETCH(_floppy);
2669 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2670 GAP = _floppy->gap;
2671 CODE2SIZE;
2672 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2673 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002674 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
2676 /* tracksize describes the size which can be filled up with sectors
2677 * of size ssize.
2678 */
2679 tracksize = _floppy->sect - _floppy->sect % ssize;
2680 if (tracksize < _floppy->sect) {
2681 SECT_PER_TRACK++;
2682 if (tracksize <= fsector_t % _floppy->sect)
2683 SECTOR--;
2684
2685 /* if we are beyond tracksize, fill up using smaller sectors */
2686 while (tracksize <= fsector_t % _floppy->sect) {
2687 while (tracksize + ssize > _floppy->sect) {
2688 SIZECODE--;
2689 ssize >>= 1;
2690 }
2691 SECTOR++;
2692 SECT_PER_TRACK++;
2693 tracksize += ssize;
2694 }
2695 max_sector = HEAD * _floppy->sect + tracksize;
2696 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2697 max_sector = _floppy->sect;
2698 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2699 /* for virtual DMA bug workaround */
2700 max_sector = _floppy->sect;
2701 }
2702
2703 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2704 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002705 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 if ((raw_cmd->track == buffer_track) &&
2707 (current_drive == buffer_drive) &&
2708 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2709 /* data already in track buffer */
2710 if (CT(COMMAND) == FD_READ) {
2711 copy_buffer(1, max_sector, buffer_max);
2712 return 1;
2713 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002714 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002716 unsigned int sectors;
2717
2718 sectors = fsector_t + blk_rq_sectors(current_req);
2719 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 max_size = ssize + ssize;
2721 else
2722 max_size = ssize;
2723 }
2724 raw_cmd->flags &= ~FD_RAW_WRITE;
2725 raw_cmd->flags |= FD_RAW_READ;
2726 COMMAND = FM_MODE(_floppy, FD_READ);
2727 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2728 unsigned long dma_limit;
2729 int direct, indirect;
2730
2731 indirect =
2732 transfer_size(ssize, max_sector,
2733 max_buffer_sectors * 2) - fsector_t;
2734
2735 /*
2736 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2737 * on a 64 bit machine!
2738 */
2739 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002740 dma_limit = (MAX_DMA_ADDRESS -
2741 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002742 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 /* 64 kb boundaries */
2745 if (CROSS_64KB(current_req->buffer, max_size << 9))
2746 max_size = (K_64 -
2747 ((unsigned long)current_req->buffer) %
2748 K_64) >> 9;
2749 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2750 /*
2751 * We try to read tracks, but if we get too many errors, we
2752 * go back to reading just one sector at a time.
2753 *
2754 * This means we should be able to read a sector even if there
2755 * are other bad sectors on this track.
2756 */
2757 if (!direct ||
2758 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002759 *errors < DP->max_errors.read_track &&
2760 ((!probing ||
2761 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002762 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 } else {
2764 raw_cmd->kernel_data = current_req->buffer;
2765 raw_cmd->length = current_count_sectors << 9;
2766 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002767 DPRINT("zero dma transfer attempted from make_raw_request\n");
2768 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 indirect, direct, fsector_t);
2770 return 0;
2771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 virtualdmabug_workaround();
2773 return 2;
2774 }
2775 }
2776
2777 if (CT(COMMAND) == FD_READ)
2778 max_size = max_sector; /* unbounded */
2779
2780 /* claim buffer track if needed */
2781 if (buffer_track != raw_cmd->track || /* bad track */
2782 buffer_drive != current_drive || /* bad drive */
2783 fsector_t > buffer_max ||
2784 fsector_t < buffer_min ||
2785 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002786 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002788 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2789 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 buffer_track = -1;
2791 buffer_drive = current_drive;
2792 buffer_max = buffer_min = aligned_sector_t;
2793 }
2794 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002795 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
2797 if (CT(COMMAND) == FD_WRITE) {
2798 /* copy write buffer to track buffer.
2799 * if we get here, we know that the write
2800 * is either aligned or the data already in the buffer
2801 * (buffer will be overwritten) */
2802#ifdef FLOPPY_SANITY_CHECK
2803 if (in_sector_offset && buffer_track == -1)
2804 DPRINT("internal error offset !=0 on write\n");
2805#endif
2806 buffer_track = raw_cmd->track;
2807 buffer_drive = current_drive;
2808 copy_buffer(ssize, max_sector,
2809 2 * max_buffer_sectors + buffer_min);
2810 } else
2811 transfer_size(ssize, max_sector,
2812 2 * max_buffer_sectors + buffer_min -
2813 aligned_sector_t);
2814
2815 /* round up current_count_sectors to get dma xfer size */
2816 raw_cmd->length = in_sector_offset + current_count_sectors;
2817 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2818 raw_cmd->length <<= 9;
2819#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 if ((raw_cmd->length < current_count_sectors << 9) ||
2821 (raw_cmd->kernel_data != current_req->buffer &&
2822 CT(COMMAND) == FD_WRITE &&
2823 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2824 aligned_sector_t < buffer_min)) ||
2825 raw_cmd->length % (128 << SIZECODE) ||
2826 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2827 DPRINT("fractionary current count b=%lx s=%lx\n",
2828 raw_cmd->length, current_count_sectors);
2829 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002830 pr_info("addr=%d, length=%ld\n",
2831 (int)((raw_cmd->kernel_data -
2832 floppy_track_buffer) >> 9),
2833 current_count_sectors);
2834 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2835 fsector_t, aligned_sector_t, max_sector, max_size);
2836 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2837 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2838 COMMAND, SECTOR, HEAD, TRACK);
2839 pr_info("buffer drive=%d\n", buffer_drive);
2840 pr_info("buffer track=%d\n", buffer_track);
2841 pr_info("buffer_min=%d\n", buffer_min);
2842 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 return 0;
2844 }
2845
2846 if (raw_cmd->kernel_data != current_req->buffer) {
2847 if (raw_cmd->kernel_data < floppy_track_buffer ||
2848 current_count_sectors < 0 ||
2849 raw_cmd->length < 0 ||
2850 raw_cmd->kernel_data + raw_cmd->length >
2851 floppy_track_buffer + (max_buffer_sectors << 10)) {
2852 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002853 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2854 fsector_t, buffer_min, raw_cmd->length >> 9);
2855 pr_info("current_count_sectors=%ld\n",
2856 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002858 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002860 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 return 0;
2862 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002863 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002864 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 DPRINT("buffer overrun in direct transfer\n");
2866 return 0;
2867 } else if (raw_cmd->length < current_count_sectors << 9) {
2868 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002869 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2870 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 }
2872 if (raw_cmd->length == 0) {
2873 DPRINT("zero dma transfer attempted from make_raw_request\n");
2874 return 0;
2875 }
2876#endif
2877
2878 virtualdmabug_workaround();
2879 return 2;
2880}
2881
2882static void redo_fd_request(void)
2883{
2884#define REPEAT {request_done(0); continue; }
2885 int drive;
2886 int tmp;
2887
2888 lastredo = jiffies;
2889 if (current_drive < N_DRIVE)
2890 floppy_off(current_drive);
2891
2892 for (;;) {
2893 if (!current_req) {
2894 struct request *req;
2895
2896 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002897 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 spin_unlock_irq(floppy_queue->queue_lock);
2899 if (!req) {
2900 do_floppy = NULL;
2901 unlock_fdc();
2902 return;
2903 }
2904 current_req = req;
2905 }
2906 drive = (long)current_req->rq_disk->private_data;
2907 set_fdc(drive);
2908 reschedule_timeout(current_reqD, "redo fd request", 0);
2909
2910 set_floppy(drive);
2911 raw_cmd = &default_raw_cmd;
2912 raw_cmd->flags = 0;
2913 if (start_motor(redo_fd_request))
2914 return;
2915 disk_change(current_drive);
2916 if (test_bit(current_drive, &fake_change) ||
Joe Perchese0298532010-03-10 15:20:55 -08002917 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 DPRINT("disk absent or changed during operation\n");
2919 REPEAT;
2920 }
2921 if (!_floppy) { /* Autodetection */
2922 if (!probing) {
2923 DRS->probed_format = 0;
2924 if (next_valid_format()) {
2925 DPRINT("no autodetectable formats\n");
2926 _floppy = NULL;
2927 REPEAT;
2928 }
2929 }
2930 probing = 1;
2931 _floppy =
2932 floppy_type + DP->autodetect[DRS->probed_format];
2933 } else
2934 probing = 0;
2935 errors = &(current_req->errors);
2936 tmp = make_raw_rw_request();
2937 if (tmp < 2) {
2938 request_done(tmp);
2939 continue;
2940 }
2941
Joe Perchese0298532010-03-10 15:20:55 -08002942 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 twaddle();
2944 schedule_bh(floppy_start);
2945 debugt("queue fd request");
2946 return;
2947 }
2948#undef REPEAT
2949}
2950
2951static struct cont_t rw_cont = {
2952 .interrupt = rw_interrupt,
2953 .redo = redo_fd_request,
2954 .error = bad_flp_intr,
2955 .done = request_done
2956};
2957
2958static void process_fd_request(void)
2959{
2960 cont = &rw_cont;
2961 schedule_bh(redo_fd_request);
2962}
2963
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002964static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965{
2966 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002967 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 return;
2969 }
2970
2971 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002972 pr_info("warning: usage count=0, current_req=%p exiting\n",
2973 current_req);
2974 pr_info("sect=%ld type=%x flags=%x\n",
2975 (long)blk_rq_pos(current_req), current_req->cmd_type,
2976 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 return;
2978 }
2979 if (test_bit(0, &fdc_busy)) {
2980 /* fdc busy, this new request will be treated when the
2981 current one is done */
2982 is_alive("do fd request, old request running");
2983 return;
2984 }
2985 lock_fdc(MAXTIMEOUT, 0);
2986 process_fd_request();
2987 is_alive("do fd request");
2988}
2989
2990static struct cont_t poll_cont = {
2991 .interrupt = success_and_wakeup,
2992 .redo = floppy_ready,
2993 .error = generic_failure,
2994 .done = generic_done
2995};
2996
2997static int poll_drive(int interruptible, int flag)
2998{
2999 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003000
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 /* no auto-sense, just clear dcl */
3002 raw_cmd = &default_raw_cmd;
3003 raw_cmd->flags = flag;
3004 raw_cmd->track = 0;
3005 raw_cmd->cmd_count = 0;
3006 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08003007 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08003008 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 WAIT(floppy_ready);
3010 return ret;
3011}
3012
3013/*
3014 * User triggered reset
3015 * ====================
3016 */
3017
3018static void reset_intr(void)
3019{
Joe Perchesb46df352010-03-10 15:20:46 -08003020 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021}
3022
3023static struct cont_t reset_cont = {
3024 .interrupt = reset_intr,
3025 .redo = success_and_wakeup,
3026 .error = generic_failure,
3027 .done = generic_done
3028};
3029
3030static int user_reset_fdc(int drive, int arg, int interruptible)
3031{
3032 int ret;
3033
Joe Perches52a0d612010-03-10 15:20:53 -08003034 if (lock_fdc(drive, interruptible))
3035 return -EINTR;
3036
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 if (arg == FD_RESET_ALWAYS)
3038 FDCS->reset = 1;
3039 if (FDCS->reset) {
3040 cont = &reset_cont;
3041 WAIT(reset_fdc);
3042 }
3043 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003044 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045}
3046
3047/*
3048 * Misc Ioctl's and support
3049 * ========================
3050 */
3051static inline int fd_copyout(void __user *param, const void *address,
3052 unsigned long size)
3053{
3054 return copy_to_user(param, address, size) ? -EFAULT : 0;
3055}
3056
Joe Perches48c8cee2010-03-10 15:20:45 -08003057static inline int fd_copyin(void __user *param, void *address,
3058 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059{
3060 return copy_from_user(address, param, size) ? -EFAULT : 0;
3061}
3062
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063static inline const char *drive_name(int type, int drive)
3064{
3065 struct floppy_struct *floppy;
3066
3067 if (type)
3068 floppy = floppy_type + type;
3069 else {
3070 if (UDP->native_format)
3071 floppy = floppy_type + UDP->native_format;
3072 else
3073 return "(null)";
3074 }
3075 if (floppy->name)
3076 return floppy->name;
3077 else
3078 return "(null)";
3079}
3080
3081/* raw commands */
3082static void raw_cmd_done(int flag)
3083{
3084 int i;
3085
3086 if (!flag) {
3087 raw_cmd->flags |= FD_RAW_FAILURE;
3088 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3089 } else {
3090 raw_cmd->reply_count = inr;
3091 if (raw_cmd->reply_count > MAX_REPLIES)
3092 raw_cmd->reply_count = 0;
3093 for (i = 0; i < raw_cmd->reply_count; i++)
3094 raw_cmd->reply[i] = reply_buffer[i];
3095
3096 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3097 unsigned long flags;
3098 flags = claim_dma_lock();
3099 raw_cmd->length = fd_get_dma_residue();
3100 release_dma_lock(flags);
3101 }
3102
3103 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3104 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3105 raw_cmd->flags |= FD_RAW_FAILURE;
3106
3107 if (disk_change(current_drive))
3108 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3109 else
3110 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3111 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3112 motor_off_callback(current_drive);
3113
3114 if (raw_cmd->next &&
3115 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3116 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3117 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3118 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3119 raw_cmd = raw_cmd->next;
3120 return;
3121 }
3122 }
3123 generic_done(flag);
3124}
3125
3126static struct cont_t raw_cmd_cont = {
3127 .interrupt = success_and_wakeup,
3128 .redo = floppy_start,
3129 .error = generic_failure,
3130 .done = raw_cmd_done
3131};
3132
3133static inline int raw_cmd_copyout(int cmd, char __user *param,
3134 struct floppy_raw_cmd *ptr)
3135{
3136 int ret;
3137
3138 while (ptr) {
Joe Perches86b12b42010-03-10 15:20:56 -08003139 ret = copy_to_user((void __user *)param, ptr, sizeof(*ptr));
3140 if (ret)
3141 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 param += sizeof(struct floppy_raw_cmd);
3143 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003144 if (ptr->length >= 0 &&
3145 ptr->length <= ptr->buffer_length) {
3146 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003147 ret = fd_copyout(ptr->data, ptr->kernel_data,
3148 length);
3149 if (ret)
3150 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 }
3153 ptr = ptr->next;
3154 }
3155 return 0;
3156}
3157
3158static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3159{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003160 struct floppy_raw_cmd *next;
3161 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
3163 this = *ptr;
3164 *ptr = NULL;
3165 while (this) {
3166 if (this->buffer_length) {
3167 fd_dma_mem_free((unsigned long)this->kernel_data,
3168 this->buffer_length);
3169 this->buffer_length = 0;
3170 }
3171 next = this->next;
3172 kfree(this);
3173 this = next;
3174 }
3175}
3176
3177static inline int raw_cmd_copyin(int cmd, char __user *param,
3178 struct floppy_raw_cmd **rcmd)
3179{
3180 struct floppy_raw_cmd *ptr;
3181 int ret;
3182 int i;
3183
3184 *rcmd = NULL;
3185 while (1) {
3186 ptr = (struct floppy_raw_cmd *)
3187 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3188 if (!ptr)
3189 return -ENOMEM;
3190 *rcmd = ptr;
Joe Perches86b12b42010-03-10 15:20:56 -08003191 ret = copy_from_user(ptr, (void __user *)param, sizeof(*ptr));
3192 if (ret)
3193 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 ptr->next = NULL;
3195 ptr->buffer_length = 0;
3196 param += sizeof(struct floppy_raw_cmd);
3197 if (ptr->cmd_count > 33)
3198 /* the command may now also take up the space
3199 * initially intended for the reply & the
3200 * reply count. Needed for long 82078 commands
3201 * such as RESTORE, which takes ... 17 command
3202 * bytes. Murphy's law #137: When you reserve
3203 * 16 bytes for a structure, you'll one day
3204 * discover that you really need 17...
3205 */
3206 return -EINVAL;
3207
3208 for (i = 0; i < 16; i++)
3209 ptr->reply[i] = 0;
3210 ptr->resultcode = 0;
3211 ptr->kernel_data = NULL;
3212
3213 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3214 if (ptr->length <= 0)
3215 return -EINVAL;
3216 ptr->kernel_data =
3217 (char *)fd_dma_mem_alloc(ptr->length);
3218 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3219 if (!ptr->kernel_data)
3220 return -ENOMEM;
3221 ptr->buffer_length = ptr->length;
3222 }
Joe Perches4575b552010-03-10 15:20:55 -08003223 if (ptr->flags & FD_RAW_WRITE) {
3224 ret = fd_copyin(ptr->data, ptr->kernel_data,
3225 ptr->length);
3226 if (ret)
3227 return ret;
3228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 rcmd = &(ptr->next);
3230 if (!(ptr->flags & FD_RAW_MORE))
3231 return 0;
3232 ptr->rate &= 0x43;
3233 }
3234}
3235
3236static int raw_cmd_ioctl(int cmd, void __user *param)
3237{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003239 int drive;
3240 int ret2;
3241 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
3243 if (FDCS->rawcmd <= 1)
3244 FDCS->rawcmd = 1;
3245 for (drive = 0; drive < N_DRIVE; drive++) {
3246 if (FDC(drive) != fdc)
3247 continue;
3248 if (drive == current_drive) {
3249 if (UDRS->fd_ref > 1) {
3250 FDCS->rawcmd = 2;
3251 break;
3252 }
3253 } else if (UDRS->fd_ref) {
3254 FDCS->rawcmd = 2;
3255 break;
3256 }
3257 }
3258
3259 if (FDCS->reset)
3260 return -EIO;
3261
3262 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3263 if (ret) {
3264 raw_cmd_free(&my_raw_cmd);
3265 return ret;
3266 }
3267
3268 raw_cmd = my_raw_cmd;
3269 cont = &raw_cmd_cont;
3270 ret = wait_til_done(floppy_start, 1);
Joe Perches87f530d2010-03-10 15:20:54 -08003271 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272
3273 if (ret != -EINTR && FDCS->reset)
3274 ret = -EIO;
3275
3276 DRS->track = NO_TRACK;
3277
3278 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3279 if (!ret)
3280 ret = ret2;
3281 raw_cmd_free(&my_raw_cmd);
3282 return ret;
3283}
3284
3285static int invalidate_drive(struct block_device *bdev)
3286{
3287 /* invalidate the buffer track to force a reread */
3288 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3289 process_fd_request();
3290 check_disk_change(bdev);
3291 return 0;
3292}
3293
3294static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3295 int drive, int type, struct block_device *bdev)
3296{
3297 int cnt;
3298
3299 /* sanity checking for parameters. */
3300 if (g->sect <= 0 ||
3301 g->head <= 0 ||
3302 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3303 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003304 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return -EINVAL;
3306 if (type) {
3307 if (!capable(CAP_SYS_ADMIN))
3308 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003309 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003310 if (lock_fdc(drive, 1)) {
3311 mutex_unlock(&open_lock);
3312 return -EINTR;
3313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 floppy_type[type] = *g;
3315 floppy_type[type].name = "user format";
3316 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3317 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3318 floppy_type[type].size + 1;
3319 process_fd_request();
3320 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3321 struct block_device *bdev = opened_bdev[cnt];
3322 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3323 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003324 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003326 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 } else {
3328 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003329
3330 if (lock_fdc(drive, 1))
3331 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003332 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 /* notice a disk change immediately, else
3334 * we lose our settings immediately*/
Joe Perches4575b552010-03-10 15:20:55 -08003335 if (poll_drive(1, FD_RAW_NEED_DISK) == -EINTR)
3336 return -EINTR;
3337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 oldStretch = g->stretch;
3339 user_params[drive] = *g;
3340 if (buffer_drive == drive)
3341 SUPBOUND(buffer_max, user_params[drive].sect);
3342 current_type[drive] = &user_params[drive];
3343 floppy_sizes[drive] = user_params[drive].size;
3344 if (cmd == FDDEFPRM)
3345 DRS->keep_data = -1;
3346 else
3347 DRS->keep_data = 1;
3348 /* invalidation. Invalidate only when needed, i.e.
3349 * when there are already sectors in the buffer cache
3350 * whose number will change. This is useful, because
3351 * mtools often changes the geometry of the disk after
3352 * looking at the boot block */
3353 if (DRS->maxblock > user_params[drive].sect ||
3354 DRS->maxtrack ||
3355 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003356 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 invalidate_drive(bdev);
3358 else
3359 process_fd_request();
3360 }
3361 return 0;
3362}
3363
3364/* handle obsolete ioctl's */
3365static int ioctl_table[] = {
3366 FDCLRPRM,
3367 FDSETPRM,
3368 FDDEFPRM,
3369 FDGETPRM,
3370 FDMSGON,
3371 FDMSGOFF,
3372 FDFMTBEG,
3373 FDFMTTRK,
3374 FDFMTEND,
3375 FDSETEMSGTRESH,
3376 FDFLUSH,
3377 FDSETMAXERRS,
3378 FDGETMAXERRS,
3379 FDGETDRVTYP,
3380 FDSETDRVPRM,
3381 FDGETDRVPRM,
3382 FDGETDRVSTAT,
3383 FDPOLLDRVSTAT,
3384 FDRESET,
3385 FDGETFDCSTAT,
3386 FDWERRORCLR,
3387 FDWERRORGET,
3388 FDRAWCMD,
3389 FDEJECT,
3390 FDTWADDLE
3391};
3392
3393static inline int normalize_ioctl(int *cmd, int *size)
3394{
3395 int i;
3396
3397 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3398 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3399 *size = _IOC_SIZE(*cmd);
3400 *cmd = ioctl_table[i];
3401 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003402 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 return -EFAULT;
3404 }
3405 return 0;
3406 }
3407 }
3408 return -EINVAL;
3409}
3410
3411static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3412{
3413 if (type)
3414 *g = &floppy_type[type];
3415 else {
Joe Perches52a0d612010-03-10 15:20:53 -08003416 if (lock_fdc(drive, 0))
3417 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003418 if (poll_drive(0, 0) == -EINTR)
3419 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 process_fd_request();
3421 *g = current_type[drive];
3422 }
3423 if (!*g)
3424 return -ENODEV;
3425 return 0;
3426}
3427
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003428static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3429{
3430 int drive = (long)bdev->bd_disk->private_data;
3431 int type = ITYPE(drive_state[drive].fd_device);
3432 struct floppy_struct *g;
3433 int ret;
3434
3435 ret = get_floppy_geometry(drive, type, &g);
3436 if (ret)
3437 return ret;
3438
3439 geo->heads = g->head;
3440 geo->sectors = g->sect;
3441 geo->cylinders = g->track;
3442 return 0;
3443}
3444
Al Viroa4af9b42008-03-02 09:27:55 -05003445static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 unsigned long param)
3447{
Al Viroa4af9b42008-03-02 09:27:55 -05003448#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
Al Viroa4af9b42008-03-02 09:27:55 -05003450 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003451 int type = ITYPE(UDRS->fd_device);
3452 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 int ret;
3454 int size;
3455 union inparam {
3456 struct floppy_struct g; /* geometry */
3457 struct format_descr f;
3458 struct floppy_max_errors max_errors;
3459 struct floppy_drive_params dp;
3460 } inparam; /* parameters coming from user space */
3461 const char *outparam; /* parameters passed back to user space */
3462
3463 /* convert compatibility eject ioctls into floppy eject ioctl.
3464 * We do this in order to provide a means to eject floppy disks before
3465 * installing the new fdutils package */
3466 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003467 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 DPRINT("obsolete eject ioctl\n");
3469 DPRINT("please use floppycontrol --eject\n");
3470 cmd = FDEJECT;
3471 }
3472
Joe Perchesa81ee542010-03-10 15:20:46 -08003473 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 return -EINVAL;
3475
Joe Perchesa81ee542010-03-10 15:20:46 -08003476 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003477 ret = normalize_ioctl(&cmd, &size);
3478 if (ret)
3479 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003480
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 /* permission checks */
3482 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3483 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3484 return -EPERM;
3485
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003486 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3487 return -EINVAL;
3488
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003490 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003491 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3492 ret = fd_copyin((void __user *)param, &inparam, size);
3493 if (ret)
3494 return ret;
3495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496
Joe Perchesda273652010-03-10 15:20:52 -08003497 switch (cmd) {
3498 case FDEJECT:
3499 if (UDRS->fd_ref != 1)
3500 /* somebody else has this drive open */
3501 return -EBUSY;
Joe Perches52a0d612010-03-10 15:20:53 -08003502 if (lock_fdc(drive, 1))
3503 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504
Joe Perchesda273652010-03-10 15:20:52 -08003505 /* do the actual eject. Fails on
3506 * non-Sparc architectures */
3507 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508
Joe Perchese0298532010-03-10 15:20:55 -08003509 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3510 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003511 process_fd_request();
3512 return ret;
3513 case FDCLRPRM:
Joe Perches52a0d612010-03-10 15:20:53 -08003514 if (lock_fdc(drive, 1))
3515 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003516 current_type[drive] = NULL;
3517 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3518 UDRS->keep_data = 0;
3519 return invalidate_drive(bdev);
3520 case FDSETPRM:
3521 case FDDEFPRM:
3522 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3523 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003524 ret = get_floppy_geometry(drive, type,
Joe Perchesda273652010-03-10 15:20:52 -08003525 (struct floppy_struct **)
Joe Perches4575b552010-03-10 15:20:55 -08003526 &outparam);
3527 if (ret)
3528 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003529 break;
3530 case FDMSGON:
3531 UDP->flags |= FTD_MSG;
3532 return 0;
3533 case FDMSGOFF:
3534 UDP->flags &= ~FTD_MSG;
3535 return 0;
3536 case FDFMTBEG:
Joe Perches52a0d612010-03-10 15:20:53 -08003537 if (lock_fdc(drive, 1))
3538 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003539 if (poll_drive(1, FD_RAW_NEED_DISK) == -EINTR)
3540 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003541 ret = UDRS->flags;
3542 process_fd_request();
3543 if (ret & FD_VERIFY)
3544 return -ENODEV;
3545 if (!(ret & FD_DISK_WRITABLE))
3546 return -EROFS;
3547 return 0;
3548 case FDFMTTRK:
3549 if (UDRS->fd_ref != 1)
3550 return -EBUSY;
3551 return do_format(drive, &inparam.f);
3552 case FDFMTEND:
3553 case FDFLUSH:
Joe Perches52a0d612010-03-10 15:20:53 -08003554 if (lock_fdc(drive, 1))
3555 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003556 return invalidate_drive(bdev);
3557 case FDSETEMSGTRESH:
3558 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3559 return 0;
3560 case FDGETMAXERRS:
3561 outparam = (const char *)&UDP->max_errors;
3562 break;
3563 case FDSETMAXERRS:
3564 UDP->max_errors = inparam.max_errors;
3565 break;
3566 case FDGETDRVTYP:
3567 outparam = drive_name(type, drive);
3568 SUPBOUND(size, strlen(outparam) + 1);
3569 break;
3570 case FDSETDRVPRM:
3571 *UDP = inparam.dp;
3572 break;
3573 case FDGETDRVPRM:
3574 outparam = (const char *)UDP;
3575 break;
3576 case FDPOLLDRVSTAT:
Joe Perches52a0d612010-03-10 15:20:53 -08003577 if (lock_fdc(drive, 1))
3578 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003579 if (poll_drive(1, FD_RAW_NEED_DISK) == -EINTR)
3580 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003581 process_fd_request();
3582 /* fall through */
3583 case FDGETDRVSTAT:
3584 outparam = (const char *)UDRS;
3585 break;
3586 case FDRESET:
3587 return user_reset_fdc(drive, (int)param, 1);
3588 case FDGETFDCSTAT:
3589 outparam = (const char *)UFDCS;
3590 break;
3591 case FDWERRORCLR:
3592 memset(UDRWE, 0, sizeof(*UDRWE));
3593 return 0;
3594 case FDWERRORGET:
3595 outparam = (const char *)UDRWE;
3596 break;
3597 case FDRAWCMD:
3598 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 return -EINVAL;
Joe Perches52a0d612010-03-10 15:20:53 -08003600 if (lock_fdc(drive, 1))
3601 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003602 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003603 i = raw_cmd_ioctl(cmd, (void __user *)param);
3604 if (i == -EINTR)
3605 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003606 process_fd_request();
3607 return i;
3608 case FDTWADDLE:
Joe Perches52a0d612010-03-10 15:20:53 -08003609 if (lock_fdc(drive, 1))
3610 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003611 twaddle();
3612 process_fd_request();
3613 return 0;
3614 default:
3615 return -EINVAL;
3616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617
3618 if (_IOC_DIR(cmd) & _IOC_READ)
3619 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003620
3621 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622}
3623
3624static void __init config_types(void)
3625{
Joe Perchesb46df352010-03-10 15:20:46 -08003626 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 int drive;
3628
3629 /* read drive info out of physical CMOS */
3630 drive = 0;
3631 if (!UDP->cmos)
3632 UDP->cmos = FLOPPY0_TYPE;
3633 drive = 1;
3634 if (!UDP->cmos && FLOPPY1_TYPE)
3635 UDP->cmos = FLOPPY1_TYPE;
3636
Jesper Juhl06f748c2007-10-16 23:30:57 -07003637 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
3639 for (drive = 0; drive < N_DRIVE; drive++) {
3640 unsigned int type = UDP->cmos;
3641 struct floppy_drive_params *params;
3642 const char *name = NULL;
3643 static char temparea[32];
3644
Tobias Klauser945f3902006-01-08 01:05:11 -08003645 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 params = &default_drive_params[type].params;
3647 if (type) {
3648 name = default_drive_params[type].name;
3649 allowed_drive_mask |= 1 << drive;
3650 } else
3651 allowed_drive_mask &= ~(1 << drive);
3652 } else {
3653 params = &default_drive_params[0].params;
3654 sprintf(temparea, "unknown type %d (usb?)", type);
3655 name = temparea;
3656 }
3657 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003658 const char *prepend;
3659 if (!has_drive) {
3660 prepend = "";
3661 has_drive = true;
3662 pr_info("Floppy drive(s):");
3663 } else {
3664 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 }
Joe Perchesb46df352010-03-10 15:20:46 -08003666
3667 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 }
3669 *UDP = *params;
3670 }
Joe Perchesb46df352010-03-10 15:20:46 -08003671
3672 if (has_drive)
3673 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674}
3675
Al Viroa4af9b42008-03-02 09:27:55 -05003676static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677{
Al Viroa4af9b42008-03-02 09:27:55 -05003678 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003680 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 if (UDRS->fd_ref < 0)
3682 UDRS->fd_ref = 0;
3683 else if (!UDRS->fd_ref--) {
3684 DPRINT("floppy_release with fd_ref == 0");
3685 UDRS->fd_ref = 0;
3686 }
3687 if (!UDRS->fd_ref)
3688 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003689 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003690
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 return 0;
3692}
3693
3694/*
3695 * floppy_open check for aliasing (/dev/fd0 can be the same as
3696 * /dev/PS0 etc), and disallows simultaneous access to the same
3697 * drive with different device numbers.
3698 */
Al Viroa4af9b42008-03-02 09:27:55 -05003699static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700{
Al Viroa4af9b42008-03-02 09:27:55 -05003701 int drive = (long)bdev->bd_disk->private_data;
3702 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 int try;
3704 int res = -EBUSY;
3705 char *tmp;
3706
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003707 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003709 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 goto out2;
3711
3712 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003713 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3714 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 }
3716
Al Viroa4af9b42008-03-02 09:27:55 -05003717 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 goto out2;
3719
Al Viroa4af9b42008-03-02 09:27:55 -05003720 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 UDRS->fd_ref = -1;
3722 else
3723 UDRS->fd_ref++;
3724
Al Viroa4af9b42008-03-02 09:27:55 -05003725 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726
3727 res = -ENXIO;
3728
3729 if (!floppy_track_buffer) {
3730 /* if opening an ED drive, reserve a big buffer,
3731 * else reserve a small one */
3732 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3733 try = 64; /* Only 48 actually useful */
3734 else
3735 try = 32; /* Only 24 actually useful */
3736
3737 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3738 if (!tmp && !floppy_track_buffer) {
3739 try >>= 1; /* buffer only one side */
3740 INFBOUND(try, 16);
3741 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3742 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003743 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 if (!tmp && !floppy_track_buffer) {
3746 DPRINT("Unable to allocate DMA memory\n");
3747 goto out;
3748 }
3749 if (floppy_track_buffer) {
3750 if (tmp)
3751 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3752 } else {
3753 buffer_min = buffer_max = -1;
3754 floppy_track_buffer = tmp;
3755 max_buffer_sectors = try;
3756 }
3757 }
3758
Al Viroa4af9b42008-03-02 09:27:55 -05003759 new_dev = MINOR(bdev->bd_dev);
3760 UDRS->fd_device = new_dev;
3761 set_capacity(disks[drive], floppy_sizes[new_dev]);
3762 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 if (buffer_drive == drive)
3764 buffer_track = -1;
3765 }
3766
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 if (UFDCS->rawcmd == 1)
3768 UFDCS->rawcmd = 2;
3769
Al Viroa4af9b42008-03-02 09:27:55 -05003770 if (!(mode & FMODE_NDELAY)) {
3771 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003773 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003774 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 goto out;
3776 }
3777 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003778 if ((mode & FMODE_WRITE) &&
3779 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 goto out;
3781 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003782 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 return 0;
3784out:
3785 if (UDRS->fd_ref < 0)
3786 UDRS->fd_ref = 0;
3787 else
3788 UDRS->fd_ref--;
3789 if (!UDRS->fd_ref)
3790 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003792 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 return res;
3794}
3795
3796/*
3797 * Check if the disk has been changed or if a change has been faked.
3798 */
3799static int check_floppy_change(struct gendisk *disk)
3800{
3801 int drive = (long)disk->private_data;
3802
Joe Perchese0298532010-03-10 15:20:55 -08003803 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3804 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 return 1;
3806
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003807 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 lock_fdc(drive, 0);
3809 poll_drive(0, 0);
3810 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 }
3812
Joe Perchese0298532010-03-10 15:20:55 -08003813 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3814 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 test_bit(drive, &fake_change) ||
3816 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3817 return 1;
3818 return 0;
3819}
3820
3821/*
3822 * This implements "read block 0" for floppy_revalidate().
3823 * Needed for format autodetection, checking whether there is
3824 * a disk in the drive, and whether that disk is writable.
3825 */
3826
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003827static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830}
3831
3832static int __floppy_read_block_0(struct block_device *bdev)
3833{
3834 struct bio bio;
3835 struct bio_vec bio_vec;
3836 struct completion complete;
3837 struct page *page;
3838 size_t size;
3839
3840 page = alloc_page(GFP_NOIO);
3841 if (!page) {
3842 process_fd_request();
3843 return -ENOMEM;
3844 }
3845
3846 size = bdev->bd_block_size;
3847 if (!size)
3848 size = 1024;
3849
3850 bio_init(&bio);
3851 bio.bi_io_vec = &bio_vec;
3852 bio_vec.bv_page = page;
3853 bio_vec.bv_len = size;
3854 bio_vec.bv_offset = 0;
3855 bio.bi_vcnt = 1;
3856 bio.bi_idx = 0;
3857 bio.bi_size = size;
3858 bio.bi_bdev = bdev;
3859 bio.bi_sector = 0;
3860 init_completion(&complete);
3861 bio.bi_private = &complete;
3862 bio.bi_end_io = floppy_rb0_complete;
3863
3864 submit_bio(READ, &bio);
3865 generic_unplug_device(bdev_get_queue(bdev));
3866 process_fd_request();
3867 wait_for_completion(&complete);
3868
3869 __free_page(page);
3870
3871 return 0;
3872}
3873
3874/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3875 * the bootblock (block 0). "Autodetection" is also needed to check whether
3876 * there is a disk in the drive at all... Thus we also do it for fixed
3877 * geometry formats */
3878static int floppy_revalidate(struct gendisk *disk)
3879{
3880 int drive = (long)disk->private_data;
3881#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3882 int cf;
3883 int res = 0;
3884
Joe Perchese0298532010-03-10 15:20:55 -08003885 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3886 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
3887 test_bit(drive, &fake_change) || NO_GEOM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003889 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 return -EFAULT;
3891 }
3892 lock_fdc(drive, 0);
Joe Perchese0298532010-03-10 15:20:55 -08003893 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3894 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3896 process_fd_request(); /*already done by another thread */
3897 return 0;
3898 }
3899 UDRS->maxblock = 0;
3900 UDRS->maxtrack = 0;
3901 if (buffer_drive == drive)
3902 buffer_track = -1;
3903 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003904 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 if (cf)
3906 UDRS->generation++;
3907 if (NO_GEOM) {
3908 /* auto-sensing */
3909 res = __floppy_read_block_0(opened_bdev[drive]);
3910 } else {
3911 if (cf)
3912 poll_drive(0, FD_RAW_NEED_DISK);
3913 process_fd_request();
3914 }
3915 }
3916 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3917 return res;
3918}
3919
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003920static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003921 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003922 .open = floppy_open,
3923 .release = floppy_release,
3924 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003925 .getgeo = fd_getgeo,
3926 .media_changed = check_floppy_change,
3927 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930/*
3931 * Floppy Driver initialization
3932 * =============================
3933 */
3934
3935/* Determine the floppy disk controller type */
3936/* This routine was written by David C. Niemi */
3937static char __init get_fdc_version(void)
3938{
3939 int r;
3940
3941 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3942 if (FDCS->reset)
3943 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003944 r = result();
3945 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 return FDC_NONE; /* No FDC present ??? */
3947 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003948 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3950 }
3951 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003952 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3953 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 return FDC_UNKNOWN;
3955 }
3956
3957 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003958 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3960 }
3961
3962 output_byte(FD_PERPENDICULAR);
3963 if (need_more_output() == MORE_OUTPUT) {
3964 output_byte(0);
3965 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003966 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 return FDC_82072A; /* 82072A as found on Sparcs. */
3968 }
3969
3970 output_byte(FD_UNLOCK);
3971 r = result();
3972 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003973 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003974 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 * LOCK/UNLOCK */
3976 }
3977 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003978 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3979 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 return FDC_UNKNOWN;
3981 }
3982 output_byte(FD_PARTID);
3983 r = result();
3984 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003985 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3986 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 return FDC_UNKNOWN;
3988 }
3989 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003990 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 return FDC_82077; /* Revised 82077AA passes all the tests */
3992 }
3993 switch (reply_buffer[0] >> 5) {
3994 case 0x0:
3995 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003996 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 return FDC_82078;
3998 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003999 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 return FDC_82078;
4001 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004002 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 return FDC_S82078B;
4004 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004005 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 return FDC_87306;
4007 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004008 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4009 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 return FDC_82078_UNKN;
4011 }
4012} /* get_fdc_version */
4013
4014/* lilo configuration */
4015
4016static void __init floppy_set_flags(int *ints, int param, int param2)
4017{
4018 int i;
4019
4020 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4021 if (param)
4022 default_drive_params[i].params.flags |= param2;
4023 else
4024 default_drive_params[i].params.flags &= ~param2;
4025 }
4026 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4027}
4028
4029static void __init daring(int *ints, int param, int param2)
4030{
4031 int i;
4032
4033 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4034 if (param) {
4035 default_drive_params[i].params.select_delay = 0;
4036 default_drive_params[i].params.flags |=
4037 FD_SILENT_DCL_CLEAR;
4038 } else {
4039 default_drive_params[i].params.select_delay =
4040 2 * HZ / 100;
4041 default_drive_params[i].params.flags &=
4042 ~FD_SILENT_DCL_CLEAR;
4043 }
4044 }
4045 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4046}
4047
4048static void __init set_cmos(int *ints, int dummy, int dummy2)
4049{
4050 int current_drive = 0;
4051
4052 if (ints[0] != 2) {
4053 DPRINT("wrong number of parameters for CMOS\n");
4054 return;
4055 }
4056 current_drive = ints[1];
4057 if (current_drive < 0 || current_drive >= 8) {
4058 DPRINT("bad drive for set_cmos\n");
4059 return;
4060 }
4061#if N_FDC > 1
4062 if (current_drive >= 4 && !FDC2)
4063 FDC2 = 0x370;
4064#endif
4065 DP->cmos = ints[2];
4066 DPRINT("setting CMOS code to %d\n", ints[2]);
4067}
4068
4069static struct param_table {
4070 const char *name;
4071 void (*fn) (int *ints, int param, int param2);
4072 int *var;
4073 int def_param;
4074 int param2;
4075} config_params[] __initdata = {
4076 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4077 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4078 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4079 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4080 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4081 {"daring", daring, NULL, 1, 0},
4082#if N_FDC > 1
4083 {"two_fdc", NULL, &FDC2, 0x370, 0},
4084 {"one_fdc", NULL, &FDC2, 0, 0},
4085#endif
4086 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4087 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4088 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4089 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4090 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4091 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4092 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4093 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4094 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4095 {"nofifo", NULL, &no_fifo, 0x20, 0},
4096 {"usefifo", NULL, &no_fifo, 0, 0},
4097 {"cmos", set_cmos, NULL, 0, 0},
4098 {"slow", NULL, &slow_floppy, 1, 0},
4099 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4100 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4101 {"L40SX", NULL, &print_unex, 0, 0}
4102
4103 EXTRA_FLOPPY_PARAMS
4104};
4105
4106static int __init floppy_setup(char *str)
4107{
4108 int i;
4109 int param;
4110 int ints[11];
4111
4112 str = get_options(str, ARRAY_SIZE(ints), ints);
4113 if (str) {
4114 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4115 if (strcmp(str, config_params[i].name) == 0) {
4116 if (ints[0])
4117 param = ints[1];
4118 else
4119 param = config_params[i].def_param;
4120 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004121 config_params[i].fn(ints, param,
4122 config_params[i].
4123 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 if (config_params[i].var) {
4125 DPRINT("%s=%d\n", str, param);
4126 *config_params[i].var = param;
4127 }
4128 return 1;
4129 }
4130 }
4131 }
4132 if (str) {
4133 DPRINT("unknown floppy option [%s]\n", str);
4134
4135 DPRINT("allowed options are:");
4136 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004137 pr_cont(" %s", config_params[i].name);
4138 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 } else
4140 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004141 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 return 0;
4143}
4144
4145static int have_no_fdc = -ENODEV;
4146
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004147static ssize_t floppy_cmos_show(struct device *dev,
4148 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004149{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004150 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004151 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004152
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004153 drive = p->id;
4154 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004155}
Joe Perches48c8cee2010-03-10 15:20:45 -08004156
4157DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004158
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159static void floppy_device_release(struct device *dev)
4160{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161}
4162
Frans Popc90cd332009-07-25 22:24:54 +02004163static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004164{
4165 int fdc;
4166
4167 for (fdc = 0; fdc < N_FDC; fdc++)
4168 if (FDCS->address != -1)
4169 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4170
4171 return 0;
4172}
4173
Alexey Dobriyan47145212009-12-14 18:00:08 -08004174static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004175 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004176 .restore = floppy_resume,
4177};
4178
4179static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004180 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004181 .name = "floppy",
4182 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004183 },
4184};
4185
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004186static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
4188static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4189{
4190 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4191 if (drive >= N_DRIVE ||
4192 !(allowed_drive_mask & (1 << drive)) ||
4193 fdc_state[FDC(drive)].version == FDC_NONE)
4194 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004195 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 return NULL;
4197 *part = 0;
4198 return get_disk(disks[drive]);
4199}
4200
4201static int __init floppy_init(void)
4202{
4203 int i, unit, drive;
4204 int err, dr;
4205
Kumar Gala68e1ee62008-09-22 14:41:31 -07004206#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004207 if (check_legacy_ioport(FDC1))
4208 return -ENODEV;
4209#endif
4210
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 raw_cmd = NULL;
4212
4213 for (dr = 0; dr < N_DRIVE; dr++) {
4214 disks[dr] = alloc_disk(1);
4215 if (!disks[dr]) {
4216 err = -ENOMEM;
4217 goto out_put_disk;
4218 }
4219
4220 disks[dr]->major = FLOPPY_MAJOR;
4221 disks[dr]->first_minor = TOMINOR(dr);
4222 disks[dr]->fops = &floppy_fops;
4223 sprintf(disks[dr]->disk_name, "fd%d", dr);
4224
4225 init_timer(&motor_off_timer[dr]);
4226 motor_off_timer[dr].data = dr;
4227 motor_off_timer[dr].function = motor_off_callback;
4228 }
4229
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 err = register_blkdev(FLOPPY_MAJOR, "fd");
4231 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004232 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004234 err = platform_driver_register(&floppy_driver);
4235 if (err)
4236 goto out_unreg_blkdev;
4237
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4239 if (!floppy_queue) {
4240 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004241 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004243 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244
4245 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4246 floppy_find, NULL, NULL);
4247
4248 for (i = 0; i < 256; i++)
4249 if (ITYPE(i))
4250 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4251 else
4252 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4253
4254 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4255 config_types();
4256
4257 for (i = 0; i < N_FDC; i++) {
4258 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004259 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 FDCS->dtr = -1;
4261 FDCS->dor = 0x4;
4262#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004263 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264#ifdef __mc68000__
4265 if (MACH_IS_SUN3X)
4266#endif
4267 FDCS->version = FDC_82072A;
4268#endif
4269 }
4270
4271 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 fdc_state[0].address = FDC1;
4273 if (fdc_state[0].address == -1) {
4274 del_timer(&fd_timeout);
4275 err = -ENODEV;
4276 goto out_unreg_region;
4277 }
4278#if N_FDC > 1
4279 fdc_state[1].address = FDC2;
4280#endif
4281
4282 fdc = 0; /* reset fdc in case of unexpected interrupt */
4283 err = floppy_grab_irq_and_dma();
4284 if (err) {
4285 del_timer(&fd_timeout);
4286 err = -EBUSY;
4287 goto out_unreg_region;
4288 }
4289
4290 /* initialise drive state */
4291 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004292 memset(UDRS, 0, sizeof(*UDRS));
4293 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004294 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4295 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4296 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 UDRS->fd_device = -1;
4298 floppy_track_buffer = NULL;
4299 max_buffer_sectors = 0;
4300 }
4301 /*
4302 * Small 10 msec delay to let through any interrupt that
4303 * initialization might have triggered, to not
4304 * confuse detection:
4305 */
4306 msleep(10);
4307
4308 for (i = 0; i < N_FDC; i++) {
4309 fdc = i;
4310 FDCS->driver_version = FD_DRIVER_VERSION;
4311 for (unit = 0; unit < 4; unit++)
4312 FDCS->track[unit] = 0;
4313 if (FDCS->address == -1)
4314 continue;
4315 FDCS->rawcmd = 2;
4316 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4317 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004318 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 FDCS->address = -1;
4320 FDCS->version = FDC_NONE;
4321 continue;
4322 }
4323 /* Try to determine the floppy controller type */
4324 FDCS->version = get_fdc_version();
4325 if (FDCS->version == FDC_NONE) {
4326 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004327 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 FDCS->address = -1;
4329 continue;
4330 }
4331 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4332 can_use_virtual_dma = 0;
4333
4334 have_no_fdc = 0;
4335 /* Not all FDCs seem to be able to handle the version command
4336 * properly, so force a reset for the standard FDC clones,
4337 * to avoid interrupt garbage.
4338 */
4339 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4340 }
4341 fdc = 0;
4342 del_timer(&fd_timeout);
4343 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 initialising = 0;
4345 if (have_no_fdc) {
4346 DPRINT("no floppy controllers found\n");
4347 err = have_no_fdc;
4348 goto out_flush_work;
4349 }
4350
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 for (drive = 0; drive < N_DRIVE; drive++) {
4352 if (!(allowed_drive_mask & (1 << drive)))
4353 continue;
4354 if (fdc_state[FDC(drive)].version == FDC_NONE)
4355 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004356
4357 floppy_device[drive].name = floppy_device_name;
4358 floppy_device[drive].id = drive;
4359 floppy_device[drive].dev.release = floppy_device_release;
4360
4361 err = platform_device_register(&floppy_device[drive]);
4362 if (err)
4363 goto out_flush_work;
4364
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004365 err = device_create_file(&floppy_device[drive].dev,
4366 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004367 if (err)
4368 goto out_unreg_platform_dev;
4369
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 /* to be cleaned up... */
4371 disks[drive]->private_data = (void *)(long)drive;
4372 disks[drive]->queue = floppy_queue;
4373 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004374 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 add_disk(disks[drive]);
4376 }
4377
4378 return 0;
4379
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004380out_unreg_platform_dev:
4381 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382out_flush_work:
4383 flush_scheduled_work();
4384 if (usage_count)
4385 floppy_release_irq_and_dma();
4386out_unreg_region:
4387 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4388 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004389out_unreg_driver:
4390 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391out_unreg_blkdev:
4392 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393out_put_disk:
4394 while (dr--) {
4395 del_timer(&motor_off_timer[dr]);
4396 put_disk(disks[dr]);
4397 }
4398 return err;
4399}
4400
4401static DEFINE_SPINLOCK(floppy_usage_lock);
4402
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004403static const struct io_region {
4404 int offset;
4405 int size;
4406} io_regions[] = {
4407 { 2, 1 },
4408 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4409 { 4, 2 },
4410 /* address + 6 is reserved, and may be taken by IDE.
4411 * Unfortunately, Adaptec doesn't know this :-(, */
4412 { 7, 1 },
4413};
4414
4415static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4416{
4417 while (p != io_regions) {
4418 p--;
4419 release_region(FDCS->address + p->offset, p->size);
4420 }
4421}
4422
4423#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4424
4425static int floppy_request_regions(int fdc)
4426{
4427 const struct io_region *p;
4428
4429 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004430 if (!request_region(FDCS->address + p->offset,
4431 p->size, "floppy")) {
4432 DPRINT("Floppy io-port 0x%04lx in use\n",
4433 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004434 floppy_release_allocated_regions(fdc, p);
4435 return -EBUSY;
4436 }
4437 }
4438 return 0;
4439}
4440
4441static void floppy_release_regions(int fdc)
4442{
4443 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4444}
4445
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446static int floppy_grab_irq_and_dma(void)
4447{
4448 unsigned long flags;
4449
4450 spin_lock_irqsave(&floppy_usage_lock, flags);
4451 if (usage_count++) {
4452 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4453 return 0;
4454 }
4455 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004456
4457 /*
4458 * We might have scheduled a free_irq(), wait it to
4459 * drain first:
4460 */
4461 flush_scheduled_work();
4462
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 if (fd_request_irq()) {
4464 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4465 FLOPPY_IRQ);
4466 spin_lock_irqsave(&floppy_usage_lock, flags);
4467 usage_count--;
4468 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4469 return -1;
4470 }
4471 if (fd_request_dma()) {
4472 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4473 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004474 if (can_use_virtual_dma & 2)
4475 use_virtual_dma = can_use_virtual_dma = 1;
4476 if (!(can_use_virtual_dma & 1)) {
4477 fd_free_irq();
4478 spin_lock_irqsave(&floppy_usage_lock, flags);
4479 usage_count--;
4480 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4481 return -1;
4482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 }
4484
4485 for (fdc = 0; fdc < N_FDC; fdc++) {
4486 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004487 if (floppy_request_regions(fdc))
4488 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 }
4490 }
4491 for (fdc = 0; fdc < N_FDC; fdc++) {
4492 if (FDCS->address != -1) {
4493 reset_fdc_info(1);
4494 fd_outb(FDCS->dor, FD_DOR);
4495 }
4496 }
4497 fdc = 0;
4498 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4499
4500 for (fdc = 0; fdc < N_FDC; fdc++)
4501 if (FDCS->address != -1)
4502 fd_outb(FDCS->dor, FD_DOR);
4503 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004504 * The driver will try and free resources and relies on us
4505 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 */
4507 fdc = 0;
4508 irqdma_allocated = 1;
4509 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004510cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 fd_free_irq();
4512 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004513 while (--fdc >= 0)
4514 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 spin_lock_irqsave(&floppy_usage_lock, flags);
4516 usage_count--;
4517 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4518 return -1;
4519}
4520
4521static void floppy_release_irq_and_dma(void)
4522{
4523 int old_fdc;
4524#ifdef FLOPPY_SANITY_CHECK
4525#ifndef __sparc__
4526 int drive;
4527#endif
4528#endif
4529 long tmpsize;
4530 unsigned long tmpaddr;
4531 unsigned long flags;
4532
4533 spin_lock_irqsave(&floppy_usage_lock, flags);
4534 if (--usage_count) {
4535 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4536 return;
4537 }
4538 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4539 if (irqdma_allocated) {
4540 fd_disable_dma();
4541 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004542 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 irqdma_allocated = 0;
4544 }
4545 set_dor(0, ~0, 8);
4546#if N_FDC > 1
4547 set_dor(1, ~8, 0);
4548#endif
4549 floppy_enable_hlt();
4550
4551 if (floppy_track_buffer && max_buffer_sectors) {
4552 tmpsize = max_buffer_sectors * 1024;
4553 tmpaddr = (unsigned long)floppy_track_buffer;
4554 floppy_track_buffer = NULL;
4555 max_buffer_sectors = 0;
4556 buffer_min = buffer_max = -1;
4557 fd_dma_mem_free(tmpaddr, tmpsize);
4558 }
4559#ifdef FLOPPY_SANITY_CHECK
4560#ifndef __sparc__
4561 for (drive = 0; drive < N_FDC * 4; drive++)
4562 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004563 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564#endif
4565
4566 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004567 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004569 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004570 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004571 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572#endif
4573 old_fdc = fdc;
4574 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004575 if (FDCS->address != -1)
4576 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 fdc = old_fdc;
4578}
4579
4580#ifdef MODULE
4581
4582static char *floppy;
4583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584static void __init parse_floppy_cfg_string(char *cfg)
4585{
4586 char *ptr;
4587
4588 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004589 ptr = cfg;
4590 while (*cfg && *cfg != ' ' && *cfg != '\t')
4591 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 if (*cfg) {
4593 *cfg = '\0';
4594 cfg++;
4595 }
4596 if (*ptr)
4597 floppy_setup(ptr);
4598 }
4599}
4600
Jon Schindler7afea3b2008-04-29 00:59:21 -07004601static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602{
4603 if (floppy)
4604 parse_floppy_cfg_string(floppy);
4605 return floppy_init();
4606}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004607module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608
Jon Schindler7afea3b2008-04-29 00:59:21 -07004609static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610{
4611 int drive;
4612
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4614 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004615 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616
4617 for (drive = 0; drive < N_DRIVE; drive++) {
4618 del_timer_sync(&motor_off_timer[drive]);
4619
4620 if ((allowed_drive_mask & (1 << drive)) &&
4621 fdc_state[FDC(drive)].version != FDC_NONE) {
4622 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004623 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4624 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 }
4626 put_disk(disks[drive]);
4627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628
4629 del_timer_sync(&fd_timeout);
4630 del_timer_sync(&fd_timer);
4631 blk_cleanup_queue(floppy_queue);
4632
4633 if (usage_count)
4634 floppy_release_irq_and_dma();
4635
4636 /* eject disk, if any */
4637 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638}
Joe Perches48c8cee2010-03-10 15:20:45 -08004639
Jon Schindler7afea3b2008-04-29 00:59:21 -07004640module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641
4642module_param(floppy, charp, 0);
4643module_param(FLOPPY_IRQ, int, 0);
4644module_param(FLOPPY_DMA, int, 0);
4645MODULE_AUTHOR("Alain L. Knaff");
4646MODULE_SUPPORTED_DEVICE("fd");
4647MODULE_LICENSE("GPL");
4648
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004649/* This doesn't actually get used other than for module information */
4650static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004651 {"PNP0700", 0},
4652 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004653};
Joe Perches48c8cee2010-03-10 15:20:45 -08004654
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004655MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4656
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657#else
4658
4659__setup("floppy=", floppy_setup);
4660module_init(floppy_init)
4661#endif
4662
4663MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);