blob: 028d7e4749d0f08f601615ce301179792f72388a [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))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
523/* Errors during formatting are counted here. */
524static int format_errors;
525
526/* Format request descriptor. */
527static struct format_descr format_req;
528
529/*
530 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
531 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
532 * H is head unload time (1=16ms, 2=32ms, etc)
533 */
534
535/*
536 * Track buffer
537 * Because these are written to by the DMA controller, they must
538 * not contain a 64k byte boundary crossing, or data will be
539 * corrupted/lost.
540 */
541static char *floppy_track_buffer;
542static int max_buffer_sectors;
543
544static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700545typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800547 void (*interrupt)(void);
548 /* this is called after the interrupt of the
549 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700550 void (*redo)(void); /* this is called to retry the operation */
551 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 done_f done; /* this is called to say if the operation has
553 * succeeded/failed */
554} *cont;
555
556static void floppy_ready(void);
557static void floppy_start(void);
558static void process_fd_request(void);
559static void recalibrate_floppy(void);
560static void floppy_shutdown(unsigned long);
561
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800562static int floppy_request_regions(int);
563static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564static int floppy_grab_irq_and_dma(void);
565static void floppy_release_irq_and_dma(void);
566
567/*
568 * The "reset" variable should be tested whenever an interrupt is scheduled,
569 * after the commands have been sent. This is to ensure that the driver doesn't
570 * get wedged when the interrupt doesn't come because of a failed command.
571 * reset doesn't need to be tested before sending commands, because
572 * output_byte is automatically disabled when reset is set.
573 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574static void reset_fdc(void);
575
576/*
577 * These are global variables, as that's the easiest way to give
578 * information to interrupts. They are the data used for the current
579 * request.
580 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800581#define NO_TRACK -1
582#define NEED_1_RECAL -2
583#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
585static int usage_count;
586
587/* buffer related variables */
588static int buffer_track = -1;
589static int buffer_drive = -1;
590static int buffer_min = -1;
591static int buffer_max = -1;
592
593/* fdc related variables, should end up in a struct */
594static struct floppy_fdc_state fdc_state[N_FDC];
595static int fdc; /* current fdc */
596
597static struct floppy_struct *_floppy = floppy_type;
598static unsigned char current_drive;
599static long current_count_sectors;
600static unsigned char fsector_t; /* sector in track */
601static unsigned char in_sector_offset; /* offset within physical sector,
602 * expressed in units of 512 bytes */
603
604#ifndef fd_eject
605static inline int fd_eject(int drive)
606{
607 return -EINVAL;
608}
609#endif
610
611/*
612 * Debugging
613 * =========
614 */
615#ifdef DEBUGT
616static long unsigned debugtimer;
617
618static inline void set_debugt(void)
619{
620 debugtimer = jiffies;
621}
622
623static inline void debugt(const char *message)
624{
625 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800626 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627}
628#else
629static inline void set_debugt(void) { }
630static inline void debugt(const char *message) { }
631#endif /* DEBUGT */
632
Joe Perchesa0a52d62010-03-10 15:20:52 -0800633typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700634static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636static const char *timeout_message;
637
638#ifdef FLOPPY_SANITY_CHECK
639static void is_alive(const char *message)
640{
641 /* this routine checks whether the floppy driver is "alive" */
642 if (test_bit(0, &fdc_busy) && command_status < 2
643 && !timer_pending(&fd_timeout)) {
644 DPRINT("timeout handler died: %s\n", message);
645 }
646}
647#endif
648
Joe Perches48c8cee2010-03-10 15:20:45 -0800649static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651#ifdef FLOPPY_SANITY_CHECK
652
653#define OLOGSIZE 20
654
Joe Perches48c8cee2010-03-10 15:20:45 -0800655static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656static unsigned long interruptjiffies;
657static unsigned long resultjiffies;
658static int resultsize;
659static unsigned long lastredo;
660
661static struct output_log {
662 unsigned char data;
663 unsigned char status;
664 unsigned long jiffies;
665} output_log[OLOGSIZE];
666
667static int output_log_pos;
668#endif
669
670#define current_reqD -1
671#define MAXTIMEOUT -2
672
673static void __reschedule_timeout(int drive, const char *message, int marg)
674{
675 if (drive == current_reqD)
676 drive = current_drive;
677 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700678 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 fd_timeout.expires = jiffies + 20UL * HZ;
680 drive = 0;
681 } else
682 fd_timeout.expires = jiffies + UDP->timeout;
683 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800684 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800685 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 timeout_message = message;
687}
688
689static void reschedule_timeout(int drive, const char *message, int marg)
690{
691 unsigned long flags;
692
693 spin_lock_irqsave(&floppy_lock, flags);
694 __reschedule_timeout(drive, message, marg);
695 spin_unlock_irqrestore(&floppy_lock, flags);
696}
697
Joe Perches48c8cee2010-03-10 15:20:45 -0800698#define INFBOUND(a, b) (a) = max_t(int, a, b)
699#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701/*
702 * Bottom half floppy driver.
703 * ==========================
704 *
705 * This part of the file contains the code talking directly to the hardware,
706 * and also the main service loop (seek-configure-spinup-command)
707 */
708
709/*
710 * disk change.
711 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
712 * and the last_checked date.
713 *
714 * last_checked is the date of the last check which showed 'no disk change'
715 * FD_DISK_CHANGE is set under two conditions:
716 * 1. The floppy has been changed after some i/o to that floppy already
717 * took place.
718 * 2. No floppy disk is in the drive. This is done in order to ensure that
719 * requests are quickly flushed in case there is no disk in the drive. It
720 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
721 * the drive.
722 *
723 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
724 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
725 * each seek. If a disk is present, the disk change line should also be
726 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
727 * change line is set, this means either that no disk is in the drive, or
728 * that it has been removed since the last seek.
729 *
730 * This means that we really have a third possibility too:
731 * The floppy has been changed after the last seek.
732 */
733
734static int disk_change(int drive)
735{
736 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800739 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 DPRINT("WARNING disk change called early\n");
741 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
742 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
743 DPRINT("probing disk change on unselected drive\n");
744 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
745 (unsigned int)FDCS->dor);
746 }
747#endif
748
Joe Perches87f530d2010-03-10 15:20:54 -0800749 debug_dcl(UDP->flags,
750 "checking disk change line for drive %d\n", drive);
751 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
752 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
753 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
754
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800756 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800758 set_bit(FD_VERIFY_BIT, &UDRS->flags);
759 /* verify write protection */
760
761 if (UDRS->maxblock) /* mark it changed */
762 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764 /* invalidate its geometry */
765 if (UDRS->keep_data >= 0) {
766 if ((UDP->flags & FTD_MSG) &&
767 current_type[drive] != NULL)
768 DPRINT("Disk type is undefined after "
769 "disk change\n");
770 current_type[drive] = NULL;
771 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
772 }
773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return 1;
775 } else {
776 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800777 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
779 return 0;
780}
781
782static inline int is_selected(int dor, int unit)
783{
784 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
785}
786
787static int set_dor(int fdc, char mask, char data)
788{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700789 unsigned char unit;
790 unsigned char drive;
791 unsigned char newdor;
792 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794 if (FDCS->address == -1)
795 return -1;
796
797 olddor = FDCS->dor;
798 newdor = (olddor & mask) | data;
799 if (newdor != olddor) {
800 unit = olddor & 0x3;
801 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
802 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800803 debug_dcl(UDP->flags,
804 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 disk_change(drive);
806 }
807 FDCS->dor = newdor;
808 fd_outb(newdor, FD_DOR);
809
810 unit = newdor & 0x3;
811 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
812 drive = REVDRIVE(fdc, unit);
813 UDRS->select_date = jiffies;
814 }
815 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 return olddor;
817}
818
819static void twaddle(void)
820{
821 if (DP->select_delay)
822 return;
823 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
824 fd_outb(FDCS->dor, FD_DOR);
825 DRS->select_date = jiffies;
826}
827
828/* reset all driver information about the current fdc. This is needed after
829 * a reset, and after a raw command. */
830static void reset_fdc_info(int mode)
831{
832 int drive;
833
834 FDCS->spec1 = FDCS->spec2 = -1;
835 FDCS->need_configure = 1;
836 FDCS->perp_mode = 1;
837 FDCS->rawcmd = 0;
838 for (drive = 0; drive < N_DRIVE; drive++)
839 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
840 UDRS->track = NEED_2_RECAL;
841}
842
843/* selects the fdc and drive, and enables the fdc's input/dma. */
844static void set_fdc(int drive)
845{
846 if (drive >= 0 && drive < N_DRIVE) {
847 fdc = FDC(drive);
848 current_drive = drive;
849 }
850 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800851 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 return;
853 }
854 set_dor(fdc, ~0, 8);
855#if N_FDC > 1
856 set_dor(1 - fdc, ~8, 0);
857#endif
858 if (FDCS->rawcmd == 2)
859 reset_fdc_info(1);
860 if (fd_inb(FD_STATUS) != STATUS_READY)
861 FDCS->reset = 1;
862}
863
864/* locks the driver */
Joe Perches74f63f42010-03-10 15:20:58 -0800865static int _lock_fdc(int drive, bool interruptible, int line)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866{
867 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800868 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 line);
870 return -1;
871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873 if (test_and_set_bit(0, &fdc_busy)) {
874 DECLARE_WAITQUEUE(wait, current);
875 add_wait_queue(&fdc_wait, &wait);
876
877 for (;;) {
878 set_current_state(TASK_INTERRUPTIBLE);
879
880 if (!test_and_set_bit(0, &fdc_busy))
881 break;
882
883 schedule();
884
885 if (!NO_SIGNAL) {
886 remove_wait_queue(&fdc_wait, &wait);
887 return -EINTR;
888 }
889 }
890
891 set_current_state(TASK_RUNNING);
892 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700893 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 }
895 command_status = FD_COMMAND_NONE;
896
897 __reschedule_timeout(drive, "lock fdc", 0);
898 set_fdc(drive);
899 return 0;
900}
901
Joe Perches48c8cee2010-03-10 15:20:45 -0800902#define lock_fdc(drive, interruptible) \
903 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905/* unlocks the driver */
906static inline void unlock_fdc(void)
907{
908 unsigned long flags;
909
910 raw_cmd = NULL;
911 if (!test_bit(0, &fdc_busy))
912 DPRINT("FDC access conflict!\n");
913
914 if (do_floppy)
915 DPRINT("device interrupt still active at FDC release: %p!\n",
916 do_floppy);
917 command_status = FD_COMMAND_NONE;
918 spin_lock_irqsave(&floppy_lock, flags);
919 del_timer(&fd_timeout);
920 cont = NULL;
921 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900922 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 do_fd_request(floppy_queue);
924 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 wake_up(&fdc_wait);
926}
927
928/* switches the motor off after a given timeout */
929static void motor_off_callback(unsigned long nr)
930{
931 unsigned char mask = ~(0x10 << UNIT(nr));
932
933 set_dor(FDC(nr), mask, 0);
934}
935
936/* schedules motor off */
937static void floppy_off(unsigned int drive)
938{
939 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700940 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 if (!(FDCS->dor & (0x10 << UNIT(drive))))
943 return;
944
945 del_timer(motor_off_timer + drive);
946
947 /* make spindle stop in a position which minimizes spinup time
948 * next time */
949 if (UDP->rps) {
950 delta = jiffies - UDRS->first_read_date + HZ -
951 UDP->spindown_offset;
952 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
953 motor_off_timer[drive].expires =
954 jiffies + UDP->spindown - delta;
955 }
956 add_timer(motor_off_timer + drive);
957}
958
959/*
960 * cycle through all N_DRIVE floppy drives, for disk change testing.
961 * stopping at current drive. This is done before any long operation, to
962 * be sure to have up to date disk change information.
963 */
964static void scandrives(void)
965{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700966 int i;
967 int drive;
968 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970 if (DP->select_delay)
971 return;
972
973 saved_drive = current_drive;
974 for (i = 0; i < N_DRIVE; i++) {
975 drive = (saved_drive + i + 1) % N_DRIVE;
976 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
977 continue; /* skip closed drives */
978 set_fdc(drive);
979 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
980 (0x10 << UNIT(drive))))
981 /* switch the motor off again, if it was off to
982 * begin with */
983 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
984 }
985 set_fdc(saved_drive);
986}
987
988static void empty(void)
989{
990}
991
David Howells65f27f32006-11-22 14:55:48 +0000992static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Joe Perches48c8cee2010-03-10 15:20:45 -0800994static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995{
David Howells65f27f32006-11-22 14:55:48 +0000996 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 schedule_work(&floppy_work);
998}
999
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001000static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002static void cancel_activity(void)
1003{
1004 unsigned long flags;
1005
1006 spin_lock_irqsave(&floppy_lock, flags);
1007 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001008 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 del_timer(&fd_timer);
1010 spin_unlock_irqrestore(&floppy_lock, flags);
1011}
1012
1013/* this function makes sure that the disk stays in the drive during the
1014 * transfer */
1015static void fd_watchdog(void)
1016{
Joe Perches87f530d2010-03-10 15:20:54 -08001017 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019 if (disk_change(current_drive)) {
1020 DPRINT("disk removed during i/o\n");
1021 cancel_activity();
1022 cont->done(0);
1023 reset_fdc();
1024 } else {
1025 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001026 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 fd_timer.expires = jiffies + HZ / 10;
1028 add_timer(&fd_timer);
1029 }
1030}
1031
1032static void main_command_interrupt(void)
1033{
1034 del_timer(&fd_timer);
1035 cont->interrupt();
1036}
1037
1038/* waits for a delay (spinup or select) to pass */
1039static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1040{
1041 if (FDCS->reset) {
1042 reset_fdc(); /* do the reset during sleep to win time
1043 * if we don't need to sleep, it's a good
1044 * occasion anyways */
1045 return 1;
1046 }
1047
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001048 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 del_timer(&fd_timer);
1050 fd_timer.function = function;
1051 fd_timer.expires = delay;
1052 add_timer(&fd_timer);
1053 return 1;
1054 }
1055 return 0;
1056}
1057
1058static DEFINE_SPINLOCK(floppy_hlt_lock);
1059static int hlt_disabled;
1060static void floppy_disable_hlt(void)
1061{
1062 unsigned long flags;
1063
1064 spin_lock_irqsave(&floppy_hlt_lock, flags);
1065 if (!hlt_disabled) {
1066 hlt_disabled = 1;
1067#ifdef HAVE_DISABLE_HLT
1068 disable_hlt();
1069#endif
1070 }
1071 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1072}
1073
1074static void floppy_enable_hlt(void)
1075{
1076 unsigned long flags;
1077
1078 spin_lock_irqsave(&floppy_hlt_lock, flags);
1079 if (hlt_disabled) {
1080 hlt_disabled = 0;
1081#ifdef HAVE_DISABLE_HLT
1082 enable_hlt();
1083#endif
1084 }
1085 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1086}
1087
1088static void setup_DMA(void)
1089{
1090 unsigned long f;
1091
1092#ifdef FLOPPY_SANITY_CHECK
1093 if (raw_cmd->length == 0) {
1094 int i;
1095
Joe Perchesb46df352010-03-10 15:20:46 -08001096 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001098 pr_cont("%x,", raw_cmd->cmd[i]);
1099 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 cont->done(0);
1101 FDCS->reset = 1;
1102 return;
1103 }
1104 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001105 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 cont->done(0);
1107 FDCS->reset = 1;
1108 return;
1109 }
1110#endif
1111 f = claim_dma_lock();
1112 fd_disable_dma();
1113#ifdef fd_dma_setup
1114 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1115 (raw_cmd->flags & FD_RAW_READ) ?
1116 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1117 release_dma_lock(f);
1118 cont->done(0);
1119 FDCS->reset = 1;
1120 return;
1121 }
1122 release_dma_lock(f);
1123#else
1124 fd_clear_dma_ff();
1125 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1126 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1127 DMA_MODE_READ : DMA_MODE_WRITE);
1128 fd_set_dma_addr(raw_cmd->kernel_data);
1129 fd_set_dma_count(raw_cmd->length);
1130 virtual_dma_port = FDCS->address;
1131 fd_enable_dma();
1132 release_dma_lock(f);
1133#endif
1134 floppy_disable_hlt();
1135}
1136
1137static void show_floppy(void);
1138
1139/* waits until the fdc becomes ready */
1140static int wait_til_ready(void)
1141{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001142 int status;
1143 int counter;
1144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 if (FDCS->reset)
1146 return -1;
1147 for (counter = 0; counter < 10000; counter++) {
1148 status = fd_inb(FD_STATUS);
1149 if (status & STATUS_READY)
1150 return status;
1151 }
1152 if (!initialising) {
1153 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1154 show_floppy();
1155 }
1156 FDCS->reset = 1;
1157 return -1;
1158}
1159
1160/* sends a command byte to the fdc */
1161static int output_byte(char byte)
1162{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001163 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001165 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 return -1;
1167 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1168 fd_outb(byte, FD_DATA);
1169#ifdef FLOPPY_SANITY_CHECK
1170 output_log[output_log_pos].data = byte;
1171 output_log[output_log_pos].status = status;
1172 output_log[output_log_pos].jiffies = jiffies;
1173 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1174#endif
1175 return 0;
1176 }
1177 FDCS->reset = 1;
1178 if (!initialising) {
1179 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1180 byte, fdc, status);
1181 show_floppy();
1182 }
1183 return -1;
1184}
1185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186/* gets the response from the fdc */
1187static int result(void)
1188{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001189 int i;
1190 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001193 status = wait_til_ready();
1194 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 break;
1196 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1197 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1198#ifdef FLOPPY_SANITY_CHECK
1199 resultjiffies = jiffies;
1200 resultsize = i;
1201#endif
1202 return i;
1203 }
1204 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1205 reply_buffer[i] = fd_inb(FD_DATA);
1206 else
1207 break;
1208 }
1209 if (!initialising) {
1210 DPRINT
1211 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1212 fdc, status, i);
1213 show_floppy();
1214 }
1215 FDCS->reset = 1;
1216 return -1;
1217}
1218
1219#define MORE_OUTPUT -2
1220/* does the fdc need more output? */
1221static int need_more_output(void)
1222{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001223 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001224
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001225 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 return -1;
1227 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1228 return MORE_OUTPUT;
1229 return result();
1230}
1231
1232/* Set perpendicular mode as required, based on data rate, if supported.
1233 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1234 */
1235static inline void perpendicular_mode(void)
1236{
1237 unsigned char perp_mode;
1238
1239 if (raw_cmd->rate & 0x40) {
1240 switch (raw_cmd->rate & 3) {
1241 case 0:
1242 perp_mode = 2;
1243 break;
1244 case 3:
1245 perp_mode = 3;
1246 break;
1247 default:
1248 DPRINT("Invalid data rate for perpendicular mode!\n");
1249 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001250 FDCS->reset = 1;
1251 /*
1252 * convenient way to return to
1253 * redo without too much hassle
1254 * (deep stack et al.)
1255 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 return;
1257 }
1258 } else
1259 perp_mode = 0;
1260
1261 if (FDCS->perp_mode == perp_mode)
1262 return;
1263 if (FDCS->version >= FDC_82077_ORIG) {
1264 output_byte(FD_PERPENDICULAR);
1265 output_byte(perp_mode);
1266 FDCS->perp_mode = perp_mode;
1267 } else if (perp_mode) {
1268 DPRINT("perpendicular mode not supported by this FDC.\n");
1269 }
1270} /* perpendicular_mode */
1271
1272static int fifo_depth = 0xa;
1273static int no_fifo;
1274
1275static int fdc_configure(void)
1276{
1277 /* Turn on FIFO */
1278 output_byte(FD_CONFIGURE);
1279 if (need_more_output() != MORE_OUTPUT)
1280 return 0;
1281 output_byte(0);
1282 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1283 output_byte(0); /* pre-compensation from track
1284 0 upwards */
1285 return 1;
1286}
1287
1288#define NOMINAL_DTR 500
1289
1290/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1291 * head load time, and DMA disable flag to values needed by floppy.
1292 *
1293 * The value "dtr" is the data transfer rate in Kbps. It is needed
1294 * to account for the data rate-based scaling done by the 82072 and 82077
1295 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1296 * 8272a).
1297 *
1298 * Note that changing the data transfer rate has a (probably deleterious)
1299 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1300 * fdc_specify is called again after each data transfer rate
1301 * change.
1302 *
1303 * srt: 1000 to 16000 in microseconds
1304 * hut: 16 to 240 milliseconds
1305 * hlt: 2 to 254 milliseconds
1306 *
1307 * These values are rounded up to the next highest available delay time.
1308 */
1309static void fdc_specify(void)
1310{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001311 unsigned char spec1;
1312 unsigned char spec2;
1313 unsigned long srt;
1314 unsigned long hlt;
1315 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 unsigned long dtr = NOMINAL_DTR;
1317 unsigned long scale_dtr = NOMINAL_DTR;
1318 int hlt_max_code = 0x7f;
1319 int hut_max_code = 0xf;
1320
1321 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1322 fdc_configure();
1323 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 }
1325
1326 switch (raw_cmd->rate & 0x03) {
1327 case 3:
1328 dtr = 1000;
1329 break;
1330 case 1:
1331 dtr = 300;
1332 if (FDCS->version >= FDC_82078) {
1333 /* chose the default rate table, not the one
1334 * where 1 = 2 Mbps */
1335 output_byte(FD_DRIVESPEC);
1336 if (need_more_output() == MORE_OUTPUT) {
1337 output_byte(UNIT(current_drive));
1338 output_byte(0xc0);
1339 }
1340 }
1341 break;
1342 case 2:
1343 dtr = 250;
1344 break;
1345 }
1346
1347 if (FDCS->version >= FDC_82072) {
1348 scale_dtr = dtr;
1349 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1350 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1351 }
1352
1353 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001354 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001355 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001357
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 SUPBOUND(srt, 0xf);
1359 INFBOUND(srt, 0);
1360
Julia Lawall061837b2008-09-22 14:57:16 -07001361 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 if (hlt < 0x01)
1363 hlt = 0x01;
1364 else if (hlt > 0x7f)
1365 hlt = hlt_max_code;
1366
Julia Lawall061837b2008-09-22 14:57:16 -07001367 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 if (hut < 0x1)
1369 hut = 0x1;
1370 else if (hut > 0xf)
1371 hut = hut_max_code;
1372
1373 spec1 = (srt << 4) | hut;
1374 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1375
1376 /* If these parameters did not change, just return with success */
1377 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1378 /* Go ahead and set spec1 and spec2 */
1379 output_byte(FD_SPECIFY);
1380 output_byte(FDCS->spec1 = spec1);
1381 output_byte(FDCS->spec2 = spec2);
1382 }
1383} /* fdc_specify */
1384
1385/* Set the FDC's data transfer rate on behalf of the specified drive.
1386 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1387 * of the specify command (i.e. using the fdc_specify function).
1388 */
1389static int fdc_dtr(void)
1390{
1391 /* If data rate not already set to desired value, set it. */
1392 if ((raw_cmd->rate & 3) == FDCS->dtr)
1393 return 0;
1394
1395 /* Set dtr */
1396 fd_outb(raw_cmd->rate & 3, FD_DCR);
1397
1398 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1399 * need a stabilization period of several milliseconds to be
1400 * enforced after data rate changes before R/W operations.
1401 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1402 */
1403 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001404 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1405 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406} /* fdc_dtr */
1407
1408static void tell_sector(void)
1409{
Joe Perchesb46df352010-03-10 15:20:46 -08001410 pr_cont(": track %d, head %d, sector %d, size %d",
1411 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412} /* tell_sector */
1413
Joe Perchesb46df352010-03-10 15:20:46 -08001414static void print_errors(void)
1415{
1416 DPRINT("");
1417 if (ST0 & ST0_ECE) {
1418 pr_cont("Recalibrate failed!");
1419 } else if (ST2 & ST2_CRC) {
1420 pr_cont("data CRC error");
1421 tell_sector();
1422 } else if (ST1 & ST1_CRC) {
1423 pr_cont("CRC error");
1424 tell_sector();
1425 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1426 (ST2 & ST2_MAM)) {
1427 if (!probing) {
1428 pr_cont("sector not found");
1429 tell_sector();
1430 } else
1431 pr_cont("probe failed...");
1432 } else if (ST2 & ST2_WC) { /* seek error */
1433 pr_cont("wrong cylinder");
1434 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1435 pr_cont("bad cylinder");
1436 } else {
1437 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1438 ST0, ST1, ST2);
1439 tell_sector();
1440 }
1441 pr_cont("\n");
1442}
1443
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444/*
1445 * OK, this error interpreting routine is called after a
1446 * DMA read/write has succeeded
1447 * or failed, so we check the results, and copy any buffers.
1448 * hhb: Added better error reporting.
1449 * ak: Made this into a separate routine.
1450 */
1451static int interpret_errors(void)
1452{
1453 char bad;
1454
1455 if (inr != 7) {
1456 DPRINT("-- FDC reply error");
1457 FDCS->reset = 1;
1458 return 1;
1459 }
1460
1461 /* check IC to find cause of interrupt */
1462 switch (ST0 & ST0_INTR) {
1463 case 0x40: /* error occurred during command execution */
1464 if (ST1 & ST1_EOC)
1465 return 0; /* occurs with pseudo-DMA */
1466 bad = 1;
1467 if (ST1 & ST1_WP) {
1468 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001469 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 cont->done(0);
1471 bad = 2;
1472 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001473 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 } else if (ST1 & ST1_OR) {
1475 if (DP->flags & FTD_MSG)
1476 DPRINT("Over/Underrun - retrying\n");
1477 bad = 0;
1478 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001479 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 }
1481 if (ST2 & ST2_WC || ST2 & ST2_BC)
1482 /* wrong cylinder => recal */
1483 DRS->track = NEED_2_RECAL;
1484 return bad;
1485 case 0x80: /* invalid command given */
1486 DPRINT("Invalid FDC command given!\n");
1487 cont->done(0);
1488 return 2;
1489 case 0xc0:
1490 DPRINT("Abnormal termination caused by polling\n");
1491 cont->error();
1492 return 2;
1493 default: /* (0) Normal command termination */
1494 return 0;
1495 }
1496}
1497
1498/*
1499 * This routine is called when everything should be correctly set up
1500 * for the transfer (i.e. floppy motor is on, the correct floppy is
1501 * selected, and the head is sitting on the right track).
1502 */
1503static void setup_rw_floppy(void)
1504{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001505 int i;
1506 int r;
1507 int flags;
1508 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 unsigned long ready_date;
1510 timeout_fn function;
1511
1512 flags = raw_cmd->flags;
1513 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1514 flags |= FD_RAW_INTR;
1515
1516 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1517 ready_date = DRS->spinup_date + DP->spinup;
1518 /* If spinup will take a long time, rerun scandrives
1519 * again just before spinup completion. Beware that
1520 * after scandrives, we must again wait for selection.
1521 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001522 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001524 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001526 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 /* wait until the floppy is spinning fast enough */
1529 if (fd_wait_for_completion(ready_date, function))
1530 return;
1531 }
1532 dflags = DRS->flags;
1533
1534 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1535 setup_DMA();
1536
1537 if (flags & FD_RAW_INTR)
1538 do_floppy = main_command_interrupt;
1539
1540 r = 0;
1541 for (i = 0; i < raw_cmd->cmd_count; i++)
1542 r |= output_byte(raw_cmd->cmd[i]);
1543
1544 debugt("rw_command: ");
1545
1546 if (r) {
1547 cont->error();
1548 reset_fdc();
1549 return;
1550 }
1551
1552 if (!(flags & FD_RAW_INTR)) {
1553 inr = result();
1554 cont->interrupt();
1555 } else if (flags & FD_RAW_NEED_DISK)
1556 fd_watchdog();
1557}
1558
1559static int blind_seek;
1560
1561/*
1562 * This is the routine called after every seek (or recalibrate) interrupt
1563 * from the floppy controller.
1564 */
1565static void seek_interrupt(void)
1566{
1567 debugt("seek interrupt:");
1568 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1569 DPRINT("seek failed\n");
1570 DRS->track = NEED_2_RECAL;
1571 cont->error();
1572 cont->redo();
1573 return;
1574 }
1575 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001576 debug_dcl(DP->flags,
1577 "clearing NEWCHANGE flag because of effective seek\n");
1578 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001579 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1580 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 DRS->select_date = jiffies;
1582 }
1583 DRS->track = ST1;
1584 floppy_ready();
1585}
1586
1587static void check_wp(void)
1588{
Joe Perchese0298532010-03-10 15:20:55 -08001589 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1590 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 output_byte(FD_GETSTATUS);
1592 output_byte(UNIT(current_drive));
1593 if (result() != 1) {
1594 FDCS->reset = 1;
1595 return;
1596 }
Joe Perchese0298532010-03-10 15:20:55 -08001597 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1598 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001599 debug_dcl(DP->flags,
1600 "checking whether disk is write protected\n");
1601 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001603 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 else
Joe Perchese0298532010-03-10 15:20:55 -08001605 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 }
1607}
1608
1609static void seek_floppy(void)
1610{
1611 int track;
1612
1613 blind_seek = 0;
1614
Joe Perches87f530d2010-03-10 15:20:54 -08001615 debug_dcl(DP->flags, "calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
Joe Perchese0298532010-03-10 15:20:55 -08001617 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1619 /* the media changed flag should be cleared after the seek.
1620 * If it isn't, this means that there is really no disk in
1621 * the drive.
1622 */
Joe Perchese0298532010-03-10 15:20:55 -08001623 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 cont->done(0);
1625 cont->redo();
1626 return;
1627 }
1628 if (DRS->track <= NEED_1_RECAL) {
1629 recalibrate_floppy();
1630 return;
Joe Perchese0298532010-03-10 15:20:55 -08001631 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1633 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1634 /* we seek to clear the media-changed condition. Does anybody
1635 * know a more elegant way, which works on all drives? */
1636 if (raw_cmd->track)
1637 track = raw_cmd->track - 1;
1638 else {
1639 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1640 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1641 blind_seek = 1;
1642 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1643 }
1644 track = 1;
1645 }
1646 } else {
1647 check_wp();
1648 if (raw_cmd->track != DRS->track &&
1649 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1650 track = raw_cmd->track;
1651 else {
1652 setup_rw_floppy();
1653 return;
1654 }
1655 }
1656
1657 do_floppy = seek_interrupt;
1658 output_byte(FD_SEEK);
1659 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001660 if (output_byte(track) < 0) {
1661 reset_fdc();
1662 return;
1663 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 debugt("seek command:");
1665}
1666
1667static void recal_interrupt(void)
1668{
1669 debugt("recal interrupt:");
1670 if (inr != 2)
1671 FDCS->reset = 1;
1672 else if (ST0 & ST0_ECE) {
1673 switch (DRS->track) {
1674 case NEED_1_RECAL:
1675 debugt("recal interrupt need 1 recal:");
1676 /* after a second recalibrate, we still haven't
1677 * reached track 0. Probably no drive. Raise an
1678 * error, as failing immediately might upset
1679 * computers possessed by the Devil :-) */
1680 cont->error();
1681 cont->redo();
1682 return;
1683 case NEED_2_RECAL:
1684 debugt("recal interrupt need 2 recal:");
1685 /* If we already did a recalibrate,
1686 * and we are not at track 0, this
1687 * means we have moved. (The only way
1688 * not to move at recalibration is to
1689 * be already at track 0.) Clear the
1690 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001691 debug_dcl(DP->flags,
1692 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Joe Perchese0298532010-03-10 15:20:55 -08001694 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 DRS->select_date = jiffies;
1696 /* fall through */
1697 default:
1698 debugt("recal interrupt default:");
1699 /* Recalibrate moves the head by at
1700 * most 80 steps. If after one
1701 * recalibrate we don't have reached
1702 * track 0, this might mean that we
1703 * started beyond track 80. Try
1704 * again. */
1705 DRS->track = NEED_1_RECAL;
1706 break;
1707 }
1708 } else
1709 DRS->track = ST1;
1710 floppy_ready();
1711}
1712
1713static void print_result(char *message, int inr)
1714{
1715 int i;
1716
1717 DPRINT("%s ", message);
1718 if (inr >= 0)
1719 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001720 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1721 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722}
1723
1724/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001725irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 int do_print;
1728 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001729 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
1731 lasthandler = handler;
1732 interruptjiffies = jiffies;
1733
1734 f = claim_dma_lock();
1735 fd_disable_dma();
1736 release_dma_lock(f);
1737
1738 floppy_enable_hlt();
1739 do_floppy = NULL;
1740 if (fdc >= N_FDC || FDCS->address == -1) {
1741 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001742 pr_info("DOR0=%x\n", fdc_state[0].dor);
1743 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1744 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 is_alive("bizarre fdc");
1746 return IRQ_NONE;
1747 }
1748
1749 FDCS->reset = 0;
1750 /* We have to clear the reset flag here, because apparently on boxes
1751 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1752 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1753 * emission of the SENSEI's.
1754 * It is OK to emit floppy commands because we are in an interrupt
1755 * handler here, and thus we have to fear no interference of other
1756 * activity.
1757 */
1758
1759 do_print = !handler && print_unex && !initialising;
1760
1761 inr = result();
1762 if (do_print)
1763 print_result("unexpected interrupt", inr);
1764 if (inr == 0) {
1765 int max_sensei = 4;
1766 do {
1767 output_byte(FD_SENSEI);
1768 inr = result();
1769 if (do_print)
1770 print_result("sensei", inr);
1771 max_sensei--;
1772 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1773 && max_sensei);
1774 }
1775 if (!handler) {
1776 FDCS->reset = 1;
1777 return IRQ_NONE;
1778 }
1779 schedule_bh(handler);
1780 is_alive("normal interrupt end");
1781
1782 /* FIXME! Was it really for us? */
1783 return IRQ_HANDLED;
1784}
1785
1786static void recalibrate_floppy(void)
1787{
1788 debugt("recalibrate floppy:");
1789 do_floppy = recal_interrupt;
1790 output_byte(FD_RECALIBRATE);
Joe Perches2300f902010-03-10 15:20:49 -08001791 if (output_byte(UNIT(current_drive)) < 0) {
1792 reset_fdc();
1793 return;
1794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795}
1796
1797/*
1798 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1799 */
1800static void reset_interrupt(void)
1801{
1802 debugt("reset interrupt:");
1803 result(); /* get the status ready for set_fdc */
1804 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001805 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 cont->error(); /* a reset just after a reset. BAD! */
1807 }
1808 cont->redo();
1809}
1810
1811/*
1812 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1813 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1814 */
1815static void reset_fdc(void)
1816{
1817 unsigned long flags;
1818
1819 do_floppy = reset_interrupt;
1820 FDCS->reset = 0;
1821 reset_fdc_info(0);
1822
1823 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1824 /* Irrelevant for systems with true DMA (i386). */
1825
1826 flags = claim_dma_lock();
1827 fd_disable_dma();
1828 release_dma_lock(flags);
1829
1830 if (FDCS->version >= FDC_82072A)
1831 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1832 else {
1833 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1834 udelay(FD_RESET_DELAY);
1835 fd_outb(FDCS->dor, FD_DOR);
1836 }
1837}
1838
1839static void show_floppy(void)
1840{
1841 int i;
1842
Joe Perchesb46df352010-03-10 15:20:46 -08001843 pr_info("\n");
1844 pr_info("floppy driver state\n");
1845 pr_info("-------------------\n");
1846 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1847 jiffies, interruptjiffies, jiffies - interruptjiffies,
1848 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
1850#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001851 pr_info("timeout_message=%s\n", timeout_message);
1852 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001854 pr_info("%2x %2x %lu\n",
1855 output_log[(i + output_log_pos) % OLOGSIZE].data,
1856 output_log[(i + output_log_pos) % OLOGSIZE].status,
1857 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1858 pr_info("last result at %lu\n", resultjiffies);
1859 pr_info("last redo_fd_request at %lu\n", lastredo);
1860 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1861 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862#endif
1863
Joe Perchesb46df352010-03-10 15:20:46 -08001864 pr_info("status=%x\n", fd_inb(FD_STATUS));
1865 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001867 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001868 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001869 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001871 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001873 pr_info("timer_function=%p\n", fd_timeout.function);
1874 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1875 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 }
Joe Perchesb46df352010-03-10 15:20:46 -08001877 pr_info("cont=%p\n", cont);
1878 pr_info("current_req=%p\n", current_req);
1879 pr_info("command_status=%d\n", command_status);
1880 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881}
1882
1883static void floppy_shutdown(unsigned long data)
1884{
1885 unsigned long flags;
1886
1887 if (!initialising)
1888 show_floppy();
1889 cancel_activity();
1890
1891 floppy_enable_hlt();
1892
1893 flags = claim_dma_lock();
1894 fd_disable_dma();
1895 release_dma_lock(flags);
1896
1897 /* avoid dma going to a random drive after shutdown */
1898
1899 if (!initialising)
1900 DPRINT("floppy timeout called\n");
1901 FDCS->reset = 1;
1902 if (cont) {
1903 cont->done(0);
1904 cont->redo(); /* this will recall reset when needed */
1905 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001906 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 process_fd_request();
1908 }
1909 is_alive("floppy shutdown");
1910}
1911
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001913static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001915 int mask;
1916 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918 mask = 0xfc;
1919 data = UNIT(current_drive);
1920 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1921 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1922 set_debugt();
1923 /* no read since this drive is running */
1924 DRS->first_read_date = 0;
1925 /* note motor start time if motor is not yet running */
1926 DRS->spinup_date = jiffies;
1927 data |= (0x10 << UNIT(current_drive));
1928 }
1929 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1930 mask &= ~(0x10 << UNIT(current_drive));
1931
1932 /* starts motor and selects floppy */
1933 del_timer(motor_off_timer + current_drive);
1934 set_dor(fdc, mask, data);
1935
1936 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001937 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1938 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939}
1940
1941static void floppy_ready(void)
1942{
Joe Perches045f9832010-03-10 15:20:47 -08001943 if (FDCS->reset) {
1944 reset_fdc();
1945 return;
1946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 if (start_motor(floppy_ready))
1948 return;
1949 if (fdc_dtr())
1950 return;
1951
Joe Perches87f530d2010-03-10 15:20:54 -08001952 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1954 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001955 twaddle(); /* this clears the dcl on certain
1956 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
1958#ifdef fd_chose_dma_mode
1959 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1960 unsigned long flags = claim_dma_lock();
1961 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1962 release_dma_lock(flags);
1963 }
1964#endif
1965
1966 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1967 perpendicular_mode();
1968 fdc_specify(); /* must be done here because of hut, hlt ... */
1969 seek_floppy();
1970 } else {
1971 if ((raw_cmd->flags & FD_RAW_READ) ||
1972 (raw_cmd->flags & FD_RAW_WRITE))
1973 fdc_specify();
1974 setup_rw_floppy();
1975 }
1976}
1977
1978static void floppy_start(void)
1979{
1980 reschedule_timeout(current_reqD, "floppy start", 0);
1981
1982 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001983 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001984 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 floppy_ready();
1986}
1987
1988/*
1989 * ========================================================================
1990 * here ends the bottom half. Exported routines are:
1991 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1992 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1993 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1994 * and set_dor.
1995 * ========================================================================
1996 */
1997/*
1998 * General purpose continuations.
1999 * ==============================
2000 */
2001
2002static void do_wakeup(void)
2003{
2004 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2005 cont = NULL;
2006 command_status += 2;
2007 wake_up(&command_done);
2008}
2009
2010static struct cont_t wakeup_cont = {
2011 .interrupt = empty,
2012 .redo = do_wakeup,
2013 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002014 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015};
2016
2017static struct cont_t intr_cont = {
2018 .interrupt = empty,
2019 .redo = process_fd_request,
2020 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002021 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022};
2023
Joe Perches74f63f42010-03-10 15:20:58 -08002024static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025{
2026 int ret;
2027
2028 schedule_bh(handler);
2029
2030 if (command_status < 2 && NO_SIGNAL) {
2031 DECLARE_WAITQUEUE(wait, current);
2032
2033 add_wait_queue(&command_done, &wait);
2034 for (;;) {
2035 set_current_state(interruptible ?
2036 TASK_INTERRUPTIBLE :
2037 TASK_UNINTERRUPTIBLE);
2038
2039 if (command_status >= 2 || !NO_SIGNAL)
2040 break;
2041
2042 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 schedule();
2044 }
2045
2046 set_current_state(TASK_RUNNING);
2047 remove_wait_queue(&command_done, &wait);
2048 }
2049
2050 if (command_status < 2) {
2051 cancel_activity();
2052 cont = &intr_cont;
2053 reset_fdc();
2054 return -EINTR;
2055 }
2056
2057 if (FDCS->reset)
2058 command_status = FD_COMMAND_ERROR;
2059 if (command_status == FD_COMMAND_OKAY)
2060 ret = 0;
2061 else
2062 ret = -EIO;
2063 command_status = FD_COMMAND_NONE;
2064 return ret;
2065}
2066
2067static void generic_done(int result)
2068{
2069 command_status = result;
2070 cont = &wakeup_cont;
2071}
2072
2073static void generic_success(void)
2074{
2075 cont->done(1);
2076}
2077
2078static void generic_failure(void)
2079{
2080 cont->done(0);
2081}
2082
2083static void success_and_wakeup(void)
2084{
2085 generic_success();
2086 cont->redo();
2087}
2088
2089/*
2090 * formatting and rw support.
2091 * ==========================
2092 */
2093
2094static int next_valid_format(void)
2095{
2096 int probed_format;
2097
2098 probed_format = DRS->probed_format;
2099 while (1) {
2100 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2101 DRS->probed_format = 0;
2102 return 1;
2103 }
2104 if (floppy_type[DP->autodetect[probed_format]].sect) {
2105 DRS->probed_format = probed_format;
2106 return 0;
2107 }
2108 probed_format++;
2109 }
2110}
2111
2112static void bad_flp_intr(void)
2113{
2114 int err_count;
2115
2116 if (probing) {
2117 DRS->probed_format++;
2118 if (!next_valid_format())
2119 return;
2120 }
2121 err_count = ++(*errors);
2122 INFBOUND(DRWE->badness, err_count);
2123 if (err_count > DP->max_errors.abort)
2124 cont->done(0);
2125 if (err_count > DP->max_errors.reset)
2126 FDCS->reset = 1;
2127 else if (err_count > DP->max_errors.recal)
2128 DRS->track = NEED_2_RECAL;
2129}
2130
2131static void set_floppy(int drive)
2132{
2133 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002134
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (type)
2136 _floppy = floppy_type + type;
2137 else
2138 _floppy = current_type[drive];
2139}
2140
2141/*
2142 * formatting support.
2143 * ===================
2144 */
2145static void format_interrupt(void)
2146{
2147 switch (interpret_errors()) {
2148 case 1:
2149 cont->error();
2150 case 2:
2151 break;
2152 case 0:
2153 cont->done(1);
2154 }
2155 cont->redo();
2156}
2157
2158#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002159#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002161
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162static void setup_format_params(int track)
2163{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002164 int n;
2165 int il;
2166 int count;
2167 int head_shift;
2168 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 struct fparm {
2170 unsigned char track, head, sect, size;
2171 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
2173 raw_cmd = &default_raw_cmd;
2174 raw_cmd->track = track;
2175
Joe Perches48c8cee2010-03-10 15:20:45 -08002176 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2177 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 raw_cmd->rate = _floppy->rate & 0x43;
2179 raw_cmd->cmd_count = NR_F;
2180 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2181 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2182 F_SIZECODE = FD_SIZECODE(_floppy);
2183 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2184 F_GAP = _floppy->fmt_gap;
2185 F_FILL = FD_FILL_BYTE;
2186
2187 raw_cmd->kernel_data = floppy_track_buffer;
2188 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2189
2190 /* allow for about 30ms for data transport per track */
2191 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2192
2193 /* a ``cylinder'' is two tracks plus a little stepping time */
2194 track_shift = 2 * head_shift + 3;
2195
2196 /* position of logical sector 1 on this track */
2197 n = (track_shift * format_req.track + head_shift * format_req.head)
2198 % F_SECT_PER_TRACK;
2199
2200 /* determine interleave */
2201 il = 1;
2202 if (_floppy->fmt_gap < 0x22)
2203 il++;
2204
2205 /* initialize field */
2206 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2207 here[count].track = format_req.track;
2208 here[count].head = format_req.head;
2209 here[count].sect = 0;
2210 here[count].size = F_SIZECODE;
2211 }
2212 /* place logical sectors */
2213 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2214 here[n].sect = count;
2215 n = (n + il) % F_SECT_PER_TRACK;
2216 if (here[n].sect) { /* sector busy, find next free sector */
2217 ++n;
2218 if (n >= F_SECT_PER_TRACK) {
2219 n -= F_SECT_PER_TRACK;
2220 while (here[n].sect)
2221 ++n;
2222 }
2223 }
2224 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002225 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002227 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 }
2229}
2230
2231static void redo_format(void)
2232{
2233 buffer_track = -1;
2234 setup_format_params(format_req.track << STRETCH(_floppy));
2235 floppy_start();
2236 debugt("queue format request");
2237}
2238
2239static struct cont_t format_cont = {
2240 .interrupt = format_interrupt,
2241 .redo = redo_format,
2242 .error = bad_flp_intr,
2243 .done = generic_done
2244};
2245
2246static int do_format(int drive, struct format_descr *tmp_format_req)
2247{
2248 int ret;
2249
Joe Perches74f63f42010-03-10 15:20:58 -08002250 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002251 return -EINTR;
2252
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 set_floppy(drive);
2254 if (!_floppy ||
2255 _floppy->track > DP->tracks ||
2256 tmp_format_req->track >= _floppy->track ||
2257 tmp_format_req->head >= _floppy->head ||
2258 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2259 !_floppy->fmt_gap) {
2260 process_fd_request();
2261 return -EINVAL;
2262 }
2263 format_req = *tmp_format_req;
2264 format_errors = 0;
2265 cont = &format_cont;
2266 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002267 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002268 if (ret == -EINTR)
2269 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 process_fd_request();
2271 return ret;
2272}
2273
2274/*
2275 * Buffer read/write and support
2276 * =============================
2277 */
2278
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002279static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280{
2281 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002282 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
2284 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002285 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002286 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002287 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
2290 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002291 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 current_req = NULL;
2293}
2294
2295/* new request_done. Can handle physical sectors which are smaller than a
2296 * logical buffer */
2297static void request_done(int uptodate)
2298{
2299 struct request_queue *q = floppy_queue;
2300 struct request *req = current_req;
2301 unsigned long flags;
2302 int block;
2303
2304 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002305 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002308 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 return;
2310 }
2311
2312 if (uptodate) {
2313 /* maintain values for invalidation on geometry
2314 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002315 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 INFBOUND(DRS->maxblock, block);
2317 if (block > _floppy->sect)
2318 DRS->maxtrack = 1;
2319
2320 /* unlock chained buffers */
2321 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002322 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 spin_unlock_irqrestore(q->queue_lock, flags);
2324 } else {
2325 if (rq_data_dir(req) == WRITE) {
2326 /* record write error information */
2327 DRWE->write_errors++;
2328 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002329 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 DRWE->first_error_generation = DRS->generation;
2331 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002332 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 DRWE->last_error_generation = DRS->generation;
2334 }
2335 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002336 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 spin_unlock_irqrestore(q->queue_lock, flags);
2338 }
2339}
2340
2341/* Interrupt handler evaluating the result of the r/w operation */
2342static void rw_interrupt(void)
2343{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002344 int eoc;
2345 int ssize;
2346 int heads;
2347 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
2349 if (R_HEAD >= 2) {
2350 /* some Toshiba floppy controllers occasionnally seem to
2351 * return bogus interrupts after read/write operations, which
2352 * can be recognized by a bad head number (>= 2) */
2353 return;
2354 }
2355
2356 if (!DRS->first_read_date)
2357 DRS->first_read_date = jiffies;
2358
2359 nr_sectors = 0;
2360 CODE2SIZE;
2361
2362 if (ST1 & ST1_EOC)
2363 eoc = 1;
2364 else
2365 eoc = 0;
2366
2367 if (COMMAND & 0x80)
2368 heads = 2;
2369 else
2370 heads = 1;
2371
2372 nr_sectors = (((R_TRACK - TRACK) * heads +
2373 R_HEAD - HEAD) * SECT_PER_TRACK +
2374 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2375
2376#ifdef FLOPPY_SANITY_CHECK
2377 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002378 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 DPRINT("long rw: %x instead of %lx\n",
2380 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002381 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2382 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2383 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2384 pr_info("heads=%d eoc=%d\n", heads, eoc);
2385 pr_info("spt=%d st=%d ss=%d\n",
2386 SECT_PER_TRACK, fsector_t, ssize);
2387 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 }
2389#endif
2390
2391 nr_sectors -= in_sector_offset;
2392 INFBOUND(nr_sectors, 0);
2393 SUPBOUND(current_count_sectors, nr_sectors);
2394
2395 switch (interpret_errors()) {
2396 case 2:
2397 cont->redo();
2398 return;
2399 case 1:
2400 if (!current_count_sectors) {
2401 cont->error();
2402 cont->redo();
2403 return;
2404 }
2405 break;
2406 case 0:
2407 if (!current_count_sectors) {
2408 cont->redo();
2409 return;
2410 }
2411 current_type[current_drive] = _floppy;
2412 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2413 break;
2414 }
2415
2416 if (probing) {
2417 if (DP->flags & FTD_MSG)
2418 DPRINT("Auto-detected floppy type %s in fd%d\n",
2419 _floppy->name, current_drive);
2420 current_type[current_drive] = _floppy;
2421 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2422 probing = 0;
2423 }
2424
2425 if (CT(COMMAND) != FD_READ ||
2426 raw_cmd->kernel_data == current_req->buffer) {
2427 /* transfer directly from buffer */
2428 cont->done(1);
2429 } else if (CT(COMMAND) == FD_READ) {
2430 buffer_track = raw_cmd->track;
2431 buffer_drive = current_drive;
2432 INFBOUND(buffer_max, nr_sectors + fsector_t);
2433 }
2434 cont->redo();
2435}
2436
2437/* Compute maximal contiguous buffer size. */
2438static int buffer_chain_size(void)
2439{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002441 int size;
2442 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 char *base;
2444
2445 base = bio_data(current_req->bio);
2446 size = 0;
2447
NeilBrown5705f702007-09-25 12:35:59 +02002448 rq_for_each_segment(bv, current_req, iter) {
2449 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2450 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
NeilBrown5705f702007-09-25 12:35:59 +02002452 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 }
2454
2455 return size >> 9;
2456}
2457
2458/* Compute the maximal transfer size */
2459static int transfer_size(int ssize, int max_sector, int max_size)
2460{
2461 SUPBOUND(max_sector, fsector_t + max_size);
2462
2463 /* alignment */
2464 max_sector -= (max_sector % _floppy->sect) % ssize;
2465
2466 /* transfer size, beginning not aligned */
2467 current_count_sectors = max_sector - fsector_t;
2468
2469 return max_sector;
2470}
2471
2472/*
2473 * Move data from/to the track buffer to/from the buffer cache.
2474 */
2475static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2476{
2477 int remaining; /* number of transferred 512-byte sectors */
2478 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002479 char *buffer;
2480 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002481 int size;
2482 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
2484 max_sector = transfer_size(ssize,
2485 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002486 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
2488 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002489 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002491 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
2493 remaining = current_count_sectors << 9;
2494#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002495 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002497 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2498 pr_info("remaining=%d\n", remaining >> 9);
2499 pr_info("current_req->nr_sectors=%u\n",
2500 blk_rq_sectors(current_req));
2501 pr_info("current_req->current_nr_sectors=%u\n",
2502 blk_rq_cur_sectors(current_req));
2503 pr_info("max_sector=%d\n", max_sector);
2504 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 }
2506#endif
2507
2508 buffer_max = max(max_sector, buffer_max);
2509
2510 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2511
Tejun Heo1011c1b2009-05-07 22:24:45 +09002512 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
NeilBrown5705f702007-09-25 12:35:59 +02002514 rq_for_each_segment(bv, current_req, iter) {
2515 if (!remaining)
2516 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517
NeilBrown5705f702007-09-25 12:35:59 +02002518 size = bv->bv_len;
2519 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
NeilBrown5705f702007-09-25 12:35:59 +02002521 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002523 if (dma_buffer + size >
2524 floppy_track_buffer + (max_buffer_sectors << 10) ||
2525 dma_buffer < floppy_track_buffer) {
2526 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002527 (int)((floppy_track_buffer - dma_buffer) >> 9));
2528 pr_info("fsector_t=%d buffer_min=%d\n",
2529 fsector_t, buffer_min);
2530 pr_info("current_count_sectors=%ld\n",
2531 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002533 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002534 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002535 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002536 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 }
NeilBrown5705f702007-09-25 12:35:59 +02002538 if (((unsigned long)buffer) % 512)
2539 DPRINT("%p buffer not aligned\n", buffer);
2540#endif
2541 if (CT(COMMAND) == FD_READ)
2542 memcpy(buffer, dma_buffer, size);
2543 else
2544 memcpy(dma_buffer, buffer, size);
2545
2546 remaining -= size;
2547 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 }
2549#ifdef FLOPPY_SANITY_CHECK
2550 if (remaining) {
2551 if (remaining > 0)
2552 max_sector -= remaining >> 9;
2553 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2554 }
2555#endif
2556}
2557
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558/* work around a bug in pseudo DMA
2559 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2560 * sending data. Hence we need a different way to signal the
2561 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2562 * does not work with MT, hence we can only transfer one head at
2563 * a time
2564 */
2565static void virtualdmabug_workaround(void)
2566{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002567 int hard_sectors;
2568 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
2570 if (CT(COMMAND) == FD_WRITE) {
2571 COMMAND &= ~0x80; /* switch off multiple track mode */
2572
2573 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2574 end_sector = SECTOR + hard_sectors - 1;
2575#ifdef FLOPPY_SANITY_CHECK
2576 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002577 pr_info("too many sectors %d > %d\n",
2578 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 return;
2580 }
2581#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002582 SECT_PER_TRACK = end_sector;
2583 /* make sure SECT_PER_TRACK
2584 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 }
2586}
2587
2588/*
2589 * Formulate a read/write request.
2590 * this routine decides where to load the data (directly to buffer, or to
2591 * tmp floppy area), how much data to load (the size of the buffer, the whole
2592 * track, or a single sector)
2593 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2594 * allocation on the fly, it should be done here. No other part should need
2595 * modification.
2596 */
2597
2598static int make_raw_rw_request(void)
2599{
2600 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002601 int max_sector;
2602 int max_size;
2603 int tracksize;
2604 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
2606 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002607 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 return 0;
2609 }
2610
2611 set_fdc((long)current_req->rq_disk->private_data);
2612
2613 raw_cmd = &default_raw_cmd;
2614 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2615 FD_RAW_NEED_SEEK;
2616 raw_cmd->cmd_count = NR_RW;
2617 if (rq_data_dir(current_req) == READ) {
2618 raw_cmd->flags |= FD_RAW_READ;
2619 COMMAND = FM_MODE(_floppy, FD_READ);
2620 } else if (rq_data_dir(current_req) == WRITE) {
2621 raw_cmd->flags |= FD_RAW_WRITE;
2622 COMMAND = FM_MODE(_floppy, FD_WRITE);
2623 } else {
2624 DPRINT("make_raw_rw_request: unknown command\n");
2625 return 0;
2626 }
2627
2628 max_sector = _floppy->sect * _floppy->head;
2629
Tejun Heo83096eb2009-05-07 22:24:39 +09002630 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2631 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002633 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 current_count_sectors = 1;
2635 return 1;
2636 } else
2637 return 0;
2638 }
2639 HEAD = fsector_t / _floppy->sect;
2640
Keith Wansbrough9e491842008-09-22 14:57:17 -07002641 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002642 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2643 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 max_sector = _floppy->sect;
2645
2646 /* 2M disks have phantom sectors on the first track */
2647 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2648 max_sector = 2 * _floppy->sect / 3;
2649 if (fsector_t >= max_sector) {
2650 current_count_sectors =
2651 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002652 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 return 1;
2654 }
2655 SIZECODE = 2;
2656 } else
2657 SIZECODE = FD_SIZECODE(_floppy);
2658 raw_cmd->rate = _floppy->rate & 0x43;
2659 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2660 raw_cmd->rate = 1;
2661
2662 if (SIZECODE)
2663 SIZECODE2 = 0xff;
2664 else
2665 SIZECODE2 = 0x80;
2666 raw_cmd->track = TRACK << STRETCH(_floppy);
2667 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2668 GAP = _floppy->gap;
2669 CODE2SIZE;
2670 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2671 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002672 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
2674 /* tracksize describes the size which can be filled up with sectors
2675 * of size ssize.
2676 */
2677 tracksize = _floppy->sect - _floppy->sect % ssize;
2678 if (tracksize < _floppy->sect) {
2679 SECT_PER_TRACK++;
2680 if (tracksize <= fsector_t % _floppy->sect)
2681 SECTOR--;
2682
2683 /* if we are beyond tracksize, fill up using smaller sectors */
2684 while (tracksize <= fsector_t % _floppy->sect) {
2685 while (tracksize + ssize > _floppy->sect) {
2686 SIZECODE--;
2687 ssize >>= 1;
2688 }
2689 SECTOR++;
2690 SECT_PER_TRACK++;
2691 tracksize += ssize;
2692 }
2693 max_sector = HEAD * _floppy->sect + tracksize;
2694 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2695 max_sector = _floppy->sect;
2696 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2697 /* for virtual DMA bug workaround */
2698 max_sector = _floppy->sect;
2699 }
2700
2701 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2702 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002703 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 if ((raw_cmd->track == buffer_track) &&
2705 (current_drive == buffer_drive) &&
2706 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2707 /* data already in track buffer */
2708 if (CT(COMMAND) == FD_READ) {
2709 copy_buffer(1, max_sector, buffer_max);
2710 return 1;
2711 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002712 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002714 unsigned int sectors;
2715
2716 sectors = fsector_t + blk_rq_sectors(current_req);
2717 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 max_size = ssize + ssize;
2719 else
2720 max_size = ssize;
2721 }
2722 raw_cmd->flags &= ~FD_RAW_WRITE;
2723 raw_cmd->flags |= FD_RAW_READ;
2724 COMMAND = FM_MODE(_floppy, FD_READ);
2725 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2726 unsigned long dma_limit;
2727 int direct, indirect;
2728
2729 indirect =
2730 transfer_size(ssize, max_sector,
2731 max_buffer_sectors * 2) - fsector_t;
2732
2733 /*
2734 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2735 * on a 64 bit machine!
2736 */
2737 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002738 dma_limit = (MAX_DMA_ADDRESS -
2739 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002740 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 /* 64 kb boundaries */
2743 if (CROSS_64KB(current_req->buffer, max_size << 9))
2744 max_size = (K_64 -
2745 ((unsigned long)current_req->buffer) %
2746 K_64) >> 9;
2747 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2748 /*
2749 * We try to read tracks, but if we get too many errors, we
2750 * go back to reading just one sector at a time.
2751 *
2752 * This means we should be able to read a sector even if there
2753 * are other bad sectors on this track.
2754 */
2755 if (!direct ||
2756 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002757 *errors < DP->max_errors.read_track &&
2758 ((!probing ||
2759 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002760 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 } else {
2762 raw_cmd->kernel_data = current_req->buffer;
2763 raw_cmd->length = current_count_sectors << 9;
2764 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002765 DPRINT("zero dma transfer attempted from make_raw_request\n");
2766 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 indirect, direct, fsector_t);
2768 return 0;
2769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 virtualdmabug_workaround();
2771 return 2;
2772 }
2773 }
2774
2775 if (CT(COMMAND) == FD_READ)
2776 max_size = max_sector; /* unbounded */
2777
2778 /* claim buffer track if needed */
2779 if (buffer_track != raw_cmd->track || /* bad track */
2780 buffer_drive != current_drive || /* bad drive */
2781 fsector_t > buffer_max ||
2782 fsector_t < buffer_min ||
2783 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002784 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002786 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2787 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 buffer_track = -1;
2789 buffer_drive = current_drive;
2790 buffer_max = buffer_min = aligned_sector_t;
2791 }
2792 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002793 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794
2795 if (CT(COMMAND) == FD_WRITE) {
2796 /* copy write buffer to track buffer.
2797 * if we get here, we know that the write
2798 * is either aligned or the data already in the buffer
2799 * (buffer will be overwritten) */
2800#ifdef FLOPPY_SANITY_CHECK
2801 if (in_sector_offset && buffer_track == -1)
2802 DPRINT("internal error offset !=0 on write\n");
2803#endif
2804 buffer_track = raw_cmd->track;
2805 buffer_drive = current_drive;
2806 copy_buffer(ssize, max_sector,
2807 2 * max_buffer_sectors + buffer_min);
2808 } else
2809 transfer_size(ssize, max_sector,
2810 2 * max_buffer_sectors + buffer_min -
2811 aligned_sector_t);
2812
2813 /* round up current_count_sectors to get dma xfer size */
2814 raw_cmd->length = in_sector_offset + current_count_sectors;
2815 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2816 raw_cmd->length <<= 9;
2817#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 if ((raw_cmd->length < current_count_sectors << 9) ||
2819 (raw_cmd->kernel_data != current_req->buffer &&
2820 CT(COMMAND) == FD_WRITE &&
2821 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2822 aligned_sector_t < buffer_min)) ||
2823 raw_cmd->length % (128 << SIZECODE) ||
2824 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2825 DPRINT("fractionary current count b=%lx s=%lx\n",
2826 raw_cmd->length, current_count_sectors);
2827 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002828 pr_info("addr=%d, length=%ld\n",
2829 (int)((raw_cmd->kernel_data -
2830 floppy_track_buffer) >> 9),
2831 current_count_sectors);
2832 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2833 fsector_t, aligned_sector_t, max_sector, max_size);
2834 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2835 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2836 COMMAND, SECTOR, HEAD, TRACK);
2837 pr_info("buffer drive=%d\n", buffer_drive);
2838 pr_info("buffer track=%d\n", buffer_track);
2839 pr_info("buffer_min=%d\n", buffer_min);
2840 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 return 0;
2842 }
2843
2844 if (raw_cmd->kernel_data != current_req->buffer) {
2845 if (raw_cmd->kernel_data < floppy_track_buffer ||
2846 current_count_sectors < 0 ||
2847 raw_cmd->length < 0 ||
2848 raw_cmd->kernel_data + raw_cmd->length >
2849 floppy_track_buffer + (max_buffer_sectors << 10)) {
2850 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002851 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2852 fsector_t, buffer_min, raw_cmd->length >> 9);
2853 pr_info("current_count_sectors=%ld\n",
2854 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002856 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002858 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 return 0;
2860 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002861 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002862 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 DPRINT("buffer overrun in direct transfer\n");
2864 return 0;
2865 } else if (raw_cmd->length < current_count_sectors << 9) {
2866 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002867 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2868 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 }
2870 if (raw_cmd->length == 0) {
2871 DPRINT("zero dma transfer attempted from make_raw_request\n");
2872 return 0;
2873 }
2874#endif
2875
2876 virtualdmabug_workaround();
2877 return 2;
2878}
2879
2880static void redo_fd_request(void)
2881{
2882#define REPEAT {request_done(0); continue; }
2883 int drive;
2884 int tmp;
2885
2886 lastredo = jiffies;
2887 if (current_drive < N_DRIVE)
2888 floppy_off(current_drive);
2889
2890 for (;;) {
2891 if (!current_req) {
2892 struct request *req;
2893
2894 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002895 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 spin_unlock_irq(floppy_queue->queue_lock);
2897 if (!req) {
2898 do_floppy = NULL;
2899 unlock_fdc();
2900 return;
2901 }
2902 current_req = req;
2903 }
2904 drive = (long)current_req->rq_disk->private_data;
2905 set_fdc(drive);
2906 reschedule_timeout(current_reqD, "redo fd request", 0);
2907
2908 set_floppy(drive);
2909 raw_cmd = &default_raw_cmd;
2910 raw_cmd->flags = 0;
2911 if (start_motor(redo_fd_request))
2912 return;
2913 disk_change(current_drive);
2914 if (test_bit(current_drive, &fake_change) ||
Joe Perchese0298532010-03-10 15:20:55 -08002915 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 DPRINT("disk absent or changed during operation\n");
2917 REPEAT;
2918 }
2919 if (!_floppy) { /* Autodetection */
2920 if (!probing) {
2921 DRS->probed_format = 0;
2922 if (next_valid_format()) {
2923 DPRINT("no autodetectable formats\n");
2924 _floppy = NULL;
2925 REPEAT;
2926 }
2927 }
2928 probing = 1;
2929 _floppy =
2930 floppy_type + DP->autodetect[DRS->probed_format];
2931 } else
2932 probing = 0;
2933 errors = &(current_req->errors);
2934 tmp = make_raw_rw_request();
2935 if (tmp < 2) {
2936 request_done(tmp);
2937 continue;
2938 }
2939
Joe Perchese0298532010-03-10 15:20:55 -08002940 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 twaddle();
2942 schedule_bh(floppy_start);
2943 debugt("queue fd request");
2944 return;
2945 }
2946#undef REPEAT
2947}
2948
2949static struct cont_t rw_cont = {
2950 .interrupt = rw_interrupt,
2951 .redo = redo_fd_request,
2952 .error = bad_flp_intr,
2953 .done = request_done
2954};
2955
2956static void process_fd_request(void)
2957{
2958 cont = &rw_cont;
2959 schedule_bh(redo_fd_request);
2960}
2961
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002962static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963{
2964 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002965 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 return;
2967 }
2968
2969 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002970 pr_info("warning: usage count=0, current_req=%p exiting\n",
2971 current_req);
2972 pr_info("sect=%ld type=%x flags=%x\n",
2973 (long)blk_rq_pos(current_req), current_req->cmd_type,
2974 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 return;
2976 }
2977 if (test_bit(0, &fdc_busy)) {
2978 /* fdc busy, this new request will be treated when the
2979 current one is done */
2980 is_alive("do fd request, old request running");
2981 return;
2982 }
Joe Perches74f63f42010-03-10 15:20:58 -08002983 lock_fdc(MAXTIMEOUT, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 process_fd_request();
2985 is_alive("do fd request");
2986}
2987
2988static struct cont_t poll_cont = {
2989 .interrupt = success_and_wakeup,
2990 .redo = floppy_ready,
2991 .error = generic_failure,
2992 .done = generic_done
2993};
2994
Joe Perches74f63f42010-03-10 15:20:58 -08002995static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 /* no auto-sense, just clear dcl */
2998 raw_cmd = &default_raw_cmd;
2999 raw_cmd->flags = flag;
3000 raw_cmd->track = 0;
3001 raw_cmd->cmd_count = 0;
3002 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08003003 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08003004 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08003005
3006 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007}
3008
3009/*
3010 * User triggered reset
3011 * ====================
3012 */
3013
3014static void reset_intr(void)
3015{
Joe Perchesb46df352010-03-10 15:20:46 -08003016 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017}
3018
3019static struct cont_t reset_cont = {
3020 .interrupt = reset_intr,
3021 .redo = success_and_wakeup,
3022 .error = generic_failure,
3023 .done = generic_done
3024};
3025
Joe Perches74f63f42010-03-10 15:20:58 -08003026static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027{
3028 int ret;
3029
Joe Perches52a0d612010-03-10 15:20:53 -08003030 if (lock_fdc(drive, interruptible))
3031 return -EINTR;
3032
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 if (arg == FD_RESET_ALWAYS)
3034 FDCS->reset = 1;
3035 if (FDCS->reset) {
3036 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08003037 ret = wait_til_done(reset_fdc, interruptible);
3038 if (ret == -EINTR)
3039 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 }
3041 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003042 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043}
3044
3045/*
3046 * Misc Ioctl's and support
3047 * ========================
3048 */
3049static inline int fd_copyout(void __user *param, const void *address,
3050 unsigned long size)
3051{
3052 return copy_to_user(param, address, size) ? -EFAULT : 0;
3053}
3054
Joe Perches48c8cee2010-03-10 15:20:45 -08003055static inline int fd_copyin(void __user *param, void *address,
3056 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057{
3058 return copy_from_user(address, param, size) ? -EFAULT : 0;
3059}
3060
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061static inline const char *drive_name(int type, int drive)
3062{
3063 struct floppy_struct *floppy;
3064
3065 if (type)
3066 floppy = floppy_type + type;
3067 else {
3068 if (UDP->native_format)
3069 floppy = floppy_type + UDP->native_format;
3070 else
3071 return "(null)";
3072 }
3073 if (floppy->name)
3074 return floppy->name;
3075 else
3076 return "(null)";
3077}
3078
3079/* raw commands */
3080static void raw_cmd_done(int flag)
3081{
3082 int i;
3083
3084 if (!flag) {
3085 raw_cmd->flags |= FD_RAW_FAILURE;
3086 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3087 } else {
3088 raw_cmd->reply_count = inr;
3089 if (raw_cmd->reply_count > MAX_REPLIES)
3090 raw_cmd->reply_count = 0;
3091 for (i = 0; i < raw_cmd->reply_count; i++)
3092 raw_cmd->reply[i] = reply_buffer[i];
3093
3094 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3095 unsigned long flags;
3096 flags = claim_dma_lock();
3097 raw_cmd->length = fd_get_dma_residue();
3098 release_dma_lock(flags);
3099 }
3100
3101 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3102 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3103 raw_cmd->flags |= FD_RAW_FAILURE;
3104
3105 if (disk_change(current_drive))
3106 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3107 else
3108 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3109 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3110 motor_off_callback(current_drive);
3111
3112 if (raw_cmd->next &&
3113 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3114 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3115 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3116 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3117 raw_cmd = raw_cmd->next;
3118 return;
3119 }
3120 }
3121 generic_done(flag);
3122}
3123
3124static struct cont_t raw_cmd_cont = {
3125 .interrupt = success_and_wakeup,
3126 .redo = floppy_start,
3127 .error = generic_failure,
3128 .done = raw_cmd_done
3129};
3130
3131static inline int raw_cmd_copyout(int cmd, char __user *param,
3132 struct floppy_raw_cmd *ptr)
3133{
3134 int ret;
3135
3136 while (ptr) {
Joe Perches86b12b42010-03-10 15:20:56 -08003137 ret = copy_to_user((void __user *)param, ptr, sizeof(*ptr));
3138 if (ret)
3139 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 param += sizeof(struct floppy_raw_cmd);
3141 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003142 if (ptr->length >= 0 &&
3143 ptr->length <= ptr->buffer_length) {
3144 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003145 ret = fd_copyout(ptr->data, ptr->kernel_data,
3146 length);
3147 if (ret)
3148 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 }
3151 ptr = ptr->next;
3152 }
3153 return 0;
3154}
3155
3156static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3157{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003158 struct floppy_raw_cmd *next;
3159 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
3161 this = *ptr;
3162 *ptr = NULL;
3163 while (this) {
3164 if (this->buffer_length) {
3165 fd_dma_mem_free((unsigned long)this->kernel_data,
3166 this->buffer_length);
3167 this->buffer_length = 0;
3168 }
3169 next = this->next;
3170 kfree(this);
3171 this = next;
3172 }
3173}
3174
3175static inline int raw_cmd_copyin(int cmd, char __user *param,
3176 struct floppy_raw_cmd **rcmd)
3177{
3178 struct floppy_raw_cmd *ptr;
3179 int ret;
3180 int i;
3181
3182 *rcmd = NULL;
3183 while (1) {
3184 ptr = (struct floppy_raw_cmd *)
3185 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3186 if (!ptr)
3187 return -ENOMEM;
3188 *rcmd = ptr;
Joe Perches86b12b42010-03-10 15:20:56 -08003189 ret = copy_from_user(ptr, (void __user *)param, sizeof(*ptr));
3190 if (ret)
3191 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 ptr->next = NULL;
3193 ptr->buffer_length = 0;
3194 param += sizeof(struct floppy_raw_cmd);
3195 if (ptr->cmd_count > 33)
3196 /* the command may now also take up the space
3197 * initially intended for the reply & the
3198 * reply count. Needed for long 82078 commands
3199 * such as RESTORE, which takes ... 17 command
3200 * bytes. Murphy's law #137: When you reserve
3201 * 16 bytes for a structure, you'll one day
3202 * discover that you really need 17...
3203 */
3204 return -EINVAL;
3205
3206 for (i = 0; i < 16; i++)
3207 ptr->reply[i] = 0;
3208 ptr->resultcode = 0;
3209 ptr->kernel_data = NULL;
3210
3211 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3212 if (ptr->length <= 0)
3213 return -EINVAL;
3214 ptr->kernel_data =
3215 (char *)fd_dma_mem_alloc(ptr->length);
3216 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3217 if (!ptr->kernel_data)
3218 return -ENOMEM;
3219 ptr->buffer_length = ptr->length;
3220 }
Joe Perches4575b552010-03-10 15:20:55 -08003221 if (ptr->flags & FD_RAW_WRITE) {
3222 ret = fd_copyin(ptr->data, ptr->kernel_data,
3223 ptr->length);
3224 if (ret)
3225 return ret;
3226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 rcmd = &(ptr->next);
3228 if (!(ptr->flags & FD_RAW_MORE))
3229 return 0;
3230 ptr->rate &= 0x43;
3231 }
3232}
3233
3234static int raw_cmd_ioctl(int cmd, void __user *param)
3235{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003237 int drive;
3238 int ret2;
3239 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
3241 if (FDCS->rawcmd <= 1)
3242 FDCS->rawcmd = 1;
3243 for (drive = 0; drive < N_DRIVE; drive++) {
3244 if (FDC(drive) != fdc)
3245 continue;
3246 if (drive == current_drive) {
3247 if (UDRS->fd_ref > 1) {
3248 FDCS->rawcmd = 2;
3249 break;
3250 }
3251 } else if (UDRS->fd_ref) {
3252 FDCS->rawcmd = 2;
3253 break;
3254 }
3255 }
3256
3257 if (FDCS->reset)
3258 return -EIO;
3259
3260 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3261 if (ret) {
3262 raw_cmd_free(&my_raw_cmd);
3263 return ret;
3264 }
3265
3266 raw_cmd = my_raw_cmd;
3267 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003268 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003269 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270
3271 if (ret != -EINTR && FDCS->reset)
3272 ret = -EIO;
3273
3274 DRS->track = NO_TRACK;
3275
3276 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3277 if (!ret)
3278 ret = ret2;
3279 raw_cmd_free(&my_raw_cmd);
3280 return ret;
3281}
3282
3283static int invalidate_drive(struct block_device *bdev)
3284{
3285 /* invalidate the buffer track to force a reread */
3286 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3287 process_fd_request();
3288 check_disk_change(bdev);
3289 return 0;
3290}
3291
3292static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3293 int drive, int type, struct block_device *bdev)
3294{
3295 int cnt;
3296
3297 /* sanity checking for parameters. */
3298 if (g->sect <= 0 ||
3299 g->head <= 0 ||
3300 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3301 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003302 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 return -EINVAL;
3304 if (type) {
3305 if (!capable(CAP_SYS_ADMIN))
3306 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003307 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003308 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003309 mutex_unlock(&open_lock);
3310 return -EINTR;
3311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 floppy_type[type] = *g;
3313 floppy_type[type].name = "user format";
3314 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3315 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3316 floppy_type[type].size + 1;
3317 process_fd_request();
3318 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3319 struct block_device *bdev = opened_bdev[cnt];
3320 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3321 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003322 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003324 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 } else {
3326 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003327
Joe Perches74f63f42010-03-10 15:20:58 -08003328 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003329 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003330 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 /* notice a disk change immediately, else
3332 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003333 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003334 return -EINTR;
3335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 oldStretch = g->stretch;
3337 user_params[drive] = *g;
3338 if (buffer_drive == drive)
3339 SUPBOUND(buffer_max, user_params[drive].sect);
3340 current_type[drive] = &user_params[drive];
3341 floppy_sizes[drive] = user_params[drive].size;
3342 if (cmd == FDDEFPRM)
3343 DRS->keep_data = -1;
3344 else
3345 DRS->keep_data = 1;
3346 /* invalidation. Invalidate only when needed, i.e.
3347 * when there are already sectors in the buffer cache
3348 * whose number will change. This is useful, because
3349 * mtools often changes the geometry of the disk after
3350 * looking at the boot block */
3351 if (DRS->maxblock > user_params[drive].sect ||
3352 DRS->maxtrack ||
3353 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003354 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 invalidate_drive(bdev);
3356 else
3357 process_fd_request();
3358 }
3359 return 0;
3360}
3361
3362/* handle obsolete ioctl's */
3363static int ioctl_table[] = {
3364 FDCLRPRM,
3365 FDSETPRM,
3366 FDDEFPRM,
3367 FDGETPRM,
3368 FDMSGON,
3369 FDMSGOFF,
3370 FDFMTBEG,
3371 FDFMTTRK,
3372 FDFMTEND,
3373 FDSETEMSGTRESH,
3374 FDFLUSH,
3375 FDSETMAXERRS,
3376 FDGETMAXERRS,
3377 FDGETDRVTYP,
3378 FDSETDRVPRM,
3379 FDGETDRVPRM,
3380 FDGETDRVSTAT,
3381 FDPOLLDRVSTAT,
3382 FDRESET,
3383 FDGETFDCSTAT,
3384 FDWERRORCLR,
3385 FDWERRORGET,
3386 FDRAWCMD,
3387 FDEJECT,
3388 FDTWADDLE
3389};
3390
3391static inline int normalize_ioctl(int *cmd, int *size)
3392{
3393 int i;
3394
3395 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3396 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3397 *size = _IOC_SIZE(*cmd);
3398 *cmd = ioctl_table[i];
3399 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003400 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 return -EFAULT;
3402 }
3403 return 0;
3404 }
3405 }
3406 return -EINVAL;
3407}
3408
3409static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3410{
3411 if (type)
3412 *g = &floppy_type[type];
3413 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003414 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003415 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003416 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003417 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 process_fd_request();
3419 *g = current_type[drive];
3420 }
3421 if (!*g)
3422 return -ENODEV;
3423 return 0;
3424}
3425
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003426static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3427{
3428 int drive = (long)bdev->bd_disk->private_data;
3429 int type = ITYPE(drive_state[drive].fd_device);
3430 struct floppy_struct *g;
3431 int ret;
3432
3433 ret = get_floppy_geometry(drive, type, &g);
3434 if (ret)
3435 return ret;
3436
3437 geo->heads = g->head;
3438 geo->sectors = g->sect;
3439 geo->cylinders = g->track;
3440 return 0;
3441}
3442
Al Viroa4af9b42008-03-02 09:27:55 -05003443static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 unsigned long param)
3445{
Al Viroa4af9b42008-03-02 09:27:55 -05003446#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447
Al Viroa4af9b42008-03-02 09:27:55 -05003448 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003449 int type = ITYPE(UDRS->fd_device);
3450 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 int ret;
3452 int size;
3453 union inparam {
3454 struct floppy_struct g; /* geometry */
3455 struct format_descr f;
3456 struct floppy_max_errors max_errors;
3457 struct floppy_drive_params dp;
3458 } inparam; /* parameters coming from user space */
3459 const char *outparam; /* parameters passed back to user space */
3460
3461 /* convert compatibility eject ioctls into floppy eject ioctl.
3462 * We do this in order to provide a means to eject floppy disks before
3463 * installing the new fdutils package */
3464 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003465 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 DPRINT("obsolete eject ioctl\n");
3467 DPRINT("please use floppycontrol --eject\n");
3468 cmd = FDEJECT;
3469 }
3470
Joe Perchesa81ee542010-03-10 15:20:46 -08003471 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 return -EINVAL;
3473
Joe Perchesa81ee542010-03-10 15:20:46 -08003474 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003475 ret = normalize_ioctl(&cmd, &size);
3476 if (ret)
3477 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003478
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 /* permission checks */
3480 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3481 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3482 return -EPERM;
3483
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003484 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3485 return -EINVAL;
3486
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003488 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003489 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3490 ret = fd_copyin((void __user *)param, &inparam, size);
3491 if (ret)
3492 return ret;
3493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494
Joe Perchesda273652010-03-10 15:20:52 -08003495 switch (cmd) {
3496 case FDEJECT:
3497 if (UDRS->fd_ref != 1)
3498 /* somebody else has this drive open */
3499 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003500 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003501 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
Joe Perchesda273652010-03-10 15:20:52 -08003503 /* do the actual eject. Fails on
3504 * non-Sparc architectures */
3505 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506
Joe Perchese0298532010-03-10 15:20:55 -08003507 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3508 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003509 process_fd_request();
3510 return ret;
3511 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003512 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003513 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003514 current_type[drive] = NULL;
3515 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3516 UDRS->keep_data = 0;
3517 return invalidate_drive(bdev);
3518 case FDSETPRM:
3519 case FDDEFPRM:
3520 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3521 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003522 ret = get_floppy_geometry(drive, type,
Joe Perchesda273652010-03-10 15:20:52 -08003523 (struct floppy_struct **)
Joe Perches4575b552010-03-10 15:20:55 -08003524 &outparam);
3525 if (ret)
3526 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003527 break;
3528 case FDMSGON:
3529 UDP->flags |= FTD_MSG;
3530 return 0;
3531 case FDMSGOFF:
3532 UDP->flags &= ~FTD_MSG;
3533 return 0;
3534 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003535 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003536 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003537 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003538 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003539 ret = UDRS->flags;
3540 process_fd_request();
3541 if (ret & FD_VERIFY)
3542 return -ENODEV;
3543 if (!(ret & FD_DISK_WRITABLE))
3544 return -EROFS;
3545 return 0;
3546 case FDFMTTRK:
3547 if (UDRS->fd_ref != 1)
3548 return -EBUSY;
3549 return do_format(drive, &inparam.f);
3550 case FDFMTEND:
3551 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003552 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003553 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003554 return invalidate_drive(bdev);
3555 case FDSETEMSGTRESH:
3556 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3557 return 0;
3558 case FDGETMAXERRS:
3559 outparam = (const char *)&UDP->max_errors;
3560 break;
3561 case FDSETMAXERRS:
3562 UDP->max_errors = inparam.max_errors;
3563 break;
3564 case FDGETDRVTYP:
3565 outparam = drive_name(type, drive);
3566 SUPBOUND(size, strlen(outparam) + 1);
3567 break;
3568 case FDSETDRVPRM:
3569 *UDP = inparam.dp;
3570 break;
3571 case FDGETDRVPRM:
3572 outparam = (const char *)UDP;
3573 break;
3574 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003575 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003576 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003577 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003578 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003579 process_fd_request();
3580 /* fall through */
3581 case FDGETDRVSTAT:
3582 outparam = (const char *)UDRS;
3583 break;
3584 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003585 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003586 case FDGETFDCSTAT:
3587 outparam = (const char *)UFDCS;
3588 break;
3589 case FDWERRORCLR:
3590 memset(UDRWE, 0, sizeof(*UDRWE));
3591 return 0;
3592 case FDWERRORGET:
3593 outparam = (const char *)UDRWE;
3594 break;
3595 case FDRAWCMD:
3596 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003598 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003599 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003600 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003601 i = raw_cmd_ioctl(cmd, (void __user *)param);
3602 if (i == -EINTR)
3603 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003604 process_fd_request();
3605 return i;
3606 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003607 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003608 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003609 twaddle();
3610 process_fd_request();
3611 return 0;
3612 default:
3613 return -EINVAL;
3614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615
3616 if (_IOC_DIR(cmd) & _IOC_READ)
3617 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003618
3619 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620}
3621
3622static void __init config_types(void)
3623{
Joe Perchesb46df352010-03-10 15:20:46 -08003624 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 int drive;
3626
3627 /* read drive info out of physical CMOS */
3628 drive = 0;
3629 if (!UDP->cmos)
3630 UDP->cmos = FLOPPY0_TYPE;
3631 drive = 1;
3632 if (!UDP->cmos && FLOPPY1_TYPE)
3633 UDP->cmos = FLOPPY1_TYPE;
3634
Jesper Juhl06f748c2007-10-16 23:30:57 -07003635 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636
3637 for (drive = 0; drive < N_DRIVE; drive++) {
3638 unsigned int type = UDP->cmos;
3639 struct floppy_drive_params *params;
3640 const char *name = NULL;
3641 static char temparea[32];
3642
Tobias Klauser945f3902006-01-08 01:05:11 -08003643 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 params = &default_drive_params[type].params;
3645 if (type) {
3646 name = default_drive_params[type].name;
3647 allowed_drive_mask |= 1 << drive;
3648 } else
3649 allowed_drive_mask &= ~(1 << drive);
3650 } else {
3651 params = &default_drive_params[0].params;
3652 sprintf(temparea, "unknown type %d (usb?)", type);
3653 name = temparea;
3654 }
3655 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003656 const char *prepend;
3657 if (!has_drive) {
3658 prepend = "";
3659 has_drive = true;
3660 pr_info("Floppy drive(s):");
3661 } else {
3662 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 }
Joe Perchesb46df352010-03-10 15:20:46 -08003664
3665 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 }
3667 *UDP = *params;
3668 }
Joe Perchesb46df352010-03-10 15:20:46 -08003669
3670 if (has_drive)
3671 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672}
3673
Al Viroa4af9b42008-03-02 09:27:55 -05003674static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675{
Al Viroa4af9b42008-03-02 09:27:55 -05003676 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003678 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 if (UDRS->fd_ref < 0)
3680 UDRS->fd_ref = 0;
3681 else if (!UDRS->fd_ref--) {
3682 DPRINT("floppy_release with fd_ref == 0");
3683 UDRS->fd_ref = 0;
3684 }
3685 if (!UDRS->fd_ref)
3686 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003687 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003688
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 return 0;
3690}
3691
3692/*
3693 * floppy_open check for aliasing (/dev/fd0 can be the same as
3694 * /dev/PS0 etc), and disallows simultaneous access to the same
3695 * drive with different device numbers.
3696 */
Al Viroa4af9b42008-03-02 09:27:55 -05003697static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698{
Al Viroa4af9b42008-03-02 09:27:55 -05003699 int drive = (long)bdev->bd_disk->private_data;
3700 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 int try;
3702 int res = -EBUSY;
3703 char *tmp;
3704
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003705 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003707 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 goto out2;
3709
3710 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003711 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3712 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 }
3714
Al Viroa4af9b42008-03-02 09:27:55 -05003715 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 goto out2;
3717
Al Viroa4af9b42008-03-02 09:27:55 -05003718 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 UDRS->fd_ref = -1;
3720 else
3721 UDRS->fd_ref++;
3722
Al Viroa4af9b42008-03-02 09:27:55 -05003723 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
3725 res = -ENXIO;
3726
3727 if (!floppy_track_buffer) {
3728 /* if opening an ED drive, reserve a big buffer,
3729 * else reserve a small one */
3730 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3731 try = 64; /* Only 48 actually useful */
3732 else
3733 try = 32; /* Only 24 actually useful */
3734
3735 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3736 if (!tmp && !floppy_track_buffer) {
3737 try >>= 1; /* buffer only one side */
3738 INFBOUND(try, 16);
3739 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3740 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003741 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 if (!tmp && !floppy_track_buffer) {
3744 DPRINT("Unable to allocate DMA memory\n");
3745 goto out;
3746 }
3747 if (floppy_track_buffer) {
3748 if (tmp)
3749 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3750 } else {
3751 buffer_min = buffer_max = -1;
3752 floppy_track_buffer = tmp;
3753 max_buffer_sectors = try;
3754 }
3755 }
3756
Al Viroa4af9b42008-03-02 09:27:55 -05003757 new_dev = MINOR(bdev->bd_dev);
3758 UDRS->fd_device = new_dev;
3759 set_capacity(disks[drive], floppy_sizes[new_dev]);
3760 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 if (buffer_drive == drive)
3762 buffer_track = -1;
3763 }
3764
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 if (UFDCS->rawcmd == 1)
3766 UFDCS->rawcmd = 2;
3767
Al Viroa4af9b42008-03-02 09:27:55 -05003768 if (!(mode & FMODE_NDELAY)) {
3769 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003771 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003772 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 goto out;
3774 }
3775 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003776 if ((mode & FMODE_WRITE) &&
3777 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 goto out;
3779 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003780 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 return 0;
3782out:
3783 if (UDRS->fd_ref < 0)
3784 UDRS->fd_ref = 0;
3785 else
3786 UDRS->fd_ref--;
3787 if (!UDRS->fd_ref)
3788 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003790 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 return res;
3792}
3793
3794/*
3795 * Check if the disk has been changed or if a change has been faked.
3796 */
3797static int check_floppy_change(struct gendisk *disk)
3798{
3799 int drive = (long)disk->private_data;
3800
Joe Perchese0298532010-03-10 15:20:55 -08003801 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3802 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 return 1;
3804
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003805 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003806 lock_fdc(drive, false);
3807 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 }
3810
Joe Perchese0298532010-03-10 15:20:55 -08003811 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3812 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 test_bit(drive, &fake_change) ||
3814 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3815 return 1;
3816 return 0;
3817}
3818
3819/*
3820 * This implements "read block 0" for floppy_revalidate().
3821 * Needed for format autodetection, checking whether there is
3822 * a disk in the drive, and whether that disk is writable.
3823 */
3824
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003825static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828}
3829
3830static int __floppy_read_block_0(struct block_device *bdev)
3831{
3832 struct bio bio;
3833 struct bio_vec bio_vec;
3834 struct completion complete;
3835 struct page *page;
3836 size_t size;
3837
3838 page = alloc_page(GFP_NOIO);
3839 if (!page) {
3840 process_fd_request();
3841 return -ENOMEM;
3842 }
3843
3844 size = bdev->bd_block_size;
3845 if (!size)
3846 size = 1024;
3847
3848 bio_init(&bio);
3849 bio.bi_io_vec = &bio_vec;
3850 bio_vec.bv_page = page;
3851 bio_vec.bv_len = size;
3852 bio_vec.bv_offset = 0;
3853 bio.bi_vcnt = 1;
3854 bio.bi_idx = 0;
3855 bio.bi_size = size;
3856 bio.bi_bdev = bdev;
3857 bio.bi_sector = 0;
3858 init_completion(&complete);
3859 bio.bi_private = &complete;
3860 bio.bi_end_io = floppy_rb0_complete;
3861
3862 submit_bio(READ, &bio);
3863 generic_unplug_device(bdev_get_queue(bdev));
3864 process_fd_request();
3865 wait_for_completion(&complete);
3866
3867 __free_page(page);
3868
3869 return 0;
3870}
3871
3872/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3873 * the bootblock (block 0). "Autodetection" is also needed to check whether
3874 * there is a disk in the drive at all... Thus we also do it for fixed
3875 * geometry formats */
3876static int floppy_revalidate(struct gendisk *disk)
3877{
3878 int drive = (long)disk->private_data;
3879#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3880 int cf;
3881 int res = 0;
3882
Joe Perchese0298532010-03-10 15:20:55 -08003883 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3884 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
3885 test_bit(drive, &fake_change) || NO_GEOM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003887 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 return -EFAULT;
3889 }
Joe Perches74f63f42010-03-10 15:20:58 -08003890 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003891 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3892 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3894 process_fd_request(); /*already done by another thread */
3895 return 0;
3896 }
3897 UDRS->maxblock = 0;
3898 UDRS->maxtrack = 0;
3899 if (buffer_drive == drive)
3900 buffer_track = -1;
3901 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003902 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 if (cf)
3904 UDRS->generation++;
3905 if (NO_GEOM) {
3906 /* auto-sensing */
3907 res = __floppy_read_block_0(opened_bdev[drive]);
3908 } else {
3909 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003910 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 process_fd_request();
3912 }
3913 }
3914 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3915 return res;
3916}
3917
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003918static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003919 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003920 .open = floppy_open,
3921 .release = floppy_release,
3922 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003923 .getgeo = fd_getgeo,
3924 .media_changed = check_floppy_change,
3925 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928/*
3929 * Floppy Driver initialization
3930 * =============================
3931 */
3932
3933/* Determine the floppy disk controller type */
3934/* This routine was written by David C. Niemi */
3935static char __init get_fdc_version(void)
3936{
3937 int r;
3938
3939 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3940 if (FDCS->reset)
3941 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003942 r = result();
3943 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 return FDC_NONE; /* No FDC present ??? */
3945 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003946 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3948 }
3949 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003950 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3951 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 return FDC_UNKNOWN;
3953 }
3954
3955 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003956 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3958 }
3959
3960 output_byte(FD_PERPENDICULAR);
3961 if (need_more_output() == MORE_OUTPUT) {
3962 output_byte(0);
3963 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003964 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 return FDC_82072A; /* 82072A as found on Sparcs. */
3966 }
3967
3968 output_byte(FD_UNLOCK);
3969 r = result();
3970 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003971 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003972 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 * LOCK/UNLOCK */
3974 }
3975 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003976 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3977 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 return FDC_UNKNOWN;
3979 }
3980 output_byte(FD_PARTID);
3981 r = result();
3982 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003983 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3984 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 return FDC_UNKNOWN;
3986 }
3987 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003988 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 return FDC_82077; /* Revised 82077AA passes all the tests */
3990 }
3991 switch (reply_buffer[0] >> 5) {
3992 case 0x0:
3993 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003994 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 return FDC_82078;
3996 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003997 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 return FDC_82078;
3999 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004000 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 return FDC_S82078B;
4002 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004003 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 return FDC_87306;
4005 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004006 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4007 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 return FDC_82078_UNKN;
4009 }
4010} /* get_fdc_version */
4011
4012/* lilo configuration */
4013
4014static void __init floppy_set_flags(int *ints, int param, int param2)
4015{
4016 int i;
4017
4018 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4019 if (param)
4020 default_drive_params[i].params.flags |= param2;
4021 else
4022 default_drive_params[i].params.flags &= ~param2;
4023 }
4024 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4025}
4026
4027static void __init daring(int *ints, int param, int param2)
4028{
4029 int i;
4030
4031 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4032 if (param) {
4033 default_drive_params[i].params.select_delay = 0;
4034 default_drive_params[i].params.flags |=
4035 FD_SILENT_DCL_CLEAR;
4036 } else {
4037 default_drive_params[i].params.select_delay =
4038 2 * HZ / 100;
4039 default_drive_params[i].params.flags &=
4040 ~FD_SILENT_DCL_CLEAR;
4041 }
4042 }
4043 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4044}
4045
4046static void __init set_cmos(int *ints, int dummy, int dummy2)
4047{
4048 int current_drive = 0;
4049
4050 if (ints[0] != 2) {
4051 DPRINT("wrong number of parameters for CMOS\n");
4052 return;
4053 }
4054 current_drive = ints[1];
4055 if (current_drive < 0 || current_drive >= 8) {
4056 DPRINT("bad drive for set_cmos\n");
4057 return;
4058 }
4059#if N_FDC > 1
4060 if (current_drive >= 4 && !FDC2)
4061 FDC2 = 0x370;
4062#endif
4063 DP->cmos = ints[2];
4064 DPRINT("setting CMOS code to %d\n", ints[2]);
4065}
4066
4067static struct param_table {
4068 const char *name;
4069 void (*fn) (int *ints, int param, int param2);
4070 int *var;
4071 int def_param;
4072 int param2;
4073} config_params[] __initdata = {
4074 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4075 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4076 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4077 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4078 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4079 {"daring", daring, NULL, 1, 0},
4080#if N_FDC > 1
4081 {"two_fdc", NULL, &FDC2, 0x370, 0},
4082 {"one_fdc", NULL, &FDC2, 0, 0},
4083#endif
4084 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4085 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4086 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4087 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4088 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4089 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4090 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4091 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4092 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4093 {"nofifo", NULL, &no_fifo, 0x20, 0},
4094 {"usefifo", NULL, &no_fifo, 0, 0},
4095 {"cmos", set_cmos, NULL, 0, 0},
4096 {"slow", NULL, &slow_floppy, 1, 0},
4097 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4098 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4099 {"L40SX", NULL, &print_unex, 0, 0}
4100
4101 EXTRA_FLOPPY_PARAMS
4102};
4103
4104static int __init floppy_setup(char *str)
4105{
4106 int i;
4107 int param;
4108 int ints[11];
4109
4110 str = get_options(str, ARRAY_SIZE(ints), ints);
4111 if (str) {
4112 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4113 if (strcmp(str, config_params[i].name) == 0) {
4114 if (ints[0])
4115 param = ints[1];
4116 else
4117 param = config_params[i].def_param;
4118 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004119 config_params[i].fn(ints, param,
4120 config_params[i].
4121 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 if (config_params[i].var) {
4123 DPRINT("%s=%d\n", str, param);
4124 *config_params[i].var = param;
4125 }
4126 return 1;
4127 }
4128 }
4129 }
4130 if (str) {
4131 DPRINT("unknown floppy option [%s]\n", str);
4132
4133 DPRINT("allowed options are:");
4134 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004135 pr_cont(" %s", config_params[i].name);
4136 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 } else
4138 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004139 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 return 0;
4141}
4142
4143static int have_no_fdc = -ENODEV;
4144
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004145static ssize_t floppy_cmos_show(struct device *dev,
4146 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004147{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004148 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004149 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004150
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004151 drive = p->id;
4152 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004153}
Joe Perches48c8cee2010-03-10 15:20:45 -08004154
4155DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004156
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157static void floppy_device_release(struct device *dev)
4158{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159}
4160
Frans Popc90cd332009-07-25 22:24:54 +02004161static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004162{
4163 int fdc;
4164
4165 for (fdc = 0; fdc < N_FDC; fdc++)
4166 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004167 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004168
4169 return 0;
4170}
4171
Alexey Dobriyan47145212009-12-14 18:00:08 -08004172static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004173 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004174 .restore = floppy_resume,
4175};
4176
4177static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004178 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004179 .name = "floppy",
4180 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004181 },
4182};
4183
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004184static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185
4186static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4187{
4188 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4189 if (drive >= N_DRIVE ||
4190 !(allowed_drive_mask & (1 << drive)) ||
4191 fdc_state[FDC(drive)].version == FDC_NONE)
4192 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004193 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 return NULL;
4195 *part = 0;
4196 return get_disk(disks[drive]);
4197}
4198
4199static int __init floppy_init(void)
4200{
4201 int i, unit, drive;
4202 int err, dr;
4203
Kumar Gala68e1ee62008-09-22 14:41:31 -07004204#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004205 if (check_legacy_ioport(FDC1))
4206 return -ENODEV;
4207#endif
4208
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 raw_cmd = NULL;
4210
4211 for (dr = 0; dr < N_DRIVE; dr++) {
4212 disks[dr] = alloc_disk(1);
4213 if (!disks[dr]) {
4214 err = -ENOMEM;
4215 goto out_put_disk;
4216 }
4217
4218 disks[dr]->major = FLOPPY_MAJOR;
4219 disks[dr]->first_minor = TOMINOR(dr);
4220 disks[dr]->fops = &floppy_fops;
4221 sprintf(disks[dr]->disk_name, "fd%d", dr);
4222
4223 init_timer(&motor_off_timer[dr]);
4224 motor_off_timer[dr].data = dr;
4225 motor_off_timer[dr].function = motor_off_callback;
4226 }
4227
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 err = register_blkdev(FLOPPY_MAJOR, "fd");
4229 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004230 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004232 err = platform_driver_register(&floppy_driver);
4233 if (err)
4234 goto out_unreg_blkdev;
4235
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4237 if (!floppy_queue) {
4238 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004239 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004241 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242
4243 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4244 floppy_find, NULL, NULL);
4245
4246 for (i = 0; i < 256; i++)
4247 if (ITYPE(i))
4248 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4249 else
4250 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4251
4252 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4253 config_types();
4254
4255 for (i = 0; i < N_FDC; i++) {
4256 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004257 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 FDCS->dtr = -1;
4259 FDCS->dor = 0x4;
4260#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004261 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262#ifdef __mc68000__
4263 if (MACH_IS_SUN3X)
4264#endif
4265 FDCS->version = FDC_82072A;
4266#endif
4267 }
4268
4269 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 fdc_state[0].address = FDC1;
4271 if (fdc_state[0].address == -1) {
4272 del_timer(&fd_timeout);
4273 err = -ENODEV;
4274 goto out_unreg_region;
4275 }
4276#if N_FDC > 1
4277 fdc_state[1].address = FDC2;
4278#endif
4279
4280 fdc = 0; /* reset fdc in case of unexpected interrupt */
4281 err = floppy_grab_irq_and_dma();
4282 if (err) {
4283 del_timer(&fd_timeout);
4284 err = -EBUSY;
4285 goto out_unreg_region;
4286 }
4287
4288 /* initialise drive state */
4289 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004290 memset(UDRS, 0, sizeof(*UDRS));
4291 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004292 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4293 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4294 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 UDRS->fd_device = -1;
4296 floppy_track_buffer = NULL;
4297 max_buffer_sectors = 0;
4298 }
4299 /*
4300 * Small 10 msec delay to let through any interrupt that
4301 * initialization might have triggered, to not
4302 * confuse detection:
4303 */
4304 msleep(10);
4305
4306 for (i = 0; i < N_FDC; i++) {
4307 fdc = i;
4308 FDCS->driver_version = FD_DRIVER_VERSION;
4309 for (unit = 0; unit < 4; unit++)
4310 FDCS->track[unit] = 0;
4311 if (FDCS->address == -1)
4312 continue;
4313 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004314 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004316 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 FDCS->address = -1;
4318 FDCS->version = FDC_NONE;
4319 continue;
4320 }
4321 /* Try to determine the floppy controller type */
4322 FDCS->version = get_fdc_version();
4323 if (FDCS->version == FDC_NONE) {
4324 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004325 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 FDCS->address = -1;
4327 continue;
4328 }
4329 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4330 can_use_virtual_dma = 0;
4331
4332 have_no_fdc = 0;
4333 /* Not all FDCs seem to be able to handle the version command
4334 * properly, so force a reset for the standard FDC clones,
4335 * to avoid interrupt garbage.
4336 */
Joe Perches74f63f42010-03-10 15:20:58 -08004337 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 }
4339 fdc = 0;
4340 del_timer(&fd_timeout);
4341 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 initialising = 0;
4343 if (have_no_fdc) {
4344 DPRINT("no floppy controllers found\n");
4345 err = have_no_fdc;
4346 goto out_flush_work;
4347 }
4348
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 for (drive = 0; drive < N_DRIVE; drive++) {
4350 if (!(allowed_drive_mask & (1 << drive)))
4351 continue;
4352 if (fdc_state[FDC(drive)].version == FDC_NONE)
4353 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004354
4355 floppy_device[drive].name = floppy_device_name;
4356 floppy_device[drive].id = drive;
4357 floppy_device[drive].dev.release = floppy_device_release;
4358
4359 err = platform_device_register(&floppy_device[drive]);
4360 if (err)
4361 goto out_flush_work;
4362
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004363 err = device_create_file(&floppy_device[drive].dev,
4364 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004365 if (err)
4366 goto out_unreg_platform_dev;
4367
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 /* to be cleaned up... */
4369 disks[drive]->private_data = (void *)(long)drive;
4370 disks[drive]->queue = floppy_queue;
4371 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004372 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 add_disk(disks[drive]);
4374 }
4375
4376 return 0;
4377
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004378out_unreg_platform_dev:
4379 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380out_flush_work:
4381 flush_scheduled_work();
4382 if (usage_count)
4383 floppy_release_irq_and_dma();
4384out_unreg_region:
4385 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4386 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004387out_unreg_driver:
4388 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389out_unreg_blkdev:
4390 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391out_put_disk:
4392 while (dr--) {
4393 del_timer(&motor_off_timer[dr]);
4394 put_disk(disks[dr]);
4395 }
4396 return err;
4397}
4398
4399static DEFINE_SPINLOCK(floppy_usage_lock);
4400
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004401static const struct io_region {
4402 int offset;
4403 int size;
4404} io_regions[] = {
4405 { 2, 1 },
4406 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4407 { 4, 2 },
4408 /* address + 6 is reserved, and may be taken by IDE.
4409 * Unfortunately, Adaptec doesn't know this :-(, */
4410 { 7, 1 },
4411};
4412
4413static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4414{
4415 while (p != io_regions) {
4416 p--;
4417 release_region(FDCS->address + p->offset, p->size);
4418 }
4419}
4420
4421#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4422
4423static int floppy_request_regions(int fdc)
4424{
4425 const struct io_region *p;
4426
4427 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004428 if (!request_region(FDCS->address + p->offset,
4429 p->size, "floppy")) {
4430 DPRINT("Floppy io-port 0x%04lx in use\n",
4431 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004432 floppy_release_allocated_regions(fdc, p);
4433 return -EBUSY;
4434 }
4435 }
4436 return 0;
4437}
4438
4439static void floppy_release_regions(int fdc)
4440{
4441 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4442}
4443
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444static int floppy_grab_irq_and_dma(void)
4445{
4446 unsigned long flags;
4447
4448 spin_lock_irqsave(&floppy_usage_lock, flags);
4449 if (usage_count++) {
4450 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4451 return 0;
4452 }
4453 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004454
4455 /*
4456 * We might have scheduled a free_irq(), wait it to
4457 * drain first:
4458 */
4459 flush_scheduled_work();
4460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 if (fd_request_irq()) {
4462 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4463 FLOPPY_IRQ);
4464 spin_lock_irqsave(&floppy_usage_lock, flags);
4465 usage_count--;
4466 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4467 return -1;
4468 }
4469 if (fd_request_dma()) {
4470 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4471 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004472 if (can_use_virtual_dma & 2)
4473 use_virtual_dma = can_use_virtual_dma = 1;
4474 if (!(can_use_virtual_dma & 1)) {
4475 fd_free_irq();
4476 spin_lock_irqsave(&floppy_usage_lock, flags);
4477 usage_count--;
4478 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4479 return -1;
4480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 }
4482
4483 for (fdc = 0; fdc < N_FDC; fdc++) {
4484 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004485 if (floppy_request_regions(fdc))
4486 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 }
4488 }
4489 for (fdc = 0; fdc < N_FDC; fdc++) {
4490 if (FDCS->address != -1) {
4491 reset_fdc_info(1);
4492 fd_outb(FDCS->dor, FD_DOR);
4493 }
4494 }
4495 fdc = 0;
4496 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4497
4498 for (fdc = 0; fdc < N_FDC; fdc++)
4499 if (FDCS->address != -1)
4500 fd_outb(FDCS->dor, FD_DOR);
4501 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004502 * The driver will try and free resources and relies on us
4503 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 */
4505 fdc = 0;
4506 irqdma_allocated = 1;
4507 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004508cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 fd_free_irq();
4510 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004511 while (--fdc >= 0)
4512 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 spin_lock_irqsave(&floppy_usage_lock, flags);
4514 usage_count--;
4515 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4516 return -1;
4517}
4518
4519static void floppy_release_irq_and_dma(void)
4520{
4521 int old_fdc;
4522#ifdef FLOPPY_SANITY_CHECK
4523#ifndef __sparc__
4524 int drive;
4525#endif
4526#endif
4527 long tmpsize;
4528 unsigned long tmpaddr;
4529 unsigned long flags;
4530
4531 spin_lock_irqsave(&floppy_usage_lock, flags);
4532 if (--usage_count) {
4533 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4534 return;
4535 }
4536 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4537 if (irqdma_allocated) {
4538 fd_disable_dma();
4539 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004540 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 irqdma_allocated = 0;
4542 }
4543 set_dor(0, ~0, 8);
4544#if N_FDC > 1
4545 set_dor(1, ~8, 0);
4546#endif
4547 floppy_enable_hlt();
4548
4549 if (floppy_track_buffer && max_buffer_sectors) {
4550 tmpsize = max_buffer_sectors * 1024;
4551 tmpaddr = (unsigned long)floppy_track_buffer;
4552 floppy_track_buffer = NULL;
4553 max_buffer_sectors = 0;
4554 buffer_min = buffer_max = -1;
4555 fd_dma_mem_free(tmpaddr, tmpsize);
4556 }
4557#ifdef FLOPPY_SANITY_CHECK
4558#ifndef __sparc__
4559 for (drive = 0; drive < N_FDC * 4; drive++)
4560 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004561 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562#endif
4563
4564 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004565 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004567 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004568 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004569 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570#endif
4571 old_fdc = fdc;
4572 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004573 if (FDCS->address != -1)
4574 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 fdc = old_fdc;
4576}
4577
4578#ifdef MODULE
4579
4580static char *floppy;
4581
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582static void __init parse_floppy_cfg_string(char *cfg)
4583{
4584 char *ptr;
4585
4586 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004587 ptr = cfg;
4588 while (*cfg && *cfg != ' ' && *cfg != '\t')
4589 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 if (*cfg) {
4591 *cfg = '\0';
4592 cfg++;
4593 }
4594 if (*ptr)
4595 floppy_setup(ptr);
4596 }
4597}
4598
Jon Schindler7afea3b2008-04-29 00:59:21 -07004599static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600{
4601 if (floppy)
4602 parse_floppy_cfg_string(floppy);
4603 return floppy_init();
4604}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004605module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606
Jon Schindler7afea3b2008-04-29 00:59:21 -07004607static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608{
4609 int drive;
4610
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4612 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004613 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614
4615 for (drive = 0; drive < N_DRIVE; drive++) {
4616 del_timer_sync(&motor_off_timer[drive]);
4617
4618 if ((allowed_drive_mask & (1 << drive)) &&
4619 fdc_state[FDC(drive)].version != FDC_NONE) {
4620 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004621 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4622 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 }
4624 put_disk(disks[drive]);
4625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626
4627 del_timer_sync(&fd_timeout);
4628 del_timer_sync(&fd_timer);
4629 blk_cleanup_queue(floppy_queue);
4630
4631 if (usage_count)
4632 floppy_release_irq_and_dma();
4633
4634 /* eject disk, if any */
4635 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636}
Joe Perches48c8cee2010-03-10 15:20:45 -08004637
Jon Schindler7afea3b2008-04-29 00:59:21 -07004638module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639
4640module_param(floppy, charp, 0);
4641module_param(FLOPPY_IRQ, int, 0);
4642module_param(FLOPPY_DMA, int, 0);
4643MODULE_AUTHOR("Alain L. Knaff");
4644MODULE_SUPPORTED_DEVICE("fd");
4645MODULE_LICENSE("GPL");
4646
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004647/* This doesn't actually get used other than for module information */
4648static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004649 {"PNP0700", 0},
4650 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004651};
Joe Perches48c8cee2010-03-10 15:20:45 -08004652
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004653MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4654
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655#else
4656
4657__setup("floppy=", floppy_setup);
4658module_init(floppy_init)
4659#endif
4660
4661MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);