blob: 8e24aa3a4e248f3075280125d328f853bc2a3c5e [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;
Joe Perches29f1c782010-03-10 15:21:00 -0800293static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Joe Perches48c8cee2010-03-10 15:20:45 -0800295#define ITYPE(x) (((x) >> 2) & 0x1f)
296#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
297#define UNIT(x) ((x) & 0x03) /* drive on fdc */
298#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700299 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Joe Perches48c8cee2010-03-10 15:20:45 -0800302#define DP (&drive_params[current_drive])
303#define DRS (&drive_state[current_drive])
304#define DRWE (&write_errors[current_drive])
305#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Joe Perches48c8cee2010-03-10 15:20:45 -0800307#define UDP (&drive_params[drive])
308#define UDRS (&drive_state[drive])
309#define UDRWE (&write_errors[drive])
310#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Joe Perches48c8cee2010-03-10 15:20:45 -0800312#define 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
Joe Perches57584c52010-03-10 15:21:00 -0800785static bool is_ready_state(int status)
786{
787 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
788 return state == STATUS_READY;
789}
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791static int set_dor(int fdc, char mask, char data)
792{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700793 unsigned char unit;
794 unsigned char drive;
795 unsigned char newdor;
796 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if (FDCS->address == -1)
799 return -1;
800
801 olddor = FDCS->dor;
802 newdor = (olddor & mask) | data;
803 if (newdor != olddor) {
804 unit = olddor & 0x3;
805 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
806 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800807 debug_dcl(UDP->flags,
808 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 disk_change(drive);
810 }
811 FDCS->dor = newdor;
812 fd_outb(newdor, FD_DOR);
813
814 unit = newdor & 0x3;
815 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
816 drive = REVDRIVE(fdc, unit);
817 UDRS->select_date = jiffies;
818 }
819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 return olddor;
821}
822
823static void twaddle(void)
824{
825 if (DP->select_delay)
826 return;
827 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
828 fd_outb(FDCS->dor, FD_DOR);
829 DRS->select_date = jiffies;
830}
831
Joe Perches57584c52010-03-10 15:21:00 -0800832/*
833 * Reset all driver information about the current fdc.
834 * This is needed after a reset, and after a raw command.
835 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836static void reset_fdc_info(int mode)
837{
838 int drive;
839
840 FDCS->spec1 = FDCS->spec2 = -1;
841 FDCS->need_configure = 1;
842 FDCS->perp_mode = 1;
843 FDCS->rawcmd = 0;
844 for (drive = 0; drive < N_DRIVE; drive++)
845 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
846 UDRS->track = NEED_2_RECAL;
847}
848
849/* selects the fdc and drive, and enables the fdc's input/dma. */
850static void set_fdc(int drive)
851{
852 if (drive >= 0 && drive < N_DRIVE) {
853 fdc = FDC(drive);
854 current_drive = drive;
855 }
856 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800857 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return;
859 }
860 set_dor(fdc, ~0, 8);
861#if N_FDC > 1
862 set_dor(1 - fdc, ~8, 0);
863#endif
864 if (FDCS->rawcmd == 2)
865 reset_fdc_info(1);
866 if (fd_inb(FD_STATUS) != STATUS_READY)
867 FDCS->reset = 1;
868}
869
870/* locks the driver */
Joe Perches74f63f42010-03-10 15:20:58 -0800871static int _lock_fdc(int drive, bool interruptible, int line)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
873 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800874 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 line);
876 return -1;
877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 if (test_and_set_bit(0, &fdc_busy)) {
880 DECLARE_WAITQUEUE(wait, current);
881 add_wait_queue(&fdc_wait, &wait);
882
883 for (;;) {
884 set_current_state(TASK_INTERRUPTIBLE);
885
886 if (!test_and_set_bit(0, &fdc_busy))
887 break;
888
889 schedule();
890
891 if (!NO_SIGNAL) {
892 remove_wait_queue(&fdc_wait, &wait);
893 return -EINTR;
894 }
895 }
896
897 set_current_state(TASK_RUNNING);
898 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700899 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 }
901 command_status = FD_COMMAND_NONE;
902
903 __reschedule_timeout(drive, "lock fdc", 0);
904 set_fdc(drive);
905 return 0;
906}
907
Joe Perches48c8cee2010-03-10 15:20:45 -0800908#define lock_fdc(drive, interruptible) \
909 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911/* unlocks the driver */
912static inline void unlock_fdc(void)
913{
914 unsigned long flags;
915
916 raw_cmd = NULL;
917 if (!test_bit(0, &fdc_busy))
918 DPRINT("FDC access conflict!\n");
919
920 if (do_floppy)
921 DPRINT("device interrupt still active at FDC release: %p!\n",
922 do_floppy);
923 command_status = FD_COMMAND_NONE;
924 spin_lock_irqsave(&floppy_lock, flags);
925 del_timer(&fd_timeout);
926 cont = NULL;
927 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900928 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 do_fd_request(floppy_queue);
930 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 wake_up(&fdc_wait);
932}
933
934/* switches the motor off after a given timeout */
935static void motor_off_callback(unsigned long nr)
936{
937 unsigned char mask = ~(0x10 << UNIT(nr));
938
939 set_dor(FDC(nr), mask, 0);
940}
941
942/* schedules motor off */
943static void floppy_off(unsigned int drive)
944{
945 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700946 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 if (!(FDCS->dor & (0x10 << UNIT(drive))))
949 return;
950
951 del_timer(motor_off_timer + drive);
952
953 /* make spindle stop in a position which minimizes spinup time
954 * next time */
955 if (UDP->rps) {
956 delta = jiffies - UDRS->first_read_date + HZ -
957 UDP->spindown_offset;
958 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
959 motor_off_timer[drive].expires =
960 jiffies + UDP->spindown - delta;
961 }
962 add_timer(motor_off_timer + drive);
963}
964
965/*
966 * cycle through all N_DRIVE floppy drives, for disk change testing.
967 * stopping at current drive. This is done before any long operation, to
968 * be sure to have up to date disk change information.
969 */
970static void scandrives(void)
971{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700972 int i;
973 int drive;
974 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 if (DP->select_delay)
977 return;
978
979 saved_drive = current_drive;
980 for (i = 0; i < N_DRIVE; i++) {
981 drive = (saved_drive + i + 1) % N_DRIVE;
982 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
983 continue; /* skip closed drives */
984 set_fdc(drive);
985 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
986 (0x10 << UNIT(drive))))
987 /* switch the motor off again, if it was off to
988 * begin with */
989 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
990 }
991 set_fdc(saved_drive);
992}
993
994static void empty(void)
995{
996}
997
David Howells65f27f32006-11-22 14:55:48 +0000998static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Joe Perches48c8cee2010-03-10 15:20:45 -08001000static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
David Howells65f27f32006-11-22 14:55:48 +00001002 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 schedule_work(&floppy_work);
1004}
1005
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001006static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008static void cancel_activity(void)
1009{
1010 unsigned long flags;
1011
1012 spin_lock_irqsave(&floppy_lock, flags);
1013 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001014 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 del_timer(&fd_timer);
1016 spin_unlock_irqrestore(&floppy_lock, flags);
1017}
1018
1019/* this function makes sure that the disk stays in the drive during the
1020 * transfer */
1021static void fd_watchdog(void)
1022{
Joe Perches87f530d2010-03-10 15:20:54 -08001023 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 if (disk_change(current_drive)) {
1026 DPRINT("disk removed during i/o\n");
1027 cancel_activity();
1028 cont->done(0);
1029 reset_fdc();
1030 } else {
1031 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001032 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 fd_timer.expires = jiffies + HZ / 10;
1034 add_timer(&fd_timer);
1035 }
1036}
1037
1038static void main_command_interrupt(void)
1039{
1040 del_timer(&fd_timer);
1041 cont->interrupt();
1042}
1043
1044/* waits for a delay (spinup or select) to pass */
1045static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1046{
1047 if (FDCS->reset) {
1048 reset_fdc(); /* do the reset during sleep to win time
1049 * if we don't need to sleep, it's a good
1050 * occasion anyways */
1051 return 1;
1052 }
1053
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001054 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 del_timer(&fd_timer);
1056 fd_timer.function = function;
1057 fd_timer.expires = delay;
1058 add_timer(&fd_timer);
1059 return 1;
1060 }
1061 return 0;
1062}
1063
1064static DEFINE_SPINLOCK(floppy_hlt_lock);
1065static int hlt_disabled;
1066static void floppy_disable_hlt(void)
1067{
1068 unsigned long flags;
1069
1070 spin_lock_irqsave(&floppy_hlt_lock, flags);
1071 if (!hlt_disabled) {
1072 hlt_disabled = 1;
1073#ifdef HAVE_DISABLE_HLT
1074 disable_hlt();
1075#endif
1076 }
1077 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1078}
1079
1080static void floppy_enable_hlt(void)
1081{
1082 unsigned long flags;
1083
1084 spin_lock_irqsave(&floppy_hlt_lock, flags);
1085 if (hlt_disabled) {
1086 hlt_disabled = 0;
1087#ifdef HAVE_DISABLE_HLT
1088 enable_hlt();
1089#endif
1090 }
1091 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1092}
1093
1094static void setup_DMA(void)
1095{
1096 unsigned long f;
1097
1098#ifdef FLOPPY_SANITY_CHECK
1099 if (raw_cmd->length == 0) {
1100 int i;
1101
Joe Perchesb46df352010-03-10 15:20:46 -08001102 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001104 pr_cont("%x,", raw_cmd->cmd[i]);
1105 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 cont->done(0);
1107 FDCS->reset = 1;
1108 return;
1109 }
1110 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001111 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 cont->done(0);
1113 FDCS->reset = 1;
1114 return;
1115 }
1116#endif
1117 f = claim_dma_lock();
1118 fd_disable_dma();
1119#ifdef fd_dma_setup
1120 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1121 (raw_cmd->flags & FD_RAW_READ) ?
1122 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1123 release_dma_lock(f);
1124 cont->done(0);
1125 FDCS->reset = 1;
1126 return;
1127 }
1128 release_dma_lock(f);
1129#else
1130 fd_clear_dma_ff();
1131 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1132 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1133 DMA_MODE_READ : DMA_MODE_WRITE);
1134 fd_set_dma_addr(raw_cmd->kernel_data);
1135 fd_set_dma_count(raw_cmd->length);
1136 virtual_dma_port = FDCS->address;
1137 fd_enable_dma();
1138 release_dma_lock(f);
1139#endif
1140 floppy_disable_hlt();
1141}
1142
1143static void show_floppy(void);
1144
1145/* waits until the fdc becomes ready */
1146static int wait_til_ready(void)
1147{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001148 int status;
1149 int counter;
1150
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 if (FDCS->reset)
1152 return -1;
1153 for (counter = 0; counter < 10000; counter++) {
1154 status = fd_inb(FD_STATUS);
1155 if (status & STATUS_READY)
1156 return status;
1157 }
Joe Perches29f1c782010-03-10 15:21:00 -08001158 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1160 show_floppy();
1161 }
1162 FDCS->reset = 1;
1163 return -1;
1164}
1165
1166/* sends a command byte to the fdc */
1167static int output_byte(char byte)
1168{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001169 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001171 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001173
1174 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 fd_outb(byte, FD_DATA);
1176#ifdef FLOPPY_SANITY_CHECK
1177 output_log[output_log_pos].data = byte;
1178 output_log[output_log_pos].status = status;
1179 output_log[output_log_pos].jiffies = jiffies;
1180 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1181#endif
1182 return 0;
1183 }
1184 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001185 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1187 byte, fdc, status);
1188 show_floppy();
1189 }
1190 return -1;
1191}
1192
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193/* gets the response from the fdc */
1194static int result(void)
1195{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001196 int i;
1197 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
1199 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001200 status = wait_til_ready();
1201 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 break;
1203 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1204 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1205#ifdef FLOPPY_SANITY_CHECK
1206 resultjiffies = jiffies;
1207 resultsize = i;
1208#endif
1209 return i;
1210 }
1211 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1212 reply_buffer[i] = fd_inb(FD_DATA);
1213 else
1214 break;
1215 }
Joe Perches29f1c782010-03-10 15:21:00 -08001216 if (initialized) {
1217 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1218 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 show_floppy();
1220 }
1221 FDCS->reset = 1;
1222 return -1;
1223}
1224
1225#define MORE_OUTPUT -2
1226/* does the fdc need more output? */
1227static int need_more_output(void)
1228{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001229 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001230
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001231 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001233
1234 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 return result();
1238}
1239
1240/* Set perpendicular mode as required, based on data rate, if supported.
1241 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1242 */
1243static inline void perpendicular_mode(void)
1244{
1245 unsigned char perp_mode;
1246
1247 if (raw_cmd->rate & 0x40) {
1248 switch (raw_cmd->rate & 3) {
1249 case 0:
1250 perp_mode = 2;
1251 break;
1252 case 3:
1253 perp_mode = 3;
1254 break;
1255 default:
1256 DPRINT("Invalid data rate for perpendicular mode!\n");
1257 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001258 FDCS->reset = 1;
1259 /*
1260 * convenient way to return to
1261 * redo without too much hassle
1262 * (deep stack et al.)
1263 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 return;
1265 }
1266 } else
1267 perp_mode = 0;
1268
1269 if (FDCS->perp_mode == perp_mode)
1270 return;
1271 if (FDCS->version >= FDC_82077_ORIG) {
1272 output_byte(FD_PERPENDICULAR);
1273 output_byte(perp_mode);
1274 FDCS->perp_mode = perp_mode;
1275 } else if (perp_mode) {
1276 DPRINT("perpendicular mode not supported by this FDC.\n");
1277 }
1278} /* perpendicular_mode */
1279
1280static int fifo_depth = 0xa;
1281static int no_fifo;
1282
1283static int fdc_configure(void)
1284{
1285 /* Turn on FIFO */
1286 output_byte(FD_CONFIGURE);
1287 if (need_more_output() != MORE_OUTPUT)
1288 return 0;
1289 output_byte(0);
1290 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1291 output_byte(0); /* pre-compensation from track
1292 0 upwards */
1293 return 1;
1294}
1295
1296#define NOMINAL_DTR 500
1297
1298/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1299 * head load time, and DMA disable flag to values needed by floppy.
1300 *
1301 * The value "dtr" is the data transfer rate in Kbps. It is needed
1302 * to account for the data rate-based scaling done by the 82072 and 82077
1303 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1304 * 8272a).
1305 *
1306 * Note that changing the data transfer rate has a (probably deleterious)
1307 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1308 * fdc_specify is called again after each data transfer rate
1309 * change.
1310 *
1311 * srt: 1000 to 16000 in microseconds
1312 * hut: 16 to 240 milliseconds
1313 * hlt: 2 to 254 milliseconds
1314 *
1315 * These values are rounded up to the next highest available delay time.
1316 */
1317static void fdc_specify(void)
1318{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001319 unsigned char spec1;
1320 unsigned char spec2;
1321 unsigned long srt;
1322 unsigned long hlt;
1323 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 unsigned long dtr = NOMINAL_DTR;
1325 unsigned long scale_dtr = NOMINAL_DTR;
1326 int hlt_max_code = 0x7f;
1327 int hut_max_code = 0xf;
1328
1329 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1330 fdc_configure();
1331 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 }
1333
1334 switch (raw_cmd->rate & 0x03) {
1335 case 3:
1336 dtr = 1000;
1337 break;
1338 case 1:
1339 dtr = 300;
1340 if (FDCS->version >= FDC_82078) {
1341 /* chose the default rate table, not the one
1342 * where 1 = 2 Mbps */
1343 output_byte(FD_DRIVESPEC);
1344 if (need_more_output() == MORE_OUTPUT) {
1345 output_byte(UNIT(current_drive));
1346 output_byte(0xc0);
1347 }
1348 }
1349 break;
1350 case 2:
1351 dtr = 250;
1352 break;
1353 }
1354
1355 if (FDCS->version >= FDC_82072) {
1356 scale_dtr = dtr;
1357 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1358 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1359 }
1360
1361 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001362 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001363 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001365
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 SUPBOUND(srt, 0xf);
1367 INFBOUND(srt, 0);
1368
Julia Lawall061837b2008-09-22 14:57:16 -07001369 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 if (hlt < 0x01)
1371 hlt = 0x01;
1372 else if (hlt > 0x7f)
1373 hlt = hlt_max_code;
1374
Julia Lawall061837b2008-09-22 14:57:16 -07001375 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (hut < 0x1)
1377 hut = 0x1;
1378 else if (hut > 0xf)
1379 hut = hut_max_code;
1380
1381 spec1 = (srt << 4) | hut;
1382 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1383
1384 /* If these parameters did not change, just return with success */
1385 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1386 /* Go ahead and set spec1 and spec2 */
1387 output_byte(FD_SPECIFY);
1388 output_byte(FDCS->spec1 = spec1);
1389 output_byte(FDCS->spec2 = spec2);
1390 }
1391} /* fdc_specify */
1392
1393/* Set the FDC's data transfer rate on behalf of the specified drive.
1394 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1395 * of the specify command (i.e. using the fdc_specify function).
1396 */
1397static int fdc_dtr(void)
1398{
1399 /* If data rate not already set to desired value, set it. */
1400 if ((raw_cmd->rate & 3) == FDCS->dtr)
1401 return 0;
1402
1403 /* Set dtr */
1404 fd_outb(raw_cmd->rate & 3, FD_DCR);
1405
1406 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1407 * need a stabilization period of several milliseconds to be
1408 * enforced after data rate changes before R/W operations.
1409 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1410 */
1411 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001412 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1413 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414} /* fdc_dtr */
1415
1416static void tell_sector(void)
1417{
Joe Perchesb46df352010-03-10 15:20:46 -08001418 pr_cont(": track %d, head %d, sector %d, size %d",
1419 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420} /* tell_sector */
1421
Joe Perchesb46df352010-03-10 15:20:46 -08001422static void print_errors(void)
1423{
1424 DPRINT("");
1425 if (ST0 & ST0_ECE) {
1426 pr_cont("Recalibrate failed!");
1427 } else if (ST2 & ST2_CRC) {
1428 pr_cont("data CRC error");
1429 tell_sector();
1430 } else if (ST1 & ST1_CRC) {
1431 pr_cont("CRC error");
1432 tell_sector();
1433 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1434 (ST2 & ST2_MAM)) {
1435 if (!probing) {
1436 pr_cont("sector not found");
1437 tell_sector();
1438 } else
1439 pr_cont("probe failed...");
1440 } else if (ST2 & ST2_WC) { /* seek error */
1441 pr_cont("wrong cylinder");
1442 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1443 pr_cont("bad cylinder");
1444 } else {
1445 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1446 ST0, ST1, ST2);
1447 tell_sector();
1448 }
1449 pr_cont("\n");
1450}
1451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452/*
1453 * OK, this error interpreting routine is called after a
1454 * DMA read/write has succeeded
1455 * or failed, so we check the results, and copy any buffers.
1456 * hhb: Added better error reporting.
1457 * ak: Made this into a separate routine.
1458 */
1459static int interpret_errors(void)
1460{
1461 char bad;
1462
1463 if (inr != 7) {
1464 DPRINT("-- FDC reply error");
1465 FDCS->reset = 1;
1466 return 1;
1467 }
1468
1469 /* check IC to find cause of interrupt */
1470 switch (ST0 & ST0_INTR) {
1471 case 0x40: /* error occurred during command execution */
1472 if (ST1 & ST1_EOC)
1473 return 0; /* occurs with pseudo-DMA */
1474 bad = 1;
1475 if (ST1 & ST1_WP) {
1476 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001477 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 cont->done(0);
1479 bad = 2;
1480 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001481 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 } else if (ST1 & ST1_OR) {
1483 if (DP->flags & FTD_MSG)
1484 DPRINT("Over/Underrun - retrying\n");
1485 bad = 0;
1486 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001487 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 }
1489 if (ST2 & ST2_WC || ST2 & ST2_BC)
1490 /* wrong cylinder => recal */
1491 DRS->track = NEED_2_RECAL;
1492 return bad;
1493 case 0x80: /* invalid command given */
1494 DPRINT("Invalid FDC command given!\n");
1495 cont->done(0);
1496 return 2;
1497 case 0xc0:
1498 DPRINT("Abnormal termination caused by polling\n");
1499 cont->error();
1500 return 2;
1501 default: /* (0) Normal command termination */
1502 return 0;
1503 }
1504}
1505
1506/*
1507 * This routine is called when everything should be correctly set up
1508 * for the transfer (i.e. floppy motor is on, the correct floppy is
1509 * selected, and the head is sitting on the right track).
1510 */
1511static void setup_rw_floppy(void)
1512{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001513 int i;
1514 int r;
1515 int flags;
1516 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 unsigned long ready_date;
1518 timeout_fn function;
1519
1520 flags = raw_cmd->flags;
1521 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1522 flags |= FD_RAW_INTR;
1523
1524 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1525 ready_date = DRS->spinup_date + DP->spinup;
1526 /* If spinup will take a long time, rerun scandrives
1527 * again just before spinup completion. Beware that
1528 * after scandrives, we must again wait for selection.
1529 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001530 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001532 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001534 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
1536 /* wait until the floppy is spinning fast enough */
1537 if (fd_wait_for_completion(ready_date, function))
1538 return;
1539 }
1540 dflags = DRS->flags;
1541
1542 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1543 setup_DMA();
1544
1545 if (flags & FD_RAW_INTR)
1546 do_floppy = main_command_interrupt;
1547
1548 r = 0;
1549 for (i = 0; i < raw_cmd->cmd_count; i++)
1550 r |= output_byte(raw_cmd->cmd[i]);
1551
1552 debugt("rw_command: ");
1553
1554 if (r) {
1555 cont->error();
1556 reset_fdc();
1557 return;
1558 }
1559
1560 if (!(flags & FD_RAW_INTR)) {
1561 inr = result();
1562 cont->interrupt();
1563 } else if (flags & FD_RAW_NEED_DISK)
1564 fd_watchdog();
1565}
1566
1567static int blind_seek;
1568
1569/*
1570 * This is the routine called after every seek (or recalibrate) interrupt
1571 * from the floppy controller.
1572 */
1573static void seek_interrupt(void)
1574{
1575 debugt("seek interrupt:");
1576 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1577 DPRINT("seek failed\n");
1578 DRS->track = NEED_2_RECAL;
1579 cont->error();
1580 cont->redo();
1581 return;
1582 }
1583 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001584 debug_dcl(DP->flags,
1585 "clearing NEWCHANGE flag because of effective seek\n");
1586 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001587 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1588 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 DRS->select_date = jiffies;
1590 }
1591 DRS->track = ST1;
1592 floppy_ready();
1593}
1594
1595static void check_wp(void)
1596{
Joe Perchese0298532010-03-10 15:20:55 -08001597 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1598 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 output_byte(FD_GETSTATUS);
1600 output_byte(UNIT(current_drive));
1601 if (result() != 1) {
1602 FDCS->reset = 1;
1603 return;
1604 }
Joe Perchese0298532010-03-10 15:20:55 -08001605 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1606 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001607 debug_dcl(DP->flags,
1608 "checking whether disk is write protected\n");
1609 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001611 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 else
Joe Perchese0298532010-03-10 15:20:55 -08001613 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 }
1615}
1616
1617static void seek_floppy(void)
1618{
1619 int track;
1620
1621 blind_seek = 0;
1622
Joe Perches87f530d2010-03-10 15:20:54 -08001623 debug_dcl(DP->flags, "calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
Joe Perchese0298532010-03-10 15:20:55 -08001625 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1627 /* the media changed flag should be cleared after the seek.
1628 * If it isn't, this means that there is really no disk in
1629 * the drive.
1630 */
Joe Perchese0298532010-03-10 15:20:55 -08001631 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 cont->done(0);
1633 cont->redo();
1634 return;
1635 }
1636 if (DRS->track <= NEED_1_RECAL) {
1637 recalibrate_floppy();
1638 return;
Joe Perchese0298532010-03-10 15:20:55 -08001639 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1641 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1642 /* we seek to clear the media-changed condition. Does anybody
1643 * know a more elegant way, which works on all drives? */
1644 if (raw_cmd->track)
1645 track = raw_cmd->track - 1;
1646 else {
1647 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1648 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1649 blind_seek = 1;
1650 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1651 }
1652 track = 1;
1653 }
1654 } else {
1655 check_wp();
1656 if (raw_cmd->track != DRS->track &&
1657 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1658 track = raw_cmd->track;
1659 else {
1660 setup_rw_floppy();
1661 return;
1662 }
1663 }
1664
1665 do_floppy = seek_interrupt;
1666 output_byte(FD_SEEK);
1667 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001668 if (output_byte(track) < 0) {
1669 reset_fdc();
1670 return;
1671 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 debugt("seek command:");
1673}
1674
1675static void recal_interrupt(void)
1676{
1677 debugt("recal interrupt:");
1678 if (inr != 2)
1679 FDCS->reset = 1;
1680 else if (ST0 & ST0_ECE) {
1681 switch (DRS->track) {
1682 case NEED_1_RECAL:
1683 debugt("recal interrupt need 1 recal:");
1684 /* after a second recalibrate, we still haven't
1685 * reached track 0. Probably no drive. Raise an
1686 * error, as failing immediately might upset
1687 * computers possessed by the Devil :-) */
1688 cont->error();
1689 cont->redo();
1690 return;
1691 case NEED_2_RECAL:
1692 debugt("recal interrupt need 2 recal:");
1693 /* If we already did a recalibrate,
1694 * and we are not at track 0, this
1695 * means we have moved. (The only way
1696 * not to move at recalibration is to
1697 * be already at track 0.) Clear the
1698 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001699 debug_dcl(DP->flags,
1700 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
Joe Perchese0298532010-03-10 15:20:55 -08001702 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 DRS->select_date = jiffies;
1704 /* fall through */
1705 default:
1706 debugt("recal interrupt default:");
1707 /* Recalibrate moves the head by at
1708 * most 80 steps. If after one
1709 * recalibrate we don't have reached
1710 * track 0, this might mean that we
1711 * started beyond track 80. Try
1712 * again. */
1713 DRS->track = NEED_1_RECAL;
1714 break;
1715 }
1716 } else
1717 DRS->track = ST1;
1718 floppy_ready();
1719}
1720
1721static void print_result(char *message, int inr)
1722{
1723 int i;
1724
1725 DPRINT("%s ", message);
1726 if (inr >= 0)
1727 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001728 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1729 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730}
1731
1732/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001733irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 int do_print;
1736 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001737 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
1739 lasthandler = handler;
1740 interruptjiffies = jiffies;
1741
1742 f = claim_dma_lock();
1743 fd_disable_dma();
1744 release_dma_lock(f);
1745
1746 floppy_enable_hlt();
1747 do_floppy = NULL;
1748 if (fdc >= N_FDC || FDCS->address == -1) {
1749 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001750 pr_info("DOR0=%x\n", fdc_state[0].dor);
1751 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1752 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 is_alive("bizarre fdc");
1754 return IRQ_NONE;
1755 }
1756
1757 FDCS->reset = 0;
1758 /* We have to clear the reset flag here, because apparently on boxes
1759 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1760 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1761 * emission of the SENSEI's.
1762 * It is OK to emit floppy commands because we are in an interrupt
1763 * handler here, and thus we have to fear no interference of other
1764 * activity.
1765 */
1766
Joe Perches29f1c782010-03-10 15:21:00 -08001767 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
1769 inr = result();
1770 if (do_print)
1771 print_result("unexpected interrupt", inr);
1772 if (inr == 0) {
1773 int max_sensei = 4;
1774 do {
1775 output_byte(FD_SENSEI);
1776 inr = result();
1777 if (do_print)
1778 print_result("sensei", inr);
1779 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001780 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1781 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 }
1783 if (!handler) {
1784 FDCS->reset = 1;
1785 return IRQ_NONE;
1786 }
1787 schedule_bh(handler);
1788 is_alive("normal interrupt end");
1789
1790 /* FIXME! Was it really for us? */
1791 return IRQ_HANDLED;
1792}
1793
1794static void recalibrate_floppy(void)
1795{
1796 debugt("recalibrate floppy:");
1797 do_floppy = recal_interrupt;
1798 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001799 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001800 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801}
1802
1803/*
1804 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1805 */
1806static void reset_interrupt(void)
1807{
1808 debugt("reset interrupt:");
1809 result(); /* get the status ready for set_fdc */
1810 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001811 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 cont->error(); /* a reset just after a reset. BAD! */
1813 }
1814 cont->redo();
1815}
1816
1817/*
1818 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1819 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1820 */
1821static void reset_fdc(void)
1822{
1823 unsigned long flags;
1824
1825 do_floppy = reset_interrupt;
1826 FDCS->reset = 0;
1827 reset_fdc_info(0);
1828
1829 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1830 /* Irrelevant for systems with true DMA (i386). */
1831
1832 flags = claim_dma_lock();
1833 fd_disable_dma();
1834 release_dma_lock(flags);
1835
1836 if (FDCS->version >= FDC_82072A)
1837 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1838 else {
1839 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1840 udelay(FD_RESET_DELAY);
1841 fd_outb(FDCS->dor, FD_DOR);
1842 }
1843}
1844
1845static void show_floppy(void)
1846{
1847 int i;
1848
Joe Perchesb46df352010-03-10 15:20:46 -08001849 pr_info("\n");
1850 pr_info("floppy driver state\n");
1851 pr_info("-------------------\n");
1852 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1853 jiffies, interruptjiffies, jiffies - interruptjiffies,
1854 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
1856#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001857 pr_info("timeout_message=%s\n", timeout_message);
1858 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001860 pr_info("%2x %2x %lu\n",
1861 output_log[(i + output_log_pos) % OLOGSIZE].data,
1862 output_log[(i + output_log_pos) % OLOGSIZE].status,
1863 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1864 pr_info("last result at %lu\n", resultjiffies);
1865 pr_info("last redo_fd_request at %lu\n", lastredo);
1866 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1867 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868#endif
1869
Joe Perchesb46df352010-03-10 15:20:46 -08001870 pr_info("status=%x\n", fd_inb(FD_STATUS));
1871 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001873 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001874 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001875 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001877 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001879 pr_info("timer_function=%p\n", fd_timeout.function);
1880 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1881 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 }
Joe Perchesb46df352010-03-10 15:20:46 -08001883 pr_info("cont=%p\n", cont);
1884 pr_info("current_req=%p\n", current_req);
1885 pr_info("command_status=%d\n", command_status);
1886 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887}
1888
1889static void floppy_shutdown(unsigned long data)
1890{
1891 unsigned long flags;
1892
Joe Perches29f1c782010-03-10 15:21:00 -08001893 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 show_floppy();
1895 cancel_activity();
1896
1897 floppy_enable_hlt();
1898
1899 flags = claim_dma_lock();
1900 fd_disable_dma();
1901 release_dma_lock(flags);
1902
1903 /* avoid dma going to a random drive after shutdown */
1904
Joe Perches29f1c782010-03-10 15:21:00 -08001905 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 DPRINT("floppy timeout called\n");
1907 FDCS->reset = 1;
1908 if (cont) {
1909 cont->done(0);
1910 cont->redo(); /* this will recall reset when needed */
1911 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001912 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 process_fd_request();
1914 }
1915 is_alive("floppy shutdown");
1916}
1917
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001919static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001921 int mask;
1922 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
1924 mask = 0xfc;
1925 data = UNIT(current_drive);
1926 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1927 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1928 set_debugt();
1929 /* no read since this drive is running */
1930 DRS->first_read_date = 0;
1931 /* note motor start time if motor is not yet running */
1932 DRS->spinup_date = jiffies;
1933 data |= (0x10 << UNIT(current_drive));
1934 }
1935 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1936 mask &= ~(0x10 << UNIT(current_drive));
1937
1938 /* starts motor and selects floppy */
1939 del_timer(motor_off_timer + current_drive);
1940 set_dor(fdc, mask, data);
1941
1942 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001943 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1944 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945}
1946
1947static void floppy_ready(void)
1948{
Joe Perches045f9832010-03-10 15:20:47 -08001949 if (FDCS->reset) {
1950 reset_fdc();
1951 return;
1952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 if (start_motor(floppy_ready))
1954 return;
1955 if (fdc_dtr())
1956 return;
1957
Joe Perches87f530d2010-03-10 15:20:54 -08001958 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1960 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001961 twaddle(); /* this clears the dcl on certain
1962 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
1964#ifdef fd_chose_dma_mode
1965 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1966 unsigned long flags = claim_dma_lock();
1967 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1968 release_dma_lock(flags);
1969 }
1970#endif
1971
1972 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1973 perpendicular_mode();
1974 fdc_specify(); /* must be done here because of hut, hlt ... */
1975 seek_floppy();
1976 } else {
1977 if ((raw_cmd->flags & FD_RAW_READ) ||
1978 (raw_cmd->flags & FD_RAW_WRITE))
1979 fdc_specify();
1980 setup_rw_floppy();
1981 }
1982}
1983
1984static void floppy_start(void)
1985{
1986 reschedule_timeout(current_reqD, "floppy start", 0);
1987
1988 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001989 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001990 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 floppy_ready();
1992}
1993
1994/*
1995 * ========================================================================
1996 * here ends the bottom half. Exported routines are:
1997 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1998 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1999 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2000 * and set_dor.
2001 * ========================================================================
2002 */
2003/*
2004 * General purpose continuations.
2005 * ==============================
2006 */
2007
2008static void do_wakeup(void)
2009{
2010 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2011 cont = NULL;
2012 command_status += 2;
2013 wake_up(&command_done);
2014}
2015
2016static struct cont_t wakeup_cont = {
2017 .interrupt = empty,
2018 .redo = do_wakeup,
2019 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002020 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021};
2022
2023static struct cont_t intr_cont = {
2024 .interrupt = empty,
2025 .redo = process_fd_request,
2026 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002027 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028};
2029
Joe Perches74f63f42010-03-10 15:20:58 -08002030static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031{
2032 int ret;
2033
2034 schedule_bh(handler);
2035
2036 if (command_status < 2 && NO_SIGNAL) {
2037 DECLARE_WAITQUEUE(wait, current);
2038
2039 add_wait_queue(&command_done, &wait);
2040 for (;;) {
2041 set_current_state(interruptible ?
2042 TASK_INTERRUPTIBLE :
2043 TASK_UNINTERRUPTIBLE);
2044
2045 if (command_status >= 2 || !NO_SIGNAL)
2046 break;
2047
2048 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 schedule();
2050 }
2051
2052 set_current_state(TASK_RUNNING);
2053 remove_wait_queue(&command_done, &wait);
2054 }
2055
2056 if (command_status < 2) {
2057 cancel_activity();
2058 cont = &intr_cont;
2059 reset_fdc();
2060 return -EINTR;
2061 }
2062
2063 if (FDCS->reset)
2064 command_status = FD_COMMAND_ERROR;
2065 if (command_status == FD_COMMAND_OKAY)
2066 ret = 0;
2067 else
2068 ret = -EIO;
2069 command_status = FD_COMMAND_NONE;
2070 return ret;
2071}
2072
2073static void generic_done(int result)
2074{
2075 command_status = result;
2076 cont = &wakeup_cont;
2077}
2078
2079static void generic_success(void)
2080{
2081 cont->done(1);
2082}
2083
2084static void generic_failure(void)
2085{
2086 cont->done(0);
2087}
2088
2089static void success_and_wakeup(void)
2090{
2091 generic_success();
2092 cont->redo();
2093}
2094
2095/*
2096 * formatting and rw support.
2097 * ==========================
2098 */
2099
2100static int next_valid_format(void)
2101{
2102 int probed_format;
2103
2104 probed_format = DRS->probed_format;
2105 while (1) {
2106 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2107 DRS->probed_format = 0;
2108 return 1;
2109 }
2110 if (floppy_type[DP->autodetect[probed_format]].sect) {
2111 DRS->probed_format = probed_format;
2112 return 0;
2113 }
2114 probed_format++;
2115 }
2116}
2117
2118static void bad_flp_intr(void)
2119{
2120 int err_count;
2121
2122 if (probing) {
2123 DRS->probed_format++;
2124 if (!next_valid_format())
2125 return;
2126 }
2127 err_count = ++(*errors);
2128 INFBOUND(DRWE->badness, err_count);
2129 if (err_count > DP->max_errors.abort)
2130 cont->done(0);
2131 if (err_count > DP->max_errors.reset)
2132 FDCS->reset = 1;
2133 else if (err_count > DP->max_errors.recal)
2134 DRS->track = NEED_2_RECAL;
2135}
2136
2137static void set_floppy(int drive)
2138{
2139 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 if (type)
2142 _floppy = floppy_type + type;
2143 else
2144 _floppy = current_type[drive];
2145}
2146
2147/*
2148 * formatting support.
2149 * ===================
2150 */
2151static void format_interrupt(void)
2152{
2153 switch (interpret_errors()) {
2154 case 1:
2155 cont->error();
2156 case 2:
2157 break;
2158 case 0:
2159 cont->done(1);
2160 }
2161 cont->redo();
2162}
2163
2164#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002165#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002167
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168static void setup_format_params(int track)
2169{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002170 int n;
2171 int il;
2172 int count;
2173 int head_shift;
2174 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 struct fparm {
2176 unsigned char track, head, sect, size;
2177 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
2179 raw_cmd = &default_raw_cmd;
2180 raw_cmd->track = track;
2181
Joe Perches48c8cee2010-03-10 15:20:45 -08002182 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2183 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 raw_cmd->rate = _floppy->rate & 0x43;
2185 raw_cmd->cmd_count = NR_F;
2186 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2187 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2188 F_SIZECODE = FD_SIZECODE(_floppy);
2189 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2190 F_GAP = _floppy->fmt_gap;
2191 F_FILL = FD_FILL_BYTE;
2192
2193 raw_cmd->kernel_data = floppy_track_buffer;
2194 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2195
2196 /* allow for about 30ms for data transport per track */
2197 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2198
2199 /* a ``cylinder'' is two tracks plus a little stepping time */
2200 track_shift = 2 * head_shift + 3;
2201
2202 /* position of logical sector 1 on this track */
2203 n = (track_shift * format_req.track + head_shift * format_req.head)
2204 % F_SECT_PER_TRACK;
2205
2206 /* determine interleave */
2207 il = 1;
2208 if (_floppy->fmt_gap < 0x22)
2209 il++;
2210
2211 /* initialize field */
2212 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2213 here[count].track = format_req.track;
2214 here[count].head = format_req.head;
2215 here[count].sect = 0;
2216 here[count].size = F_SIZECODE;
2217 }
2218 /* place logical sectors */
2219 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2220 here[n].sect = count;
2221 n = (n + il) % F_SECT_PER_TRACK;
2222 if (here[n].sect) { /* sector busy, find next free sector */
2223 ++n;
2224 if (n >= F_SECT_PER_TRACK) {
2225 n -= F_SECT_PER_TRACK;
2226 while (here[n].sect)
2227 ++n;
2228 }
2229 }
2230 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002231 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002233 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 }
2235}
2236
2237static void redo_format(void)
2238{
2239 buffer_track = -1;
2240 setup_format_params(format_req.track << STRETCH(_floppy));
2241 floppy_start();
2242 debugt("queue format request");
2243}
2244
2245static struct cont_t format_cont = {
2246 .interrupt = format_interrupt,
2247 .redo = redo_format,
2248 .error = bad_flp_intr,
2249 .done = generic_done
2250};
2251
2252static int do_format(int drive, struct format_descr *tmp_format_req)
2253{
2254 int ret;
2255
Joe Perches74f63f42010-03-10 15:20:58 -08002256 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002257 return -EINTR;
2258
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 set_floppy(drive);
2260 if (!_floppy ||
2261 _floppy->track > DP->tracks ||
2262 tmp_format_req->track >= _floppy->track ||
2263 tmp_format_req->head >= _floppy->head ||
2264 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2265 !_floppy->fmt_gap) {
2266 process_fd_request();
2267 return -EINVAL;
2268 }
2269 format_req = *tmp_format_req;
2270 format_errors = 0;
2271 cont = &format_cont;
2272 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002273 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002274 if (ret == -EINTR)
2275 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 process_fd_request();
2277 return ret;
2278}
2279
2280/*
2281 * Buffer read/write and support
2282 * =============================
2283 */
2284
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002285static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286{
2287 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002288 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
2290 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002291 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002292 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002293 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
2296 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002297 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 current_req = NULL;
2299}
2300
2301/* new request_done. Can handle physical sectors which are smaller than a
2302 * logical buffer */
2303static void request_done(int uptodate)
2304{
2305 struct request_queue *q = floppy_queue;
2306 struct request *req = current_req;
2307 unsigned long flags;
2308 int block;
2309
2310 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002311 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
2313 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002314 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 return;
2316 }
2317
2318 if (uptodate) {
2319 /* maintain values for invalidation on geometry
2320 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002321 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 INFBOUND(DRS->maxblock, block);
2323 if (block > _floppy->sect)
2324 DRS->maxtrack = 1;
2325
2326 /* unlock chained buffers */
2327 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002328 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 spin_unlock_irqrestore(q->queue_lock, flags);
2330 } else {
2331 if (rq_data_dir(req) == WRITE) {
2332 /* record write error information */
2333 DRWE->write_errors++;
2334 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002335 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 DRWE->first_error_generation = DRS->generation;
2337 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002338 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 DRWE->last_error_generation = DRS->generation;
2340 }
2341 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002342 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 spin_unlock_irqrestore(q->queue_lock, flags);
2344 }
2345}
2346
2347/* Interrupt handler evaluating the result of the r/w operation */
2348static void rw_interrupt(void)
2349{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002350 int eoc;
2351 int ssize;
2352 int heads;
2353 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354
2355 if (R_HEAD >= 2) {
2356 /* some Toshiba floppy controllers occasionnally seem to
2357 * return bogus interrupts after read/write operations, which
2358 * can be recognized by a bad head number (>= 2) */
2359 return;
2360 }
2361
2362 if (!DRS->first_read_date)
2363 DRS->first_read_date = jiffies;
2364
2365 nr_sectors = 0;
2366 CODE2SIZE;
2367
2368 if (ST1 & ST1_EOC)
2369 eoc = 1;
2370 else
2371 eoc = 0;
2372
2373 if (COMMAND & 0x80)
2374 heads = 2;
2375 else
2376 heads = 1;
2377
2378 nr_sectors = (((R_TRACK - TRACK) * heads +
2379 R_HEAD - HEAD) * SECT_PER_TRACK +
2380 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2381
2382#ifdef FLOPPY_SANITY_CHECK
2383 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002384 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 DPRINT("long rw: %x instead of %lx\n",
2386 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002387 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2388 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2389 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2390 pr_info("heads=%d eoc=%d\n", heads, eoc);
2391 pr_info("spt=%d st=%d ss=%d\n",
2392 SECT_PER_TRACK, fsector_t, ssize);
2393 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 }
2395#endif
2396
2397 nr_sectors -= in_sector_offset;
2398 INFBOUND(nr_sectors, 0);
2399 SUPBOUND(current_count_sectors, nr_sectors);
2400
2401 switch (interpret_errors()) {
2402 case 2:
2403 cont->redo();
2404 return;
2405 case 1:
2406 if (!current_count_sectors) {
2407 cont->error();
2408 cont->redo();
2409 return;
2410 }
2411 break;
2412 case 0:
2413 if (!current_count_sectors) {
2414 cont->redo();
2415 return;
2416 }
2417 current_type[current_drive] = _floppy;
2418 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2419 break;
2420 }
2421
2422 if (probing) {
2423 if (DP->flags & FTD_MSG)
2424 DPRINT("Auto-detected floppy type %s in fd%d\n",
2425 _floppy->name, current_drive);
2426 current_type[current_drive] = _floppy;
2427 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2428 probing = 0;
2429 }
2430
2431 if (CT(COMMAND) != FD_READ ||
2432 raw_cmd->kernel_data == current_req->buffer) {
2433 /* transfer directly from buffer */
2434 cont->done(1);
2435 } else if (CT(COMMAND) == FD_READ) {
2436 buffer_track = raw_cmd->track;
2437 buffer_drive = current_drive;
2438 INFBOUND(buffer_max, nr_sectors + fsector_t);
2439 }
2440 cont->redo();
2441}
2442
2443/* Compute maximal contiguous buffer size. */
2444static int buffer_chain_size(void)
2445{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002447 int size;
2448 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 char *base;
2450
2451 base = bio_data(current_req->bio);
2452 size = 0;
2453
NeilBrown5705f702007-09-25 12:35:59 +02002454 rq_for_each_segment(bv, current_req, iter) {
2455 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2456 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
NeilBrown5705f702007-09-25 12:35:59 +02002458 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 }
2460
2461 return size >> 9;
2462}
2463
2464/* Compute the maximal transfer size */
2465static int transfer_size(int ssize, int max_sector, int max_size)
2466{
2467 SUPBOUND(max_sector, fsector_t + max_size);
2468
2469 /* alignment */
2470 max_sector -= (max_sector % _floppy->sect) % ssize;
2471
2472 /* transfer size, beginning not aligned */
2473 current_count_sectors = max_sector - fsector_t;
2474
2475 return max_sector;
2476}
2477
2478/*
2479 * Move data from/to the track buffer to/from the buffer cache.
2480 */
2481static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2482{
2483 int remaining; /* number of transferred 512-byte sectors */
2484 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002485 char *buffer;
2486 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002487 int size;
2488 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490 max_sector = transfer_size(ssize,
2491 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002492 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
2494 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002495 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002497 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
2499 remaining = current_count_sectors << 9;
2500#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002501 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002503 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2504 pr_info("remaining=%d\n", remaining >> 9);
2505 pr_info("current_req->nr_sectors=%u\n",
2506 blk_rq_sectors(current_req));
2507 pr_info("current_req->current_nr_sectors=%u\n",
2508 blk_rq_cur_sectors(current_req));
2509 pr_info("max_sector=%d\n", max_sector);
2510 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 }
2512#endif
2513
2514 buffer_max = max(max_sector, buffer_max);
2515
2516 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2517
Tejun Heo1011c1b2009-05-07 22:24:45 +09002518 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
NeilBrown5705f702007-09-25 12:35:59 +02002520 rq_for_each_segment(bv, current_req, iter) {
2521 if (!remaining)
2522 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
NeilBrown5705f702007-09-25 12:35:59 +02002524 size = bv->bv_len;
2525 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
NeilBrown5705f702007-09-25 12:35:59 +02002527 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002529 if (dma_buffer + size >
2530 floppy_track_buffer + (max_buffer_sectors << 10) ||
2531 dma_buffer < floppy_track_buffer) {
2532 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002533 (int)((floppy_track_buffer - dma_buffer) >> 9));
2534 pr_info("fsector_t=%d buffer_min=%d\n",
2535 fsector_t, buffer_min);
2536 pr_info("current_count_sectors=%ld\n",
2537 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002539 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002540 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002541 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002542 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 }
NeilBrown5705f702007-09-25 12:35:59 +02002544 if (((unsigned long)buffer) % 512)
2545 DPRINT("%p buffer not aligned\n", buffer);
2546#endif
2547 if (CT(COMMAND) == FD_READ)
2548 memcpy(buffer, dma_buffer, size);
2549 else
2550 memcpy(dma_buffer, buffer, size);
2551
2552 remaining -= size;
2553 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 }
2555#ifdef FLOPPY_SANITY_CHECK
2556 if (remaining) {
2557 if (remaining > 0)
2558 max_sector -= remaining >> 9;
2559 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2560 }
2561#endif
2562}
2563
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564/* work around a bug in pseudo DMA
2565 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2566 * sending data. Hence we need a different way to signal the
2567 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2568 * does not work with MT, hence we can only transfer one head at
2569 * a time
2570 */
2571static void virtualdmabug_workaround(void)
2572{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002573 int hard_sectors;
2574 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575
2576 if (CT(COMMAND) == FD_WRITE) {
2577 COMMAND &= ~0x80; /* switch off multiple track mode */
2578
2579 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2580 end_sector = SECTOR + hard_sectors - 1;
2581#ifdef FLOPPY_SANITY_CHECK
2582 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002583 pr_info("too many sectors %d > %d\n",
2584 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 return;
2586 }
2587#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002588 SECT_PER_TRACK = end_sector;
2589 /* make sure SECT_PER_TRACK
2590 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 }
2592}
2593
2594/*
2595 * Formulate a read/write request.
2596 * this routine decides where to load the data (directly to buffer, or to
2597 * tmp floppy area), how much data to load (the size of the buffer, the whole
2598 * track, or a single sector)
2599 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2600 * allocation on the fly, it should be done here. No other part should need
2601 * modification.
2602 */
2603
2604static int make_raw_rw_request(void)
2605{
2606 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002607 int max_sector;
2608 int max_size;
2609 int tracksize;
2610 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
2612 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002613 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 return 0;
2615 }
2616
2617 set_fdc((long)current_req->rq_disk->private_data);
2618
2619 raw_cmd = &default_raw_cmd;
2620 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2621 FD_RAW_NEED_SEEK;
2622 raw_cmd->cmd_count = NR_RW;
2623 if (rq_data_dir(current_req) == READ) {
2624 raw_cmd->flags |= FD_RAW_READ;
2625 COMMAND = FM_MODE(_floppy, FD_READ);
2626 } else if (rq_data_dir(current_req) == WRITE) {
2627 raw_cmd->flags |= FD_RAW_WRITE;
2628 COMMAND = FM_MODE(_floppy, FD_WRITE);
2629 } else {
2630 DPRINT("make_raw_rw_request: unknown command\n");
2631 return 0;
2632 }
2633
2634 max_sector = _floppy->sect * _floppy->head;
2635
Tejun Heo83096eb2009-05-07 22:24:39 +09002636 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2637 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002639 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 current_count_sectors = 1;
2641 return 1;
2642 } else
2643 return 0;
2644 }
2645 HEAD = fsector_t / _floppy->sect;
2646
Keith Wansbrough9e491842008-09-22 14:57:17 -07002647 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002648 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2649 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 max_sector = _floppy->sect;
2651
2652 /* 2M disks have phantom sectors on the first track */
2653 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2654 max_sector = 2 * _floppy->sect / 3;
2655 if (fsector_t >= max_sector) {
2656 current_count_sectors =
2657 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002658 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 return 1;
2660 }
2661 SIZECODE = 2;
2662 } else
2663 SIZECODE = FD_SIZECODE(_floppy);
2664 raw_cmd->rate = _floppy->rate & 0x43;
2665 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2666 raw_cmd->rate = 1;
2667
2668 if (SIZECODE)
2669 SIZECODE2 = 0xff;
2670 else
2671 SIZECODE2 = 0x80;
2672 raw_cmd->track = TRACK << STRETCH(_floppy);
2673 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2674 GAP = _floppy->gap;
2675 CODE2SIZE;
2676 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2677 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002678 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
2680 /* tracksize describes the size which can be filled up with sectors
2681 * of size ssize.
2682 */
2683 tracksize = _floppy->sect - _floppy->sect % ssize;
2684 if (tracksize < _floppy->sect) {
2685 SECT_PER_TRACK++;
2686 if (tracksize <= fsector_t % _floppy->sect)
2687 SECTOR--;
2688
2689 /* if we are beyond tracksize, fill up using smaller sectors */
2690 while (tracksize <= fsector_t % _floppy->sect) {
2691 while (tracksize + ssize > _floppy->sect) {
2692 SIZECODE--;
2693 ssize >>= 1;
2694 }
2695 SECTOR++;
2696 SECT_PER_TRACK++;
2697 tracksize += ssize;
2698 }
2699 max_sector = HEAD * _floppy->sect + tracksize;
2700 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2701 max_sector = _floppy->sect;
2702 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2703 /* for virtual DMA bug workaround */
2704 max_sector = _floppy->sect;
2705 }
2706
2707 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2708 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002709 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 if ((raw_cmd->track == buffer_track) &&
2711 (current_drive == buffer_drive) &&
2712 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2713 /* data already in track buffer */
2714 if (CT(COMMAND) == FD_READ) {
2715 copy_buffer(1, max_sector, buffer_max);
2716 return 1;
2717 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002718 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002720 unsigned int sectors;
2721
2722 sectors = fsector_t + blk_rq_sectors(current_req);
2723 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 max_size = ssize + ssize;
2725 else
2726 max_size = ssize;
2727 }
2728 raw_cmd->flags &= ~FD_RAW_WRITE;
2729 raw_cmd->flags |= FD_RAW_READ;
2730 COMMAND = FM_MODE(_floppy, FD_READ);
2731 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2732 unsigned long dma_limit;
2733 int direct, indirect;
2734
2735 indirect =
2736 transfer_size(ssize, max_sector,
2737 max_buffer_sectors * 2) - fsector_t;
2738
2739 /*
2740 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2741 * on a 64 bit machine!
2742 */
2743 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002744 dma_limit = (MAX_DMA_ADDRESS -
2745 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002746 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 /* 64 kb boundaries */
2749 if (CROSS_64KB(current_req->buffer, max_size << 9))
2750 max_size = (K_64 -
2751 ((unsigned long)current_req->buffer) %
2752 K_64) >> 9;
2753 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2754 /*
2755 * We try to read tracks, but if we get too many errors, we
2756 * go back to reading just one sector at a time.
2757 *
2758 * This means we should be able to read a sector even if there
2759 * are other bad sectors on this track.
2760 */
2761 if (!direct ||
2762 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002763 *errors < DP->max_errors.read_track &&
2764 ((!probing ||
2765 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002766 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 } else {
2768 raw_cmd->kernel_data = current_req->buffer;
2769 raw_cmd->length = current_count_sectors << 9;
2770 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002771 DPRINT("zero dma transfer attempted from make_raw_request\n");
2772 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 indirect, direct, fsector_t);
2774 return 0;
2775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 virtualdmabug_workaround();
2777 return 2;
2778 }
2779 }
2780
2781 if (CT(COMMAND) == FD_READ)
2782 max_size = max_sector; /* unbounded */
2783
2784 /* claim buffer track if needed */
2785 if (buffer_track != raw_cmd->track || /* bad track */
2786 buffer_drive != current_drive || /* bad drive */
2787 fsector_t > buffer_max ||
2788 fsector_t < buffer_min ||
2789 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002790 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002792 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2793 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 buffer_track = -1;
2795 buffer_drive = current_drive;
2796 buffer_max = buffer_min = aligned_sector_t;
2797 }
2798 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002799 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
2801 if (CT(COMMAND) == FD_WRITE) {
2802 /* copy write buffer to track buffer.
2803 * if we get here, we know that the write
2804 * is either aligned or the data already in the buffer
2805 * (buffer will be overwritten) */
2806#ifdef FLOPPY_SANITY_CHECK
2807 if (in_sector_offset && buffer_track == -1)
2808 DPRINT("internal error offset !=0 on write\n");
2809#endif
2810 buffer_track = raw_cmd->track;
2811 buffer_drive = current_drive;
2812 copy_buffer(ssize, max_sector,
2813 2 * max_buffer_sectors + buffer_min);
2814 } else
2815 transfer_size(ssize, max_sector,
2816 2 * max_buffer_sectors + buffer_min -
2817 aligned_sector_t);
2818
2819 /* round up current_count_sectors to get dma xfer size */
2820 raw_cmd->length = in_sector_offset + current_count_sectors;
2821 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2822 raw_cmd->length <<= 9;
2823#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 if ((raw_cmd->length < current_count_sectors << 9) ||
2825 (raw_cmd->kernel_data != current_req->buffer &&
2826 CT(COMMAND) == FD_WRITE &&
2827 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2828 aligned_sector_t < buffer_min)) ||
2829 raw_cmd->length % (128 << SIZECODE) ||
2830 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2831 DPRINT("fractionary current count b=%lx s=%lx\n",
2832 raw_cmd->length, current_count_sectors);
2833 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002834 pr_info("addr=%d, length=%ld\n",
2835 (int)((raw_cmd->kernel_data -
2836 floppy_track_buffer) >> 9),
2837 current_count_sectors);
2838 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2839 fsector_t, aligned_sector_t, max_sector, max_size);
2840 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2841 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2842 COMMAND, SECTOR, HEAD, TRACK);
2843 pr_info("buffer drive=%d\n", buffer_drive);
2844 pr_info("buffer track=%d\n", buffer_track);
2845 pr_info("buffer_min=%d\n", buffer_min);
2846 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 return 0;
2848 }
2849
2850 if (raw_cmd->kernel_data != current_req->buffer) {
2851 if (raw_cmd->kernel_data < floppy_track_buffer ||
2852 current_count_sectors < 0 ||
2853 raw_cmd->length < 0 ||
2854 raw_cmd->kernel_data + raw_cmd->length >
2855 floppy_track_buffer + (max_buffer_sectors << 10)) {
2856 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002857 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2858 fsector_t, buffer_min, raw_cmd->length >> 9);
2859 pr_info("current_count_sectors=%ld\n",
2860 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002862 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002864 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 return 0;
2866 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002867 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002868 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 DPRINT("buffer overrun in direct transfer\n");
2870 return 0;
2871 } else if (raw_cmd->length < current_count_sectors << 9) {
2872 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002873 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2874 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 }
2876 if (raw_cmd->length == 0) {
2877 DPRINT("zero dma transfer attempted from make_raw_request\n");
2878 return 0;
2879 }
2880#endif
2881
2882 virtualdmabug_workaround();
2883 return 2;
2884}
2885
2886static void redo_fd_request(void)
2887{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 int drive;
2889 int tmp;
2890
2891 lastredo = jiffies;
2892 if (current_drive < N_DRIVE)
2893 floppy_off(current_drive);
2894
Joe Perches0da31322010-03-10 15:21:03 -08002895do_request:
2896 if (!current_req) {
2897 struct request *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
Joe Perches0da31322010-03-10 15:21:03 -08002899 spin_lock_irq(floppy_queue->queue_lock);
2900 req = blk_fetch_request(floppy_queue);
2901 spin_unlock_irq(floppy_queue->queue_lock);
2902 if (!req) {
2903 do_floppy = NULL;
2904 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 }
Joe Perches0da31322010-03-10 15:21:03 -08002907 current_req = req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 }
Joe Perches0da31322010-03-10 15:21:03 -08002909 drive = (long)current_req->rq_disk->private_data;
2910 set_fdc(drive);
2911 reschedule_timeout(current_reqD, "redo fd request", 0);
2912
2913 set_floppy(drive);
2914 raw_cmd = &default_raw_cmd;
2915 raw_cmd->flags = 0;
2916 if (start_motor(redo_fd_request))
2917 return;
2918
2919 disk_change(current_drive);
2920 if (test_bit(current_drive, &fake_change) ||
2921 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2922 DPRINT("disk absent or changed during operation\n");
2923 request_done(0);
2924 goto do_request;
2925 }
2926 if (!_floppy) { /* Autodetection */
2927 if (!probing) {
2928 DRS->probed_format = 0;
2929 if (next_valid_format()) {
2930 DPRINT("no autodetectable formats\n");
2931 _floppy = NULL;
2932 request_done(0);
2933 goto do_request;
2934 }
2935 }
2936 probing = 1;
2937 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2938 } else
2939 probing = 0;
2940 errors = &(current_req->errors);
2941 tmp = make_raw_rw_request();
2942 if (tmp < 2) {
2943 request_done(tmp);
2944 goto do_request;
2945 }
2946
2947 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2948 twaddle();
2949 schedule_bh(floppy_start);
2950 debugt("queue fd request");
2951 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952}
2953
2954static struct cont_t rw_cont = {
2955 .interrupt = rw_interrupt,
2956 .redo = redo_fd_request,
2957 .error = bad_flp_intr,
2958 .done = request_done
2959};
2960
2961static void process_fd_request(void)
2962{
2963 cont = &rw_cont;
2964 schedule_bh(redo_fd_request);
2965}
2966
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002967static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968{
2969 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002970 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 return;
2972 }
2973
2974 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002975 pr_info("warning: usage count=0, current_req=%p exiting\n",
2976 current_req);
2977 pr_info("sect=%ld type=%x flags=%x\n",
2978 (long)blk_rq_pos(current_req), current_req->cmd_type,
2979 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 return;
2981 }
2982 if (test_bit(0, &fdc_busy)) {
2983 /* fdc busy, this new request will be treated when the
2984 current one is done */
2985 is_alive("do fd request, old request running");
2986 return;
2987 }
Joe Perches74f63f42010-03-10 15:20:58 -08002988 lock_fdc(MAXTIMEOUT, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 process_fd_request();
2990 is_alive("do fd request");
2991}
2992
2993static struct cont_t poll_cont = {
2994 .interrupt = success_and_wakeup,
2995 .redo = floppy_ready,
2996 .error = generic_failure,
2997 .done = generic_done
2998};
2999
Joe Perches74f63f42010-03-10 15:20:58 -08003000static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 /* no auto-sense, just clear dcl */
3003 raw_cmd = &default_raw_cmd;
3004 raw_cmd->flags = flag;
3005 raw_cmd->track = 0;
3006 raw_cmd->cmd_count = 0;
3007 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08003008 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08003009 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08003010
3011 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012}
3013
3014/*
3015 * User triggered reset
3016 * ====================
3017 */
3018
3019static void reset_intr(void)
3020{
Joe Perchesb46df352010-03-10 15:20:46 -08003021 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022}
3023
3024static struct cont_t reset_cont = {
3025 .interrupt = reset_intr,
3026 .redo = success_and_wakeup,
3027 .error = generic_failure,
3028 .done = generic_done
3029};
3030
Joe Perches74f63f42010-03-10 15:20:58 -08003031static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032{
3033 int ret;
3034
Joe Perches52a0d612010-03-10 15:20:53 -08003035 if (lock_fdc(drive, interruptible))
3036 return -EINTR;
3037
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 if (arg == FD_RESET_ALWAYS)
3039 FDCS->reset = 1;
3040 if (FDCS->reset) {
3041 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08003042 ret = wait_til_done(reset_fdc, interruptible);
3043 if (ret == -EINTR)
3044 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 }
3046 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003047 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048}
3049
3050/*
3051 * Misc Ioctl's and support
3052 * ========================
3053 */
3054static inline int fd_copyout(void __user *param, const void *address,
3055 unsigned long size)
3056{
3057 return copy_to_user(param, address, size) ? -EFAULT : 0;
3058}
3059
Joe Perches48c8cee2010-03-10 15:20:45 -08003060static inline int fd_copyin(void __user *param, void *address,
3061 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062{
3063 return copy_from_user(address, param, size) ? -EFAULT : 0;
3064}
3065
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066static inline const char *drive_name(int type, int drive)
3067{
3068 struct floppy_struct *floppy;
3069
3070 if (type)
3071 floppy = floppy_type + type;
3072 else {
3073 if (UDP->native_format)
3074 floppy = floppy_type + UDP->native_format;
3075 else
3076 return "(null)";
3077 }
3078 if (floppy->name)
3079 return floppy->name;
3080 else
3081 return "(null)";
3082}
3083
3084/* raw commands */
3085static void raw_cmd_done(int flag)
3086{
3087 int i;
3088
3089 if (!flag) {
3090 raw_cmd->flags |= FD_RAW_FAILURE;
3091 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3092 } else {
3093 raw_cmd->reply_count = inr;
3094 if (raw_cmd->reply_count > MAX_REPLIES)
3095 raw_cmd->reply_count = 0;
3096 for (i = 0; i < raw_cmd->reply_count; i++)
3097 raw_cmd->reply[i] = reply_buffer[i];
3098
3099 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3100 unsigned long flags;
3101 flags = claim_dma_lock();
3102 raw_cmd->length = fd_get_dma_residue();
3103 release_dma_lock(flags);
3104 }
3105
3106 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3107 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3108 raw_cmd->flags |= FD_RAW_FAILURE;
3109
3110 if (disk_change(current_drive))
3111 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3112 else
3113 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3114 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3115 motor_off_callback(current_drive);
3116
3117 if (raw_cmd->next &&
3118 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3119 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3120 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3121 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3122 raw_cmd = raw_cmd->next;
3123 return;
3124 }
3125 }
3126 generic_done(flag);
3127}
3128
3129static struct cont_t raw_cmd_cont = {
3130 .interrupt = success_and_wakeup,
3131 .redo = floppy_start,
3132 .error = generic_failure,
3133 .done = raw_cmd_done
3134};
3135
3136static inline int raw_cmd_copyout(int cmd, char __user *param,
3137 struct floppy_raw_cmd *ptr)
3138{
3139 int ret;
3140
3141 while (ptr) {
Joe Perches86b12b42010-03-10 15:20:56 -08003142 ret = copy_to_user((void __user *)param, ptr, sizeof(*ptr));
3143 if (ret)
3144 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 param += sizeof(struct floppy_raw_cmd);
3146 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003147 if (ptr->length >= 0 &&
3148 ptr->length <= ptr->buffer_length) {
3149 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003150 ret = fd_copyout(ptr->data, ptr->kernel_data,
3151 length);
3152 if (ret)
3153 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 }
3156 ptr = ptr->next;
3157 }
3158 return 0;
3159}
3160
3161static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3162{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003163 struct floppy_raw_cmd *next;
3164 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165
3166 this = *ptr;
3167 *ptr = NULL;
3168 while (this) {
3169 if (this->buffer_length) {
3170 fd_dma_mem_free((unsigned long)this->kernel_data,
3171 this->buffer_length);
3172 this->buffer_length = 0;
3173 }
3174 next = this->next;
3175 kfree(this);
3176 this = next;
3177 }
3178}
3179
3180static inline int raw_cmd_copyin(int cmd, char __user *param,
3181 struct floppy_raw_cmd **rcmd)
3182{
3183 struct floppy_raw_cmd *ptr;
3184 int ret;
3185 int i;
3186
3187 *rcmd = NULL;
3188 while (1) {
3189 ptr = (struct floppy_raw_cmd *)
3190 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3191 if (!ptr)
3192 return -ENOMEM;
3193 *rcmd = ptr;
Joe Perches86b12b42010-03-10 15:20:56 -08003194 ret = copy_from_user(ptr, (void __user *)param, sizeof(*ptr));
3195 if (ret)
3196 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 ptr->next = NULL;
3198 ptr->buffer_length = 0;
3199 param += sizeof(struct floppy_raw_cmd);
3200 if (ptr->cmd_count > 33)
3201 /* the command may now also take up the space
3202 * initially intended for the reply & the
3203 * reply count. Needed for long 82078 commands
3204 * such as RESTORE, which takes ... 17 command
3205 * bytes. Murphy's law #137: When you reserve
3206 * 16 bytes for a structure, you'll one day
3207 * discover that you really need 17...
3208 */
3209 return -EINVAL;
3210
3211 for (i = 0; i < 16; i++)
3212 ptr->reply[i] = 0;
3213 ptr->resultcode = 0;
3214 ptr->kernel_data = NULL;
3215
3216 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3217 if (ptr->length <= 0)
3218 return -EINVAL;
3219 ptr->kernel_data =
3220 (char *)fd_dma_mem_alloc(ptr->length);
3221 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3222 if (!ptr->kernel_data)
3223 return -ENOMEM;
3224 ptr->buffer_length = ptr->length;
3225 }
Joe Perches4575b552010-03-10 15:20:55 -08003226 if (ptr->flags & FD_RAW_WRITE) {
3227 ret = fd_copyin(ptr->data, ptr->kernel_data,
3228 ptr->length);
3229 if (ret)
3230 return ret;
3231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 rcmd = &(ptr->next);
3233 if (!(ptr->flags & FD_RAW_MORE))
3234 return 0;
3235 ptr->rate &= 0x43;
3236 }
3237}
3238
3239static int raw_cmd_ioctl(int cmd, void __user *param)
3240{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003242 int drive;
3243 int ret2;
3244 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
3246 if (FDCS->rawcmd <= 1)
3247 FDCS->rawcmd = 1;
3248 for (drive = 0; drive < N_DRIVE; drive++) {
3249 if (FDC(drive) != fdc)
3250 continue;
3251 if (drive == current_drive) {
3252 if (UDRS->fd_ref > 1) {
3253 FDCS->rawcmd = 2;
3254 break;
3255 }
3256 } else if (UDRS->fd_ref) {
3257 FDCS->rawcmd = 2;
3258 break;
3259 }
3260 }
3261
3262 if (FDCS->reset)
3263 return -EIO;
3264
3265 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3266 if (ret) {
3267 raw_cmd_free(&my_raw_cmd);
3268 return ret;
3269 }
3270
3271 raw_cmd = my_raw_cmd;
3272 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003273 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003274 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275
3276 if (ret != -EINTR && FDCS->reset)
3277 ret = -EIO;
3278
3279 DRS->track = NO_TRACK;
3280
3281 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3282 if (!ret)
3283 ret = ret2;
3284 raw_cmd_free(&my_raw_cmd);
3285 return ret;
3286}
3287
3288static int invalidate_drive(struct block_device *bdev)
3289{
3290 /* invalidate the buffer track to force a reread */
3291 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3292 process_fd_request();
3293 check_disk_change(bdev);
3294 return 0;
3295}
3296
3297static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3298 int drive, int type, struct block_device *bdev)
3299{
3300 int cnt;
3301
3302 /* sanity checking for parameters. */
3303 if (g->sect <= 0 ||
3304 g->head <= 0 ||
3305 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3306 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003307 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 return -EINVAL;
3309 if (type) {
3310 if (!capable(CAP_SYS_ADMIN))
3311 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003312 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003313 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003314 mutex_unlock(&open_lock);
3315 return -EINTR;
3316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 floppy_type[type] = *g;
3318 floppy_type[type].name = "user format";
3319 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3320 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3321 floppy_type[type].size + 1;
3322 process_fd_request();
3323 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3324 struct block_device *bdev = opened_bdev[cnt];
3325 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3326 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003327 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003329 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 } else {
3331 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003332
Joe Perches74f63f42010-03-10 15:20:58 -08003333 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003334 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003335 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 /* notice a disk change immediately, else
3337 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003338 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003339 return -EINTR;
3340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 oldStretch = g->stretch;
3342 user_params[drive] = *g;
3343 if (buffer_drive == drive)
3344 SUPBOUND(buffer_max, user_params[drive].sect);
3345 current_type[drive] = &user_params[drive];
3346 floppy_sizes[drive] = user_params[drive].size;
3347 if (cmd == FDDEFPRM)
3348 DRS->keep_data = -1;
3349 else
3350 DRS->keep_data = 1;
3351 /* invalidation. Invalidate only when needed, i.e.
3352 * when there are already sectors in the buffer cache
3353 * whose number will change. This is useful, because
3354 * mtools often changes the geometry of the disk after
3355 * looking at the boot block */
3356 if (DRS->maxblock > user_params[drive].sect ||
3357 DRS->maxtrack ||
3358 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003359 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 invalidate_drive(bdev);
3361 else
3362 process_fd_request();
3363 }
3364 return 0;
3365}
3366
3367/* handle obsolete ioctl's */
3368static int ioctl_table[] = {
3369 FDCLRPRM,
3370 FDSETPRM,
3371 FDDEFPRM,
3372 FDGETPRM,
3373 FDMSGON,
3374 FDMSGOFF,
3375 FDFMTBEG,
3376 FDFMTTRK,
3377 FDFMTEND,
3378 FDSETEMSGTRESH,
3379 FDFLUSH,
3380 FDSETMAXERRS,
3381 FDGETMAXERRS,
3382 FDGETDRVTYP,
3383 FDSETDRVPRM,
3384 FDGETDRVPRM,
3385 FDGETDRVSTAT,
3386 FDPOLLDRVSTAT,
3387 FDRESET,
3388 FDGETFDCSTAT,
3389 FDWERRORCLR,
3390 FDWERRORGET,
3391 FDRAWCMD,
3392 FDEJECT,
3393 FDTWADDLE
3394};
3395
3396static inline int normalize_ioctl(int *cmd, int *size)
3397{
3398 int i;
3399
3400 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3401 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3402 *size = _IOC_SIZE(*cmd);
3403 *cmd = ioctl_table[i];
3404 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003405 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 return -EFAULT;
3407 }
3408 return 0;
3409 }
3410 }
3411 return -EINVAL;
3412}
3413
3414static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3415{
3416 if (type)
3417 *g = &floppy_type[type];
3418 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003419 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003420 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003421 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003422 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 process_fd_request();
3424 *g = current_type[drive];
3425 }
3426 if (!*g)
3427 return -ENODEV;
3428 return 0;
3429}
3430
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003431static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3432{
3433 int drive = (long)bdev->bd_disk->private_data;
3434 int type = ITYPE(drive_state[drive].fd_device);
3435 struct floppy_struct *g;
3436 int ret;
3437
3438 ret = get_floppy_geometry(drive, type, &g);
3439 if (ret)
3440 return ret;
3441
3442 geo->heads = g->head;
3443 geo->sectors = g->sect;
3444 geo->cylinders = g->track;
3445 return 0;
3446}
3447
Al Viroa4af9b42008-03-02 09:27:55 -05003448static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 unsigned long param)
3450{
Al Viroa4af9b42008-03-02 09:27:55 -05003451#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452
Al Viroa4af9b42008-03-02 09:27:55 -05003453 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003454 int type = ITYPE(UDRS->fd_device);
3455 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 int ret;
3457 int size;
3458 union inparam {
3459 struct floppy_struct g; /* geometry */
3460 struct format_descr f;
3461 struct floppy_max_errors max_errors;
3462 struct floppy_drive_params dp;
3463 } inparam; /* parameters coming from user space */
3464 const char *outparam; /* parameters passed back to user space */
3465
3466 /* convert compatibility eject ioctls into floppy eject ioctl.
3467 * We do this in order to provide a means to eject floppy disks before
3468 * installing the new fdutils package */
3469 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003470 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 DPRINT("obsolete eject ioctl\n");
3472 DPRINT("please use floppycontrol --eject\n");
3473 cmd = FDEJECT;
3474 }
3475
Joe Perchesa81ee542010-03-10 15:20:46 -08003476 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 return -EINVAL;
3478
Joe Perchesa81ee542010-03-10 15:20:46 -08003479 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003480 ret = normalize_ioctl(&cmd, &size);
3481 if (ret)
3482 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003483
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 /* permission checks */
3485 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3486 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3487 return -EPERM;
3488
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003489 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3490 return -EINVAL;
3491
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003493 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003494 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3495 ret = fd_copyin((void __user *)param, &inparam, size);
3496 if (ret)
3497 return ret;
3498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499
Joe Perchesda273652010-03-10 15:20:52 -08003500 switch (cmd) {
3501 case FDEJECT:
3502 if (UDRS->fd_ref != 1)
3503 /* somebody else has this drive open */
3504 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003505 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003506 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507
Joe Perchesda273652010-03-10 15:20:52 -08003508 /* do the actual eject. Fails on
3509 * non-Sparc architectures */
3510 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511
Joe Perchese0298532010-03-10 15:20:55 -08003512 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3513 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003514 process_fd_request();
3515 return ret;
3516 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003517 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003518 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003519 current_type[drive] = NULL;
3520 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3521 UDRS->keep_data = 0;
3522 return invalidate_drive(bdev);
3523 case FDSETPRM:
3524 case FDDEFPRM:
3525 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3526 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003527 ret = get_floppy_geometry(drive, type,
Joe Perchesda273652010-03-10 15:20:52 -08003528 (struct floppy_struct **)
Joe Perches4575b552010-03-10 15:20:55 -08003529 &outparam);
3530 if (ret)
3531 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003532 break;
3533 case FDMSGON:
3534 UDP->flags |= FTD_MSG;
3535 return 0;
3536 case FDMSGOFF:
3537 UDP->flags &= ~FTD_MSG;
3538 return 0;
3539 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003540 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003541 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003542 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003543 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003544 ret = UDRS->flags;
3545 process_fd_request();
3546 if (ret & FD_VERIFY)
3547 return -ENODEV;
3548 if (!(ret & FD_DISK_WRITABLE))
3549 return -EROFS;
3550 return 0;
3551 case FDFMTTRK:
3552 if (UDRS->fd_ref != 1)
3553 return -EBUSY;
3554 return do_format(drive, &inparam.f);
3555 case FDFMTEND:
3556 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003557 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003558 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003559 return invalidate_drive(bdev);
3560 case FDSETEMSGTRESH:
3561 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3562 return 0;
3563 case FDGETMAXERRS:
3564 outparam = (const char *)&UDP->max_errors;
3565 break;
3566 case FDSETMAXERRS:
3567 UDP->max_errors = inparam.max_errors;
3568 break;
3569 case FDGETDRVTYP:
3570 outparam = drive_name(type, drive);
3571 SUPBOUND(size, strlen(outparam) + 1);
3572 break;
3573 case FDSETDRVPRM:
3574 *UDP = inparam.dp;
3575 break;
3576 case FDGETDRVPRM:
3577 outparam = (const char *)UDP;
3578 break;
3579 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003580 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003581 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003582 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003583 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003584 process_fd_request();
3585 /* fall through */
3586 case FDGETDRVSTAT:
3587 outparam = (const char *)UDRS;
3588 break;
3589 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003590 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003591 case FDGETFDCSTAT:
3592 outparam = (const char *)UFDCS;
3593 break;
3594 case FDWERRORCLR:
3595 memset(UDRWE, 0, sizeof(*UDRWE));
3596 return 0;
3597 case FDWERRORGET:
3598 outparam = (const char *)UDRWE;
3599 break;
3600 case FDRAWCMD:
3601 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003603 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003604 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003605 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003606 i = raw_cmd_ioctl(cmd, (void __user *)param);
3607 if (i == -EINTR)
3608 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003609 process_fd_request();
3610 return i;
3611 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003612 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003613 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003614 twaddle();
3615 process_fd_request();
3616 return 0;
3617 default:
3618 return -EINVAL;
3619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620
3621 if (_IOC_DIR(cmd) & _IOC_READ)
3622 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003623
3624 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625}
3626
3627static void __init config_types(void)
3628{
Joe Perchesb46df352010-03-10 15:20:46 -08003629 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 int drive;
3631
3632 /* read drive info out of physical CMOS */
3633 drive = 0;
3634 if (!UDP->cmos)
3635 UDP->cmos = FLOPPY0_TYPE;
3636 drive = 1;
3637 if (!UDP->cmos && FLOPPY1_TYPE)
3638 UDP->cmos = FLOPPY1_TYPE;
3639
Jesper Juhl06f748c2007-10-16 23:30:57 -07003640 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
3642 for (drive = 0; drive < N_DRIVE; drive++) {
3643 unsigned int type = UDP->cmos;
3644 struct floppy_drive_params *params;
3645 const char *name = NULL;
3646 static char temparea[32];
3647
Tobias Klauser945f3902006-01-08 01:05:11 -08003648 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 params = &default_drive_params[type].params;
3650 if (type) {
3651 name = default_drive_params[type].name;
3652 allowed_drive_mask |= 1 << drive;
3653 } else
3654 allowed_drive_mask &= ~(1 << drive);
3655 } else {
3656 params = &default_drive_params[0].params;
3657 sprintf(temparea, "unknown type %d (usb?)", type);
3658 name = temparea;
3659 }
3660 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003661 const char *prepend;
3662 if (!has_drive) {
3663 prepend = "";
3664 has_drive = true;
3665 pr_info("Floppy drive(s):");
3666 } else {
3667 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 }
Joe Perchesb46df352010-03-10 15:20:46 -08003669
3670 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 }
3672 *UDP = *params;
3673 }
Joe Perchesb46df352010-03-10 15:20:46 -08003674
3675 if (has_drive)
3676 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677}
3678
Al Viroa4af9b42008-03-02 09:27:55 -05003679static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680{
Al Viroa4af9b42008-03-02 09:27:55 -05003681 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003683 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 if (UDRS->fd_ref < 0)
3685 UDRS->fd_ref = 0;
3686 else if (!UDRS->fd_ref--) {
3687 DPRINT("floppy_release with fd_ref == 0");
3688 UDRS->fd_ref = 0;
3689 }
3690 if (!UDRS->fd_ref)
3691 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003692 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003693
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 return 0;
3695}
3696
3697/*
3698 * floppy_open check for aliasing (/dev/fd0 can be the same as
3699 * /dev/PS0 etc), and disallows simultaneous access to the same
3700 * drive with different device numbers.
3701 */
Al Viroa4af9b42008-03-02 09:27:55 -05003702static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703{
Al Viroa4af9b42008-03-02 09:27:55 -05003704 int drive = (long)bdev->bd_disk->private_data;
3705 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 int try;
3707 int res = -EBUSY;
3708 char *tmp;
3709
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003710 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003712 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 goto out2;
3714
3715 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003716 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3717 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 }
3719
Al Viroa4af9b42008-03-02 09:27:55 -05003720 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 goto out2;
3722
Al Viroa4af9b42008-03-02 09:27:55 -05003723 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 UDRS->fd_ref = -1;
3725 else
3726 UDRS->fd_ref++;
3727
Al Viroa4af9b42008-03-02 09:27:55 -05003728 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729
3730 res = -ENXIO;
3731
3732 if (!floppy_track_buffer) {
3733 /* if opening an ED drive, reserve a big buffer,
3734 * else reserve a small one */
3735 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3736 try = 64; /* Only 48 actually useful */
3737 else
3738 try = 32; /* Only 24 actually useful */
3739
3740 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3741 if (!tmp && !floppy_track_buffer) {
3742 try >>= 1; /* buffer only one side */
3743 INFBOUND(try, 16);
3744 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3745 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003746 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 if (!tmp && !floppy_track_buffer) {
3749 DPRINT("Unable to allocate DMA memory\n");
3750 goto out;
3751 }
3752 if (floppy_track_buffer) {
3753 if (tmp)
3754 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3755 } else {
3756 buffer_min = buffer_max = -1;
3757 floppy_track_buffer = tmp;
3758 max_buffer_sectors = try;
3759 }
3760 }
3761
Al Viroa4af9b42008-03-02 09:27:55 -05003762 new_dev = MINOR(bdev->bd_dev);
3763 UDRS->fd_device = new_dev;
3764 set_capacity(disks[drive], floppy_sizes[new_dev]);
3765 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 if (buffer_drive == drive)
3767 buffer_track = -1;
3768 }
3769
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 if (UFDCS->rawcmd == 1)
3771 UFDCS->rawcmd = 2;
3772
Al Viroa4af9b42008-03-02 09:27:55 -05003773 if (!(mode & FMODE_NDELAY)) {
3774 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003776 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003777 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 goto out;
3779 }
3780 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003781 if ((mode & FMODE_WRITE) &&
3782 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 goto out;
3784 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003785 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 return 0;
3787out:
3788 if (UDRS->fd_ref < 0)
3789 UDRS->fd_ref = 0;
3790 else
3791 UDRS->fd_ref--;
3792 if (!UDRS->fd_ref)
3793 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003795 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 return res;
3797}
3798
3799/*
3800 * Check if the disk has been changed or if a change has been faked.
3801 */
3802static int check_floppy_change(struct gendisk *disk)
3803{
3804 int drive = (long)disk->private_data;
3805
Joe Perchese0298532010-03-10 15:20:55 -08003806 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3807 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 return 1;
3809
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003810 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003811 lock_fdc(drive, false);
3812 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 }
3815
Joe Perchese0298532010-03-10 15:20:55 -08003816 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3817 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 test_bit(drive, &fake_change) ||
3819 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3820 return 1;
3821 return 0;
3822}
3823
3824/*
3825 * This implements "read block 0" for floppy_revalidate().
3826 * Needed for format autodetection, checking whether there is
3827 * a disk in the drive, and whether that disk is writable.
3828 */
3829
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003830static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833}
3834
3835static int __floppy_read_block_0(struct block_device *bdev)
3836{
3837 struct bio bio;
3838 struct bio_vec bio_vec;
3839 struct completion complete;
3840 struct page *page;
3841 size_t size;
3842
3843 page = alloc_page(GFP_NOIO);
3844 if (!page) {
3845 process_fd_request();
3846 return -ENOMEM;
3847 }
3848
3849 size = bdev->bd_block_size;
3850 if (!size)
3851 size = 1024;
3852
3853 bio_init(&bio);
3854 bio.bi_io_vec = &bio_vec;
3855 bio_vec.bv_page = page;
3856 bio_vec.bv_len = size;
3857 bio_vec.bv_offset = 0;
3858 bio.bi_vcnt = 1;
3859 bio.bi_idx = 0;
3860 bio.bi_size = size;
3861 bio.bi_bdev = bdev;
3862 bio.bi_sector = 0;
3863 init_completion(&complete);
3864 bio.bi_private = &complete;
3865 bio.bi_end_io = floppy_rb0_complete;
3866
3867 submit_bio(READ, &bio);
3868 generic_unplug_device(bdev_get_queue(bdev));
3869 process_fd_request();
3870 wait_for_completion(&complete);
3871
3872 __free_page(page);
3873
3874 return 0;
3875}
3876
3877/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3878 * the bootblock (block 0). "Autodetection" is also needed to check whether
3879 * there is a disk in the drive at all... Thus we also do it for fixed
3880 * geometry formats */
3881static int floppy_revalidate(struct gendisk *disk)
3882{
3883 int drive = (long)disk->private_data;
3884#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3885 int cf;
3886 int res = 0;
3887
Joe Perchese0298532010-03-10 15:20:55 -08003888 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3889 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
3890 test_bit(drive, &fake_change) || NO_GEOM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003892 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 return -EFAULT;
3894 }
Joe Perches74f63f42010-03-10 15:20:58 -08003895 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003896 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3897 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3899 process_fd_request(); /*already done by another thread */
3900 return 0;
3901 }
3902 UDRS->maxblock = 0;
3903 UDRS->maxtrack = 0;
3904 if (buffer_drive == drive)
3905 buffer_track = -1;
3906 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003907 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 if (cf)
3909 UDRS->generation++;
3910 if (NO_GEOM) {
3911 /* auto-sensing */
3912 res = __floppy_read_block_0(opened_bdev[drive]);
3913 } else {
3914 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003915 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 process_fd_request();
3917 }
3918 }
3919 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3920 return res;
3921}
3922
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003923static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003924 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003925 .open = floppy_open,
3926 .release = floppy_release,
3927 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003928 .getgeo = fd_getgeo,
3929 .media_changed = check_floppy_change,
3930 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933/*
3934 * Floppy Driver initialization
3935 * =============================
3936 */
3937
3938/* Determine the floppy disk controller type */
3939/* This routine was written by David C. Niemi */
3940static char __init get_fdc_version(void)
3941{
3942 int r;
3943
3944 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3945 if (FDCS->reset)
3946 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003947 r = result();
3948 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 return FDC_NONE; /* No FDC present ??? */
3950 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003951 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3953 }
3954 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003955 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3956 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 return FDC_UNKNOWN;
3958 }
3959
3960 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003961 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3963 }
3964
3965 output_byte(FD_PERPENDICULAR);
3966 if (need_more_output() == MORE_OUTPUT) {
3967 output_byte(0);
3968 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003969 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 return FDC_82072A; /* 82072A as found on Sparcs. */
3971 }
3972
3973 output_byte(FD_UNLOCK);
3974 r = result();
3975 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003976 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003977 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 * LOCK/UNLOCK */
3979 }
3980 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003981 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3982 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 return FDC_UNKNOWN;
3984 }
3985 output_byte(FD_PARTID);
3986 r = result();
3987 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003988 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3989 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 return FDC_UNKNOWN;
3991 }
3992 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003993 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 return FDC_82077; /* Revised 82077AA passes all the tests */
3995 }
3996 switch (reply_buffer[0] >> 5) {
3997 case 0x0:
3998 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003999 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 return FDC_82078;
4001 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004002 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 return FDC_82078;
4004 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004005 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 return FDC_S82078B;
4007 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004008 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 return FDC_87306;
4010 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004011 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4012 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 return FDC_82078_UNKN;
4014 }
4015} /* get_fdc_version */
4016
4017/* lilo configuration */
4018
4019static void __init floppy_set_flags(int *ints, int param, int param2)
4020{
4021 int i;
4022
4023 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4024 if (param)
4025 default_drive_params[i].params.flags |= param2;
4026 else
4027 default_drive_params[i].params.flags &= ~param2;
4028 }
4029 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4030}
4031
4032static void __init daring(int *ints, int param, int param2)
4033{
4034 int i;
4035
4036 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4037 if (param) {
4038 default_drive_params[i].params.select_delay = 0;
4039 default_drive_params[i].params.flags |=
4040 FD_SILENT_DCL_CLEAR;
4041 } else {
4042 default_drive_params[i].params.select_delay =
4043 2 * HZ / 100;
4044 default_drive_params[i].params.flags &=
4045 ~FD_SILENT_DCL_CLEAR;
4046 }
4047 }
4048 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4049}
4050
4051static void __init set_cmos(int *ints, int dummy, int dummy2)
4052{
4053 int current_drive = 0;
4054
4055 if (ints[0] != 2) {
4056 DPRINT("wrong number of parameters for CMOS\n");
4057 return;
4058 }
4059 current_drive = ints[1];
4060 if (current_drive < 0 || current_drive >= 8) {
4061 DPRINT("bad drive for set_cmos\n");
4062 return;
4063 }
4064#if N_FDC > 1
4065 if (current_drive >= 4 && !FDC2)
4066 FDC2 = 0x370;
4067#endif
4068 DP->cmos = ints[2];
4069 DPRINT("setting CMOS code to %d\n", ints[2]);
4070}
4071
4072static struct param_table {
4073 const char *name;
4074 void (*fn) (int *ints, int param, int param2);
4075 int *var;
4076 int def_param;
4077 int param2;
4078} config_params[] __initdata = {
4079 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4080 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4081 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4082 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4083 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4084 {"daring", daring, NULL, 1, 0},
4085#if N_FDC > 1
4086 {"two_fdc", NULL, &FDC2, 0x370, 0},
4087 {"one_fdc", NULL, &FDC2, 0, 0},
4088#endif
4089 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4090 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4091 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4092 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4093 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4094 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4095 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4096 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4097 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4098 {"nofifo", NULL, &no_fifo, 0x20, 0},
4099 {"usefifo", NULL, &no_fifo, 0, 0},
4100 {"cmos", set_cmos, NULL, 0, 0},
4101 {"slow", NULL, &slow_floppy, 1, 0},
4102 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4103 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4104 {"L40SX", NULL, &print_unex, 0, 0}
4105
4106 EXTRA_FLOPPY_PARAMS
4107};
4108
4109static int __init floppy_setup(char *str)
4110{
4111 int i;
4112 int param;
4113 int ints[11];
4114
4115 str = get_options(str, ARRAY_SIZE(ints), ints);
4116 if (str) {
4117 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4118 if (strcmp(str, config_params[i].name) == 0) {
4119 if (ints[0])
4120 param = ints[1];
4121 else
4122 param = config_params[i].def_param;
4123 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004124 config_params[i].fn(ints, param,
4125 config_params[i].
4126 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 if (config_params[i].var) {
4128 DPRINT("%s=%d\n", str, param);
4129 *config_params[i].var = param;
4130 }
4131 return 1;
4132 }
4133 }
4134 }
4135 if (str) {
4136 DPRINT("unknown floppy option [%s]\n", str);
4137
4138 DPRINT("allowed options are:");
4139 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004140 pr_cont(" %s", config_params[i].name);
4141 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 } else
4143 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004144 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 return 0;
4146}
4147
4148static int have_no_fdc = -ENODEV;
4149
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004150static ssize_t floppy_cmos_show(struct device *dev,
4151 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004152{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004153 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004154 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004155
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004156 drive = p->id;
4157 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004158}
Joe Perches48c8cee2010-03-10 15:20:45 -08004159
4160DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004161
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162static void floppy_device_release(struct device *dev)
4163{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164}
4165
Frans Popc90cd332009-07-25 22:24:54 +02004166static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004167{
4168 int fdc;
4169
4170 for (fdc = 0; fdc < N_FDC; fdc++)
4171 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004172 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004173
4174 return 0;
4175}
4176
Alexey Dobriyan47145212009-12-14 18:00:08 -08004177static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004178 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004179 .restore = floppy_resume,
4180};
4181
4182static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004183 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004184 .name = "floppy",
4185 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004186 },
4187};
4188
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004189static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190
4191static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4192{
4193 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4194 if (drive >= N_DRIVE ||
4195 !(allowed_drive_mask & (1 << drive)) ||
4196 fdc_state[FDC(drive)].version == FDC_NONE)
4197 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004198 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 return NULL;
4200 *part = 0;
4201 return get_disk(disks[drive]);
4202}
4203
4204static int __init floppy_init(void)
4205{
4206 int i, unit, drive;
4207 int err, dr;
4208
Kumar Gala68e1ee62008-09-22 14:41:31 -07004209#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004210 if (check_legacy_ioport(FDC1))
4211 return -ENODEV;
4212#endif
4213
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 raw_cmd = NULL;
4215
4216 for (dr = 0; dr < N_DRIVE; dr++) {
4217 disks[dr] = alloc_disk(1);
4218 if (!disks[dr]) {
4219 err = -ENOMEM;
4220 goto out_put_disk;
4221 }
4222
4223 disks[dr]->major = FLOPPY_MAJOR;
4224 disks[dr]->first_minor = TOMINOR(dr);
4225 disks[dr]->fops = &floppy_fops;
4226 sprintf(disks[dr]->disk_name, "fd%d", dr);
4227
4228 init_timer(&motor_off_timer[dr]);
4229 motor_off_timer[dr].data = dr;
4230 motor_off_timer[dr].function = motor_off_callback;
4231 }
4232
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 err = register_blkdev(FLOPPY_MAJOR, "fd");
4234 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004235 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004237 err = platform_driver_register(&floppy_driver);
4238 if (err)
4239 goto out_unreg_blkdev;
4240
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4242 if (!floppy_queue) {
4243 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004244 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004246 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247
4248 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4249 floppy_find, NULL, NULL);
4250
4251 for (i = 0; i < 256; i++)
4252 if (ITYPE(i))
4253 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4254 else
4255 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4256
4257 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4258 config_types();
4259
4260 for (i = 0; i < N_FDC; i++) {
4261 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004262 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 FDCS->dtr = -1;
4264 FDCS->dor = 0x4;
4265#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004266 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267#ifdef __mc68000__
4268 if (MACH_IS_SUN3X)
4269#endif
4270 FDCS->version = FDC_82072A;
4271#endif
4272 }
4273
4274 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 fdc_state[0].address = FDC1;
4276 if (fdc_state[0].address == -1) {
4277 del_timer(&fd_timeout);
4278 err = -ENODEV;
4279 goto out_unreg_region;
4280 }
4281#if N_FDC > 1
4282 fdc_state[1].address = FDC2;
4283#endif
4284
4285 fdc = 0; /* reset fdc in case of unexpected interrupt */
4286 err = floppy_grab_irq_and_dma();
4287 if (err) {
4288 del_timer(&fd_timeout);
4289 err = -EBUSY;
4290 goto out_unreg_region;
4291 }
4292
4293 /* initialise drive state */
4294 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004295 memset(UDRS, 0, sizeof(*UDRS));
4296 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004297 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4298 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4299 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 UDRS->fd_device = -1;
4301 floppy_track_buffer = NULL;
4302 max_buffer_sectors = 0;
4303 }
4304 /*
4305 * Small 10 msec delay to let through any interrupt that
4306 * initialization might have triggered, to not
4307 * confuse detection:
4308 */
4309 msleep(10);
4310
4311 for (i = 0; i < N_FDC; i++) {
4312 fdc = i;
4313 FDCS->driver_version = FD_DRIVER_VERSION;
4314 for (unit = 0; unit < 4; unit++)
4315 FDCS->track[unit] = 0;
4316 if (FDCS->address == -1)
4317 continue;
4318 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004319 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004321 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 FDCS->address = -1;
4323 FDCS->version = FDC_NONE;
4324 continue;
4325 }
4326 /* Try to determine the floppy controller type */
4327 FDCS->version = get_fdc_version();
4328 if (FDCS->version == FDC_NONE) {
4329 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004330 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 FDCS->address = -1;
4332 continue;
4333 }
4334 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4335 can_use_virtual_dma = 0;
4336
4337 have_no_fdc = 0;
4338 /* Not all FDCs seem to be able to handle the version command
4339 * properly, so force a reset for the standard FDC clones,
4340 * to avoid interrupt garbage.
4341 */
Joe Perches74f63f42010-03-10 15:20:58 -08004342 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 }
4344 fdc = 0;
4345 del_timer(&fd_timeout);
4346 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004347 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 if (have_no_fdc) {
4349 DPRINT("no floppy controllers found\n");
4350 err = have_no_fdc;
4351 goto out_flush_work;
4352 }
4353
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 for (drive = 0; drive < N_DRIVE; drive++) {
4355 if (!(allowed_drive_mask & (1 << drive)))
4356 continue;
4357 if (fdc_state[FDC(drive)].version == FDC_NONE)
4358 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004359
4360 floppy_device[drive].name = floppy_device_name;
4361 floppy_device[drive].id = drive;
4362 floppy_device[drive].dev.release = floppy_device_release;
4363
4364 err = platform_device_register(&floppy_device[drive]);
4365 if (err)
4366 goto out_flush_work;
4367
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004368 err = device_create_file(&floppy_device[drive].dev,
4369 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004370 if (err)
4371 goto out_unreg_platform_dev;
4372
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 /* to be cleaned up... */
4374 disks[drive]->private_data = (void *)(long)drive;
4375 disks[drive]->queue = floppy_queue;
4376 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004377 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 add_disk(disks[drive]);
4379 }
4380
4381 return 0;
4382
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004383out_unreg_platform_dev:
4384 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385out_flush_work:
4386 flush_scheduled_work();
4387 if (usage_count)
4388 floppy_release_irq_and_dma();
4389out_unreg_region:
4390 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4391 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004392out_unreg_driver:
4393 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394out_unreg_blkdev:
4395 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396out_put_disk:
4397 while (dr--) {
4398 del_timer(&motor_off_timer[dr]);
4399 put_disk(disks[dr]);
4400 }
4401 return err;
4402}
4403
4404static DEFINE_SPINLOCK(floppy_usage_lock);
4405
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004406static const struct io_region {
4407 int offset;
4408 int size;
4409} io_regions[] = {
4410 { 2, 1 },
4411 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4412 { 4, 2 },
4413 /* address + 6 is reserved, and may be taken by IDE.
4414 * Unfortunately, Adaptec doesn't know this :-(, */
4415 { 7, 1 },
4416};
4417
4418static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4419{
4420 while (p != io_regions) {
4421 p--;
4422 release_region(FDCS->address + p->offset, p->size);
4423 }
4424}
4425
4426#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4427
4428static int floppy_request_regions(int fdc)
4429{
4430 const struct io_region *p;
4431
4432 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004433 if (!request_region(FDCS->address + p->offset,
4434 p->size, "floppy")) {
4435 DPRINT("Floppy io-port 0x%04lx in use\n",
4436 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004437 floppy_release_allocated_regions(fdc, p);
4438 return -EBUSY;
4439 }
4440 }
4441 return 0;
4442}
4443
4444static void floppy_release_regions(int fdc)
4445{
4446 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4447}
4448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449static int floppy_grab_irq_and_dma(void)
4450{
4451 unsigned long flags;
4452
4453 spin_lock_irqsave(&floppy_usage_lock, flags);
4454 if (usage_count++) {
4455 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4456 return 0;
4457 }
4458 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004459
4460 /*
4461 * We might have scheduled a free_irq(), wait it to
4462 * drain first:
4463 */
4464 flush_scheduled_work();
4465
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 if (fd_request_irq()) {
4467 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4468 FLOPPY_IRQ);
4469 spin_lock_irqsave(&floppy_usage_lock, flags);
4470 usage_count--;
4471 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4472 return -1;
4473 }
4474 if (fd_request_dma()) {
4475 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4476 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004477 if (can_use_virtual_dma & 2)
4478 use_virtual_dma = can_use_virtual_dma = 1;
4479 if (!(can_use_virtual_dma & 1)) {
4480 fd_free_irq();
4481 spin_lock_irqsave(&floppy_usage_lock, flags);
4482 usage_count--;
4483 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4484 return -1;
4485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 }
4487
4488 for (fdc = 0; fdc < N_FDC; fdc++) {
4489 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004490 if (floppy_request_regions(fdc))
4491 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 }
4493 }
4494 for (fdc = 0; fdc < N_FDC; fdc++) {
4495 if (FDCS->address != -1) {
4496 reset_fdc_info(1);
4497 fd_outb(FDCS->dor, FD_DOR);
4498 }
4499 }
4500 fdc = 0;
4501 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4502
4503 for (fdc = 0; fdc < N_FDC; fdc++)
4504 if (FDCS->address != -1)
4505 fd_outb(FDCS->dor, FD_DOR);
4506 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004507 * The driver will try and free resources and relies on us
4508 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 */
4510 fdc = 0;
4511 irqdma_allocated = 1;
4512 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004513cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 fd_free_irq();
4515 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004516 while (--fdc >= 0)
4517 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 spin_lock_irqsave(&floppy_usage_lock, flags);
4519 usage_count--;
4520 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4521 return -1;
4522}
4523
4524static void floppy_release_irq_and_dma(void)
4525{
4526 int old_fdc;
4527#ifdef FLOPPY_SANITY_CHECK
4528#ifndef __sparc__
4529 int drive;
4530#endif
4531#endif
4532 long tmpsize;
4533 unsigned long tmpaddr;
4534 unsigned long flags;
4535
4536 spin_lock_irqsave(&floppy_usage_lock, flags);
4537 if (--usage_count) {
4538 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4539 return;
4540 }
4541 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4542 if (irqdma_allocated) {
4543 fd_disable_dma();
4544 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004545 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 irqdma_allocated = 0;
4547 }
4548 set_dor(0, ~0, 8);
4549#if N_FDC > 1
4550 set_dor(1, ~8, 0);
4551#endif
4552 floppy_enable_hlt();
4553
4554 if (floppy_track_buffer && max_buffer_sectors) {
4555 tmpsize = max_buffer_sectors * 1024;
4556 tmpaddr = (unsigned long)floppy_track_buffer;
4557 floppy_track_buffer = NULL;
4558 max_buffer_sectors = 0;
4559 buffer_min = buffer_max = -1;
4560 fd_dma_mem_free(tmpaddr, tmpsize);
4561 }
4562#ifdef FLOPPY_SANITY_CHECK
4563#ifndef __sparc__
4564 for (drive = 0; drive < N_FDC * 4; drive++)
4565 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004566 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567#endif
4568
4569 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004570 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004572 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004573 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004574 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575#endif
4576 old_fdc = fdc;
4577 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004578 if (FDCS->address != -1)
4579 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 fdc = old_fdc;
4581}
4582
4583#ifdef MODULE
4584
4585static char *floppy;
4586
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587static void __init parse_floppy_cfg_string(char *cfg)
4588{
4589 char *ptr;
4590
4591 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004592 ptr = cfg;
4593 while (*cfg && *cfg != ' ' && *cfg != '\t')
4594 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 if (*cfg) {
4596 *cfg = '\0';
4597 cfg++;
4598 }
4599 if (*ptr)
4600 floppy_setup(ptr);
4601 }
4602}
4603
Jon Schindler7afea3b2008-04-29 00:59:21 -07004604static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605{
4606 if (floppy)
4607 parse_floppy_cfg_string(floppy);
4608 return floppy_init();
4609}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004610module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611
Jon Schindler7afea3b2008-04-29 00:59:21 -07004612static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613{
4614 int drive;
4615
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4617 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004618 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619
4620 for (drive = 0; drive < N_DRIVE; drive++) {
4621 del_timer_sync(&motor_off_timer[drive]);
4622
4623 if ((allowed_drive_mask & (1 << drive)) &&
4624 fdc_state[FDC(drive)].version != FDC_NONE) {
4625 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004626 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4627 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 }
4629 put_disk(disks[drive]);
4630 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631
4632 del_timer_sync(&fd_timeout);
4633 del_timer_sync(&fd_timer);
4634 blk_cleanup_queue(floppy_queue);
4635
4636 if (usage_count)
4637 floppy_release_irq_and_dma();
4638
4639 /* eject disk, if any */
4640 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641}
Joe Perches48c8cee2010-03-10 15:20:45 -08004642
Jon Schindler7afea3b2008-04-29 00:59:21 -07004643module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644
4645module_param(floppy, charp, 0);
4646module_param(FLOPPY_IRQ, int, 0);
4647module_param(FLOPPY_DMA, int, 0);
4648MODULE_AUTHOR("Alain L. Knaff");
4649MODULE_SUPPORTED_DEVICE("fd");
4650MODULE_LICENSE("GPL");
4651
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004652/* This doesn't actually get used other than for module information */
4653static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004654 {"PNP0700", 0},
4655 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004656};
Joe Perches48c8cee2010-03-10 15:20:45 -08004657
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004658MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4659
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660#else
4661
4662__setup("floppy=", floppy_setup);
4663module_init(floppy_init)
4664#endif
4665
4666MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);