blob: 6b75e70ca6287c51077298e63e8f324fdf9f2dd6 [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#include <linux/blkdev.h>
254#include <linux/blkpg.h>
255#include <linux/cdrom.h> /* for the compatibility eject ioctl */
256#include <linux/completion.h>
257
258static struct request *current_req;
259static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800260static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262#ifndef fd_get_dma_residue
263#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
264#endif
265
266/* Dma Memory related stuff */
267
268#ifndef fd_dma_mem_free
269#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
270#endif
271
272#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800273#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274#endif
275
276static inline void fallback_on_nodma_alloc(char **addr, size_t l)
277{
278#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
279 if (*addr)
280 return; /* we have the memory */
281 if (can_use_virtual_dma != 2)
282 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800283 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 *addr = (char *)nodma_mem_alloc(l);
285#else
286 return;
287#endif
288}
289
290/* End dma memory related stuff */
291
292static unsigned long fake_change;
293static int initialising = 1;
294
Joe Perches48c8cee2010-03-10 15:20:45 -0800295#define ITYPE(x) (((x) >> 2) & 0x1f)
296#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
297#define UNIT(x) ((x) & 0x03) /* drive on fdc */
298#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700299 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Joe Perches48c8cee2010-03-10 15:20:45 -0800302#define DP (&drive_params[current_drive])
303#define DRS (&drive_state[current_drive])
304#define DRWE (&write_errors[current_drive])
305#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Joe Perches48c8cee2010-03-10 15:20:45 -0800307#define UDP (&drive_params[drive])
308#define UDRS (&drive_state[drive])
309#define UDRWE (&write_errors[drive])
310#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Joe Perches48c8cee2010-03-10 15:20:45 -0800312#define DPRINT(format, args...) \
Joe Perches4d18ef02010-03-10 15:20:59 -0800313 pr_info("floppy%d: " format, current_drive, ##args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Joe Perches48c8cee2010-03-10 15:20:45 -0800315#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
316#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800319#define COMMAND (raw_cmd->cmd[0])
320#define DR_SELECT (raw_cmd->cmd[1])
321#define TRACK (raw_cmd->cmd[2])
322#define HEAD (raw_cmd->cmd[3])
323#define SECTOR (raw_cmd->cmd[4])
324#define SIZECODE (raw_cmd->cmd[5])
325#define SECT_PER_TRACK (raw_cmd->cmd[6])
326#define GAP (raw_cmd->cmd[7])
327#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328#define NR_RW 9
329
330/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800331#define F_SIZECODE (raw_cmd->cmd[2])
332#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
333#define F_GAP (raw_cmd->cmd[4])
334#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335#define NR_F 6
336
337/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800338 * Maximum disk size (in kilobytes).
339 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 * [Now it is rather a minimum]
341 */
342#define MAX_DISK_SIZE 4 /* 3984 */
343
344/*
345 * globals used by 'result()'
346 */
347#define MAX_REPLIES 16
348static unsigned char reply_buffer[MAX_REPLIES];
349static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800350#define ST0 (reply_buffer[0])
351#define ST1 (reply_buffer[1])
352#define ST2 (reply_buffer[2])
353#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
354#define R_TRACK (reply_buffer[3])
355#define R_HEAD (reply_buffer[4])
356#define R_SECTOR (reply_buffer[5])
357#define R_SIZECODE (reply_buffer[6])
358
359#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361/*
362 * this struct defines the different floppy drive types.
363 */
364static struct {
365 struct floppy_drive_params params;
366 const char *name; /* name printed while booting */
367} default_drive_params[] = {
368/* NOTE: the time values in jiffies should be in msec!
369 CMOS drive type
370 | Maximum data rate supported by drive type
371 | | Head load time, msec
372 | | | Head unload time, msec (not used)
373 | | | | Step rate interval, usec
374 | | | | | Time needed for spinup time (jiffies)
375 | | | | | | Timeout for spinning down (jiffies)
376 | | | | | | | Spindown offset (where disk stops)
377 | | | | | | | | Select delay
378 | | | | | | | | | RPS
379 | | | | | | | | | | Max number of tracks
380 | | | | | | | | | | | Interrupt timeout
381 | | | | | | | | | | | | Max nonintlv. sectors
382 | | | | | | | | | | | | | -Max Errors- flags */
383{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
384 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
385
386{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
387 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
388
389{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
390 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
391
392{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
393 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
394
395{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
396 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
397
398{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
399 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
400
401{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
402 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
403/* | --autodetected formats--- | | |
404 * read_track | | Name printed when booting
405 * | Native format
406 * Frequency of disk change checks */
407};
408
409static struct floppy_drive_params drive_params[N_DRIVE];
410static struct floppy_drive_struct drive_state[N_DRIVE];
411static struct floppy_write_errors write_errors[N_DRIVE];
412static struct timer_list motor_off_timer[N_DRIVE];
413static struct gendisk *disks[N_DRIVE];
414static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800415static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
417
418/*
419 * This struct defines the different floppy types.
420 *
421 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
422 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
423 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
424 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
425 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
426 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
427 * side 0 is on physical side 0 (but with the misnamed sector IDs).
428 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700429 * 'options'.
430 *
431 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
432 * The LSB (bit 2) is flipped. For most disks, the first sector
433 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
434 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
435 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
436 *
437 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 */
439/*
440 Size
441 | Sectors per track
442 | | Head
443 | | | Tracks
444 | | | | Stretch
445 | | | | | Gap 1 size
446 | | | | | | Data rate, | 0x40 for perp
447 | | | | | | | Spec1 (stepping rate, head unload
448 | | | | | | | | /fmt gap (gap2) */
449static struct floppy_struct floppy_type[32] = {
450 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
451 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
452 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
453 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
454 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
455 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
456 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
457 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
458 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
459 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
460
461 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
462 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
463 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
464 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
465 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
466 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
467 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
468 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
469 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
470 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
471
472 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
473 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
474 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
475 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
476 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
477 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
478 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
479 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
480 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
484 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
485};
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487#define SECTSIZE (_FD_SECTSIZE(*floppy))
488
489/* Auto-detection: Disk type used until the next media change occurs. */
490static struct floppy_struct *current_type[N_DRIVE];
491
492/*
493 * User-provided type information. current_type points to
494 * the respective entry of this array.
495 */
496static struct floppy_struct user_params[N_DRIVE];
497
498static sector_t floppy_sizes[256];
499
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200500static char floppy_device_name[] = "floppy";
501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502/*
503 * The driver is trying to determine the correct media format
504 * while probing is set. rw_interrupt() clears it after a
505 * successful access.
506 */
507static int probing;
508
509/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800510#define FD_COMMAND_NONE -1
511#define FD_COMMAND_ERROR 2
512#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514static volatile int command_status = FD_COMMAND_NONE;
515static unsigned long fdc_busy;
516static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
517static DECLARE_WAIT_QUEUE_HEAD(command_done);
518
519#define NO_SIGNAL (!interruptible || !signal_pending(current))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521/* Errors during formatting are counted here. */
522static int format_errors;
523
524/* Format request descriptor. */
525static struct format_descr format_req;
526
527/*
528 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
529 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
530 * H is head unload time (1=16ms, 2=32ms, etc)
531 */
532
533/*
534 * Track buffer
535 * Because these are written to by the DMA controller, they must
536 * not contain a 64k byte boundary crossing, or data will be
537 * corrupted/lost.
538 */
539static char *floppy_track_buffer;
540static int max_buffer_sectors;
541
542static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700543typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800545 void (*interrupt)(void);
546 /* this is called after the interrupt of the
547 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700548 void (*redo)(void); /* this is called to retry the operation */
549 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 done_f done; /* this is called to say if the operation has
551 * succeeded/failed */
552} *cont;
553
554static void floppy_ready(void);
555static void floppy_start(void);
556static void process_fd_request(void);
557static void recalibrate_floppy(void);
558static void floppy_shutdown(unsigned long);
559
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800560static int floppy_request_regions(int);
561static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562static int floppy_grab_irq_and_dma(void);
563static void floppy_release_irq_and_dma(void);
564
565/*
566 * The "reset" variable should be tested whenever an interrupt is scheduled,
567 * after the commands have been sent. This is to ensure that the driver doesn't
568 * get wedged when the interrupt doesn't come because of a failed command.
569 * reset doesn't need to be tested before sending commands, because
570 * output_byte is automatically disabled when reset is set.
571 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572static void reset_fdc(void);
573
574/*
575 * These are global variables, as that's the easiest way to give
576 * information to interrupts. They are the data used for the current
577 * request.
578 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800579#define NO_TRACK -1
580#define NEED_1_RECAL -2
581#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583static int usage_count;
584
585/* buffer related variables */
586static int buffer_track = -1;
587static int buffer_drive = -1;
588static int buffer_min = -1;
589static int buffer_max = -1;
590
591/* fdc related variables, should end up in a struct */
592static struct floppy_fdc_state fdc_state[N_FDC];
593static int fdc; /* current fdc */
594
595static struct floppy_struct *_floppy = floppy_type;
596static unsigned char current_drive;
597static long current_count_sectors;
598static unsigned char fsector_t; /* sector in track */
599static unsigned char in_sector_offset; /* offset within physical sector,
600 * expressed in units of 512 bytes */
601
602#ifndef fd_eject
603static inline int fd_eject(int drive)
604{
605 return -EINVAL;
606}
607#endif
608
609/*
610 * Debugging
611 * =========
612 */
613#ifdef DEBUGT
614static long unsigned debugtimer;
615
616static inline void set_debugt(void)
617{
618 debugtimer = jiffies;
619}
620
621static inline void debugt(const char *message)
622{
623 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800624 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625}
626#else
627static inline void set_debugt(void) { }
628static inline void debugt(const char *message) { }
629#endif /* DEBUGT */
630
Joe Perchesa0a52d62010-03-10 15:20:52 -0800631typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700632static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634static const char *timeout_message;
635
636#ifdef FLOPPY_SANITY_CHECK
637static void is_alive(const char *message)
638{
639 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800640 if (test_bit(0, &fdc_busy) && command_status < 2 &&
641 !timer_pending(&fd_timeout)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 DPRINT("timeout handler died: %s\n", message);
643 }
644}
645#endif
646
Joe Perches48c8cee2010-03-10 15:20:45 -0800647static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649#ifdef FLOPPY_SANITY_CHECK
650
651#define OLOGSIZE 20
652
Joe Perches48c8cee2010-03-10 15:20:45 -0800653static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654static unsigned long interruptjiffies;
655static unsigned long resultjiffies;
656static int resultsize;
657static unsigned long lastredo;
658
659static struct output_log {
660 unsigned char data;
661 unsigned char status;
662 unsigned long jiffies;
663} output_log[OLOGSIZE];
664
665static int output_log_pos;
666#endif
667
668#define current_reqD -1
669#define MAXTIMEOUT -2
670
671static void __reschedule_timeout(int drive, const char *message, int marg)
672{
673 if (drive == current_reqD)
674 drive = current_drive;
675 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700676 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 fd_timeout.expires = jiffies + 20UL * HZ;
678 drive = 0;
679 } else
680 fd_timeout.expires = jiffies + UDP->timeout;
681 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800682 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800683 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 timeout_message = message;
685}
686
687static void reschedule_timeout(int drive, const char *message, int marg)
688{
689 unsigned long flags;
690
691 spin_lock_irqsave(&floppy_lock, flags);
692 __reschedule_timeout(drive, message, marg);
693 spin_unlock_irqrestore(&floppy_lock, flags);
694}
695
Joe Perches48c8cee2010-03-10 15:20:45 -0800696#define INFBOUND(a, b) (a) = max_t(int, a, b)
697#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699/*
700 * Bottom half floppy driver.
701 * ==========================
702 *
703 * This part of the file contains the code talking directly to the hardware,
704 * and also the main service loop (seek-configure-spinup-command)
705 */
706
707/*
708 * disk change.
709 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
710 * and the last_checked date.
711 *
712 * last_checked is the date of the last check which showed 'no disk change'
713 * FD_DISK_CHANGE is set under two conditions:
714 * 1. The floppy has been changed after some i/o to that floppy already
715 * took place.
716 * 2. No floppy disk is in the drive. This is done in order to ensure that
717 * requests are quickly flushed in case there is no disk in the drive. It
718 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
719 * the drive.
720 *
721 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
722 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
723 * each seek. If a disk is present, the disk change line should also be
724 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
725 * change line is set, this means either that no disk is in the drive, or
726 * that it has been removed since the last seek.
727 *
728 * This means that we really have a third possibility too:
729 * The floppy has been changed after the last seek.
730 */
731
732static int disk_change(int drive)
733{
734 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800737 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 DPRINT("WARNING disk change called early\n");
739 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
740 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
741 DPRINT("probing disk change on unselected drive\n");
742 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
743 (unsigned int)FDCS->dor);
744 }
745#endif
746
Joe Perches87f530d2010-03-10 15:20:54 -0800747 debug_dcl(UDP->flags,
748 "checking disk change line for drive %d\n", drive);
749 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
750 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
751 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
752
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800754 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800756 set_bit(FD_VERIFY_BIT, &UDRS->flags);
757 /* verify write protection */
758
759 if (UDRS->maxblock) /* mark it changed */
760 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 /* invalidate its geometry */
763 if (UDRS->keep_data >= 0) {
764 if ((UDP->flags & FTD_MSG) &&
765 current_type[drive] != NULL)
766 DPRINT("Disk type is undefined after "
767 "disk change\n");
768 current_type[drive] = NULL;
769 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
770 }
771
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return 1;
773 } else {
774 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800775 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
777 return 0;
778}
779
780static inline int is_selected(int dor, int unit)
781{
782 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
783}
784
785static int set_dor(int fdc, char mask, char data)
786{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700787 unsigned char unit;
788 unsigned char drive;
789 unsigned char newdor;
790 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 if (FDCS->address == -1)
793 return -1;
794
795 olddor = FDCS->dor;
796 newdor = (olddor & mask) | data;
797 if (newdor != olddor) {
798 unit = olddor & 0x3;
799 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
800 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800801 debug_dcl(UDP->flags,
802 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 disk_change(drive);
804 }
805 FDCS->dor = newdor;
806 fd_outb(newdor, FD_DOR);
807
808 unit = newdor & 0x3;
809 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
810 drive = REVDRIVE(fdc, unit);
811 UDRS->select_date = jiffies;
812 }
813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 return olddor;
815}
816
817static void twaddle(void)
818{
819 if (DP->select_delay)
820 return;
821 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
822 fd_outb(FDCS->dor, FD_DOR);
823 DRS->select_date = jiffies;
824}
825
826/* reset all driver information about the current fdc. This is needed after
827 * a reset, and after a raw command. */
828static void reset_fdc_info(int mode)
829{
830 int drive;
831
832 FDCS->spec1 = FDCS->spec2 = -1;
833 FDCS->need_configure = 1;
834 FDCS->perp_mode = 1;
835 FDCS->rawcmd = 0;
836 for (drive = 0; drive < N_DRIVE; drive++)
837 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
838 UDRS->track = NEED_2_RECAL;
839}
840
841/* selects the fdc and drive, and enables the fdc's input/dma. */
842static void set_fdc(int drive)
843{
844 if (drive >= 0 && drive < N_DRIVE) {
845 fdc = FDC(drive);
846 current_drive = drive;
847 }
848 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800849 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 return;
851 }
852 set_dor(fdc, ~0, 8);
853#if N_FDC > 1
854 set_dor(1 - fdc, ~8, 0);
855#endif
856 if (FDCS->rawcmd == 2)
857 reset_fdc_info(1);
858 if (fd_inb(FD_STATUS) != STATUS_READY)
859 FDCS->reset = 1;
860}
861
862/* locks the driver */
Joe Perches74f63f42010-03-10 15:20:58 -0800863static int _lock_fdc(int drive, bool interruptible, int line)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
865 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800866 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 line);
868 return -1;
869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
871 if (test_and_set_bit(0, &fdc_busy)) {
872 DECLARE_WAITQUEUE(wait, current);
873 add_wait_queue(&fdc_wait, &wait);
874
875 for (;;) {
876 set_current_state(TASK_INTERRUPTIBLE);
877
878 if (!test_and_set_bit(0, &fdc_busy))
879 break;
880
881 schedule();
882
883 if (!NO_SIGNAL) {
884 remove_wait_queue(&fdc_wait, &wait);
885 return -EINTR;
886 }
887 }
888
889 set_current_state(TASK_RUNNING);
890 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700891 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 }
893 command_status = FD_COMMAND_NONE;
894
895 __reschedule_timeout(drive, "lock fdc", 0);
896 set_fdc(drive);
897 return 0;
898}
899
Joe Perches48c8cee2010-03-10 15:20:45 -0800900#define lock_fdc(drive, interruptible) \
901 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903/* unlocks the driver */
904static inline void unlock_fdc(void)
905{
906 unsigned long flags;
907
908 raw_cmd = NULL;
909 if (!test_bit(0, &fdc_busy))
910 DPRINT("FDC access conflict!\n");
911
912 if (do_floppy)
913 DPRINT("device interrupt still active at FDC release: %p!\n",
914 do_floppy);
915 command_status = FD_COMMAND_NONE;
916 spin_lock_irqsave(&floppy_lock, flags);
917 del_timer(&fd_timeout);
918 cont = NULL;
919 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900920 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 do_fd_request(floppy_queue);
922 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 wake_up(&fdc_wait);
924}
925
926/* switches the motor off after a given timeout */
927static void motor_off_callback(unsigned long nr)
928{
929 unsigned char mask = ~(0x10 << UNIT(nr));
930
931 set_dor(FDC(nr), mask, 0);
932}
933
934/* schedules motor off */
935static void floppy_off(unsigned int drive)
936{
937 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700938 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 if (!(FDCS->dor & (0x10 << UNIT(drive))))
941 return;
942
943 del_timer(motor_off_timer + drive);
944
945 /* make spindle stop in a position which minimizes spinup time
946 * next time */
947 if (UDP->rps) {
948 delta = jiffies - UDRS->first_read_date + HZ -
949 UDP->spindown_offset;
950 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
951 motor_off_timer[drive].expires =
952 jiffies + UDP->spindown - delta;
953 }
954 add_timer(motor_off_timer + drive);
955}
956
957/*
958 * cycle through all N_DRIVE floppy drives, for disk change testing.
959 * stopping at current drive. This is done before any long operation, to
960 * be sure to have up to date disk change information.
961 */
962static void scandrives(void)
963{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700964 int i;
965 int drive;
966 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968 if (DP->select_delay)
969 return;
970
971 saved_drive = current_drive;
972 for (i = 0; i < N_DRIVE; i++) {
973 drive = (saved_drive + i + 1) % N_DRIVE;
974 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
975 continue; /* skip closed drives */
976 set_fdc(drive);
977 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
978 (0x10 << UNIT(drive))))
979 /* switch the motor off again, if it was off to
980 * begin with */
981 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
982 }
983 set_fdc(saved_drive);
984}
985
986static void empty(void)
987{
988}
989
David Howells65f27f32006-11-22 14:55:48 +0000990static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Joe Perches48c8cee2010-03-10 15:20:45 -0800992static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993{
David Howells65f27f32006-11-22 14:55:48 +0000994 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 schedule_work(&floppy_work);
996}
997
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700998static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000static void cancel_activity(void)
1001{
1002 unsigned long flags;
1003
1004 spin_lock_irqsave(&floppy_lock, flags);
1005 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001006 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 del_timer(&fd_timer);
1008 spin_unlock_irqrestore(&floppy_lock, flags);
1009}
1010
1011/* this function makes sure that the disk stays in the drive during the
1012 * transfer */
1013static void fd_watchdog(void)
1014{
Joe Perches87f530d2010-03-10 15:20:54 -08001015 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
1017 if (disk_change(current_drive)) {
1018 DPRINT("disk removed during i/o\n");
1019 cancel_activity();
1020 cont->done(0);
1021 reset_fdc();
1022 } else {
1023 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001024 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 fd_timer.expires = jiffies + HZ / 10;
1026 add_timer(&fd_timer);
1027 }
1028}
1029
1030static void main_command_interrupt(void)
1031{
1032 del_timer(&fd_timer);
1033 cont->interrupt();
1034}
1035
1036/* waits for a delay (spinup or select) to pass */
1037static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1038{
1039 if (FDCS->reset) {
1040 reset_fdc(); /* do the reset during sleep to win time
1041 * if we don't need to sleep, it's a good
1042 * occasion anyways */
1043 return 1;
1044 }
1045
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001046 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 del_timer(&fd_timer);
1048 fd_timer.function = function;
1049 fd_timer.expires = delay;
1050 add_timer(&fd_timer);
1051 return 1;
1052 }
1053 return 0;
1054}
1055
1056static DEFINE_SPINLOCK(floppy_hlt_lock);
1057static int hlt_disabled;
1058static void floppy_disable_hlt(void)
1059{
1060 unsigned long flags;
1061
1062 spin_lock_irqsave(&floppy_hlt_lock, flags);
1063 if (!hlt_disabled) {
1064 hlt_disabled = 1;
1065#ifdef HAVE_DISABLE_HLT
1066 disable_hlt();
1067#endif
1068 }
1069 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1070}
1071
1072static void floppy_enable_hlt(void)
1073{
1074 unsigned long flags;
1075
1076 spin_lock_irqsave(&floppy_hlt_lock, flags);
1077 if (hlt_disabled) {
1078 hlt_disabled = 0;
1079#ifdef HAVE_DISABLE_HLT
1080 enable_hlt();
1081#endif
1082 }
1083 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1084}
1085
1086static void setup_DMA(void)
1087{
1088 unsigned long f;
1089
1090#ifdef FLOPPY_SANITY_CHECK
1091 if (raw_cmd->length == 0) {
1092 int i;
1093
Joe Perchesb46df352010-03-10 15:20:46 -08001094 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001096 pr_cont("%x,", raw_cmd->cmd[i]);
1097 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 cont->done(0);
1099 FDCS->reset = 1;
1100 return;
1101 }
1102 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001103 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 cont->done(0);
1105 FDCS->reset = 1;
1106 return;
1107 }
1108#endif
1109 f = claim_dma_lock();
1110 fd_disable_dma();
1111#ifdef fd_dma_setup
1112 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1113 (raw_cmd->flags & FD_RAW_READ) ?
1114 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1115 release_dma_lock(f);
1116 cont->done(0);
1117 FDCS->reset = 1;
1118 return;
1119 }
1120 release_dma_lock(f);
1121#else
1122 fd_clear_dma_ff();
1123 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1124 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1125 DMA_MODE_READ : DMA_MODE_WRITE);
1126 fd_set_dma_addr(raw_cmd->kernel_data);
1127 fd_set_dma_count(raw_cmd->length);
1128 virtual_dma_port = FDCS->address;
1129 fd_enable_dma();
1130 release_dma_lock(f);
1131#endif
1132 floppy_disable_hlt();
1133}
1134
1135static void show_floppy(void);
1136
1137/* waits until the fdc becomes ready */
1138static int wait_til_ready(void)
1139{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001140 int status;
1141 int counter;
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 if (FDCS->reset)
1144 return -1;
1145 for (counter = 0; counter < 10000; counter++) {
1146 status = fd_inb(FD_STATUS);
1147 if (status & STATUS_READY)
1148 return status;
1149 }
1150 if (!initialising) {
1151 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1152 show_floppy();
1153 }
1154 FDCS->reset = 1;
1155 return -1;
1156}
1157
1158/* sends a command byte to the fdc */
1159static int output_byte(char byte)
1160{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001161 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001163 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 return -1;
1165 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1166 fd_outb(byte, FD_DATA);
1167#ifdef FLOPPY_SANITY_CHECK
1168 output_log[output_log_pos].data = byte;
1169 output_log[output_log_pos].status = status;
1170 output_log[output_log_pos].jiffies = jiffies;
1171 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1172#endif
1173 return 0;
1174 }
1175 FDCS->reset = 1;
1176 if (!initialising) {
1177 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1178 byte, fdc, status);
1179 show_floppy();
1180 }
1181 return -1;
1182}
1183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184/* gets the response from the fdc */
1185static int result(void)
1186{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001187 int i;
1188 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001191 status = wait_til_ready();
1192 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 break;
1194 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1195 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1196#ifdef FLOPPY_SANITY_CHECK
1197 resultjiffies = jiffies;
1198 resultsize = i;
1199#endif
1200 return i;
1201 }
1202 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1203 reply_buffer[i] = fd_inb(FD_DATA);
1204 else
1205 break;
1206 }
1207 if (!initialising) {
1208 DPRINT
1209 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1210 fdc, status, i);
1211 show_floppy();
1212 }
1213 FDCS->reset = 1;
1214 return -1;
1215}
1216
1217#define MORE_OUTPUT -2
1218/* does the fdc need more output? */
1219static int need_more_output(void)
1220{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001221 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001222
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001223 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 return -1;
1225 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1226 return MORE_OUTPUT;
1227 return result();
1228}
1229
1230/* Set perpendicular mode as required, based on data rate, if supported.
1231 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1232 */
1233static inline void perpendicular_mode(void)
1234{
1235 unsigned char perp_mode;
1236
1237 if (raw_cmd->rate & 0x40) {
1238 switch (raw_cmd->rate & 3) {
1239 case 0:
1240 perp_mode = 2;
1241 break;
1242 case 3:
1243 perp_mode = 3;
1244 break;
1245 default:
1246 DPRINT("Invalid data rate for perpendicular mode!\n");
1247 cont->done(0);
Joe Perchesbb57f0c2010-03-10 15:20:50 -08001248 FDCS->reset = 1;
1249 /*
1250 * convenient way to return to
1251 * redo without too much hassle
1252 * (deep stack et al.)
1253 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 return;
1255 }
1256 } else
1257 perp_mode = 0;
1258
1259 if (FDCS->perp_mode == perp_mode)
1260 return;
1261 if (FDCS->version >= FDC_82077_ORIG) {
1262 output_byte(FD_PERPENDICULAR);
1263 output_byte(perp_mode);
1264 FDCS->perp_mode = perp_mode;
1265 } else if (perp_mode) {
1266 DPRINT("perpendicular mode not supported by this FDC.\n");
1267 }
1268} /* perpendicular_mode */
1269
1270static int fifo_depth = 0xa;
1271static int no_fifo;
1272
1273static int fdc_configure(void)
1274{
1275 /* Turn on FIFO */
1276 output_byte(FD_CONFIGURE);
1277 if (need_more_output() != MORE_OUTPUT)
1278 return 0;
1279 output_byte(0);
1280 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1281 output_byte(0); /* pre-compensation from track
1282 0 upwards */
1283 return 1;
1284}
1285
1286#define NOMINAL_DTR 500
1287
1288/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1289 * head load time, and DMA disable flag to values needed by floppy.
1290 *
1291 * The value "dtr" is the data transfer rate in Kbps. It is needed
1292 * to account for the data rate-based scaling done by the 82072 and 82077
1293 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1294 * 8272a).
1295 *
1296 * Note that changing the data transfer rate has a (probably deleterious)
1297 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1298 * fdc_specify is called again after each data transfer rate
1299 * change.
1300 *
1301 * srt: 1000 to 16000 in microseconds
1302 * hut: 16 to 240 milliseconds
1303 * hlt: 2 to 254 milliseconds
1304 *
1305 * These values are rounded up to the next highest available delay time.
1306 */
1307static void fdc_specify(void)
1308{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001309 unsigned char spec1;
1310 unsigned char spec2;
1311 unsigned long srt;
1312 unsigned long hlt;
1313 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 unsigned long dtr = NOMINAL_DTR;
1315 unsigned long scale_dtr = NOMINAL_DTR;
1316 int hlt_max_code = 0x7f;
1317 int hut_max_code = 0xf;
1318
1319 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1320 fdc_configure();
1321 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 }
1323
1324 switch (raw_cmd->rate & 0x03) {
1325 case 3:
1326 dtr = 1000;
1327 break;
1328 case 1:
1329 dtr = 300;
1330 if (FDCS->version >= FDC_82078) {
1331 /* chose the default rate table, not the one
1332 * where 1 = 2 Mbps */
1333 output_byte(FD_DRIVESPEC);
1334 if (need_more_output() == MORE_OUTPUT) {
1335 output_byte(UNIT(current_drive));
1336 output_byte(0xc0);
1337 }
1338 }
1339 break;
1340 case 2:
1341 dtr = 250;
1342 break;
1343 }
1344
1345 if (FDCS->version >= FDC_82072) {
1346 scale_dtr = dtr;
1347 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1348 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1349 }
1350
1351 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001352 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001353 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001355
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 SUPBOUND(srt, 0xf);
1357 INFBOUND(srt, 0);
1358
Julia Lawall061837b2008-09-22 14:57:16 -07001359 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 if (hlt < 0x01)
1361 hlt = 0x01;
1362 else if (hlt > 0x7f)
1363 hlt = hlt_max_code;
1364
Julia Lawall061837b2008-09-22 14:57:16 -07001365 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (hut < 0x1)
1367 hut = 0x1;
1368 else if (hut > 0xf)
1369 hut = hut_max_code;
1370
1371 spec1 = (srt << 4) | hut;
1372 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1373
1374 /* If these parameters did not change, just return with success */
1375 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1376 /* Go ahead and set spec1 and spec2 */
1377 output_byte(FD_SPECIFY);
1378 output_byte(FDCS->spec1 = spec1);
1379 output_byte(FDCS->spec2 = spec2);
1380 }
1381} /* fdc_specify */
1382
1383/* Set the FDC's data transfer rate on behalf of the specified drive.
1384 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1385 * of the specify command (i.e. using the fdc_specify function).
1386 */
1387static int fdc_dtr(void)
1388{
1389 /* If data rate not already set to desired value, set it. */
1390 if ((raw_cmd->rate & 3) == FDCS->dtr)
1391 return 0;
1392
1393 /* Set dtr */
1394 fd_outb(raw_cmd->rate & 3, FD_DCR);
1395
1396 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1397 * need a stabilization period of several milliseconds to be
1398 * enforced after data rate changes before R/W operations.
1399 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1400 */
1401 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001402 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1403 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404} /* fdc_dtr */
1405
1406static void tell_sector(void)
1407{
Joe Perchesb46df352010-03-10 15:20:46 -08001408 pr_cont(": track %d, head %d, sector %d, size %d",
1409 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410} /* tell_sector */
1411
Joe Perchesb46df352010-03-10 15:20:46 -08001412static void print_errors(void)
1413{
1414 DPRINT("");
1415 if (ST0 & ST0_ECE) {
1416 pr_cont("Recalibrate failed!");
1417 } else if (ST2 & ST2_CRC) {
1418 pr_cont("data CRC error");
1419 tell_sector();
1420 } else if (ST1 & ST1_CRC) {
1421 pr_cont("CRC error");
1422 tell_sector();
1423 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1424 (ST2 & ST2_MAM)) {
1425 if (!probing) {
1426 pr_cont("sector not found");
1427 tell_sector();
1428 } else
1429 pr_cont("probe failed...");
1430 } else if (ST2 & ST2_WC) { /* seek error */
1431 pr_cont("wrong cylinder");
1432 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1433 pr_cont("bad cylinder");
1434 } else {
1435 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1436 ST0, ST1, ST2);
1437 tell_sector();
1438 }
1439 pr_cont("\n");
1440}
1441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442/*
1443 * OK, this error interpreting routine is called after a
1444 * DMA read/write has succeeded
1445 * or failed, so we check the results, and copy any buffers.
1446 * hhb: Added better error reporting.
1447 * ak: Made this into a separate routine.
1448 */
1449static int interpret_errors(void)
1450{
1451 char bad;
1452
1453 if (inr != 7) {
1454 DPRINT("-- FDC reply error");
1455 FDCS->reset = 1;
1456 return 1;
1457 }
1458
1459 /* check IC to find cause of interrupt */
1460 switch (ST0 & ST0_INTR) {
1461 case 0x40: /* error occurred during command execution */
1462 if (ST1 & ST1_EOC)
1463 return 0; /* occurs with pseudo-DMA */
1464 bad = 1;
1465 if (ST1 & ST1_WP) {
1466 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001467 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 cont->done(0);
1469 bad = 2;
1470 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001471 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 } else if (ST1 & ST1_OR) {
1473 if (DP->flags & FTD_MSG)
1474 DPRINT("Over/Underrun - retrying\n");
1475 bad = 0;
1476 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001477 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 }
1479 if (ST2 & ST2_WC || ST2 & ST2_BC)
1480 /* wrong cylinder => recal */
1481 DRS->track = NEED_2_RECAL;
1482 return bad;
1483 case 0x80: /* invalid command given */
1484 DPRINT("Invalid FDC command given!\n");
1485 cont->done(0);
1486 return 2;
1487 case 0xc0:
1488 DPRINT("Abnormal termination caused by polling\n");
1489 cont->error();
1490 return 2;
1491 default: /* (0) Normal command termination */
1492 return 0;
1493 }
1494}
1495
1496/*
1497 * This routine is called when everything should be correctly set up
1498 * for the transfer (i.e. floppy motor is on, the correct floppy is
1499 * selected, and the head is sitting on the right track).
1500 */
1501static void setup_rw_floppy(void)
1502{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001503 int i;
1504 int r;
1505 int flags;
1506 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 unsigned long ready_date;
1508 timeout_fn function;
1509
1510 flags = raw_cmd->flags;
1511 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1512 flags |= FD_RAW_INTR;
1513
1514 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1515 ready_date = DRS->spinup_date + DP->spinup;
1516 /* If spinup will take a long time, rerun scandrives
1517 * again just before spinup completion. Beware that
1518 * after scandrives, we must again wait for selection.
1519 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001520 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001522 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001524 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
1526 /* wait until the floppy is spinning fast enough */
1527 if (fd_wait_for_completion(ready_date, function))
1528 return;
1529 }
1530 dflags = DRS->flags;
1531
1532 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1533 setup_DMA();
1534
1535 if (flags & FD_RAW_INTR)
1536 do_floppy = main_command_interrupt;
1537
1538 r = 0;
1539 for (i = 0; i < raw_cmd->cmd_count; i++)
1540 r |= output_byte(raw_cmd->cmd[i]);
1541
1542 debugt("rw_command: ");
1543
1544 if (r) {
1545 cont->error();
1546 reset_fdc();
1547 return;
1548 }
1549
1550 if (!(flags & FD_RAW_INTR)) {
1551 inr = result();
1552 cont->interrupt();
1553 } else if (flags & FD_RAW_NEED_DISK)
1554 fd_watchdog();
1555}
1556
1557static int blind_seek;
1558
1559/*
1560 * This is the routine called after every seek (or recalibrate) interrupt
1561 * from the floppy controller.
1562 */
1563static void seek_interrupt(void)
1564{
1565 debugt("seek interrupt:");
1566 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1567 DPRINT("seek failed\n");
1568 DRS->track = NEED_2_RECAL;
1569 cont->error();
1570 cont->redo();
1571 return;
1572 }
1573 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001574 debug_dcl(DP->flags,
1575 "clearing NEWCHANGE flag because of effective seek\n");
1576 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001577 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1578 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 DRS->select_date = jiffies;
1580 }
1581 DRS->track = ST1;
1582 floppy_ready();
1583}
1584
1585static void check_wp(void)
1586{
Joe Perchese0298532010-03-10 15:20:55 -08001587 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1588 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 output_byte(FD_GETSTATUS);
1590 output_byte(UNIT(current_drive));
1591 if (result() != 1) {
1592 FDCS->reset = 1;
1593 return;
1594 }
Joe Perchese0298532010-03-10 15:20:55 -08001595 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1596 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001597 debug_dcl(DP->flags,
1598 "checking whether disk is write protected\n");
1599 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001601 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 else
Joe Perchese0298532010-03-10 15:20:55 -08001603 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 }
1605}
1606
1607static void seek_floppy(void)
1608{
1609 int track;
1610
1611 blind_seek = 0;
1612
Joe Perches87f530d2010-03-10 15:20:54 -08001613 debug_dcl(DP->flags, "calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Joe Perchese0298532010-03-10 15:20:55 -08001615 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1617 /* the media changed flag should be cleared after the seek.
1618 * If it isn't, this means that there is really no disk in
1619 * the drive.
1620 */
Joe Perchese0298532010-03-10 15:20:55 -08001621 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 cont->done(0);
1623 cont->redo();
1624 return;
1625 }
1626 if (DRS->track <= NEED_1_RECAL) {
1627 recalibrate_floppy();
1628 return;
Joe Perchese0298532010-03-10 15:20:55 -08001629 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1631 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1632 /* we seek to clear the media-changed condition. Does anybody
1633 * know a more elegant way, which works on all drives? */
1634 if (raw_cmd->track)
1635 track = raw_cmd->track - 1;
1636 else {
1637 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1638 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1639 blind_seek = 1;
1640 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1641 }
1642 track = 1;
1643 }
1644 } else {
1645 check_wp();
1646 if (raw_cmd->track != DRS->track &&
1647 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1648 track = raw_cmd->track;
1649 else {
1650 setup_rw_floppy();
1651 return;
1652 }
1653 }
1654
1655 do_floppy = seek_interrupt;
1656 output_byte(FD_SEEK);
1657 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001658 if (output_byte(track) < 0) {
1659 reset_fdc();
1660 return;
1661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 debugt("seek command:");
1663}
1664
1665static void recal_interrupt(void)
1666{
1667 debugt("recal interrupt:");
1668 if (inr != 2)
1669 FDCS->reset = 1;
1670 else if (ST0 & ST0_ECE) {
1671 switch (DRS->track) {
1672 case NEED_1_RECAL:
1673 debugt("recal interrupt need 1 recal:");
1674 /* after a second recalibrate, we still haven't
1675 * reached track 0. Probably no drive. Raise an
1676 * error, as failing immediately might upset
1677 * computers possessed by the Devil :-) */
1678 cont->error();
1679 cont->redo();
1680 return;
1681 case NEED_2_RECAL:
1682 debugt("recal interrupt need 2 recal:");
1683 /* If we already did a recalibrate,
1684 * and we are not at track 0, this
1685 * means we have moved. (The only way
1686 * not to move at recalibration is to
1687 * be already at track 0.) Clear the
1688 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001689 debug_dcl(DP->flags,
1690 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
Joe Perchese0298532010-03-10 15:20:55 -08001692 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 DRS->select_date = jiffies;
1694 /* fall through */
1695 default:
1696 debugt("recal interrupt default:");
1697 /* Recalibrate moves the head by at
1698 * most 80 steps. If after one
1699 * recalibrate we don't have reached
1700 * track 0, this might mean that we
1701 * started beyond track 80. Try
1702 * again. */
1703 DRS->track = NEED_1_RECAL;
1704 break;
1705 }
1706 } else
1707 DRS->track = ST1;
1708 floppy_ready();
1709}
1710
1711static void print_result(char *message, int inr)
1712{
1713 int i;
1714
1715 DPRINT("%s ", message);
1716 if (inr >= 0)
1717 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001718 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1719 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720}
1721
1722/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001723irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 int do_print;
1726 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001727 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 lasthandler = handler;
1730 interruptjiffies = jiffies;
1731
1732 f = claim_dma_lock();
1733 fd_disable_dma();
1734 release_dma_lock(f);
1735
1736 floppy_enable_hlt();
1737 do_floppy = NULL;
1738 if (fdc >= N_FDC || FDCS->address == -1) {
1739 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001740 pr_info("DOR0=%x\n", fdc_state[0].dor);
1741 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1742 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 is_alive("bizarre fdc");
1744 return IRQ_NONE;
1745 }
1746
1747 FDCS->reset = 0;
1748 /* We have to clear the reset flag here, because apparently on boxes
1749 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1750 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1751 * emission of the SENSEI's.
1752 * It is OK to emit floppy commands because we are in an interrupt
1753 * handler here, and thus we have to fear no interference of other
1754 * activity.
1755 */
1756
1757 do_print = !handler && print_unex && !initialising;
1758
1759 inr = result();
1760 if (do_print)
1761 print_result("unexpected interrupt", inr);
1762 if (inr == 0) {
1763 int max_sensei = 4;
1764 do {
1765 output_byte(FD_SENSEI);
1766 inr = result();
1767 if (do_print)
1768 print_result("sensei", inr);
1769 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001770 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1771 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 }
1773 if (!handler) {
1774 FDCS->reset = 1;
1775 return IRQ_NONE;
1776 }
1777 schedule_bh(handler);
1778 is_alive("normal interrupt end");
1779
1780 /* FIXME! Was it really for us? */
1781 return IRQ_HANDLED;
1782}
1783
1784static void recalibrate_floppy(void)
1785{
1786 debugt("recalibrate floppy:");
1787 do_floppy = recal_interrupt;
1788 output_byte(FD_RECALIBRATE);
Joe Perches2300f902010-03-10 15:20:49 -08001789 if (output_byte(UNIT(current_drive)) < 0) {
1790 reset_fdc();
1791 return;
1792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793}
1794
1795/*
1796 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1797 */
1798static void reset_interrupt(void)
1799{
1800 debugt("reset interrupt:");
1801 result(); /* get the status ready for set_fdc */
1802 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001803 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 cont->error(); /* a reset just after a reset. BAD! */
1805 }
1806 cont->redo();
1807}
1808
1809/*
1810 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1811 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1812 */
1813static void reset_fdc(void)
1814{
1815 unsigned long flags;
1816
1817 do_floppy = reset_interrupt;
1818 FDCS->reset = 0;
1819 reset_fdc_info(0);
1820
1821 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1822 /* Irrelevant for systems with true DMA (i386). */
1823
1824 flags = claim_dma_lock();
1825 fd_disable_dma();
1826 release_dma_lock(flags);
1827
1828 if (FDCS->version >= FDC_82072A)
1829 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1830 else {
1831 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1832 udelay(FD_RESET_DELAY);
1833 fd_outb(FDCS->dor, FD_DOR);
1834 }
1835}
1836
1837static void show_floppy(void)
1838{
1839 int i;
1840
Joe Perchesb46df352010-03-10 15:20:46 -08001841 pr_info("\n");
1842 pr_info("floppy driver state\n");
1843 pr_info("-------------------\n");
1844 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1845 jiffies, interruptjiffies, jiffies - interruptjiffies,
1846 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
1848#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001849 pr_info("timeout_message=%s\n", timeout_message);
1850 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001852 pr_info("%2x %2x %lu\n",
1853 output_log[(i + output_log_pos) % OLOGSIZE].data,
1854 output_log[(i + output_log_pos) % OLOGSIZE].status,
1855 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1856 pr_info("last result at %lu\n", resultjiffies);
1857 pr_info("last redo_fd_request at %lu\n", lastredo);
1858 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1859 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860#endif
1861
Joe Perchesb46df352010-03-10 15:20:46 -08001862 pr_info("status=%x\n", fd_inb(FD_STATUS));
1863 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001865 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001866 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001867 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001869 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001871 pr_info("timer_function=%p\n", fd_timeout.function);
1872 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1873 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 }
Joe Perchesb46df352010-03-10 15:20:46 -08001875 pr_info("cont=%p\n", cont);
1876 pr_info("current_req=%p\n", current_req);
1877 pr_info("command_status=%d\n", command_status);
1878 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879}
1880
1881static void floppy_shutdown(unsigned long data)
1882{
1883 unsigned long flags;
1884
1885 if (!initialising)
1886 show_floppy();
1887 cancel_activity();
1888
1889 floppy_enable_hlt();
1890
1891 flags = claim_dma_lock();
1892 fd_disable_dma();
1893 release_dma_lock(flags);
1894
1895 /* avoid dma going to a random drive after shutdown */
1896
1897 if (!initialising)
1898 DPRINT("floppy timeout called\n");
1899 FDCS->reset = 1;
1900 if (cont) {
1901 cont->done(0);
1902 cont->redo(); /* this will recall reset when needed */
1903 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001904 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 process_fd_request();
1906 }
1907 is_alive("floppy shutdown");
1908}
1909
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001911static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001913 int mask;
1914 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916 mask = 0xfc;
1917 data = UNIT(current_drive);
1918 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1919 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1920 set_debugt();
1921 /* no read since this drive is running */
1922 DRS->first_read_date = 0;
1923 /* note motor start time if motor is not yet running */
1924 DRS->spinup_date = jiffies;
1925 data |= (0x10 << UNIT(current_drive));
1926 }
1927 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1928 mask &= ~(0x10 << UNIT(current_drive));
1929
1930 /* starts motor and selects floppy */
1931 del_timer(motor_off_timer + current_drive);
1932 set_dor(fdc, mask, data);
1933
1934 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001935 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1936 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937}
1938
1939static void floppy_ready(void)
1940{
Joe Perches045f9832010-03-10 15:20:47 -08001941 if (FDCS->reset) {
1942 reset_fdc();
1943 return;
1944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 if (start_motor(floppy_ready))
1946 return;
1947 if (fdc_dtr())
1948 return;
1949
Joe Perches87f530d2010-03-10 15:20:54 -08001950 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1952 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c2010-03-10 15:20:50 -08001953 twaddle(); /* this clears the dcl on certain
1954 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
1956#ifdef fd_chose_dma_mode
1957 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1958 unsigned long flags = claim_dma_lock();
1959 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1960 release_dma_lock(flags);
1961 }
1962#endif
1963
1964 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1965 perpendicular_mode();
1966 fdc_specify(); /* must be done here because of hut, hlt ... */
1967 seek_floppy();
1968 } else {
1969 if ((raw_cmd->flags & FD_RAW_READ) ||
1970 (raw_cmd->flags & FD_RAW_WRITE))
1971 fdc_specify();
1972 setup_rw_floppy();
1973 }
1974}
1975
1976static void floppy_start(void)
1977{
1978 reschedule_timeout(current_reqD, "floppy start", 0);
1979
1980 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001981 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001982 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 floppy_ready();
1984}
1985
1986/*
1987 * ========================================================================
1988 * here ends the bottom half. Exported routines are:
1989 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1990 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1991 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1992 * and set_dor.
1993 * ========================================================================
1994 */
1995/*
1996 * General purpose continuations.
1997 * ==============================
1998 */
1999
2000static void do_wakeup(void)
2001{
2002 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2003 cont = NULL;
2004 command_status += 2;
2005 wake_up(&command_done);
2006}
2007
2008static struct cont_t wakeup_cont = {
2009 .interrupt = empty,
2010 .redo = do_wakeup,
2011 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002012 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013};
2014
2015static struct cont_t intr_cont = {
2016 .interrupt = empty,
2017 .redo = process_fd_request,
2018 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002019 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020};
2021
Joe Perches74f63f42010-03-10 15:20:58 -08002022static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023{
2024 int ret;
2025
2026 schedule_bh(handler);
2027
2028 if (command_status < 2 && NO_SIGNAL) {
2029 DECLARE_WAITQUEUE(wait, current);
2030
2031 add_wait_queue(&command_done, &wait);
2032 for (;;) {
2033 set_current_state(interruptible ?
2034 TASK_INTERRUPTIBLE :
2035 TASK_UNINTERRUPTIBLE);
2036
2037 if (command_status >= 2 || !NO_SIGNAL)
2038 break;
2039
2040 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 schedule();
2042 }
2043
2044 set_current_state(TASK_RUNNING);
2045 remove_wait_queue(&command_done, &wait);
2046 }
2047
2048 if (command_status < 2) {
2049 cancel_activity();
2050 cont = &intr_cont;
2051 reset_fdc();
2052 return -EINTR;
2053 }
2054
2055 if (FDCS->reset)
2056 command_status = FD_COMMAND_ERROR;
2057 if (command_status == FD_COMMAND_OKAY)
2058 ret = 0;
2059 else
2060 ret = -EIO;
2061 command_status = FD_COMMAND_NONE;
2062 return ret;
2063}
2064
2065static void generic_done(int result)
2066{
2067 command_status = result;
2068 cont = &wakeup_cont;
2069}
2070
2071static void generic_success(void)
2072{
2073 cont->done(1);
2074}
2075
2076static void generic_failure(void)
2077{
2078 cont->done(0);
2079}
2080
2081static void success_and_wakeup(void)
2082{
2083 generic_success();
2084 cont->redo();
2085}
2086
2087/*
2088 * formatting and rw support.
2089 * ==========================
2090 */
2091
2092static int next_valid_format(void)
2093{
2094 int probed_format;
2095
2096 probed_format = DRS->probed_format;
2097 while (1) {
2098 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2099 DRS->probed_format = 0;
2100 return 1;
2101 }
2102 if (floppy_type[DP->autodetect[probed_format]].sect) {
2103 DRS->probed_format = probed_format;
2104 return 0;
2105 }
2106 probed_format++;
2107 }
2108}
2109
2110static void bad_flp_intr(void)
2111{
2112 int err_count;
2113
2114 if (probing) {
2115 DRS->probed_format++;
2116 if (!next_valid_format())
2117 return;
2118 }
2119 err_count = ++(*errors);
2120 INFBOUND(DRWE->badness, err_count);
2121 if (err_count > DP->max_errors.abort)
2122 cont->done(0);
2123 if (err_count > DP->max_errors.reset)
2124 FDCS->reset = 1;
2125 else if (err_count > DP->max_errors.recal)
2126 DRS->track = NEED_2_RECAL;
2127}
2128
2129static void set_floppy(int drive)
2130{
2131 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 if (type)
2134 _floppy = floppy_type + type;
2135 else
2136 _floppy = current_type[drive];
2137}
2138
2139/*
2140 * formatting support.
2141 * ===================
2142 */
2143static void format_interrupt(void)
2144{
2145 switch (interpret_errors()) {
2146 case 1:
2147 cont->error();
2148 case 2:
2149 break;
2150 case 0:
2151 cont->done(1);
2152 }
2153 cont->redo();
2154}
2155
2156#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002157#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002159
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160static void setup_format_params(int track)
2161{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002162 int n;
2163 int il;
2164 int count;
2165 int head_shift;
2166 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 struct fparm {
2168 unsigned char track, head, sect, size;
2169 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
2171 raw_cmd = &default_raw_cmd;
2172 raw_cmd->track = track;
2173
Joe Perches48c8cee2010-03-10 15:20:45 -08002174 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2175 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 raw_cmd->rate = _floppy->rate & 0x43;
2177 raw_cmd->cmd_count = NR_F;
2178 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2179 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2180 F_SIZECODE = FD_SIZECODE(_floppy);
2181 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2182 F_GAP = _floppy->fmt_gap;
2183 F_FILL = FD_FILL_BYTE;
2184
2185 raw_cmd->kernel_data = floppy_track_buffer;
2186 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2187
2188 /* allow for about 30ms for data transport per track */
2189 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2190
2191 /* a ``cylinder'' is two tracks plus a little stepping time */
2192 track_shift = 2 * head_shift + 3;
2193
2194 /* position of logical sector 1 on this track */
2195 n = (track_shift * format_req.track + head_shift * format_req.head)
2196 % F_SECT_PER_TRACK;
2197
2198 /* determine interleave */
2199 il = 1;
2200 if (_floppy->fmt_gap < 0x22)
2201 il++;
2202
2203 /* initialize field */
2204 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2205 here[count].track = format_req.track;
2206 here[count].head = format_req.head;
2207 here[count].sect = 0;
2208 here[count].size = F_SIZECODE;
2209 }
2210 /* place logical sectors */
2211 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2212 here[n].sect = count;
2213 n = (n + il) % F_SECT_PER_TRACK;
2214 if (here[n].sect) { /* sector busy, find next free sector */
2215 ++n;
2216 if (n >= F_SECT_PER_TRACK) {
2217 n -= F_SECT_PER_TRACK;
2218 while (here[n].sect)
2219 ++n;
2220 }
2221 }
2222 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002223 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002225 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 }
2227}
2228
2229static void redo_format(void)
2230{
2231 buffer_track = -1;
2232 setup_format_params(format_req.track << STRETCH(_floppy));
2233 floppy_start();
2234 debugt("queue format request");
2235}
2236
2237static struct cont_t format_cont = {
2238 .interrupt = format_interrupt,
2239 .redo = redo_format,
2240 .error = bad_flp_intr,
2241 .done = generic_done
2242};
2243
2244static int do_format(int drive, struct format_descr *tmp_format_req)
2245{
2246 int ret;
2247
Joe Perches74f63f42010-03-10 15:20:58 -08002248 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002249 return -EINTR;
2250
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 set_floppy(drive);
2252 if (!_floppy ||
2253 _floppy->track > DP->tracks ||
2254 tmp_format_req->track >= _floppy->track ||
2255 tmp_format_req->head >= _floppy->head ||
2256 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2257 !_floppy->fmt_gap) {
2258 process_fd_request();
2259 return -EINVAL;
2260 }
2261 format_req = *tmp_format_req;
2262 format_errors = 0;
2263 cont = &format_cont;
2264 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002265 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002266 if (ret == -EINTR)
2267 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 process_fd_request();
2269 return ret;
2270}
2271
2272/*
2273 * Buffer read/write and support
2274 * =============================
2275 */
2276
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002277static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278{
2279 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002280 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281
2282 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002283 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002284 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002285 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287
2288 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002289 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 current_req = NULL;
2291}
2292
2293/* new request_done. Can handle physical sectors which are smaller than a
2294 * logical buffer */
2295static void request_done(int uptodate)
2296{
2297 struct request_queue *q = floppy_queue;
2298 struct request *req = current_req;
2299 unsigned long flags;
2300 int block;
2301
2302 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002303 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
2305 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002306 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 return;
2308 }
2309
2310 if (uptodate) {
2311 /* maintain values for invalidation on geometry
2312 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002313 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 INFBOUND(DRS->maxblock, block);
2315 if (block > _floppy->sect)
2316 DRS->maxtrack = 1;
2317
2318 /* unlock chained buffers */
2319 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002320 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 spin_unlock_irqrestore(q->queue_lock, flags);
2322 } else {
2323 if (rq_data_dir(req) == WRITE) {
2324 /* record write error information */
2325 DRWE->write_errors++;
2326 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002327 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 DRWE->first_error_generation = DRS->generation;
2329 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002330 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 DRWE->last_error_generation = DRS->generation;
2332 }
2333 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002334 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 spin_unlock_irqrestore(q->queue_lock, flags);
2336 }
2337}
2338
2339/* Interrupt handler evaluating the result of the r/w operation */
2340static void rw_interrupt(void)
2341{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002342 int eoc;
2343 int ssize;
2344 int heads;
2345 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
2347 if (R_HEAD >= 2) {
2348 /* some Toshiba floppy controllers occasionnally seem to
2349 * return bogus interrupts after read/write operations, which
2350 * can be recognized by a bad head number (>= 2) */
2351 return;
2352 }
2353
2354 if (!DRS->first_read_date)
2355 DRS->first_read_date = jiffies;
2356
2357 nr_sectors = 0;
2358 CODE2SIZE;
2359
2360 if (ST1 & ST1_EOC)
2361 eoc = 1;
2362 else
2363 eoc = 0;
2364
2365 if (COMMAND & 0x80)
2366 heads = 2;
2367 else
2368 heads = 1;
2369
2370 nr_sectors = (((R_TRACK - TRACK) * heads +
2371 R_HEAD - HEAD) * SECT_PER_TRACK +
2372 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2373
2374#ifdef FLOPPY_SANITY_CHECK
2375 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002376 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 DPRINT("long rw: %x instead of %lx\n",
2378 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002379 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2380 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2381 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2382 pr_info("heads=%d eoc=%d\n", heads, eoc);
2383 pr_info("spt=%d st=%d ss=%d\n",
2384 SECT_PER_TRACK, fsector_t, ssize);
2385 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 }
2387#endif
2388
2389 nr_sectors -= in_sector_offset;
2390 INFBOUND(nr_sectors, 0);
2391 SUPBOUND(current_count_sectors, nr_sectors);
2392
2393 switch (interpret_errors()) {
2394 case 2:
2395 cont->redo();
2396 return;
2397 case 1:
2398 if (!current_count_sectors) {
2399 cont->error();
2400 cont->redo();
2401 return;
2402 }
2403 break;
2404 case 0:
2405 if (!current_count_sectors) {
2406 cont->redo();
2407 return;
2408 }
2409 current_type[current_drive] = _floppy;
2410 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2411 break;
2412 }
2413
2414 if (probing) {
2415 if (DP->flags & FTD_MSG)
2416 DPRINT("Auto-detected floppy type %s in fd%d\n",
2417 _floppy->name, current_drive);
2418 current_type[current_drive] = _floppy;
2419 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2420 probing = 0;
2421 }
2422
2423 if (CT(COMMAND) != FD_READ ||
2424 raw_cmd->kernel_data == current_req->buffer) {
2425 /* transfer directly from buffer */
2426 cont->done(1);
2427 } else if (CT(COMMAND) == FD_READ) {
2428 buffer_track = raw_cmd->track;
2429 buffer_drive = current_drive;
2430 INFBOUND(buffer_max, nr_sectors + fsector_t);
2431 }
2432 cont->redo();
2433}
2434
2435/* Compute maximal contiguous buffer size. */
2436static int buffer_chain_size(void)
2437{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002439 int size;
2440 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 char *base;
2442
2443 base = bio_data(current_req->bio);
2444 size = 0;
2445
NeilBrown5705f702007-09-25 12:35:59 +02002446 rq_for_each_segment(bv, current_req, iter) {
2447 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2448 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
NeilBrown5705f702007-09-25 12:35:59 +02002450 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 }
2452
2453 return size >> 9;
2454}
2455
2456/* Compute the maximal transfer size */
2457static int transfer_size(int ssize, int max_sector, int max_size)
2458{
2459 SUPBOUND(max_sector, fsector_t + max_size);
2460
2461 /* alignment */
2462 max_sector -= (max_sector % _floppy->sect) % ssize;
2463
2464 /* transfer size, beginning not aligned */
2465 current_count_sectors = max_sector - fsector_t;
2466
2467 return max_sector;
2468}
2469
2470/*
2471 * Move data from/to the track buffer to/from the buffer cache.
2472 */
2473static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2474{
2475 int remaining; /* number of transferred 512-byte sectors */
2476 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002477 char *buffer;
2478 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002479 int size;
2480 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 max_sector = transfer_size(ssize,
2483 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002484 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
2486 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002487 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002489 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
2491 remaining = current_count_sectors << 9;
2492#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002493 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002495 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2496 pr_info("remaining=%d\n", remaining >> 9);
2497 pr_info("current_req->nr_sectors=%u\n",
2498 blk_rq_sectors(current_req));
2499 pr_info("current_req->current_nr_sectors=%u\n",
2500 blk_rq_cur_sectors(current_req));
2501 pr_info("max_sector=%d\n", max_sector);
2502 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 }
2504#endif
2505
2506 buffer_max = max(max_sector, buffer_max);
2507
2508 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2509
Tejun Heo1011c1b2009-05-07 22:24:45 +09002510 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
NeilBrown5705f702007-09-25 12:35:59 +02002512 rq_for_each_segment(bv, current_req, iter) {
2513 if (!remaining)
2514 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
NeilBrown5705f702007-09-25 12:35:59 +02002516 size = bv->bv_len;
2517 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518
NeilBrown5705f702007-09-25 12:35:59 +02002519 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002521 if (dma_buffer + size >
2522 floppy_track_buffer + (max_buffer_sectors << 10) ||
2523 dma_buffer < floppy_track_buffer) {
2524 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002525 (int)((floppy_track_buffer - dma_buffer) >> 9));
2526 pr_info("fsector_t=%d buffer_min=%d\n",
2527 fsector_t, buffer_min);
2528 pr_info("current_count_sectors=%ld\n",
2529 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002531 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002532 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002533 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002534 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 }
NeilBrown5705f702007-09-25 12:35:59 +02002536 if (((unsigned long)buffer) % 512)
2537 DPRINT("%p buffer not aligned\n", buffer);
2538#endif
2539 if (CT(COMMAND) == FD_READ)
2540 memcpy(buffer, dma_buffer, size);
2541 else
2542 memcpy(dma_buffer, buffer, size);
2543
2544 remaining -= size;
2545 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 }
2547#ifdef FLOPPY_SANITY_CHECK
2548 if (remaining) {
2549 if (remaining > 0)
2550 max_sector -= remaining >> 9;
2551 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2552 }
2553#endif
2554}
2555
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556/* work around a bug in pseudo DMA
2557 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2558 * sending data. Hence we need a different way to signal the
2559 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2560 * does not work with MT, hence we can only transfer one head at
2561 * a time
2562 */
2563static void virtualdmabug_workaround(void)
2564{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002565 int hard_sectors;
2566 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
2568 if (CT(COMMAND) == FD_WRITE) {
2569 COMMAND &= ~0x80; /* switch off multiple track mode */
2570
2571 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2572 end_sector = SECTOR + hard_sectors - 1;
2573#ifdef FLOPPY_SANITY_CHECK
2574 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002575 pr_info("too many sectors %d > %d\n",
2576 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 return;
2578 }
2579#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002580 SECT_PER_TRACK = end_sector;
2581 /* make sure SECT_PER_TRACK
2582 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 }
2584}
2585
2586/*
2587 * Formulate a read/write request.
2588 * this routine decides where to load the data (directly to buffer, or to
2589 * tmp floppy area), how much data to load (the size of the buffer, the whole
2590 * track, or a single sector)
2591 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2592 * allocation on the fly, it should be done here. No other part should need
2593 * modification.
2594 */
2595
2596static int make_raw_rw_request(void)
2597{
2598 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002599 int max_sector;
2600 int max_size;
2601 int tracksize;
2602 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
2604 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002605 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 return 0;
2607 }
2608
2609 set_fdc((long)current_req->rq_disk->private_data);
2610
2611 raw_cmd = &default_raw_cmd;
2612 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2613 FD_RAW_NEED_SEEK;
2614 raw_cmd->cmd_count = NR_RW;
2615 if (rq_data_dir(current_req) == READ) {
2616 raw_cmd->flags |= FD_RAW_READ;
2617 COMMAND = FM_MODE(_floppy, FD_READ);
2618 } else if (rq_data_dir(current_req) == WRITE) {
2619 raw_cmd->flags |= FD_RAW_WRITE;
2620 COMMAND = FM_MODE(_floppy, FD_WRITE);
2621 } else {
2622 DPRINT("make_raw_rw_request: unknown command\n");
2623 return 0;
2624 }
2625
2626 max_sector = _floppy->sect * _floppy->head;
2627
Tejun Heo83096eb2009-05-07 22:24:39 +09002628 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2629 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002631 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 current_count_sectors = 1;
2633 return 1;
2634 } else
2635 return 0;
2636 }
2637 HEAD = fsector_t / _floppy->sect;
2638
Keith Wansbrough9e491842008-09-22 14:57:17 -07002639 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002640 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2641 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 max_sector = _floppy->sect;
2643
2644 /* 2M disks have phantom sectors on the first track */
2645 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2646 max_sector = 2 * _floppy->sect / 3;
2647 if (fsector_t >= max_sector) {
2648 current_count_sectors =
2649 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002650 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 return 1;
2652 }
2653 SIZECODE = 2;
2654 } else
2655 SIZECODE = FD_SIZECODE(_floppy);
2656 raw_cmd->rate = _floppy->rate & 0x43;
2657 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2658 raw_cmd->rate = 1;
2659
2660 if (SIZECODE)
2661 SIZECODE2 = 0xff;
2662 else
2663 SIZECODE2 = 0x80;
2664 raw_cmd->track = TRACK << STRETCH(_floppy);
2665 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2666 GAP = _floppy->gap;
2667 CODE2SIZE;
2668 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2669 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002670 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
2672 /* tracksize describes the size which can be filled up with sectors
2673 * of size ssize.
2674 */
2675 tracksize = _floppy->sect - _floppy->sect % ssize;
2676 if (tracksize < _floppy->sect) {
2677 SECT_PER_TRACK++;
2678 if (tracksize <= fsector_t % _floppy->sect)
2679 SECTOR--;
2680
2681 /* if we are beyond tracksize, fill up using smaller sectors */
2682 while (tracksize <= fsector_t % _floppy->sect) {
2683 while (tracksize + ssize > _floppy->sect) {
2684 SIZECODE--;
2685 ssize >>= 1;
2686 }
2687 SECTOR++;
2688 SECT_PER_TRACK++;
2689 tracksize += ssize;
2690 }
2691 max_sector = HEAD * _floppy->sect + tracksize;
2692 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2693 max_sector = _floppy->sect;
2694 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2695 /* for virtual DMA bug workaround */
2696 max_sector = _floppy->sect;
2697 }
2698
2699 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2700 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002701 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 if ((raw_cmd->track == buffer_track) &&
2703 (current_drive == buffer_drive) &&
2704 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2705 /* data already in track buffer */
2706 if (CT(COMMAND) == FD_READ) {
2707 copy_buffer(1, max_sector, buffer_max);
2708 return 1;
2709 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002710 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002712 unsigned int sectors;
2713
2714 sectors = fsector_t + blk_rq_sectors(current_req);
2715 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 max_size = ssize + ssize;
2717 else
2718 max_size = ssize;
2719 }
2720 raw_cmd->flags &= ~FD_RAW_WRITE;
2721 raw_cmd->flags |= FD_RAW_READ;
2722 COMMAND = FM_MODE(_floppy, FD_READ);
2723 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2724 unsigned long dma_limit;
2725 int direct, indirect;
2726
2727 indirect =
2728 transfer_size(ssize, max_sector,
2729 max_buffer_sectors * 2) - fsector_t;
2730
2731 /*
2732 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2733 * on a 64 bit machine!
2734 */
2735 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002736 dma_limit = (MAX_DMA_ADDRESS -
2737 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002738 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 /* 64 kb boundaries */
2741 if (CROSS_64KB(current_req->buffer, max_size << 9))
2742 max_size = (K_64 -
2743 ((unsigned long)current_req->buffer) %
2744 K_64) >> 9;
2745 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2746 /*
2747 * We try to read tracks, but if we get too many errors, we
2748 * go back to reading just one sector at a time.
2749 *
2750 * This means we should be able to read a sector even if there
2751 * are other bad sectors on this track.
2752 */
2753 if (!direct ||
2754 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002755 *errors < DP->max_errors.read_track &&
2756 ((!probing ||
2757 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002758 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 } else {
2760 raw_cmd->kernel_data = current_req->buffer;
2761 raw_cmd->length = current_count_sectors << 9;
2762 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002763 DPRINT("zero dma transfer attempted from make_raw_request\n");
2764 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 indirect, direct, fsector_t);
2766 return 0;
2767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 virtualdmabug_workaround();
2769 return 2;
2770 }
2771 }
2772
2773 if (CT(COMMAND) == FD_READ)
2774 max_size = max_sector; /* unbounded */
2775
2776 /* claim buffer track if needed */
2777 if (buffer_track != raw_cmd->track || /* bad track */
2778 buffer_drive != current_drive || /* bad drive */
2779 fsector_t > buffer_max ||
2780 fsector_t < buffer_min ||
2781 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002782 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c2010-03-10 15:20:50 -08002784 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2785 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 buffer_track = -1;
2787 buffer_drive = current_drive;
2788 buffer_max = buffer_min = aligned_sector_t;
2789 }
2790 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c2010-03-10 15:20:50 -08002791 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 if (CT(COMMAND) == FD_WRITE) {
2794 /* copy write buffer to track buffer.
2795 * if we get here, we know that the write
2796 * is either aligned or the data already in the buffer
2797 * (buffer will be overwritten) */
2798#ifdef FLOPPY_SANITY_CHECK
2799 if (in_sector_offset && buffer_track == -1)
2800 DPRINT("internal error offset !=0 on write\n");
2801#endif
2802 buffer_track = raw_cmd->track;
2803 buffer_drive = current_drive;
2804 copy_buffer(ssize, max_sector,
2805 2 * max_buffer_sectors + buffer_min);
2806 } else
2807 transfer_size(ssize, max_sector,
2808 2 * max_buffer_sectors + buffer_min -
2809 aligned_sector_t);
2810
2811 /* round up current_count_sectors to get dma xfer size */
2812 raw_cmd->length = in_sector_offset + current_count_sectors;
2813 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2814 raw_cmd->length <<= 9;
2815#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 if ((raw_cmd->length < current_count_sectors << 9) ||
2817 (raw_cmd->kernel_data != current_req->buffer &&
2818 CT(COMMAND) == FD_WRITE &&
2819 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2820 aligned_sector_t < buffer_min)) ||
2821 raw_cmd->length % (128 << SIZECODE) ||
2822 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2823 DPRINT("fractionary current count b=%lx s=%lx\n",
2824 raw_cmd->length, current_count_sectors);
2825 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002826 pr_info("addr=%d, length=%ld\n",
2827 (int)((raw_cmd->kernel_data -
2828 floppy_track_buffer) >> 9),
2829 current_count_sectors);
2830 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2831 fsector_t, aligned_sector_t, max_sector, max_size);
2832 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2833 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2834 COMMAND, SECTOR, HEAD, TRACK);
2835 pr_info("buffer drive=%d\n", buffer_drive);
2836 pr_info("buffer track=%d\n", buffer_track);
2837 pr_info("buffer_min=%d\n", buffer_min);
2838 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 return 0;
2840 }
2841
2842 if (raw_cmd->kernel_data != current_req->buffer) {
2843 if (raw_cmd->kernel_data < floppy_track_buffer ||
2844 current_count_sectors < 0 ||
2845 raw_cmd->length < 0 ||
2846 raw_cmd->kernel_data + raw_cmd->length >
2847 floppy_track_buffer + (max_buffer_sectors << 10)) {
2848 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002849 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2850 fsector_t, buffer_min, raw_cmd->length >> 9);
2851 pr_info("current_count_sectors=%ld\n",
2852 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002854 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002856 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 return 0;
2858 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002859 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002860 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 DPRINT("buffer overrun in direct transfer\n");
2862 return 0;
2863 } else if (raw_cmd->length < current_count_sectors << 9) {
2864 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002865 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2866 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 }
2868 if (raw_cmd->length == 0) {
2869 DPRINT("zero dma transfer attempted from make_raw_request\n");
2870 return 0;
2871 }
2872#endif
2873
2874 virtualdmabug_workaround();
2875 return 2;
2876}
2877
2878static void redo_fd_request(void)
2879{
2880#define REPEAT {request_done(0); continue; }
2881 int drive;
2882 int tmp;
2883
2884 lastredo = jiffies;
2885 if (current_drive < N_DRIVE)
2886 floppy_off(current_drive);
2887
2888 for (;;) {
2889 if (!current_req) {
2890 struct request *req;
2891
2892 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002893 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 spin_unlock_irq(floppy_queue->queue_lock);
2895 if (!req) {
2896 do_floppy = NULL;
2897 unlock_fdc();
2898 return;
2899 }
2900 current_req = req;
2901 }
2902 drive = (long)current_req->rq_disk->private_data;
2903 set_fdc(drive);
2904 reschedule_timeout(current_reqD, "redo fd request", 0);
2905
2906 set_floppy(drive);
2907 raw_cmd = &default_raw_cmd;
2908 raw_cmd->flags = 0;
2909 if (start_motor(redo_fd_request))
2910 return;
2911 disk_change(current_drive);
2912 if (test_bit(current_drive, &fake_change) ||
Joe Perchese0298532010-03-10 15:20:55 -08002913 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 DPRINT("disk absent or changed during operation\n");
2915 REPEAT;
2916 }
2917 if (!_floppy) { /* Autodetection */
2918 if (!probing) {
2919 DRS->probed_format = 0;
2920 if (next_valid_format()) {
2921 DPRINT("no autodetectable formats\n");
2922 _floppy = NULL;
2923 REPEAT;
2924 }
2925 }
2926 probing = 1;
2927 _floppy =
2928 floppy_type + DP->autodetect[DRS->probed_format];
2929 } else
2930 probing = 0;
2931 errors = &(current_req->errors);
2932 tmp = make_raw_rw_request();
2933 if (tmp < 2) {
2934 request_done(tmp);
2935 continue;
2936 }
2937
Joe Perchese0298532010-03-10 15:20:55 -08002938 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 twaddle();
2940 schedule_bh(floppy_start);
2941 debugt("queue fd request");
2942 return;
2943 }
2944#undef REPEAT
2945}
2946
2947static struct cont_t rw_cont = {
2948 .interrupt = rw_interrupt,
2949 .redo = redo_fd_request,
2950 .error = bad_flp_intr,
2951 .done = request_done
2952};
2953
2954static void process_fd_request(void)
2955{
2956 cont = &rw_cont;
2957 schedule_bh(redo_fd_request);
2958}
2959
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002960static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961{
2962 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002963 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 return;
2965 }
2966
2967 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002968 pr_info("warning: usage count=0, current_req=%p exiting\n",
2969 current_req);
2970 pr_info("sect=%ld type=%x flags=%x\n",
2971 (long)blk_rq_pos(current_req), current_req->cmd_type,
2972 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 return;
2974 }
2975 if (test_bit(0, &fdc_busy)) {
2976 /* fdc busy, this new request will be treated when the
2977 current one is done */
2978 is_alive("do fd request, old request running");
2979 return;
2980 }
Joe Perches74f63f42010-03-10 15:20:58 -08002981 lock_fdc(MAXTIMEOUT, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 process_fd_request();
2983 is_alive("do fd request");
2984}
2985
2986static struct cont_t poll_cont = {
2987 .interrupt = success_and_wakeup,
2988 .redo = floppy_ready,
2989 .error = generic_failure,
2990 .done = generic_done
2991};
2992
Joe Perches74f63f42010-03-10 15:20:58 -08002993static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 /* no auto-sense, just clear dcl */
2996 raw_cmd = &default_raw_cmd;
2997 raw_cmd->flags = flag;
2998 raw_cmd->track = 0;
2999 raw_cmd->cmd_count = 0;
3000 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08003001 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08003002 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08003003
3004 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005}
3006
3007/*
3008 * User triggered reset
3009 * ====================
3010 */
3011
3012static void reset_intr(void)
3013{
Joe Perchesb46df352010-03-10 15:20:46 -08003014 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015}
3016
3017static struct cont_t reset_cont = {
3018 .interrupt = reset_intr,
3019 .redo = success_and_wakeup,
3020 .error = generic_failure,
3021 .done = generic_done
3022};
3023
Joe Perches74f63f42010-03-10 15:20:58 -08003024static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025{
3026 int ret;
3027
Joe Perches52a0d612010-03-10 15:20:53 -08003028 if (lock_fdc(drive, interruptible))
3029 return -EINTR;
3030
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 if (arg == FD_RESET_ALWAYS)
3032 FDCS->reset = 1;
3033 if (FDCS->reset) {
3034 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08003035 ret = wait_til_done(reset_fdc, interruptible);
3036 if (ret == -EINTR)
3037 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 }
3039 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003040 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041}
3042
3043/*
3044 * Misc Ioctl's and support
3045 * ========================
3046 */
3047static inline int fd_copyout(void __user *param, const void *address,
3048 unsigned long size)
3049{
3050 return copy_to_user(param, address, size) ? -EFAULT : 0;
3051}
3052
Joe Perches48c8cee2010-03-10 15:20:45 -08003053static inline int fd_copyin(void __user *param, void *address,
3054 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055{
3056 return copy_from_user(address, param, size) ? -EFAULT : 0;
3057}
3058
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059static inline const char *drive_name(int type, int drive)
3060{
3061 struct floppy_struct *floppy;
3062
3063 if (type)
3064 floppy = floppy_type + type;
3065 else {
3066 if (UDP->native_format)
3067 floppy = floppy_type + UDP->native_format;
3068 else
3069 return "(null)";
3070 }
3071 if (floppy->name)
3072 return floppy->name;
3073 else
3074 return "(null)";
3075}
3076
3077/* raw commands */
3078static void raw_cmd_done(int flag)
3079{
3080 int i;
3081
3082 if (!flag) {
3083 raw_cmd->flags |= FD_RAW_FAILURE;
3084 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3085 } else {
3086 raw_cmd->reply_count = inr;
3087 if (raw_cmd->reply_count > MAX_REPLIES)
3088 raw_cmd->reply_count = 0;
3089 for (i = 0; i < raw_cmd->reply_count; i++)
3090 raw_cmd->reply[i] = reply_buffer[i];
3091
3092 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3093 unsigned long flags;
3094 flags = claim_dma_lock();
3095 raw_cmd->length = fd_get_dma_residue();
3096 release_dma_lock(flags);
3097 }
3098
3099 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3100 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3101 raw_cmd->flags |= FD_RAW_FAILURE;
3102
3103 if (disk_change(current_drive))
3104 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3105 else
3106 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3107 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3108 motor_off_callback(current_drive);
3109
3110 if (raw_cmd->next &&
3111 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3112 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3113 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3114 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3115 raw_cmd = raw_cmd->next;
3116 return;
3117 }
3118 }
3119 generic_done(flag);
3120}
3121
3122static struct cont_t raw_cmd_cont = {
3123 .interrupt = success_and_wakeup,
3124 .redo = floppy_start,
3125 .error = generic_failure,
3126 .done = raw_cmd_done
3127};
3128
3129static inline int raw_cmd_copyout(int cmd, char __user *param,
3130 struct floppy_raw_cmd *ptr)
3131{
3132 int ret;
3133
3134 while (ptr) {
Joe Perches86b12b42010-03-10 15:20:56 -08003135 ret = copy_to_user((void __user *)param, ptr, sizeof(*ptr));
3136 if (ret)
3137 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 param += sizeof(struct floppy_raw_cmd);
3139 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c2010-03-10 15:20:50 -08003140 if (ptr->length >= 0 &&
3141 ptr->length <= ptr->buffer_length) {
3142 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003143 ret = fd_copyout(ptr->data, ptr->kernel_data,
3144 length);
3145 if (ret)
3146 return ret;
Joe Perchesbb57f0c2010-03-10 15:20:50 -08003147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 }
3149 ptr = ptr->next;
3150 }
3151 return 0;
3152}
3153
3154static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3155{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003156 struct floppy_raw_cmd *next;
3157 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158
3159 this = *ptr;
3160 *ptr = NULL;
3161 while (this) {
3162 if (this->buffer_length) {
3163 fd_dma_mem_free((unsigned long)this->kernel_data,
3164 this->buffer_length);
3165 this->buffer_length = 0;
3166 }
3167 next = this->next;
3168 kfree(this);
3169 this = next;
3170 }
3171}
3172
3173static inline int raw_cmd_copyin(int cmd, char __user *param,
3174 struct floppy_raw_cmd **rcmd)
3175{
3176 struct floppy_raw_cmd *ptr;
3177 int ret;
3178 int i;
3179
3180 *rcmd = NULL;
3181 while (1) {
3182 ptr = (struct floppy_raw_cmd *)
3183 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3184 if (!ptr)
3185 return -ENOMEM;
3186 *rcmd = ptr;
Joe Perches86b12b42010-03-10 15:20:56 -08003187 ret = copy_from_user(ptr, (void __user *)param, sizeof(*ptr));
3188 if (ret)
3189 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 ptr->next = NULL;
3191 ptr->buffer_length = 0;
3192 param += sizeof(struct floppy_raw_cmd);
3193 if (ptr->cmd_count > 33)
3194 /* the command may now also take up the space
3195 * initially intended for the reply & the
3196 * reply count. Needed for long 82078 commands
3197 * such as RESTORE, which takes ... 17 command
3198 * bytes. Murphy's law #137: When you reserve
3199 * 16 bytes for a structure, you'll one day
3200 * discover that you really need 17...
3201 */
3202 return -EINVAL;
3203
3204 for (i = 0; i < 16; i++)
3205 ptr->reply[i] = 0;
3206 ptr->resultcode = 0;
3207 ptr->kernel_data = NULL;
3208
3209 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3210 if (ptr->length <= 0)
3211 return -EINVAL;
3212 ptr->kernel_data =
3213 (char *)fd_dma_mem_alloc(ptr->length);
3214 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3215 if (!ptr->kernel_data)
3216 return -ENOMEM;
3217 ptr->buffer_length = ptr->length;
3218 }
Joe Perches4575b552010-03-10 15:20:55 -08003219 if (ptr->flags & FD_RAW_WRITE) {
3220 ret = fd_copyin(ptr->data, ptr->kernel_data,
3221 ptr->length);
3222 if (ret)
3223 return ret;
3224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 rcmd = &(ptr->next);
3226 if (!(ptr->flags & FD_RAW_MORE))
3227 return 0;
3228 ptr->rate &= 0x43;
3229 }
3230}
3231
3232static int raw_cmd_ioctl(int cmd, void __user *param)
3233{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003235 int drive;
3236 int ret2;
3237 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238
3239 if (FDCS->rawcmd <= 1)
3240 FDCS->rawcmd = 1;
3241 for (drive = 0; drive < N_DRIVE; drive++) {
3242 if (FDC(drive) != fdc)
3243 continue;
3244 if (drive == current_drive) {
3245 if (UDRS->fd_ref > 1) {
3246 FDCS->rawcmd = 2;
3247 break;
3248 }
3249 } else if (UDRS->fd_ref) {
3250 FDCS->rawcmd = 2;
3251 break;
3252 }
3253 }
3254
3255 if (FDCS->reset)
3256 return -EIO;
3257
3258 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3259 if (ret) {
3260 raw_cmd_free(&my_raw_cmd);
3261 return ret;
3262 }
3263
3264 raw_cmd = my_raw_cmd;
3265 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003266 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003267 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268
3269 if (ret != -EINTR && FDCS->reset)
3270 ret = -EIO;
3271
3272 DRS->track = NO_TRACK;
3273
3274 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3275 if (!ret)
3276 ret = ret2;
3277 raw_cmd_free(&my_raw_cmd);
3278 return ret;
3279}
3280
3281static int invalidate_drive(struct block_device *bdev)
3282{
3283 /* invalidate the buffer track to force a reread */
3284 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3285 process_fd_request();
3286 check_disk_change(bdev);
3287 return 0;
3288}
3289
3290static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3291 int drive, int type, struct block_device *bdev)
3292{
3293 int cnt;
3294
3295 /* sanity checking for parameters. */
3296 if (g->sect <= 0 ||
3297 g->head <= 0 ||
3298 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3299 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003300 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 return -EINVAL;
3302 if (type) {
3303 if (!capable(CAP_SYS_ADMIN))
3304 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003305 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003306 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003307 mutex_unlock(&open_lock);
3308 return -EINTR;
3309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 floppy_type[type] = *g;
3311 floppy_type[type].name = "user format";
3312 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3313 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3314 floppy_type[type].size + 1;
3315 process_fd_request();
3316 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3317 struct block_device *bdev = opened_bdev[cnt];
3318 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3319 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003320 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003322 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 } else {
3324 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003325
Joe Perches74f63f42010-03-10 15:20:58 -08003326 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003327 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003328 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 /* notice a disk change immediately, else
3330 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003331 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003332 return -EINTR;
3333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 oldStretch = g->stretch;
3335 user_params[drive] = *g;
3336 if (buffer_drive == drive)
3337 SUPBOUND(buffer_max, user_params[drive].sect);
3338 current_type[drive] = &user_params[drive];
3339 floppy_sizes[drive] = user_params[drive].size;
3340 if (cmd == FDDEFPRM)
3341 DRS->keep_data = -1;
3342 else
3343 DRS->keep_data = 1;
3344 /* invalidation. Invalidate only when needed, i.e.
3345 * when there are already sectors in the buffer cache
3346 * whose number will change. This is useful, because
3347 * mtools often changes the geometry of the disk after
3348 * looking at the boot block */
3349 if (DRS->maxblock > user_params[drive].sect ||
3350 DRS->maxtrack ||
3351 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003352 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 invalidate_drive(bdev);
3354 else
3355 process_fd_request();
3356 }
3357 return 0;
3358}
3359
3360/* handle obsolete ioctl's */
3361static int ioctl_table[] = {
3362 FDCLRPRM,
3363 FDSETPRM,
3364 FDDEFPRM,
3365 FDGETPRM,
3366 FDMSGON,
3367 FDMSGOFF,
3368 FDFMTBEG,
3369 FDFMTTRK,
3370 FDFMTEND,
3371 FDSETEMSGTRESH,
3372 FDFLUSH,
3373 FDSETMAXERRS,
3374 FDGETMAXERRS,
3375 FDGETDRVTYP,
3376 FDSETDRVPRM,
3377 FDGETDRVPRM,
3378 FDGETDRVSTAT,
3379 FDPOLLDRVSTAT,
3380 FDRESET,
3381 FDGETFDCSTAT,
3382 FDWERRORCLR,
3383 FDWERRORGET,
3384 FDRAWCMD,
3385 FDEJECT,
3386 FDTWADDLE
3387};
3388
3389static inline int normalize_ioctl(int *cmd, int *size)
3390{
3391 int i;
3392
3393 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3394 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3395 *size = _IOC_SIZE(*cmd);
3396 *cmd = ioctl_table[i];
3397 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003398 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 return -EFAULT;
3400 }
3401 return 0;
3402 }
3403 }
3404 return -EINVAL;
3405}
3406
3407static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3408{
3409 if (type)
3410 *g = &floppy_type[type];
3411 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003412 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003413 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003414 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003415 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 process_fd_request();
3417 *g = current_type[drive];
3418 }
3419 if (!*g)
3420 return -ENODEV;
3421 return 0;
3422}
3423
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003424static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3425{
3426 int drive = (long)bdev->bd_disk->private_data;
3427 int type = ITYPE(drive_state[drive].fd_device);
3428 struct floppy_struct *g;
3429 int ret;
3430
3431 ret = get_floppy_geometry(drive, type, &g);
3432 if (ret)
3433 return ret;
3434
3435 geo->heads = g->head;
3436 geo->sectors = g->sect;
3437 geo->cylinders = g->track;
3438 return 0;
3439}
3440
Al Viroa4af9b42008-03-02 09:27:55 -05003441static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 unsigned long param)
3443{
Al Viroa4af9b42008-03-02 09:27:55 -05003444#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445
Al Viroa4af9b42008-03-02 09:27:55 -05003446 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003447 int type = ITYPE(UDRS->fd_device);
3448 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 int ret;
3450 int size;
3451 union inparam {
3452 struct floppy_struct g; /* geometry */
3453 struct format_descr f;
3454 struct floppy_max_errors max_errors;
3455 struct floppy_drive_params dp;
3456 } inparam; /* parameters coming from user space */
3457 const char *outparam; /* parameters passed back to user space */
3458
3459 /* convert compatibility eject ioctls into floppy eject ioctl.
3460 * We do this in order to provide a means to eject floppy disks before
3461 * installing the new fdutils package */
3462 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003463 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 DPRINT("obsolete eject ioctl\n");
3465 DPRINT("please use floppycontrol --eject\n");
3466 cmd = FDEJECT;
3467 }
3468
Joe Perchesa81ee542010-03-10 15:20:46 -08003469 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 return -EINVAL;
3471
Joe Perchesa81ee542010-03-10 15:20:46 -08003472 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003473 ret = normalize_ioctl(&cmd, &size);
3474 if (ret)
3475 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003476
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 /* permission checks */
3478 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3479 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3480 return -EPERM;
3481
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003482 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3483 return -EINVAL;
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003486 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003487 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3488 ret = fd_copyin((void __user *)param, &inparam, size);
3489 if (ret)
3490 return ret;
3491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492
Joe Perchesda273652010-03-10 15:20:52 -08003493 switch (cmd) {
3494 case FDEJECT:
3495 if (UDRS->fd_ref != 1)
3496 /* somebody else has this drive open */
3497 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003498 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003499 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
Joe Perchesda273652010-03-10 15:20:52 -08003501 /* do the actual eject. Fails on
3502 * non-Sparc architectures */
3503 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504
Joe Perchese0298532010-03-10 15:20:55 -08003505 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3506 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003507 process_fd_request();
3508 return ret;
3509 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003510 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003511 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003512 current_type[drive] = NULL;
3513 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3514 UDRS->keep_data = 0;
3515 return invalidate_drive(bdev);
3516 case FDSETPRM:
3517 case FDDEFPRM:
3518 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3519 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003520 ret = get_floppy_geometry(drive, type,
Joe Perchesda273652010-03-10 15:20:52 -08003521 (struct floppy_struct **)
Joe Perches4575b552010-03-10 15:20:55 -08003522 &outparam);
3523 if (ret)
3524 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003525 break;
3526 case FDMSGON:
3527 UDP->flags |= FTD_MSG;
3528 return 0;
3529 case FDMSGOFF:
3530 UDP->flags &= ~FTD_MSG;
3531 return 0;
3532 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003533 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003534 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003535 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003536 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003537 ret = UDRS->flags;
3538 process_fd_request();
3539 if (ret & FD_VERIFY)
3540 return -ENODEV;
3541 if (!(ret & FD_DISK_WRITABLE))
3542 return -EROFS;
3543 return 0;
3544 case FDFMTTRK:
3545 if (UDRS->fd_ref != 1)
3546 return -EBUSY;
3547 return do_format(drive, &inparam.f);
3548 case FDFMTEND:
3549 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003550 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003551 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003552 return invalidate_drive(bdev);
3553 case FDSETEMSGTRESH:
3554 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3555 return 0;
3556 case FDGETMAXERRS:
3557 outparam = (const char *)&UDP->max_errors;
3558 break;
3559 case FDSETMAXERRS:
3560 UDP->max_errors = inparam.max_errors;
3561 break;
3562 case FDGETDRVTYP:
3563 outparam = drive_name(type, drive);
3564 SUPBOUND(size, strlen(outparam) + 1);
3565 break;
3566 case FDSETDRVPRM:
3567 *UDP = inparam.dp;
3568 break;
3569 case FDGETDRVPRM:
3570 outparam = (const char *)UDP;
3571 break;
3572 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003573 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003574 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003575 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003576 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003577 process_fd_request();
3578 /* fall through */
3579 case FDGETDRVSTAT:
3580 outparam = (const char *)UDRS;
3581 break;
3582 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003583 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003584 case FDGETFDCSTAT:
3585 outparam = (const char *)UFDCS;
3586 break;
3587 case FDWERRORCLR:
3588 memset(UDRWE, 0, sizeof(*UDRWE));
3589 return 0;
3590 case FDWERRORGET:
3591 outparam = (const char *)UDRWE;
3592 break;
3593 case FDRAWCMD:
3594 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003596 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003597 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003598 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003599 i = raw_cmd_ioctl(cmd, (void __user *)param);
3600 if (i == -EINTR)
3601 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003602 process_fd_request();
3603 return i;
3604 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003605 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003606 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003607 twaddle();
3608 process_fd_request();
3609 return 0;
3610 default:
3611 return -EINVAL;
3612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613
3614 if (_IOC_DIR(cmd) & _IOC_READ)
3615 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003616
3617 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618}
3619
3620static void __init config_types(void)
3621{
Joe Perchesb46df352010-03-10 15:20:46 -08003622 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 int drive;
3624
3625 /* read drive info out of physical CMOS */
3626 drive = 0;
3627 if (!UDP->cmos)
3628 UDP->cmos = FLOPPY0_TYPE;
3629 drive = 1;
3630 if (!UDP->cmos && FLOPPY1_TYPE)
3631 UDP->cmos = FLOPPY1_TYPE;
3632
Jesper Juhl06f748c2007-10-16 23:30:57 -07003633 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634
3635 for (drive = 0; drive < N_DRIVE; drive++) {
3636 unsigned int type = UDP->cmos;
3637 struct floppy_drive_params *params;
3638 const char *name = NULL;
3639 static char temparea[32];
3640
Tobias Klauser945f3902006-01-08 01:05:11 -08003641 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 params = &default_drive_params[type].params;
3643 if (type) {
3644 name = default_drive_params[type].name;
3645 allowed_drive_mask |= 1 << drive;
3646 } else
3647 allowed_drive_mask &= ~(1 << drive);
3648 } else {
3649 params = &default_drive_params[0].params;
3650 sprintf(temparea, "unknown type %d (usb?)", type);
3651 name = temparea;
3652 }
3653 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003654 const char *prepend;
3655 if (!has_drive) {
3656 prepend = "";
3657 has_drive = true;
3658 pr_info("Floppy drive(s):");
3659 } else {
3660 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 }
Joe Perchesb46df352010-03-10 15:20:46 -08003662
3663 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 }
3665 *UDP = *params;
3666 }
Joe Perchesb46df352010-03-10 15:20:46 -08003667
3668 if (has_drive)
3669 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670}
3671
Al Viroa4af9b42008-03-02 09:27:55 -05003672static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673{
Al Viroa4af9b42008-03-02 09:27:55 -05003674 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003676 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 if (UDRS->fd_ref < 0)
3678 UDRS->fd_ref = 0;
3679 else if (!UDRS->fd_ref--) {
3680 DPRINT("floppy_release with fd_ref == 0");
3681 UDRS->fd_ref = 0;
3682 }
3683 if (!UDRS->fd_ref)
3684 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003685 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003686
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 return 0;
3688}
3689
3690/*
3691 * floppy_open check for aliasing (/dev/fd0 can be the same as
3692 * /dev/PS0 etc), and disallows simultaneous access to the same
3693 * drive with different device numbers.
3694 */
Al Viroa4af9b42008-03-02 09:27:55 -05003695static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696{
Al Viroa4af9b42008-03-02 09:27:55 -05003697 int drive = (long)bdev->bd_disk->private_data;
3698 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 int try;
3700 int res = -EBUSY;
3701 char *tmp;
3702
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003703 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003705 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 goto out2;
3707
3708 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003709 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3710 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 }
3712
Al Viroa4af9b42008-03-02 09:27:55 -05003713 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 goto out2;
3715
Al Viroa4af9b42008-03-02 09:27:55 -05003716 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 UDRS->fd_ref = -1;
3718 else
3719 UDRS->fd_ref++;
3720
Al Viroa4af9b42008-03-02 09:27:55 -05003721 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
3723 res = -ENXIO;
3724
3725 if (!floppy_track_buffer) {
3726 /* if opening an ED drive, reserve a big buffer,
3727 * else reserve a small one */
3728 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3729 try = 64; /* Only 48 actually useful */
3730 else
3731 try = 32; /* Only 24 actually useful */
3732
3733 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3734 if (!tmp && !floppy_track_buffer) {
3735 try >>= 1; /* buffer only one side */
3736 INFBOUND(try, 16);
3737 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3738 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003739 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 if (!tmp && !floppy_track_buffer) {
3742 DPRINT("Unable to allocate DMA memory\n");
3743 goto out;
3744 }
3745 if (floppy_track_buffer) {
3746 if (tmp)
3747 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3748 } else {
3749 buffer_min = buffer_max = -1;
3750 floppy_track_buffer = tmp;
3751 max_buffer_sectors = try;
3752 }
3753 }
3754
Al Viroa4af9b42008-03-02 09:27:55 -05003755 new_dev = MINOR(bdev->bd_dev);
3756 UDRS->fd_device = new_dev;
3757 set_capacity(disks[drive], floppy_sizes[new_dev]);
3758 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 if (buffer_drive == drive)
3760 buffer_track = -1;
3761 }
3762
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 if (UFDCS->rawcmd == 1)
3764 UFDCS->rawcmd = 2;
3765
Al Viroa4af9b42008-03-02 09:27:55 -05003766 if (!(mode & FMODE_NDELAY)) {
3767 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003769 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003770 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 goto out;
3772 }
3773 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003774 if ((mode & FMODE_WRITE) &&
3775 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 goto out;
3777 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003778 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 return 0;
3780out:
3781 if (UDRS->fd_ref < 0)
3782 UDRS->fd_ref = 0;
3783 else
3784 UDRS->fd_ref--;
3785 if (!UDRS->fd_ref)
3786 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003788 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 return res;
3790}
3791
3792/*
3793 * Check if the disk has been changed or if a change has been faked.
3794 */
3795static int check_floppy_change(struct gendisk *disk)
3796{
3797 int drive = (long)disk->private_data;
3798
Joe Perchese0298532010-03-10 15:20:55 -08003799 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3800 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 return 1;
3802
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003803 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003804 lock_fdc(drive, false);
3805 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 }
3808
Joe Perchese0298532010-03-10 15:20:55 -08003809 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3810 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 test_bit(drive, &fake_change) ||
3812 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3813 return 1;
3814 return 0;
3815}
3816
3817/*
3818 * This implements "read block 0" for floppy_revalidate().
3819 * Needed for format autodetection, checking whether there is
3820 * a disk in the drive, and whether that disk is writable.
3821 */
3822
Joe Perchesbb57f0c2010-03-10 15:20:50 -08003823static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826}
3827
3828static int __floppy_read_block_0(struct block_device *bdev)
3829{
3830 struct bio bio;
3831 struct bio_vec bio_vec;
3832 struct completion complete;
3833 struct page *page;
3834 size_t size;
3835
3836 page = alloc_page(GFP_NOIO);
3837 if (!page) {
3838 process_fd_request();
3839 return -ENOMEM;
3840 }
3841
3842 size = bdev->bd_block_size;
3843 if (!size)
3844 size = 1024;
3845
3846 bio_init(&bio);
3847 bio.bi_io_vec = &bio_vec;
3848 bio_vec.bv_page = page;
3849 bio_vec.bv_len = size;
3850 bio_vec.bv_offset = 0;
3851 bio.bi_vcnt = 1;
3852 bio.bi_idx = 0;
3853 bio.bi_size = size;
3854 bio.bi_bdev = bdev;
3855 bio.bi_sector = 0;
3856 init_completion(&complete);
3857 bio.bi_private = &complete;
3858 bio.bi_end_io = floppy_rb0_complete;
3859
3860 submit_bio(READ, &bio);
3861 generic_unplug_device(bdev_get_queue(bdev));
3862 process_fd_request();
3863 wait_for_completion(&complete);
3864
3865 __free_page(page);
3866
3867 return 0;
3868}
3869
3870/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3871 * the bootblock (block 0). "Autodetection" is also needed to check whether
3872 * there is a disk in the drive at all... Thus we also do it for fixed
3873 * geometry formats */
3874static int floppy_revalidate(struct gendisk *disk)
3875{
3876 int drive = (long)disk->private_data;
3877#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3878 int cf;
3879 int res = 0;
3880
Joe Perchese0298532010-03-10 15:20:55 -08003881 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3882 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
3883 test_bit(drive, &fake_change) || NO_GEOM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003885 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 return -EFAULT;
3887 }
Joe Perches74f63f42010-03-10 15:20:58 -08003888 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003889 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3890 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3892 process_fd_request(); /*already done by another thread */
3893 return 0;
3894 }
3895 UDRS->maxblock = 0;
3896 UDRS->maxtrack = 0;
3897 if (buffer_drive == drive)
3898 buffer_track = -1;
3899 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003900 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 if (cf)
3902 UDRS->generation++;
3903 if (NO_GEOM) {
3904 /* auto-sensing */
3905 res = __floppy_read_block_0(opened_bdev[drive]);
3906 } else {
3907 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003908 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 process_fd_request();
3910 }
3911 }
3912 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3913 return res;
3914}
3915
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003916static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003917 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003918 .open = floppy_open,
3919 .release = floppy_release,
3920 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003921 .getgeo = fd_getgeo,
3922 .media_changed = check_floppy_change,
3923 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926/*
3927 * Floppy Driver initialization
3928 * =============================
3929 */
3930
3931/* Determine the floppy disk controller type */
3932/* This routine was written by David C. Niemi */
3933static char __init get_fdc_version(void)
3934{
3935 int r;
3936
3937 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3938 if (FDCS->reset)
3939 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003940 r = result();
3941 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 return FDC_NONE; /* No FDC present ??? */
3943 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003944 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3946 }
3947 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003948 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3949 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 return FDC_UNKNOWN;
3951 }
3952
3953 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003954 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3956 }
3957
3958 output_byte(FD_PERPENDICULAR);
3959 if (need_more_output() == MORE_OUTPUT) {
3960 output_byte(0);
3961 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003962 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 return FDC_82072A; /* 82072A as found on Sparcs. */
3964 }
3965
3966 output_byte(FD_UNLOCK);
3967 r = result();
3968 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003969 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003970 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 * LOCK/UNLOCK */
3972 }
3973 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003974 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3975 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 return FDC_UNKNOWN;
3977 }
3978 output_byte(FD_PARTID);
3979 r = result();
3980 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003981 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3982 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 return FDC_UNKNOWN;
3984 }
3985 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003986 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 return FDC_82077; /* Revised 82077AA passes all the tests */
3988 }
3989 switch (reply_buffer[0] >> 5) {
3990 case 0x0:
3991 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003992 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 return FDC_82078;
3994 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003995 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 return FDC_82078;
3997 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003998 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 return FDC_S82078B;
4000 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004001 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 return FDC_87306;
4003 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004004 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4005 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 return FDC_82078_UNKN;
4007 }
4008} /* get_fdc_version */
4009
4010/* lilo configuration */
4011
4012static void __init floppy_set_flags(int *ints, int param, int param2)
4013{
4014 int i;
4015
4016 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4017 if (param)
4018 default_drive_params[i].params.flags |= param2;
4019 else
4020 default_drive_params[i].params.flags &= ~param2;
4021 }
4022 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4023}
4024
4025static void __init daring(int *ints, int param, int param2)
4026{
4027 int i;
4028
4029 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4030 if (param) {
4031 default_drive_params[i].params.select_delay = 0;
4032 default_drive_params[i].params.flags |=
4033 FD_SILENT_DCL_CLEAR;
4034 } else {
4035 default_drive_params[i].params.select_delay =
4036 2 * HZ / 100;
4037 default_drive_params[i].params.flags &=
4038 ~FD_SILENT_DCL_CLEAR;
4039 }
4040 }
4041 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4042}
4043
4044static void __init set_cmos(int *ints, int dummy, int dummy2)
4045{
4046 int current_drive = 0;
4047
4048 if (ints[0] != 2) {
4049 DPRINT("wrong number of parameters for CMOS\n");
4050 return;
4051 }
4052 current_drive = ints[1];
4053 if (current_drive < 0 || current_drive >= 8) {
4054 DPRINT("bad drive for set_cmos\n");
4055 return;
4056 }
4057#if N_FDC > 1
4058 if (current_drive >= 4 && !FDC2)
4059 FDC2 = 0x370;
4060#endif
4061 DP->cmos = ints[2];
4062 DPRINT("setting CMOS code to %d\n", ints[2]);
4063}
4064
4065static struct param_table {
4066 const char *name;
4067 void (*fn) (int *ints, int param, int param2);
4068 int *var;
4069 int def_param;
4070 int param2;
4071} config_params[] __initdata = {
4072 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4073 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4074 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4075 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4076 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4077 {"daring", daring, NULL, 1, 0},
4078#if N_FDC > 1
4079 {"two_fdc", NULL, &FDC2, 0x370, 0},
4080 {"one_fdc", NULL, &FDC2, 0, 0},
4081#endif
4082 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4083 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4084 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4085 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4086 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4087 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4088 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4089 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4090 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4091 {"nofifo", NULL, &no_fifo, 0x20, 0},
4092 {"usefifo", NULL, &no_fifo, 0, 0},
4093 {"cmos", set_cmos, NULL, 0, 0},
4094 {"slow", NULL, &slow_floppy, 1, 0},
4095 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4096 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4097 {"L40SX", NULL, &print_unex, 0, 0}
4098
4099 EXTRA_FLOPPY_PARAMS
4100};
4101
4102static int __init floppy_setup(char *str)
4103{
4104 int i;
4105 int param;
4106 int ints[11];
4107
4108 str = get_options(str, ARRAY_SIZE(ints), ints);
4109 if (str) {
4110 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4111 if (strcmp(str, config_params[i].name) == 0) {
4112 if (ints[0])
4113 param = ints[1];
4114 else
4115 param = config_params[i].def_param;
4116 if (config_params[i].fn)
Joe Perchesbb57f0c2010-03-10 15:20:50 -08004117 config_params[i].fn(ints, param,
4118 config_params[i].
4119 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 if (config_params[i].var) {
4121 DPRINT("%s=%d\n", str, param);
4122 *config_params[i].var = param;
4123 }
4124 return 1;
4125 }
4126 }
4127 }
4128 if (str) {
4129 DPRINT("unknown floppy option [%s]\n", str);
4130
4131 DPRINT("allowed options are:");
4132 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004133 pr_cont(" %s", config_params[i].name);
4134 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 } else
4136 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004137 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 return 0;
4139}
4140
4141static int have_no_fdc = -ENODEV;
4142
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004143static ssize_t floppy_cmos_show(struct device *dev,
4144 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004145{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004146 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004147 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004148
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004149 drive = p->id;
4150 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004151}
Joe Perches48c8cee2010-03-10 15:20:45 -08004152
4153DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004154
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155static void floppy_device_release(struct device *dev)
4156{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157}
4158
Frans Popc90cd332009-07-25 22:24:54 +02004159static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004160{
4161 int fdc;
4162
4163 for (fdc = 0; fdc < N_FDC; fdc++)
4164 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004165 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004166
4167 return 0;
4168}
4169
Alexey Dobriyan47145212009-12-14 18:00:08 -08004170static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004171 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004172 .restore = floppy_resume,
4173};
4174
4175static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004176 .driver = {
Joe Perchesbb57f0c2010-03-10 15:20:50 -08004177 .name = "floppy",
4178 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004179 },
4180};
4181
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004182static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183
4184static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4185{
4186 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4187 if (drive >= N_DRIVE ||
4188 !(allowed_drive_mask & (1 << drive)) ||
4189 fdc_state[FDC(drive)].version == FDC_NONE)
4190 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004191 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 return NULL;
4193 *part = 0;
4194 return get_disk(disks[drive]);
4195}
4196
4197static int __init floppy_init(void)
4198{
4199 int i, unit, drive;
4200 int err, dr;
4201
Kumar Gala68e1ee62008-09-22 14:41:31 -07004202#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004203 if (check_legacy_ioport(FDC1))
4204 return -ENODEV;
4205#endif
4206
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 raw_cmd = NULL;
4208
4209 for (dr = 0; dr < N_DRIVE; dr++) {
4210 disks[dr] = alloc_disk(1);
4211 if (!disks[dr]) {
4212 err = -ENOMEM;
4213 goto out_put_disk;
4214 }
4215
4216 disks[dr]->major = FLOPPY_MAJOR;
4217 disks[dr]->first_minor = TOMINOR(dr);
4218 disks[dr]->fops = &floppy_fops;
4219 sprintf(disks[dr]->disk_name, "fd%d", dr);
4220
4221 init_timer(&motor_off_timer[dr]);
4222 motor_off_timer[dr].data = dr;
4223 motor_off_timer[dr].function = motor_off_callback;
4224 }
4225
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 err = register_blkdev(FLOPPY_MAJOR, "fd");
4227 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004228 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004230 err = platform_driver_register(&floppy_driver);
4231 if (err)
4232 goto out_unreg_blkdev;
4233
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4235 if (!floppy_queue) {
4236 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004237 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004239 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
4241 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4242 floppy_find, NULL, NULL);
4243
4244 for (i = 0; i < 256; i++)
4245 if (ITYPE(i))
4246 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4247 else
4248 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4249
4250 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4251 config_types();
4252
4253 for (i = 0; i < N_FDC; i++) {
4254 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004255 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 FDCS->dtr = -1;
4257 FDCS->dor = 0x4;
4258#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004259 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260#ifdef __mc68000__
4261 if (MACH_IS_SUN3X)
4262#endif
4263 FDCS->version = FDC_82072A;
4264#endif
4265 }
4266
4267 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 fdc_state[0].address = FDC1;
4269 if (fdc_state[0].address == -1) {
4270 del_timer(&fd_timeout);
4271 err = -ENODEV;
4272 goto out_unreg_region;
4273 }
4274#if N_FDC > 1
4275 fdc_state[1].address = FDC2;
4276#endif
4277
4278 fdc = 0; /* reset fdc in case of unexpected interrupt */
4279 err = floppy_grab_irq_and_dma();
4280 if (err) {
4281 del_timer(&fd_timeout);
4282 err = -EBUSY;
4283 goto out_unreg_region;
4284 }
4285
4286 /* initialise drive state */
4287 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004288 memset(UDRS, 0, sizeof(*UDRS));
4289 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004290 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4291 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4292 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 UDRS->fd_device = -1;
4294 floppy_track_buffer = NULL;
4295 max_buffer_sectors = 0;
4296 }
4297 /*
4298 * Small 10 msec delay to let through any interrupt that
4299 * initialization might have triggered, to not
4300 * confuse detection:
4301 */
4302 msleep(10);
4303
4304 for (i = 0; i < N_FDC; i++) {
4305 fdc = i;
4306 FDCS->driver_version = FD_DRIVER_VERSION;
4307 for (unit = 0; unit < 4; unit++)
4308 FDCS->track[unit] = 0;
4309 if (FDCS->address == -1)
4310 continue;
4311 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004312 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004314 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 FDCS->address = -1;
4316 FDCS->version = FDC_NONE;
4317 continue;
4318 }
4319 /* Try to determine the floppy controller type */
4320 FDCS->version = get_fdc_version();
4321 if (FDCS->version == FDC_NONE) {
4322 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004323 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 FDCS->address = -1;
4325 continue;
4326 }
4327 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4328 can_use_virtual_dma = 0;
4329
4330 have_no_fdc = 0;
4331 /* Not all FDCs seem to be able to handle the version command
4332 * properly, so force a reset for the standard FDC clones,
4333 * to avoid interrupt garbage.
4334 */
Joe Perches74f63f42010-03-10 15:20:58 -08004335 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 }
4337 fdc = 0;
4338 del_timer(&fd_timeout);
4339 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 initialising = 0;
4341 if (have_no_fdc) {
4342 DPRINT("no floppy controllers found\n");
4343 err = have_no_fdc;
4344 goto out_flush_work;
4345 }
4346
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 for (drive = 0; drive < N_DRIVE; drive++) {
4348 if (!(allowed_drive_mask & (1 << drive)))
4349 continue;
4350 if (fdc_state[FDC(drive)].version == FDC_NONE)
4351 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004352
4353 floppy_device[drive].name = floppy_device_name;
4354 floppy_device[drive].id = drive;
4355 floppy_device[drive].dev.release = floppy_device_release;
4356
4357 err = platform_device_register(&floppy_device[drive]);
4358 if (err)
4359 goto out_flush_work;
4360
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004361 err = device_create_file(&floppy_device[drive].dev,
4362 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004363 if (err)
4364 goto out_unreg_platform_dev;
4365
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 /* to be cleaned up... */
4367 disks[drive]->private_data = (void *)(long)drive;
4368 disks[drive]->queue = floppy_queue;
4369 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004370 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 add_disk(disks[drive]);
4372 }
4373
4374 return 0;
4375
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004376out_unreg_platform_dev:
4377 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378out_flush_work:
4379 flush_scheduled_work();
4380 if (usage_count)
4381 floppy_release_irq_and_dma();
4382out_unreg_region:
4383 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4384 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004385out_unreg_driver:
4386 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387out_unreg_blkdev:
4388 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389out_put_disk:
4390 while (dr--) {
4391 del_timer(&motor_off_timer[dr]);
4392 put_disk(disks[dr]);
4393 }
4394 return err;
4395}
4396
4397static DEFINE_SPINLOCK(floppy_usage_lock);
4398
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004399static const struct io_region {
4400 int offset;
4401 int size;
4402} io_regions[] = {
4403 { 2, 1 },
4404 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4405 { 4, 2 },
4406 /* address + 6 is reserved, and may be taken by IDE.
4407 * Unfortunately, Adaptec doesn't know this :-(, */
4408 { 7, 1 },
4409};
4410
4411static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4412{
4413 while (p != io_regions) {
4414 p--;
4415 release_region(FDCS->address + p->offset, p->size);
4416 }
4417}
4418
4419#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4420
4421static int floppy_request_regions(int fdc)
4422{
4423 const struct io_region *p;
4424
4425 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c2010-03-10 15:20:50 -08004426 if (!request_region(FDCS->address + p->offset,
4427 p->size, "floppy")) {
4428 DPRINT("Floppy io-port 0x%04lx in use\n",
4429 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004430 floppy_release_allocated_regions(fdc, p);
4431 return -EBUSY;
4432 }
4433 }
4434 return 0;
4435}
4436
4437static void floppy_release_regions(int fdc)
4438{
4439 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4440}
4441
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442static int floppy_grab_irq_and_dma(void)
4443{
4444 unsigned long flags;
4445
4446 spin_lock_irqsave(&floppy_usage_lock, flags);
4447 if (usage_count++) {
4448 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4449 return 0;
4450 }
4451 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004452
4453 /*
4454 * We might have scheduled a free_irq(), wait it to
4455 * drain first:
4456 */
4457 flush_scheduled_work();
4458
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 if (fd_request_irq()) {
4460 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4461 FLOPPY_IRQ);
4462 spin_lock_irqsave(&floppy_usage_lock, flags);
4463 usage_count--;
4464 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4465 return -1;
4466 }
4467 if (fd_request_dma()) {
4468 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4469 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004470 if (can_use_virtual_dma & 2)
4471 use_virtual_dma = can_use_virtual_dma = 1;
4472 if (!(can_use_virtual_dma & 1)) {
4473 fd_free_irq();
4474 spin_lock_irqsave(&floppy_usage_lock, flags);
4475 usage_count--;
4476 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4477 return -1;
4478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 }
4480
4481 for (fdc = 0; fdc < N_FDC; fdc++) {
4482 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004483 if (floppy_request_regions(fdc))
4484 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 }
4486 }
4487 for (fdc = 0; fdc < N_FDC; fdc++) {
4488 if (FDCS->address != -1) {
4489 reset_fdc_info(1);
4490 fd_outb(FDCS->dor, FD_DOR);
4491 }
4492 }
4493 fdc = 0;
4494 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4495
4496 for (fdc = 0; fdc < N_FDC; fdc++)
4497 if (FDCS->address != -1)
4498 fd_outb(FDCS->dor, FD_DOR);
4499 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004500 * The driver will try and free resources and relies on us
4501 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 */
4503 fdc = 0;
4504 irqdma_allocated = 1;
4505 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004506cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 fd_free_irq();
4508 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004509 while (--fdc >= 0)
4510 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 spin_lock_irqsave(&floppy_usage_lock, flags);
4512 usage_count--;
4513 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4514 return -1;
4515}
4516
4517static void floppy_release_irq_and_dma(void)
4518{
4519 int old_fdc;
4520#ifdef FLOPPY_SANITY_CHECK
4521#ifndef __sparc__
4522 int drive;
4523#endif
4524#endif
4525 long tmpsize;
4526 unsigned long tmpaddr;
4527 unsigned long flags;
4528
4529 spin_lock_irqsave(&floppy_usage_lock, flags);
4530 if (--usage_count) {
4531 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4532 return;
4533 }
4534 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4535 if (irqdma_allocated) {
4536 fd_disable_dma();
4537 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004538 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 irqdma_allocated = 0;
4540 }
4541 set_dor(0, ~0, 8);
4542#if N_FDC > 1
4543 set_dor(1, ~8, 0);
4544#endif
4545 floppy_enable_hlt();
4546
4547 if (floppy_track_buffer && max_buffer_sectors) {
4548 tmpsize = max_buffer_sectors * 1024;
4549 tmpaddr = (unsigned long)floppy_track_buffer;
4550 floppy_track_buffer = NULL;
4551 max_buffer_sectors = 0;
4552 buffer_min = buffer_max = -1;
4553 fd_dma_mem_free(tmpaddr, tmpsize);
4554 }
4555#ifdef FLOPPY_SANITY_CHECK
4556#ifndef __sparc__
4557 for (drive = 0; drive < N_FDC * 4; drive++)
4558 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004559 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560#endif
4561
4562 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004563 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004565 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004566 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004567 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568#endif
4569 old_fdc = fdc;
4570 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004571 if (FDCS->address != -1)
4572 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 fdc = old_fdc;
4574}
4575
4576#ifdef MODULE
4577
4578static char *floppy;
4579
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580static void __init parse_floppy_cfg_string(char *cfg)
4581{
4582 char *ptr;
4583
4584 while (*cfg) {
Joe Perchesbb57f0c2010-03-10 15:20:50 -08004585 ptr = cfg;
4586 while (*cfg && *cfg != ' ' && *cfg != '\t')
4587 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 if (*cfg) {
4589 *cfg = '\0';
4590 cfg++;
4591 }
4592 if (*ptr)
4593 floppy_setup(ptr);
4594 }
4595}
4596
Jon Schindler7afea3b2008-04-29 00:59:21 -07004597static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598{
4599 if (floppy)
4600 parse_floppy_cfg_string(floppy);
4601 return floppy_init();
4602}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004603module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604
Jon Schindler7afea3b2008-04-29 00:59:21 -07004605static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606{
4607 int drive;
4608
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4610 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004611 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612
4613 for (drive = 0; drive < N_DRIVE; drive++) {
4614 del_timer_sync(&motor_off_timer[drive]);
4615
4616 if ((allowed_drive_mask & (1 << drive)) &&
4617 fdc_state[FDC(drive)].version != FDC_NONE) {
4618 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004619 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4620 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 }
4622 put_disk(disks[drive]);
4623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624
4625 del_timer_sync(&fd_timeout);
4626 del_timer_sync(&fd_timer);
4627 blk_cleanup_queue(floppy_queue);
4628
4629 if (usage_count)
4630 floppy_release_irq_and_dma();
4631
4632 /* eject disk, if any */
4633 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634}
Joe Perches48c8cee2010-03-10 15:20:45 -08004635
Jon Schindler7afea3b2008-04-29 00:59:21 -07004636module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637
4638module_param(floppy, charp, 0);
4639module_param(FLOPPY_IRQ, int, 0);
4640module_param(FLOPPY_DMA, int, 0);
4641MODULE_AUTHOR("Alain L. Knaff");
4642MODULE_SUPPORTED_DEVICE("fd");
4643MODULE_LICENSE("GPL");
4644
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004645/* This doesn't actually get used other than for module information */
4646static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004647 {"PNP0700", 0},
4648 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004649};
Joe Perches48c8cee2010-03-10 15:20:45 -08004650
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004651MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4652
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653#else
4654
4655__setup("floppy=", floppy_setup);
4656module_init(floppy_init)
4657#endif
4658
4659MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);