blob: 35ce4e3f04dd22b5680fff3a288cf0950c4aa915 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/block/floppy.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1993, 1994 Alain Knaff
6 * Copyright (C) 1998 Alan Cox
7 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009/*
10 * 02.12.91 - Changed to static variables to indicate need for reset
11 * and recalibrate. This makes some things easier (output_byte reset
12 * checking etc), and means less interrupt jumping in case of errors,
13 * so the code is hopefully easier to understand.
14 */
15
16/*
17 * This file is certainly a mess. I've tried my best to get it working,
18 * but I don't like programming floppies, and I have only one anyway.
19 * Urgel. I should check for more errors, and do more graceful error
20 * recovery. Seems there are problems with several drives. I've tried to
21 * correct them. No promises.
22 */
23
24/*
25 * As with hd.c, all routines within this file can (and will) be called
26 * by interrupts, so extreme caution is needed. A hardware interrupt
27 * handler may not sleep, or a kernel panic will happen. Thus I cannot
28 * call "floppy-on" directly, but have to set a special timer interrupt
29 * etc.
30 */
31
32/*
33 * 28.02.92 - made track-buffering routines, based on the routines written
34 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
35 */
36
37/*
38 * Automatic floppy-detection and formatting written by Werner Almesberger
39 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
40 * the floppy-change signal detection.
41 */
42
43/*
44 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
45 * FDC data overrun bug, added some preliminary stuff for vertical
46 * recording support.
47 *
48 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
49 *
50 * TODO: Errors are still not counted properly.
51 */
52
53/* 1992/9/20
54 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
55 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
56 * Christoph H. Hochst\"atter.
57 * I have fixed the shift values to the ones I always use. Maybe a new
58 * ioctl() should be created to be able to modify them.
59 * There is a bug in the driver that makes it impossible to format a
60 * floppy as the first thing after bootup.
61 */
62
63/*
64 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
65 * this helped the floppy driver as well. Much cleaner, and still seems to
66 * work.
67 */
68
69/* 1994/6/24 --bbroad-- added the floppy table entries and made
70 * minor modifications to allow 2.88 floppies to be run.
71 */
72
73/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
74 * disk types.
75 */
76
77/*
78 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
79 * format bug fixes, but unfortunately some new bugs too...
80 */
81
82/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
83 * errors to allow safe writing by specialized programs.
84 */
85
86/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
87 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
88 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
89 * drives are "upside-down").
90 */
91
92/*
93 * 1995/8/26 -- Andreas Busse -- added Mips support.
94 */
95
96/*
97 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
98 * features to asm/floppy.h.
99 */
100
101/*
James Nelsonb88b0982005-11-08 16:52:12 +0100102 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
103 */
104
105/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
107 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
108 * use of '0' for NULL.
109 */
110
111/*
112 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
113 * failures.
114 */
115
116/*
117 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
118 */
119
120/*
121 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
122 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
123 * being used to store jiffies, which are unsigned longs).
124 */
125
126/*
127 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
128 * - get rid of check_region
129 * - s/suser/capable/
130 */
131
132/*
133 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
134 * floppy controller (lingering task on list after module is gone... boom.)
135 */
136
137/*
138 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
139 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
140 * requires many non-obvious changes in arch dependent code.
141 */
142
143/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
144 * Better audit of register_blkdev.
145 */
146
147#define FLOPPY_SANITY_CHECK
148#undef FLOPPY_SILENT_DCL_CLEAR
149
150#define REALLY_SLOW_IO
151
152#define DEBUGT 2
Joe Perches48c8cee2010-03-10 15:20:45 -0800153#define DCL_DEBUG /* debug disk change line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Joe Perches87f530d2010-03-10 15:20:54 -0800155#ifdef DCL_DEBUG
156#define debug_dcl(test, fmt, args...) \
157 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
158#else
159#define debug_dcl(test, fmt, args...) \
160 do { if (0) DPRINT(fmt, ##args); } while (0)
161#endif
162
163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164/* do print messages for unexpected interrupts */
165static int print_unex = 1;
166#include <linux/module.h>
167#include <linux/sched.h>
168#include <linux/fs.h>
169#include <linux/kernel.h>
170#include <linux/timer.h>
171#include <linux/workqueue.h>
172#define FDPATCHES
173#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174#include <linux/fd.h>
175#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#include <linux/errno.h>
177#include <linux/slab.h>
178#include <linux/mm.h>
179#include <linux/bio.h>
180#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800181#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#include <linux/fcntl.h>
183#include <linux/delay.h>
184#include <linux/mc146818rtc.h> /* CMOS defines */
185#include <linux/ioport.h>
186#include <linux/interrupt.h>
187#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100188#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700189#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800191#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800192#include <linux/io.h>
193#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195/*
196 * PS/2 floppies have much slower step rates than regular floppies.
197 * It's been recommended that take about 1/4 of the default speed
198 * in some more extreme cases.
199 */
200static int slow_floppy;
201
202#include <asm/dma.h>
203#include <asm/irq.h>
204#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206static int FLOPPY_IRQ = 6;
207static int FLOPPY_DMA = 2;
208static int can_use_virtual_dma = 2;
209/* =======
210 * can use virtual DMA:
211 * 0 = use of virtual DMA disallowed by config
212 * 1 = use of virtual DMA prescribed by config
213 * 2 = no virtual DMA preference configured. By default try hard DMA,
214 * but fall back on virtual DMA when not enough memory available
215 */
216
217static int use_virtual_dma;
218/* =======
219 * use virtual DMA
220 * 0 using hard DMA
221 * 1 using virtual DMA
222 * This variable is set to virtual when a DMA mem problem arises, and
223 * reset back in floppy_grab_irq_and_dma.
224 * It is not safe to reset it in other circumstances, because the floppy
225 * driver may have several buffers in use at once, and we do currently not
226 * record each buffers capabilities
227 */
228
229static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100232irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235#define K_64 0x10000 /* 64KB */
236
237/* the following is the mask of allowed drives. By default units 2 and
238 * 3 of both floppy controllers are disabled, because switching on the
239 * motor of these drives causes system hangs on some PCI computers. drive
240 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
241 * a drive is allowed.
242 *
243 * NOTE: This must come before we include the arch floppy header because
244 * some ports reference this variable from there. -DaveM
245 */
246
247static int allowed_drive_mask = 0x33;
248
249#include <asm/floppy.h>
250
251static int irqdma_allocated;
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253#define DEVICE_NAME "floppy"
254
255#include <linux/blkdev.h>
256#include <linux/blkpg.h>
257#include <linux/cdrom.h> /* for the compatibility eject ioctl */
258#include <linux/completion.h>
259
260static struct request *current_req;
261static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800262static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264#ifndef fd_get_dma_residue
265#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
266#endif
267
268/* Dma Memory related stuff */
269
270#ifndef fd_dma_mem_free
271#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
272#endif
273
274#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800275#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276#endif
277
278static inline void fallback_on_nodma_alloc(char **addr, size_t l)
279{
280#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
281 if (*addr)
282 return; /* we have the memory */
283 if (can_use_virtual_dma != 2)
284 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800285 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 *addr = (char *)nodma_mem_alloc(l);
287#else
288 return;
289#endif
290}
291
292/* End dma memory related stuff */
293
294static unsigned long fake_change;
295static int initialising = 1;
296
Joe Perches48c8cee2010-03-10 15:20:45 -0800297#define ITYPE(x) (((x) >> 2) & 0x1f)
298#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
299#define UNIT(x) ((x) & 0x03) /* drive on fdc */
300#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700301 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Joe Perches48c8cee2010-03-10 15:20:45 -0800304#define DP (&drive_params[current_drive])
305#define DRS (&drive_state[current_drive])
306#define DRWE (&write_errors[current_drive])
307#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Joe Perches48c8cee2010-03-10 15:20:45 -0800309#define UDP (&drive_params[drive])
310#define UDRS (&drive_state[drive])
311#define UDRWE (&write_errors[drive])
312#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Joe Perches48c8cee2010-03-10 15:20:45 -0800314#define DPRINT(format, args...) \
Joe Perchesb46df352010-03-10 15:20:46 -0800315 pr_info(DEVICE_NAME "%d: " format, current_drive, ##args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Joe Perches48c8cee2010-03-10 15:20:45 -0800317#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
318#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
319
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800321#define COMMAND (raw_cmd->cmd[0])
322#define DR_SELECT (raw_cmd->cmd[1])
323#define TRACK (raw_cmd->cmd[2])
324#define HEAD (raw_cmd->cmd[3])
325#define SECTOR (raw_cmd->cmd[4])
326#define SIZECODE (raw_cmd->cmd[5])
327#define SECT_PER_TRACK (raw_cmd->cmd[6])
328#define GAP (raw_cmd->cmd[7])
329#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330#define NR_RW 9
331
332/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800333#define F_SIZECODE (raw_cmd->cmd[2])
334#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
335#define F_GAP (raw_cmd->cmd[4])
336#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337#define NR_F 6
338
339/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800340 * Maximum disk size (in kilobytes).
341 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 * [Now it is rather a minimum]
343 */
344#define MAX_DISK_SIZE 4 /* 3984 */
345
346/*
347 * globals used by 'result()'
348 */
349#define MAX_REPLIES 16
350static unsigned char reply_buffer[MAX_REPLIES];
351static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800352#define ST0 (reply_buffer[0])
353#define ST1 (reply_buffer[1])
354#define ST2 (reply_buffer[2])
355#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
356#define R_TRACK (reply_buffer[3])
357#define R_HEAD (reply_buffer[4])
358#define R_SECTOR (reply_buffer[5])
359#define R_SIZECODE (reply_buffer[6])
360
361#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363/*
364 * this struct defines the different floppy drive types.
365 */
366static struct {
367 struct floppy_drive_params params;
368 const char *name; /* name printed while booting */
369} default_drive_params[] = {
370/* NOTE: the time values in jiffies should be in msec!
371 CMOS drive type
372 | Maximum data rate supported by drive type
373 | | Head load time, msec
374 | | | Head unload time, msec (not used)
375 | | | | Step rate interval, usec
376 | | | | | Time needed for spinup time (jiffies)
377 | | | | | | Timeout for spinning down (jiffies)
378 | | | | | | | Spindown offset (where disk stops)
379 | | | | | | | | Select delay
380 | | | | | | | | | RPS
381 | | | | | | | | | | Max number of tracks
382 | | | | | | | | | | | Interrupt timeout
383 | | | | | | | | | | | | Max nonintlv. sectors
384 | | | | | | | | | | | | | -Max Errors- flags */
385{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
386 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
387
388{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
389 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
390
391{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
392 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
393
394{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
395 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
396
397{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
398 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
399
400{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
401 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
402
403{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
404 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
405/* | --autodetected formats--- | | |
406 * read_track | | Name printed when booting
407 * | Native format
408 * Frequency of disk change checks */
409};
410
411static struct floppy_drive_params drive_params[N_DRIVE];
412static struct floppy_drive_struct drive_state[N_DRIVE];
413static struct floppy_write_errors write_errors[N_DRIVE];
414static struct timer_list motor_off_timer[N_DRIVE];
415static struct gendisk *disks[N_DRIVE];
416static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800417static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
419
420/*
421 * This struct defines the different floppy types.
422 *
423 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
424 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
425 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
426 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
427 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
428 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
429 * side 0 is on physical side 0 (but with the misnamed sector IDs).
430 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700431 * 'options'.
432 *
433 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
434 * The LSB (bit 2) is flipped. For most disks, the first sector
435 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
436 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
437 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
438 *
439 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 */
441/*
442 Size
443 | Sectors per track
444 | | Head
445 | | | Tracks
446 | | | | Stretch
447 | | | | | Gap 1 size
448 | | | | | | Data rate, | 0x40 for perp
449 | | | | | | | Spec1 (stepping rate, head unload
450 | | | | | | | | /fmt gap (gap2) */
451static struct floppy_struct floppy_type[32] = {
452 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
453 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
454 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
455 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
456 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
457 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
458 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
459 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
460 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
461 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
462
463 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
464 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
465 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
466 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
467 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
468 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
469 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
470 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
471 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
472 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
473
474 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
475 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
476 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
477 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
478 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
479 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
480 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
481 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
482 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
486 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
487};
488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489#define SECTSIZE (_FD_SECTSIZE(*floppy))
490
491/* Auto-detection: Disk type used until the next media change occurs. */
492static struct floppy_struct *current_type[N_DRIVE];
493
494/*
495 * User-provided type information. current_type points to
496 * the respective entry of this array.
497 */
498static struct floppy_struct user_params[N_DRIVE];
499
500static sector_t floppy_sizes[256];
501
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200502static char floppy_device_name[] = "floppy";
503
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504/*
505 * The driver is trying to determine the correct media format
506 * while probing is set. rw_interrupt() clears it after a
507 * successful access.
508 */
509static int probing;
510
511/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800512#define FD_COMMAND_NONE -1
513#define FD_COMMAND_ERROR 2
514#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516static volatile int command_status = FD_COMMAND_NONE;
517static unsigned long fdc_busy;
518static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
519static DECLARE_WAIT_QUEUE_HEAD(command_done);
520
521#define NO_SIGNAL (!interruptible || !signal_pending(current))
Joe Perches48c8cee2010-03-10 15:20:45 -0800522#define CALL(x) if ((x) == -EINTR) return -EINTR
523#define ECALL(x) if ((ret = (x))) return ret;
524#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
525#define WAIT(x) _WAIT((x),interruptible)
526#define IWAIT(x) _WAIT((x),1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
528/* Errors during formatting are counted here. */
529static int format_errors;
530
531/* Format request descriptor. */
532static struct format_descr format_req;
533
534/*
535 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
536 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
537 * H is head unload time (1=16ms, 2=32ms, etc)
538 */
539
540/*
541 * Track buffer
542 * Because these are written to by the DMA controller, they must
543 * not contain a 64k byte boundary crossing, or data will be
544 * corrupted/lost.
545 */
546static char *floppy_track_buffer;
547static int max_buffer_sectors;
548
549static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700550typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800552 void (*interrupt)(void);
553 /* this is called after the interrupt of the
554 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700555 void (*redo)(void); /* this is called to retry the operation */
556 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 done_f done; /* this is called to say if the operation has
558 * succeeded/failed */
559} *cont;
560
561static void floppy_ready(void);
562static void floppy_start(void);
563static void process_fd_request(void);
564static void recalibrate_floppy(void);
565static void floppy_shutdown(unsigned long);
566
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800567static int floppy_request_regions(int);
568static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569static int floppy_grab_irq_and_dma(void);
570static void floppy_release_irq_and_dma(void);
571
572/*
573 * The "reset" variable should be tested whenever an interrupt is scheduled,
574 * after the commands have been sent. This is to ensure that the driver doesn't
575 * get wedged when the interrupt doesn't come because of a failed command.
576 * reset doesn't need to be tested before sending commands, because
577 * output_byte is automatically disabled when reset is set.
578 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579static void reset_fdc(void);
580
581/*
582 * These are global variables, as that's the easiest way to give
583 * information to interrupts. They are the data used for the current
584 * request.
585 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800586#define NO_TRACK -1
587#define NEED_1_RECAL -2
588#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590static int usage_count;
591
592/* buffer related variables */
593static int buffer_track = -1;
594static int buffer_drive = -1;
595static int buffer_min = -1;
596static int buffer_max = -1;
597
598/* fdc related variables, should end up in a struct */
599static struct floppy_fdc_state fdc_state[N_FDC];
600static int fdc; /* current fdc */
601
602static struct floppy_struct *_floppy = floppy_type;
603static unsigned char current_drive;
604static long current_count_sectors;
605static unsigned char fsector_t; /* sector in track */
606static unsigned char in_sector_offset; /* offset within physical sector,
607 * expressed in units of 512 bytes */
608
609#ifndef fd_eject
610static inline int fd_eject(int drive)
611{
612 return -EINVAL;
613}
614#endif
615
616/*
617 * Debugging
618 * =========
619 */
620#ifdef DEBUGT
621static long unsigned debugtimer;
622
623static inline void set_debugt(void)
624{
625 debugtimer = jiffies;
626}
627
628static inline void debugt(const char *message)
629{
630 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800631 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632}
633#else
634static inline void set_debugt(void) { }
635static inline void debugt(const char *message) { }
636#endif /* DEBUGT */
637
Joe Perchesa0a52d62010-03-10 15:20:52 -0800638typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700639static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641static const char *timeout_message;
642
643#ifdef FLOPPY_SANITY_CHECK
644static void is_alive(const char *message)
645{
646 /* this routine checks whether the floppy driver is "alive" */
647 if (test_bit(0, &fdc_busy) && command_status < 2
648 && !timer_pending(&fd_timeout)) {
649 DPRINT("timeout handler died: %s\n", message);
650 }
651}
652#endif
653
Joe Perches48c8cee2010-03-10 15:20:45 -0800654static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656#ifdef FLOPPY_SANITY_CHECK
657
658#define OLOGSIZE 20
659
Joe Perches48c8cee2010-03-10 15:20:45 -0800660static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661static unsigned long interruptjiffies;
662static unsigned long resultjiffies;
663static int resultsize;
664static unsigned long lastredo;
665
666static struct output_log {
667 unsigned char data;
668 unsigned char status;
669 unsigned long jiffies;
670} output_log[OLOGSIZE];
671
672static int output_log_pos;
673#endif
674
675#define current_reqD -1
676#define MAXTIMEOUT -2
677
678static void __reschedule_timeout(int drive, const char *message, int marg)
679{
680 if (drive == current_reqD)
681 drive = current_drive;
682 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700683 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 fd_timeout.expires = jiffies + 20UL * HZ;
685 drive = 0;
686 } else
687 fd_timeout.expires = jiffies + UDP->timeout;
688 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800689 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800690 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 timeout_message = message;
692}
693
694static void reschedule_timeout(int drive, const char *message, int marg)
695{
696 unsigned long flags;
697
698 spin_lock_irqsave(&floppy_lock, flags);
699 __reschedule_timeout(drive, message, marg);
700 spin_unlock_irqrestore(&floppy_lock, flags);
701}
702
Joe Perches48c8cee2010-03-10 15:20:45 -0800703#define INFBOUND(a, b) (a) = max_t(int, a, b)
704#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706/*
707 * Bottom half floppy driver.
708 * ==========================
709 *
710 * This part of the file contains the code talking directly to the hardware,
711 * and also the main service loop (seek-configure-spinup-command)
712 */
713
714/*
715 * disk change.
716 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
717 * and the last_checked date.
718 *
719 * last_checked is the date of the last check which showed 'no disk change'
720 * FD_DISK_CHANGE is set under two conditions:
721 * 1. The floppy has been changed after some i/o to that floppy already
722 * took place.
723 * 2. No floppy disk is in the drive. This is done in order to ensure that
724 * requests are quickly flushed in case there is no disk in the drive. It
725 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
726 * the drive.
727 *
728 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
729 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
730 * each seek. If a disk is present, the disk change line should also be
731 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
732 * change line is set, this means either that no disk is in the drive, or
733 * that it has been removed since the last seek.
734 *
735 * This means that we really have a third possibility too:
736 * The floppy has been changed after the last seek.
737 */
738
739static int disk_change(int drive)
740{
741 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800744 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 DPRINT("WARNING disk change called early\n");
746 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
747 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
748 DPRINT("probing disk change on unselected drive\n");
749 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
750 (unsigned int)FDCS->dor);
751 }
752#endif
753
Joe Perches87f530d2010-03-10 15:20:54 -0800754 debug_dcl(UDP->flags,
755 "checking disk change line for drive %d\n", drive);
756 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
757 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
758 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800761 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800763 set_bit(FD_VERIFY_BIT, &UDRS->flags);
764 /* verify write protection */
765
766 if (UDRS->maxblock) /* mark it changed */
767 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 /* invalidate its geometry */
770 if (UDRS->keep_data >= 0) {
771 if ((UDP->flags & FTD_MSG) &&
772 current_type[drive] != NULL)
773 DPRINT("Disk type is undefined after "
774 "disk change\n");
775 current_type[drive] = NULL;
776 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
777 }
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return 1;
780 } else {
781 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800782 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784 return 0;
785}
786
787static inline int is_selected(int dor, int unit)
788{
789 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
790}
791
792static int set_dor(int fdc, char mask, char data)
793{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700794 unsigned char unit;
795 unsigned char drive;
796 unsigned char newdor;
797 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 if (FDCS->address == -1)
800 return -1;
801
802 olddor = FDCS->dor;
803 newdor = (olddor & mask) | data;
804 if (newdor != olddor) {
805 unit = olddor & 0x3;
806 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
807 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800808 debug_dcl(UDP->flags,
809 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 disk_change(drive);
811 }
812 FDCS->dor = newdor;
813 fd_outb(newdor, FD_DOR);
814
815 unit = newdor & 0x3;
816 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
817 drive = REVDRIVE(fdc, unit);
818 UDRS->select_date = jiffies;
819 }
820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return olddor;
822}
823
824static void twaddle(void)
825{
826 if (DP->select_delay)
827 return;
828 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
829 fd_outb(FDCS->dor, FD_DOR);
830 DRS->select_date = jiffies;
831}
832
833/* reset all driver information about the current fdc. This is needed after
834 * a reset, and after a raw command. */
835static void reset_fdc_info(int mode)
836{
837 int drive;
838
839 FDCS->spec1 = FDCS->spec2 = -1;
840 FDCS->need_configure = 1;
841 FDCS->perp_mode = 1;
842 FDCS->rawcmd = 0;
843 for (drive = 0; drive < N_DRIVE; drive++)
844 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
845 UDRS->track = NEED_2_RECAL;
846}
847
848/* selects the fdc and drive, and enables the fdc's input/dma. */
849static void set_fdc(int drive)
850{
851 if (drive >= 0 && drive < N_DRIVE) {
852 fdc = FDC(drive);
853 current_drive = drive;
854 }
855 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800856 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 return;
858 }
859 set_dor(fdc, ~0, 8);
860#if N_FDC > 1
861 set_dor(1 - fdc, ~8, 0);
862#endif
863 if (FDCS->rawcmd == 2)
864 reset_fdc_info(1);
865 if (fd_inb(FD_STATUS) != STATUS_READY)
866 FDCS->reset = 1;
867}
868
869/* locks the driver */
870static int _lock_fdc(int drive, int interruptible, int line)
871{
872 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800873 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 line);
875 return -1;
876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
878 if (test_and_set_bit(0, &fdc_busy)) {
879 DECLARE_WAITQUEUE(wait, current);
880 add_wait_queue(&fdc_wait, &wait);
881
882 for (;;) {
883 set_current_state(TASK_INTERRUPTIBLE);
884
885 if (!test_and_set_bit(0, &fdc_busy))
886 break;
887
888 schedule();
889
890 if (!NO_SIGNAL) {
891 remove_wait_queue(&fdc_wait, &wait);
892 return -EINTR;
893 }
894 }
895
896 set_current_state(TASK_RUNNING);
897 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700898 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 }
900 command_status = FD_COMMAND_NONE;
901
902 __reschedule_timeout(drive, "lock fdc", 0);
903 set_fdc(drive);
904 return 0;
905}
906
Joe Perches48c8cee2010-03-10 15:20:45 -0800907#define lock_fdc(drive, interruptible) \
908 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910/* unlocks the driver */
911static inline void unlock_fdc(void)
912{
913 unsigned long flags;
914
915 raw_cmd = NULL;
916 if (!test_bit(0, &fdc_busy))
917 DPRINT("FDC access conflict!\n");
918
919 if (do_floppy)
920 DPRINT("device interrupt still active at FDC release: %p!\n",
921 do_floppy);
922 command_status = FD_COMMAND_NONE;
923 spin_lock_irqsave(&floppy_lock, flags);
924 del_timer(&fd_timeout);
925 cont = NULL;
926 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900927 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 do_fd_request(floppy_queue);
929 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 wake_up(&fdc_wait);
931}
932
933/* switches the motor off after a given timeout */
934static void motor_off_callback(unsigned long nr)
935{
936 unsigned char mask = ~(0x10 << UNIT(nr));
937
938 set_dor(FDC(nr), mask, 0);
939}
940
941/* schedules motor off */
942static void floppy_off(unsigned int drive)
943{
944 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700945 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 if (!(FDCS->dor & (0x10 << UNIT(drive))))
948 return;
949
950 del_timer(motor_off_timer + drive);
951
952 /* make spindle stop in a position which minimizes spinup time
953 * next time */
954 if (UDP->rps) {
955 delta = jiffies - UDRS->first_read_date + HZ -
956 UDP->spindown_offset;
957 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
958 motor_off_timer[drive].expires =
959 jiffies + UDP->spindown - delta;
960 }
961 add_timer(motor_off_timer + drive);
962}
963
964/*
965 * cycle through all N_DRIVE floppy drives, for disk change testing.
966 * stopping at current drive. This is done before any long operation, to
967 * be sure to have up to date disk change information.
968 */
969static void scandrives(void)
970{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700971 int i;
972 int drive;
973 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 if (DP->select_delay)
976 return;
977
978 saved_drive = current_drive;
979 for (i = 0; i < N_DRIVE; i++) {
980 drive = (saved_drive + i + 1) % N_DRIVE;
981 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
982 continue; /* skip closed drives */
983 set_fdc(drive);
984 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
985 (0x10 << UNIT(drive))))
986 /* switch the motor off again, if it was off to
987 * begin with */
988 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
989 }
990 set_fdc(saved_drive);
991}
992
993static void empty(void)
994{
995}
996
David Howells65f27f32006-11-22 14:55:48 +0000997static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
Joe Perches48c8cee2010-03-10 15:20:45 -0800999static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
David Howells65f27f32006-11-22 14:55:48 +00001001 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 schedule_work(&floppy_work);
1003}
1004
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001005static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007static void cancel_activity(void)
1008{
1009 unsigned long flags;
1010
1011 spin_lock_irqsave(&floppy_lock, flags);
1012 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001013 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 del_timer(&fd_timer);
1015 spin_unlock_irqrestore(&floppy_lock, flags);
1016}
1017
1018/* this function makes sure that the disk stays in the drive during the
1019 * transfer */
1020static void fd_watchdog(void)
1021{
Joe Perches87f530d2010-03-10 15:20:54 -08001022 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 if (disk_change(current_drive)) {
1025 DPRINT("disk removed during i/o\n");
1026 cancel_activity();
1027 cont->done(0);
1028 reset_fdc();
1029 } else {
1030 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001031 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 fd_timer.expires = jiffies + HZ / 10;
1033 add_timer(&fd_timer);
1034 }
1035}
1036
1037static void main_command_interrupt(void)
1038{
1039 del_timer(&fd_timer);
1040 cont->interrupt();
1041}
1042
1043/* waits for a delay (spinup or select) to pass */
1044static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1045{
1046 if (FDCS->reset) {
1047 reset_fdc(); /* do the reset during sleep to win time
1048 * if we don't need to sleep, it's a good
1049 * occasion anyways */
1050 return 1;
1051 }
1052
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001053 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 del_timer(&fd_timer);
1055 fd_timer.function = function;
1056 fd_timer.expires = delay;
1057 add_timer(&fd_timer);
1058 return 1;
1059 }
1060 return 0;
1061}
1062
1063static DEFINE_SPINLOCK(floppy_hlt_lock);
1064static int hlt_disabled;
1065static void floppy_disable_hlt(void)
1066{
1067 unsigned long flags;
1068
1069 spin_lock_irqsave(&floppy_hlt_lock, flags);
1070 if (!hlt_disabled) {
1071 hlt_disabled = 1;
1072#ifdef HAVE_DISABLE_HLT
1073 disable_hlt();
1074#endif
1075 }
1076 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1077}
1078
1079static void floppy_enable_hlt(void)
1080{
1081 unsigned long flags;
1082
1083 spin_lock_irqsave(&floppy_hlt_lock, flags);
1084 if (hlt_disabled) {
1085 hlt_disabled = 0;
1086#ifdef HAVE_DISABLE_HLT
1087 enable_hlt();
1088#endif
1089 }
1090 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1091}
1092
1093static void setup_DMA(void)
1094{
1095 unsigned long f;
1096
1097#ifdef FLOPPY_SANITY_CHECK
1098 if (raw_cmd->length == 0) {
1099 int i;
1100
Joe Perchesb46df352010-03-10 15:20:46 -08001101 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001103 pr_cont("%x,", raw_cmd->cmd[i]);
1104 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 cont->done(0);
1106 FDCS->reset = 1;
1107 return;
1108 }
1109 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001110 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 cont->done(0);
1112 FDCS->reset = 1;
1113 return;
1114 }
1115#endif
1116 f = claim_dma_lock();
1117 fd_disable_dma();
1118#ifdef fd_dma_setup
1119 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1120 (raw_cmd->flags & FD_RAW_READ) ?
1121 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1122 release_dma_lock(f);
1123 cont->done(0);
1124 FDCS->reset = 1;
1125 return;
1126 }
1127 release_dma_lock(f);
1128#else
1129 fd_clear_dma_ff();
1130 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1131 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1132 DMA_MODE_READ : DMA_MODE_WRITE);
1133 fd_set_dma_addr(raw_cmd->kernel_data);
1134 fd_set_dma_count(raw_cmd->length);
1135 virtual_dma_port = FDCS->address;
1136 fd_enable_dma();
1137 release_dma_lock(f);
1138#endif
1139 floppy_disable_hlt();
1140}
1141
1142static void show_floppy(void);
1143
1144/* waits until the fdc becomes ready */
1145static int wait_til_ready(void)
1146{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001147 int status;
1148 int counter;
1149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 if (FDCS->reset)
1151 return -1;
1152 for (counter = 0; counter < 10000; counter++) {
1153 status = fd_inb(FD_STATUS);
1154 if (status & STATUS_READY)
1155 return status;
1156 }
1157 if (!initialising) {
1158 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1159 show_floppy();
1160 }
1161 FDCS->reset = 1;
1162 return -1;
1163}
1164
1165/* sends a command byte to the fdc */
1166static int output_byte(char byte)
1167{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001168 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001170 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 return -1;
1172 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1173 fd_outb(byte, FD_DATA);
1174#ifdef FLOPPY_SANITY_CHECK
1175 output_log[output_log_pos].data = byte;
1176 output_log[output_log_pos].status = status;
1177 output_log[output_log_pos].jiffies = jiffies;
1178 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1179#endif
1180 return 0;
1181 }
1182 FDCS->reset = 1;
1183 if (!initialising) {
1184 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1185 byte, fdc, status);
1186 show_floppy();
1187 }
1188 return -1;
1189}
1190
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191/* gets the response from the fdc */
1192static int result(void)
1193{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001194 int i;
1195 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
1197 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001198 status = wait_til_ready();
1199 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 break;
1201 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1202 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1203#ifdef FLOPPY_SANITY_CHECK
1204 resultjiffies = jiffies;
1205 resultsize = i;
1206#endif
1207 return i;
1208 }
1209 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1210 reply_buffer[i] = fd_inb(FD_DATA);
1211 else
1212 break;
1213 }
1214 if (!initialising) {
1215 DPRINT
1216 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1217 fdc, status, i);
1218 show_floppy();
1219 }
1220 FDCS->reset = 1;
1221 return -1;
1222}
1223
1224#define MORE_OUTPUT -2
1225/* does the fdc need more output? */
1226static int need_more_output(void)
1227{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001228 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001229
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001230 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 return -1;
1232 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1233 return MORE_OUTPUT;
1234 return result();
1235}
1236
1237/* Set perpendicular mode as required, based on data rate, if supported.
1238 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1239 */
1240static inline void perpendicular_mode(void)
1241{
1242 unsigned char perp_mode;
1243
1244 if (raw_cmd->rate & 0x40) {
1245 switch (raw_cmd->rate & 3) {
1246 case 0:
1247 perp_mode = 2;
1248 break;
1249 case 3:
1250 perp_mode = 3;
1251 break;
1252 default:
1253 DPRINT("Invalid data rate for perpendicular mode!\n");
1254 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001255 FDCS->reset = 1;
1256 /*
1257 * convenient way to return to
1258 * redo without too much hassle
1259 * (deep stack et al.)
1260 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 return;
1262 }
1263 } else
1264 perp_mode = 0;
1265
1266 if (FDCS->perp_mode == perp_mode)
1267 return;
1268 if (FDCS->version >= FDC_82077_ORIG) {
1269 output_byte(FD_PERPENDICULAR);
1270 output_byte(perp_mode);
1271 FDCS->perp_mode = perp_mode;
1272 } else if (perp_mode) {
1273 DPRINT("perpendicular mode not supported by this FDC.\n");
1274 }
1275} /* perpendicular_mode */
1276
1277static int fifo_depth = 0xa;
1278static int no_fifo;
1279
1280static int fdc_configure(void)
1281{
1282 /* Turn on FIFO */
1283 output_byte(FD_CONFIGURE);
1284 if (need_more_output() != MORE_OUTPUT)
1285 return 0;
1286 output_byte(0);
1287 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1288 output_byte(0); /* pre-compensation from track
1289 0 upwards */
1290 return 1;
1291}
1292
1293#define NOMINAL_DTR 500
1294
1295/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1296 * head load time, and DMA disable flag to values needed by floppy.
1297 *
1298 * The value "dtr" is the data transfer rate in Kbps. It is needed
1299 * to account for the data rate-based scaling done by the 82072 and 82077
1300 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1301 * 8272a).
1302 *
1303 * Note that changing the data transfer rate has a (probably deleterious)
1304 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1305 * fdc_specify is called again after each data transfer rate
1306 * change.
1307 *
1308 * srt: 1000 to 16000 in microseconds
1309 * hut: 16 to 240 milliseconds
1310 * hlt: 2 to 254 milliseconds
1311 *
1312 * These values are rounded up to the next highest available delay time.
1313 */
1314static void fdc_specify(void)
1315{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001316 unsigned char spec1;
1317 unsigned char spec2;
1318 unsigned long srt;
1319 unsigned long hlt;
1320 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 unsigned long dtr = NOMINAL_DTR;
1322 unsigned long scale_dtr = NOMINAL_DTR;
1323 int hlt_max_code = 0x7f;
1324 int hut_max_code = 0xf;
1325
1326 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1327 fdc_configure();
1328 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 }
1330
1331 switch (raw_cmd->rate & 0x03) {
1332 case 3:
1333 dtr = 1000;
1334 break;
1335 case 1:
1336 dtr = 300;
1337 if (FDCS->version >= FDC_82078) {
1338 /* chose the default rate table, not the one
1339 * where 1 = 2 Mbps */
1340 output_byte(FD_DRIVESPEC);
1341 if (need_more_output() == MORE_OUTPUT) {
1342 output_byte(UNIT(current_drive));
1343 output_byte(0xc0);
1344 }
1345 }
1346 break;
1347 case 2:
1348 dtr = 250;
1349 break;
1350 }
1351
1352 if (FDCS->version >= FDC_82072) {
1353 scale_dtr = dtr;
1354 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1355 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1356 }
1357
1358 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001359 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001360 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 SUPBOUND(srt, 0xf);
1364 INFBOUND(srt, 0);
1365
Julia Lawall061837b2008-09-22 14:57:16 -07001366 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 if (hlt < 0x01)
1368 hlt = 0x01;
1369 else if (hlt > 0x7f)
1370 hlt = hlt_max_code;
1371
Julia Lawall061837b2008-09-22 14:57:16 -07001372 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (hut < 0x1)
1374 hut = 0x1;
1375 else if (hut > 0xf)
1376 hut = hut_max_code;
1377
1378 spec1 = (srt << 4) | hut;
1379 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1380
1381 /* If these parameters did not change, just return with success */
1382 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1383 /* Go ahead and set spec1 and spec2 */
1384 output_byte(FD_SPECIFY);
1385 output_byte(FDCS->spec1 = spec1);
1386 output_byte(FDCS->spec2 = spec2);
1387 }
1388} /* fdc_specify */
1389
1390/* Set the FDC's data transfer rate on behalf of the specified drive.
1391 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1392 * of the specify command (i.e. using the fdc_specify function).
1393 */
1394static int fdc_dtr(void)
1395{
1396 /* If data rate not already set to desired value, set it. */
1397 if ((raw_cmd->rate & 3) == FDCS->dtr)
1398 return 0;
1399
1400 /* Set dtr */
1401 fd_outb(raw_cmd->rate & 3, FD_DCR);
1402
1403 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1404 * need a stabilization period of several milliseconds to be
1405 * enforced after data rate changes before R/W operations.
1406 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1407 */
1408 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001409 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1410 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411} /* fdc_dtr */
1412
1413static void tell_sector(void)
1414{
Joe Perchesb46df352010-03-10 15:20:46 -08001415 pr_cont(": track %d, head %d, sector %d, size %d",
1416 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417} /* tell_sector */
1418
Joe Perchesb46df352010-03-10 15:20:46 -08001419static void print_errors(void)
1420{
1421 DPRINT("");
1422 if (ST0 & ST0_ECE) {
1423 pr_cont("Recalibrate failed!");
1424 } else if (ST2 & ST2_CRC) {
1425 pr_cont("data CRC error");
1426 tell_sector();
1427 } else if (ST1 & ST1_CRC) {
1428 pr_cont("CRC error");
1429 tell_sector();
1430 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1431 (ST2 & ST2_MAM)) {
1432 if (!probing) {
1433 pr_cont("sector not found");
1434 tell_sector();
1435 } else
1436 pr_cont("probe failed...");
1437 } else if (ST2 & ST2_WC) { /* seek error */
1438 pr_cont("wrong cylinder");
1439 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1440 pr_cont("bad cylinder");
1441 } else {
1442 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1443 ST0, ST1, ST2);
1444 tell_sector();
1445 }
1446 pr_cont("\n");
1447}
1448
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449/*
1450 * OK, this error interpreting routine is called after a
1451 * DMA read/write has succeeded
1452 * or failed, so we check the results, and copy any buffers.
1453 * hhb: Added better error reporting.
1454 * ak: Made this into a separate routine.
1455 */
1456static int interpret_errors(void)
1457{
1458 char bad;
1459
1460 if (inr != 7) {
1461 DPRINT("-- FDC reply error");
1462 FDCS->reset = 1;
1463 return 1;
1464 }
1465
1466 /* check IC to find cause of interrupt */
1467 switch (ST0 & ST0_INTR) {
1468 case 0x40: /* error occurred during command execution */
1469 if (ST1 & ST1_EOC)
1470 return 0; /* occurs with pseudo-DMA */
1471 bad = 1;
1472 if (ST1 & ST1_WP) {
1473 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001474 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 cont->done(0);
1476 bad = 2;
1477 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001478 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 } else if (ST1 & ST1_OR) {
1480 if (DP->flags & FTD_MSG)
1481 DPRINT("Over/Underrun - retrying\n");
1482 bad = 0;
1483 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001484 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 }
1486 if (ST2 & ST2_WC || ST2 & ST2_BC)
1487 /* wrong cylinder => recal */
1488 DRS->track = NEED_2_RECAL;
1489 return bad;
1490 case 0x80: /* invalid command given */
1491 DPRINT("Invalid FDC command given!\n");
1492 cont->done(0);
1493 return 2;
1494 case 0xc0:
1495 DPRINT("Abnormal termination caused by polling\n");
1496 cont->error();
1497 return 2;
1498 default: /* (0) Normal command termination */
1499 return 0;
1500 }
1501}
1502
1503/*
1504 * This routine is called when everything should be correctly set up
1505 * for the transfer (i.e. floppy motor is on, the correct floppy is
1506 * selected, and the head is sitting on the right track).
1507 */
1508static void setup_rw_floppy(void)
1509{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001510 int i;
1511 int r;
1512 int flags;
1513 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 unsigned long ready_date;
1515 timeout_fn function;
1516
1517 flags = raw_cmd->flags;
1518 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1519 flags |= FD_RAW_INTR;
1520
1521 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1522 ready_date = DRS->spinup_date + DP->spinup;
1523 /* If spinup will take a long time, rerun scandrives
1524 * again just before spinup completion. Beware that
1525 * after scandrives, we must again wait for selection.
1526 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001527 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001529 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001531 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
1533 /* wait until the floppy is spinning fast enough */
1534 if (fd_wait_for_completion(ready_date, function))
1535 return;
1536 }
1537 dflags = DRS->flags;
1538
1539 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1540 setup_DMA();
1541
1542 if (flags & FD_RAW_INTR)
1543 do_floppy = main_command_interrupt;
1544
1545 r = 0;
1546 for (i = 0; i < raw_cmd->cmd_count; i++)
1547 r |= output_byte(raw_cmd->cmd[i]);
1548
1549 debugt("rw_command: ");
1550
1551 if (r) {
1552 cont->error();
1553 reset_fdc();
1554 return;
1555 }
1556
1557 if (!(flags & FD_RAW_INTR)) {
1558 inr = result();
1559 cont->interrupt();
1560 } else if (flags & FD_RAW_NEED_DISK)
1561 fd_watchdog();
1562}
1563
1564static int blind_seek;
1565
1566/*
1567 * This is the routine called after every seek (or recalibrate) interrupt
1568 * from the floppy controller.
1569 */
1570static void seek_interrupt(void)
1571{
1572 debugt("seek interrupt:");
1573 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1574 DPRINT("seek failed\n");
1575 DRS->track = NEED_2_RECAL;
1576 cont->error();
1577 cont->redo();
1578 return;
1579 }
1580 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001581 debug_dcl(DP->flags,
1582 "clearing NEWCHANGE flag because of effective seek\n");
1583 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001584 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1585 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 DRS->select_date = jiffies;
1587 }
1588 DRS->track = ST1;
1589 floppy_ready();
1590}
1591
1592static void check_wp(void)
1593{
Joe Perchese0298532010-03-10 15:20:55 -08001594 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1595 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 output_byte(FD_GETSTATUS);
1597 output_byte(UNIT(current_drive));
1598 if (result() != 1) {
1599 FDCS->reset = 1;
1600 return;
1601 }
Joe Perchese0298532010-03-10 15:20:55 -08001602 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1603 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001604 debug_dcl(DP->flags,
1605 "checking whether disk is write protected\n");
1606 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001608 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 else
Joe Perchese0298532010-03-10 15:20:55 -08001610 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 }
1612}
1613
1614static void seek_floppy(void)
1615{
1616 int track;
1617
1618 blind_seek = 0;
1619
Joe Perches87f530d2010-03-10 15:20:54 -08001620 debug_dcl(DP->flags, "calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Joe Perchese0298532010-03-10 15:20:55 -08001622 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1624 /* the media changed flag should be cleared after the seek.
1625 * If it isn't, this means that there is really no disk in
1626 * the drive.
1627 */
Joe Perchese0298532010-03-10 15:20:55 -08001628 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 cont->done(0);
1630 cont->redo();
1631 return;
1632 }
1633 if (DRS->track <= NEED_1_RECAL) {
1634 recalibrate_floppy();
1635 return;
Joe Perchese0298532010-03-10 15:20:55 -08001636 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1638 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1639 /* we seek to clear the media-changed condition. Does anybody
1640 * know a more elegant way, which works on all drives? */
1641 if (raw_cmd->track)
1642 track = raw_cmd->track - 1;
1643 else {
1644 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1645 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1646 blind_seek = 1;
1647 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1648 }
1649 track = 1;
1650 }
1651 } else {
1652 check_wp();
1653 if (raw_cmd->track != DRS->track &&
1654 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1655 track = raw_cmd->track;
1656 else {
1657 setup_rw_floppy();
1658 return;
1659 }
1660 }
1661
1662 do_floppy = seek_interrupt;
1663 output_byte(FD_SEEK);
1664 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001665 if (output_byte(track) < 0) {
1666 reset_fdc();
1667 return;
1668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 debugt("seek command:");
1670}
1671
1672static void recal_interrupt(void)
1673{
1674 debugt("recal interrupt:");
1675 if (inr != 2)
1676 FDCS->reset = 1;
1677 else if (ST0 & ST0_ECE) {
1678 switch (DRS->track) {
1679 case NEED_1_RECAL:
1680 debugt("recal interrupt need 1 recal:");
1681 /* after a second recalibrate, we still haven't
1682 * reached track 0. Probably no drive. Raise an
1683 * error, as failing immediately might upset
1684 * computers possessed by the Devil :-) */
1685 cont->error();
1686 cont->redo();
1687 return;
1688 case NEED_2_RECAL:
1689 debugt("recal interrupt need 2 recal:");
1690 /* If we already did a recalibrate,
1691 * and we are not at track 0, this
1692 * means we have moved. (The only way
1693 * not to move at recalibration is to
1694 * be already at track 0.) Clear the
1695 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001696 debug_dcl(DP->flags,
1697 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
Joe Perchese0298532010-03-10 15:20:55 -08001699 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 DRS->select_date = jiffies;
1701 /* fall through */
1702 default:
1703 debugt("recal interrupt default:");
1704 /* Recalibrate moves the head by at
1705 * most 80 steps. If after one
1706 * recalibrate we don't have reached
1707 * track 0, this might mean that we
1708 * started beyond track 80. Try
1709 * again. */
1710 DRS->track = NEED_1_RECAL;
1711 break;
1712 }
1713 } else
1714 DRS->track = ST1;
1715 floppy_ready();
1716}
1717
1718static void print_result(char *message, int inr)
1719{
1720 int i;
1721
1722 DPRINT("%s ", message);
1723 if (inr >= 0)
1724 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001725 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1726 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727}
1728
1729/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001730irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 int do_print;
1733 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001734 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
1736 lasthandler = handler;
1737 interruptjiffies = jiffies;
1738
1739 f = claim_dma_lock();
1740 fd_disable_dma();
1741 release_dma_lock(f);
1742
1743 floppy_enable_hlt();
1744 do_floppy = NULL;
1745 if (fdc >= N_FDC || FDCS->address == -1) {
1746 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001747 pr_info("DOR0=%x\n", fdc_state[0].dor);
1748 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1749 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 is_alive("bizarre fdc");
1751 return IRQ_NONE;
1752 }
1753
1754 FDCS->reset = 0;
1755 /* We have to clear the reset flag here, because apparently on boxes
1756 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1757 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1758 * emission of the SENSEI's.
1759 * It is OK to emit floppy commands because we are in an interrupt
1760 * handler here, and thus we have to fear no interference of other
1761 * activity.
1762 */
1763
1764 do_print = !handler && print_unex && !initialising;
1765
1766 inr = result();
1767 if (do_print)
1768 print_result("unexpected interrupt", inr);
1769 if (inr == 0) {
1770 int max_sensei = 4;
1771 do {
1772 output_byte(FD_SENSEI);
1773 inr = result();
1774 if (do_print)
1775 print_result("sensei", inr);
1776 max_sensei--;
1777 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1778 && max_sensei);
1779 }
1780 if (!handler) {
1781 FDCS->reset = 1;
1782 return IRQ_NONE;
1783 }
1784 schedule_bh(handler);
1785 is_alive("normal interrupt end");
1786
1787 /* FIXME! Was it really for us? */
1788 return IRQ_HANDLED;
1789}
1790
1791static void recalibrate_floppy(void)
1792{
1793 debugt("recalibrate floppy:");
1794 do_floppy = recal_interrupt;
1795 output_byte(FD_RECALIBRATE);
Joe Perches2300f902010-03-10 15:20:49 -08001796 if (output_byte(UNIT(current_drive)) < 0) {
1797 reset_fdc();
1798 return;
1799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800}
1801
1802/*
1803 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1804 */
1805static void reset_interrupt(void)
1806{
1807 debugt("reset interrupt:");
1808 result(); /* get the status ready for set_fdc */
1809 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001810 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 cont->error(); /* a reset just after a reset. BAD! */
1812 }
1813 cont->redo();
1814}
1815
1816/*
1817 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1818 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1819 */
1820static void reset_fdc(void)
1821{
1822 unsigned long flags;
1823
1824 do_floppy = reset_interrupt;
1825 FDCS->reset = 0;
1826 reset_fdc_info(0);
1827
1828 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1829 /* Irrelevant for systems with true DMA (i386). */
1830
1831 flags = claim_dma_lock();
1832 fd_disable_dma();
1833 release_dma_lock(flags);
1834
1835 if (FDCS->version >= FDC_82072A)
1836 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1837 else {
1838 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1839 udelay(FD_RESET_DELAY);
1840 fd_outb(FDCS->dor, FD_DOR);
1841 }
1842}
1843
1844static void show_floppy(void)
1845{
1846 int i;
1847
Joe Perchesb46df352010-03-10 15:20:46 -08001848 pr_info("\n");
1849 pr_info("floppy driver state\n");
1850 pr_info("-------------------\n");
1851 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1852 jiffies, interruptjiffies, jiffies - interruptjiffies,
1853 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
1855#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001856 pr_info("timeout_message=%s\n", timeout_message);
1857 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001859 pr_info("%2x %2x %lu\n",
1860 output_log[(i + output_log_pos) % OLOGSIZE].data,
1861 output_log[(i + output_log_pos) % OLOGSIZE].status,
1862 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1863 pr_info("last result at %lu\n", resultjiffies);
1864 pr_info("last redo_fd_request at %lu\n", lastredo);
1865 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1866 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867#endif
1868
Joe Perchesb46df352010-03-10 15:20:46 -08001869 pr_info("status=%x\n", fd_inb(FD_STATUS));
1870 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001872 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001873 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001874 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001876 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001878 pr_info("timer_function=%p\n", fd_timeout.function);
1879 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1880 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 }
Joe Perchesb46df352010-03-10 15:20:46 -08001882 pr_info("cont=%p\n", cont);
1883 pr_info("current_req=%p\n", current_req);
1884 pr_info("command_status=%d\n", command_status);
1885 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886}
1887
1888static void floppy_shutdown(unsigned long data)
1889{
1890 unsigned long flags;
1891
1892 if (!initialising)
1893 show_floppy();
1894 cancel_activity();
1895
1896 floppy_enable_hlt();
1897
1898 flags = claim_dma_lock();
1899 fd_disable_dma();
1900 release_dma_lock(flags);
1901
1902 /* avoid dma going to a random drive after shutdown */
1903
1904 if (!initialising)
1905 DPRINT("floppy timeout called\n");
1906 FDCS->reset = 1;
1907 if (cont) {
1908 cont->done(0);
1909 cont->redo(); /* this will recall reset when needed */
1910 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001911 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 process_fd_request();
1913 }
1914 is_alive("floppy shutdown");
1915}
1916
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001918static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001920 int mask;
1921 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
1923 mask = 0xfc;
1924 data = UNIT(current_drive);
1925 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1926 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1927 set_debugt();
1928 /* no read since this drive is running */
1929 DRS->first_read_date = 0;
1930 /* note motor start time if motor is not yet running */
1931 DRS->spinup_date = jiffies;
1932 data |= (0x10 << UNIT(current_drive));
1933 }
1934 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1935 mask &= ~(0x10 << UNIT(current_drive));
1936
1937 /* starts motor and selects floppy */
1938 del_timer(motor_off_timer + current_drive);
1939 set_dor(fdc, mask, data);
1940
1941 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001942 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1943 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944}
1945
1946static void floppy_ready(void)
1947{
Joe Perches045f9832010-03-10 15:20:47 -08001948 if (FDCS->reset) {
1949 reset_fdc();
1950 return;
1951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 if (start_motor(floppy_ready))
1953 return;
1954 if (fdc_dtr())
1955 return;
1956
Joe Perches87f530d2010-03-10 15:20:54 -08001957 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1959 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001960 twaddle(); /* this clears the dcl on certain
1961 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962
1963#ifdef fd_chose_dma_mode
1964 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1965 unsigned long flags = claim_dma_lock();
1966 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1967 release_dma_lock(flags);
1968 }
1969#endif
1970
1971 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1972 perpendicular_mode();
1973 fdc_specify(); /* must be done here because of hut, hlt ... */
1974 seek_floppy();
1975 } else {
1976 if ((raw_cmd->flags & FD_RAW_READ) ||
1977 (raw_cmd->flags & FD_RAW_WRITE))
1978 fdc_specify();
1979 setup_rw_floppy();
1980 }
1981}
1982
1983static void floppy_start(void)
1984{
1985 reschedule_timeout(current_reqD, "floppy start", 0);
1986
1987 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001988 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001989 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 floppy_ready();
1991}
1992
1993/*
1994 * ========================================================================
1995 * here ends the bottom half. Exported routines are:
1996 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1997 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1998 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1999 * and set_dor.
2000 * ========================================================================
2001 */
2002/*
2003 * General purpose continuations.
2004 * ==============================
2005 */
2006
2007static void do_wakeup(void)
2008{
2009 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2010 cont = NULL;
2011 command_status += 2;
2012 wake_up(&command_done);
2013}
2014
2015static struct cont_t wakeup_cont = {
2016 .interrupt = empty,
2017 .redo = do_wakeup,
2018 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002019 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020};
2021
2022static struct cont_t intr_cont = {
2023 .interrupt = empty,
2024 .redo = process_fd_request,
2025 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002026 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027};
2028
Jesper Juhl06f748c2007-10-16 23:30:57 -07002029static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030{
2031 int ret;
2032
2033 schedule_bh(handler);
2034
2035 if (command_status < 2 && NO_SIGNAL) {
2036 DECLARE_WAITQUEUE(wait, current);
2037
2038 add_wait_queue(&command_done, &wait);
2039 for (;;) {
2040 set_current_state(interruptible ?
2041 TASK_INTERRUPTIBLE :
2042 TASK_UNINTERRUPTIBLE);
2043
2044 if (command_status >= 2 || !NO_SIGNAL)
2045 break;
2046
2047 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 schedule();
2049 }
2050
2051 set_current_state(TASK_RUNNING);
2052 remove_wait_queue(&command_done, &wait);
2053 }
2054
2055 if (command_status < 2) {
2056 cancel_activity();
2057 cont = &intr_cont;
2058 reset_fdc();
2059 return -EINTR;
2060 }
2061
2062 if (FDCS->reset)
2063 command_status = FD_COMMAND_ERROR;
2064 if (command_status == FD_COMMAND_OKAY)
2065 ret = 0;
2066 else
2067 ret = -EIO;
2068 command_status = FD_COMMAND_NONE;
2069 return ret;
2070}
2071
2072static void generic_done(int result)
2073{
2074 command_status = result;
2075 cont = &wakeup_cont;
2076}
2077
2078static void generic_success(void)
2079{
2080 cont->done(1);
2081}
2082
2083static void generic_failure(void)
2084{
2085 cont->done(0);
2086}
2087
2088static void success_and_wakeup(void)
2089{
2090 generic_success();
2091 cont->redo();
2092}
2093
2094/*
2095 * formatting and rw support.
2096 * ==========================
2097 */
2098
2099static int next_valid_format(void)
2100{
2101 int probed_format;
2102
2103 probed_format = DRS->probed_format;
2104 while (1) {
2105 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2106 DRS->probed_format = 0;
2107 return 1;
2108 }
2109 if (floppy_type[DP->autodetect[probed_format]].sect) {
2110 DRS->probed_format = probed_format;
2111 return 0;
2112 }
2113 probed_format++;
2114 }
2115}
2116
2117static void bad_flp_intr(void)
2118{
2119 int err_count;
2120
2121 if (probing) {
2122 DRS->probed_format++;
2123 if (!next_valid_format())
2124 return;
2125 }
2126 err_count = ++(*errors);
2127 INFBOUND(DRWE->badness, err_count);
2128 if (err_count > DP->max_errors.abort)
2129 cont->done(0);
2130 if (err_count > DP->max_errors.reset)
2131 FDCS->reset = 1;
2132 else if (err_count > DP->max_errors.recal)
2133 DRS->track = NEED_2_RECAL;
2134}
2135
2136static void set_floppy(int drive)
2137{
2138 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002139
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 if (type)
2141 _floppy = floppy_type + type;
2142 else
2143 _floppy = current_type[drive];
2144}
2145
2146/*
2147 * formatting support.
2148 * ===================
2149 */
2150static void format_interrupt(void)
2151{
2152 switch (interpret_errors()) {
2153 case 1:
2154 cont->error();
2155 case 2:
2156 break;
2157 case 0:
2158 cont->done(1);
2159 }
2160 cont->redo();
2161}
2162
2163#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002164#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002166
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167static void setup_format_params(int track)
2168{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002169 int n;
2170 int il;
2171 int count;
2172 int head_shift;
2173 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 struct fparm {
2175 unsigned char track, head, sect, size;
2176 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
2178 raw_cmd = &default_raw_cmd;
2179 raw_cmd->track = track;
2180
Joe Perches48c8cee2010-03-10 15:20:45 -08002181 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2182 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 raw_cmd->rate = _floppy->rate & 0x43;
2184 raw_cmd->cmd_count = NR_F;
2185 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2186 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2187 F_SIZECODE = FD_SIZECODE(_floppy);
2188 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2189 F_GAP = _floppy->fmt_gap;
2190 F_FILL = FD_FILL_BYTE;
2191
2192 raw_cmd->kernel_data = floppy_track_buffer;
2193 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2194
2195 /* allow for about 30ms for data transport per track */
2196 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2197
2198 /* a ``cylinder'' is two tracks plus a little stepping time */
2199 track_shift = 2 * head_shift + 3;
2200
2201 /* position of logical sector 1 on this track */
2202 n = (track_shift * format_req.track + head_shift * format_req.head)
2203 % F_SECT_PER_TRACK;
2204
2205 /* determine interleave */
2206 il = 1;
2207 if (_floppy->fmt_gap < 0x22)
2208 il++;
2209
2210 /* initialize field */
2211 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2212 here[count].track = format_req.track;
2213 here[count].head = format_req.head;
2214 here[count].sect = 0;
2215 here[count].size = F_SIZECODE;
2216 }
2217 /* place logical sectors */
2218 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2219 here[n].sect = count;
2220 n = (n + il) % F_SECT_PER_TRACK;
2221 if (here[n].sect) { /* sector busy, find next free sector */
2222 ++n;
2223 if (n >= F_SECT_PER_TRACK) {
2224 n -= F_SECT_PER_TRACK;
2225 while (here[n].sect)
2226 ++n;
2227 }
2228 }
2229 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002230 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002232 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 }
2234}
2235
2236static void redo_format(void)
2237{
2238 buffer_track = -1;
2239 setup_format_params(format_req.track << STRETCH(_floppy));
2240 floppy_start();
2241 debugt("queue format request");
2242}
2243
2244static struct cont_t format_cont = {
2245 .interrupt = format_interrupt,
2246 .redo = redo_format,
2247 .error = bad_flp_intr,
2248 .done = generic_done
2249};
2250
2251static int do_format(int drive, struct format_descr *tmp_format_req)
2252{
2253 int ret;
2254
Joe Perches52a0d612010-03-10 15:20:53 -08002255 if (lock_fdc(drive, 1))
2256 return -EINTR;
2257
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 set_floppy(drive);
2259 if (!_floppy ||
2260 _floppy->track > DP->tracks ||
2261 tmp_format_req->track >= _floppy->track ||
2262 tmp_format_req->head >= _floppy->head ||
2263 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2264 !_floppy->fmt_gap) {
2265 process_fd_request();
2266 return -EINVAL;
2267 }
2268 format_req = *tmp_format_req;
2269 format_errors = 0;
2270 cont = &format_cont;
2271 errors = &format_errors;
2272 IWAIT(redo_format);
2273 process_fd_request();
2274 return ret;
2275}
2276
2277/*
2278 * Buffer read/write and support
2279 * =============================
2280 */
2281
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002282static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283{
2284 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002285 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
2287 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002288 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002289 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002290 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
2293 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002294 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 current_req = NULL;
2296}
2297
2298/* new request_done. Can handle physical sectors which are smaller than a
2299 * logical buffer */
2300static void request_done(int uptodate)
2301{
2302 struct request_queue *q = floppy_queue;
2303 struct request *req = current_req;
2304 unsigned long flags;
2305 int block;
2306
2307 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002308 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
2310 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002311 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 return;
2313 }
2314
2315 if (uptodate) {
2316 /* maintain values for invalidation on geometry
2317 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002318 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 INFBOUND(DRS->maxblock, block);
2320 if (block > _floppy->sect)
2321 DRS->maxtrack = 1;
2322
2323 /* unlock chained buffers */
2324 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002325 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 spin_unlock_irqrestore(q->queue_lock, flags);
2327 } else {
2328 if (rq_data_dir(req) == WRITE) {
2329 /* record write error information */
2330 DRWE->write_errors++;
2331 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002332 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 DRWE->first_error_generation = DRS->generation;
2334 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002335 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 DRWE->last_error_generation = DRS->generation;
2337 }
2338 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002339 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 spin_unlock_irqrestore(q->queue_lock, flags);
2341 }
2342}
2343
2344/* Interrupt handler evaluating the result of the r/w operation */
2345static void rw_interrupt(void)
2346{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002347 int eoc;
2348 int ssize;
2349 int heads;
2350 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
2352 if (R_HEAD >= 2) {
2353 /* some Toshiba floppy controllers occasionnally seem to
2354 * return bogus interrupts after read/write operations, which
2355 * can be recognized by a bad head number (>= 2) */
2356 return;
2357 }
2358
2359 if (!DRS->first_read_date)
2360 DRS->first_read_date = jiffies;
2361
2362 nr_sectors = 0;
2363 CODE2SIZE;
2364
2365 if (ST1 & ST1_EOC)
2366 eoc = 1;
2367 else
2368 eoc = 0;
2369
2370 if (COMMAND & 0x80)
2371 heads = 2;
2372 else
2373 heads = 1;
2374
2375 nr_sectors = (((R_TRACK - TRACK) * heads +
2376 R_HEAD - HEAD) * SECT_PER_TRACK +
2377 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2378
2379#ifdef FLOPPY_SANITY_CHECK
2380 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002381 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 DPRINT("long rw: %x instead of %lx\n",
2383 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002384 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2385 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2386 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2387 pr_info("heads=%d eoc=%d\n", heads, eoc);
2388 pr_info("spt=%d st=%d ss=%d\n",
2389 SECT_PER_TRACK, fsector_t, ssize);
2390 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 }
2392#endif
2393
2394 nr_sectors -= in_sector_offset;
2395 INFBOUND(nr_sectors, 0);
2396 SUPBOUND(current_count_sectors, nr_sectors);
2397
2398 switch (interpret_errors()) {
2399 case 2:
2400 cont->redo();
2401 return;
2402 case 1:
2403 if (!current_count_sectors) {
2404 cont->error();
2405 cont->redo();
2406 return;
2407 }
2408 break;
2409 case 0:
2410 if (!current_count_sectors) {
2411 cont->redo();
2412 return;
2413 }
2414 current_type[current_drive] = _floppy;
2415 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2416 break;
2417 }
2418
2419 if (probing) {
2420 if (DP->flags & FTD_MSG)
2421 DPRINT("Auto-detected floppy type %s in fd%d\n",
2422 _floppy->name, current_drive);
2423 current_type[current_drive] = _floppy;
2424 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2425 probing = 0;
2426 }
2427
2428 if (CT(COMMAND) != FD_READ ||
2429 raw_cmd->kernel_data == current_req->buffer) {
2430 /* transfer directly from buffer */
2431 cont->done(1);
2432 } else if (CT(COMMAND) == FD_READ) {
2433 buffer_track = raw_cmd->track;
2434 buffer_drive = current_drive;
2435 INFBOUND(buffer_max, nr_sectors + fsector_t);
2436 }
2437 cont->redo();
2438}
2439
2440/* Compute maximal contiguous buffer size. */
2441static int buffer_chain_size(void)
2442{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002444 int size;
2445 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 char *base;
2447
2448 base = bio_data(current_req->bio);
2449 size = 0;
2450
NeilBrown5705f702007-09-25 12:35:59 +02002451 rq_for_each_segment(bv, current_req, iter) {
2452 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2453 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
NeilBrown5705f702007-09-25 12:35:59 +02002455 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 }
2457
2458 return size >> 9;
2459}
2460
2461/* Compute the maximal transfer size */
2462static int transfer_size(int ssize, int max_sector, int max_size)
2463{
2464 SUPBOUND(max_sector, fsector_t + max_size);
2465
2466 /* alignment */
2467 max_sector -= (max_sector % _floppy->sect) % ssize;
2468
2469 /* transfer size, beginning not aligned */
2470 current_count_sectors = max_sector - fsector_t;
2471
2472 return max_sector;
2473}
2474
2475/*
2476 * Move data from/to the track buffer to/from the buffer cache.
2477 */
2478static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2479{
2480 int remaining; /* number of transferred 512-byte sectors */
2481 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002482 char *buffer;
2483 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002484 int size;
2485 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
2487 max_sector = transfer_size(ssize,
2488 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002489 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
2491 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002492 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002494 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
2496 remaining = current_count_sectors << 9;
2497#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002498 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002500 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2501 pr_info("remaining=%d\n", remaining >> 9);
2502 pr_info("current_req->nr_sectors=%u\n",
2503 blk_rq_sectors(current_req));
2504 pr_info("current_req->current_nr_sectors=%u\n",
2505 blk_rq_cur_sectors(current_req));
2506 pr_info("max_sector=%d\n", max_sector);
2507 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 }
2509#endif
2510
2511 buffer_max = max(max_sector, buffer_max);
2512
2513 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2514
Tejun Heo1011c1b2009-05-07 22:24:45 +09002515 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516
NeilBrown5705f702007-09-25 12:35:59 +02002517 rq_for_each_segment(bv, current_req, iter) {
2518 if (!remaining)
2519 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
NeilBrown5705f702007-09-25 12:35:59 +02002521 size = bv->bv_len;
2522 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
NeilBrown5705f702007-09-25 12:35:59 +02002524 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002526 if (dma_buffer + size >
2527 floppy_track_buffer + (max_buffer_sectors << 10) ||
2528 dma_buffer < floppy_track_buffer) {
2529 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002530 (int)((floppy_track_buffer - dma_buffer) >> 9));
2531 pr_info("fsector_t=%d buffer_min=%d\n",
2532 fsector_t, buffer_min);
2533 pr_info("current_count_sectors=%ld\n",
2534 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002536 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002537 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002538 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 }
NeilBrown5705f702007-09-25 12:35:59 +02002541 if (((unsigned long)buffer) % 512)
2542 DPRINT("%p buffer not aligned\n", buffer);
2543#endif
2544 if (CT(COMMAND) == FD_READ)
2545 memcpy(buffer, dma_buffer, size);
2546 else
2547 memcpy(dma_buffer, buffer, size);
2548
2549 remaining -= size;
2550 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 }
2552#ifdef FLOPPY_SANITY_CHECK
2553 if (remaining) {
2554 if (remaining > 0)
2555 max_sector -= remaining >> 9;
2556 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2557 }
2558#endif
2559}
2560
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561/* work around a bug in pseudo DMA
2562 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2563 * sending data. Hence we need a different way to signal the
2564 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2565 * does not work with MT, hence we can only transfer one head at
2566 * a time
2567 */
2568static void virtualdmabug_workaround(void)
2569{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002570 int hard_sectors;
2571 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
2573 if (CT(COMMAND) == FD_WRITE) {
2574 COMMAND &= ~0x80; /* switch off multiple track mode */
2575
2576 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2577 end_sector = SECTOR + hard_sectors - 1;
2578#ifdef FLOPPY_SANITY_CHECK
2579 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002580 pr_info("too many sectors %d > %d\n",
2581 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 return;
2583 }
2584#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002585 SECT_PER_TRACK = end_sector;
2586 /* make sure SECT_PER_TRACK
2587 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 }
2589}
2590
2591/*
2592 * Formulate a read/write request.
2593 * this routine decides where to load the data (directly to buffer, or to
2594 * tmp floppy area), how much data to load (the size of the buffer, the whole
2595 * track, or a single sector)
2596 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2597 * allocation on the fly, it should be done here. No other part should need
2598 * modification.
2599 */
2600
2601static int make_raw_rw_request(void)
2602{
2603 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002604 int max_sector;
2605 int max_size;
2606 int tracksize;
2607 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608
2609 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002610 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 return 0;
2612 }
2613
2614 set_fdc((long)current_req->rq_disk->private_data);
2615
2616 raw_cmd = &default_raw_cmd;
2617 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2618 FD_RAW_NEED_SEEK;
2619 raw_cmd->cmd_count = NR_RW;
2620 if (rq_data_dir(current_req) == READ) {
2621 raw_cmd->flags |= FD_RAW_READ;
2622 COMMAND = FM_MODE(_floppy, FD_READ);
2623 } else if (rq_data_dir(current_req) == WRITE) {
2624 raw_cmd->flags |= FD_RAW_WRITE;
2625 COMMAND = FM_MODE(_floppy, FD_WRITE);
2626 } else {
2627 DPRINT("make_raw_rw_request: unknown command\n");
2628 return 0;
2629 }
2630
2631 max_sector = _floppy->sect * _floppy->head;
2632
Tejun Heo83096eb2009-05-07 22:24:39 +09002633 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2634 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002636 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 current_count_sectors = 1;
2638 return 1;
2639 } else
2640 return 0;
2641 }
2642 HEAD = fsector_t / _floppy->sect;
2643
Keith Wansbrough9e491842008-09-22 14:57:17 -07002644 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002645 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2646 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 max_sector = _floppy->sect;
2648
2649 /* 2M disks have phantom sectors on the first track */
2650 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2651 max_sector = 2 * _floppy->sect / 3;
2652 if (fsector_t >= max_sector) {
2653 current_count_sectors =
2654 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002655 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 return 1;
2657 }
2658 SIZECODE = 2;
2659 } else
2660 SIZECODE = FD_SIZECODE(_floppy);
2661 raw_cmd->rate = _floppy->rate & 0x43;
2662 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2663 raw_cmd->rate = 1;
2664
2665 if (SIZECODE)
2666 SIZECODE2 = 0xff;
2667 else
2668 SIZECODE2 = 0x80;
2669 raw_cmd->track = TRACK << STRETCH(_floppy);
2670 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2671 GAP = _floppy->gap;
2672 CODE2SIZE;
2673 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2674 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002675 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676
2677 /* tracksize describes the size which can be filled up with sectors
2678 * of size ssize.
2679 */
2680 tracksize = _floppy->sect - _floppy->sect % ssize;
2681 if (tracksize < _floppy->sect) {
2682 SECT_PER_TRACK++;
2683 if (tracksize <= fsector_t % _floppy->sect)
2684 SECTOR--;
2685
2686 /* if we are beyond tracksize, fill up using smaller sectors */
2687 while (tracksize <= fsector_t % _floppy->sect) {
2688 while (tracksize + ssize > _floppy->sect) {
2689 SIZECODE--;
2690 ssize >>= 1;
2691 }
2692 SECTOR++;
2693 SECT_PER_TRACK++;
2694 tracksize += ssize;
2695 }
2696 max_sector = HEAD * _floppy->sect + tracksize;
2697 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2698 max_sector = _floppy->sect;
2699 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2700 /* for virtual DMA bug workaround */
2701 max_sector = _floppy->sect;
2702 }
2703
2704 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2705 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002706 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 if ((raw_cmd->track == buffer_track) &&
2708 (current_drive == buffer_drive) &&
2709 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2710 /* data already in track buffer */
2711 if (CT(COMMAND) == FD_READ) {
2712 copy_buffer(1, max_sector, buffer_max);
2713 return 1;
2714 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002715 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002717 unsigned int sectors;
2718
2719 sectors = fsector_t + blk_rq_sectors(current_req);
2720 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 max_size = ssize + ssize;
2722 else
2723 max_size = ssize;
2724 }
2725 raw_cmd->flags &= ~FD_RAW_WRITE;
2726 raw_cmd->flags |= FD_RAW_READ;
2727 COMMAND = FM_MODE(_floppy, FD_READ);
2728 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2729 unsigned long dma_limit;
2730 int direct, indirect;
2731
2732 indirect =
2733 transfer_size(ssize, max_sector,
2734 max_buffer_sectors * 2) - fsector_t;
2735
2736 /*
2737 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2738 * on a 64 bit machine!
2739 */
2740 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002741 dma_limit = (MAX_DMA_ADDRESS -
2742 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002743 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 /* 64 kb boundaries */
2746 if (CROSS_64KB(current_req->buffer, max_size << 9))
2747 max_size = (K_64 -
2748 ((unsigned long)current_req->buffer) %
2749 K_64) >> 9;
2750 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2751 /*
2752 * We try to read tracks, but if we get too many errors, we
2753 * go back to reading just one sector at a time.
2754 *
2755 * This means we should be able to read a sector even if there
2756 * are other bad sectors on this track.
2757 */
2758 if (!direct ||
2759 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002760 *errors < DP->max_errors.read_track &&
2761 ((!probing ||
2762 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002763 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 } else {
2765 raw_cmd->kernel_data = current_req->buffer;
2766 raw_cmd->length = current_count_sectors << 9;
2767 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002768 DPRINT("zero dma transfer attempted from make_raw_request\n");
2769 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 indirect, direct, fsector_t);
2771 return 0;
2772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 virtualdmabug_workaround();
2774 return 2;
2775 }
2776 }
2777
2778 if (CT(COMMAND) == FD_READ)
2779 max_size = max_sector; /* unbounded */
2780
2781 /* claim buffer track if needed */
2782 if (buffer_track != raw_cmd->track || /* bad track */
2783 buffer_drive != current_drive || /* bad drive */
2784 fsector_t > buffer_max ||
2785 fsector_t < buffer_min ||
2786 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002787 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002789 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2790 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 buffer_track = -1;
2792 buffer_drive = current_drive;
2793 buffer_max = buffer_min = aligned_sector_t;
2794 }
2795 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002796 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797
2798 if (CT(COMMAND) == FD_WRITE) {
2799 /* copy write buffer to track buffer.
2800 * if we get here, we know that the write
2801 * is either aligned or the data already in the buffer
2802 * (buffer will be overwritten) */
2803#ifdef FLOPPY_SANITY_CHECK
2804 if (in_sector_offset && buffer_track == -1)
2805 DPRINT("internal error offset !=0 on write\n");
2806#endif
2807 buffer_track = raw_cmd->track;
2808 buffer_drive = current_drive;
2809 copy_buffer(ssize, max_sector,
2810 2 * max_buffer_sectors + buffer_min);
2811 } else
2812 transfer_size(ssize, max_sector,
2813 2 * max_buffer_sectors + buffer_min -
2814 aligned_sector_t);
2815
2816 /* round up current_count_sectors to get dma xfer size */
2817 raw_cmd->length = in_sector_offset + current_count_sectors;
2818 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2819 raw_cmd->length <<= 9;
2820#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 if ((raw_cmd->length < current_count_sectors << 9) ||
2822 (raw_cmd->kernel_data != current_req->buffer &&
2823 CT(COMMAND) == FD_WRITE &&
2824 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2825 aligned_sector_t < buffer_min)) ||
2826 raw_cmd->length % (128 << SIZECODE) ||
2827 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2828 DPRINT("fractionary current count b=%lx s=%lx\n",
2829 raw_cmd->length, current_count_sectors);
2830 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002831 pr_info("addr=%d, length=%ld\n",
2832 (int)((raw_cmd->kernel_data -
2833 floppy_track_buffer) >> 9),
2834 current_count_sectors);
2835 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2836 fsector_t, aligned_sector_t, max_sector, max_size);
2837 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2838 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2839 COMMAND, SECTOR, HEAD, TRACK);
2840 pr_info("buffer drive=%d\n", buffer_drive);
2841 pr_info("buffer track=%d\n", buffer_track);
2842 pr_info("buffer_min=%d\n", buffer_min);
2843 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 return 0;
2845 }
2846
2847 if (raw_cmd->kernel_data != current_req->buffer) {
2848 if (raw_cmd->kernel_data < floppy_track_buffer ||
2849 current_count_sectors < 0 ||
2850 raw_cmd->length < 0 ||
2851 raw_cmd->kernel_data + raw_cmd->length >
2852 floppy_track_buffer + (max_buffer_sectors << 10)) {
2853 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002854 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2855 fsector_t, buffer_min, raw_cmd->length >> 9);
2856 pr_info("current_count_sectors=%ld\n",
2857 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002859 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002861 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 return 0;
2863 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002864 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002865 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 DPRINT("buffer overrun in direct transfer\n");
2867 return 0;
2868 } else if (raw_cmd->length < current_count_sectors << 9) {
2869 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002870 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2871 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 }
2873 if (raw_cmd->length == 0) {
2874 DPRINT("zero dma transfer attempted from make_raw_request\n");
2875 return 0;
2876 }
2877#endif
2878
2879 virtualdmabug_workaround();
2880 return 2;
2881}
2882
2883static void redo_fd_request(void)
2884{
2885#define REPEAT {request_done(0); continue; }
2886 int drive;
2887 int tmp;
2888
2889 lastredo = jiffies;
2890 if (current_drive < N_DRIVE)
2891 floppy_off(current_drive);
2892
2893 for (;;) {
2894 if (!current_req) {
2895 struct request *req;
2896
2897 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002898 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 spin_unlock_irq(floppy_queue->queue_lock);
2900 if (!req) {
2901 do_floppy = NULL;
2902 unlock_fdc();
2903 return;
2904 }
2905 current_req = req;
2906 }
2907 drive = (long)current_req->rq_disk->private_data;
2908 set_fdc(drive);
2909 reschedule_timeout(current_reqD, "redo fd request", 0);
2910
2911 set_floppy(drive);
2912 raw_cmd = &default_raw_cmd;
2913 raw_cmd->flags = 0;
2914 if (start_motor(redo_fd_request))
2915 return;
2916 disk_change(current_drive);
2917 if (test_bit(current_drive, &fake_change) ||
Joe Perchese0298532010-03-10 15:20:55 -08002918 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 DPRINT("disk absent or changed during operation\n");
2920 REPEAT;
2921 }
2922 if (!_floppy) { /* Autodetection */
2923 if (!probing) {
2924 DRS->probed_format = 0;
2925 if (next_valid_format()) {
2926 DPRINT("no autodetectable formats\n");
2927 _floppy = NULL;
2928 REPEAT;
2929 }
2930 }
2931 probing = 1;
2932 _floppy =
2933 floppy_type + DP->autodetect[DRS->probed_format];
2934 } else
2935 probing = 0;
2936 errors = &(current_req->errors);
2937 tmp = make_raw_rw_request();
2938 if (tmp < 2) {
2939 request_done(tmp);
2940 continue;
2941 }
2942
Joe Perchese0298532010-03-10 15:20:55 -08002943 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 twaddle();
2945 schedule_bh(floppy_start);
2946 debugt("queue fd request");
2947 return;
2948 }
2949#undef REPEAT
2950}
2951
2952static struct cont_t rw_cont = {
2953 .interrupt = rw_interrupt,
2954 .redo = redo_fd_request,
2955 .error = bad_flp_intr,
2956 .done = request_done
2957};
2958
2959static void process_fd_request(void)
2960{
2961 cont = &rw_cont;
2962 schedule_bh(redo_fd_request);
2963}
2964
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002965static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966{
2967 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002968 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 return;
2970 }
2971
2972 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002973 pr_info("warning: usage count=0, current_req=%p exiting\n",
2974 current_req);
2975 pr_info("sect=%ld type=%x flags=%x\n",
2976 (long)blk_rq_pos(current_req), current_req->cmd_type,
2977 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 return;
2979 }
2980 if (test_bit(0, &fdc_busy)) {
2981 /* fdc busy, this new request will be treated when the
2982 current one is done */
2983 is_alive("do fd request, old request running");
2984 return;
2985 }
2986 lock_fdc(MAXTIMEOUT, 0);
2987 process_fd_request();
2988 is_alive("do fd request");
2989}
2990
2991static struct cont_t poll_cont = {
2992 .interrupt = success_and_wakeup,
2993 .redo = floppy_ready,
2994 .error = generic_failure,
2995 .done = generic_done
2996};
2997
2998static int poll_drive(int interruptible, int flag)
2999{
3000 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 WAIT(floppy_ready);
3011 return ret;
3012}
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
3031static int user_reset_fdc(int drive, int arg, int interruptible)
3032{
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;
3042 WAIT(reset_fdc);
3043 }
3044 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003045 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046}
3047
3048/*
3049 * Misc Ioctl's and support
3050 * ========================
3051 */
3052static inline int fd_copyout(void __user *param, const void *address,
3053 unsigned long size)
3054{
3055 return copy_to_user(param, address, size) ? -EFAULT : 0;
3056}
3057
Joe Perches48c8cee2010-03-10 15:20:45 -08003058static inline int fd_copyin(void __user *param, void *address,
3059 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060{
3061 return copy_from_user(address, param, size) ? -EFAULT : 0;
3062}
3063
Joe Perches48c8cee2010-03-10 15:20:45 -08003064#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3065 ? -EFAULT : 0)
3066#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3067 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
Joe Perches48c8cee2010-03-10 15:20:45 -08003069#define COPYOUT(x) ECALL(_COPYOUT(x))
3070#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071
3072static inline const char *drive_name(int type, int drive)
3073{
3074 struct floppy_struct *floppy;
3075
3076 if (type)
3077 floppy = floppy_type + type;
3078 else {
3079 if (UDP->native_format)
3080 floppy = floppy_type + UDP->native_format;
3081 else
3082 return "(null)";
3083 }
3084 if (floppy->name)
3085 return floppy->name;
3086 else
3087 return "(null)";
3088}
3089
3090/* raw commands */
3091static void raw_cmd_done(int flag)
3092{
3093 int i;
3094
3095 if (!flag) {
3096 raw_cmd->flags |= FD_RAW_FAILURE;
3097 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3098 } else {
3099 raw_cmd->reply_count = inr;
3100 if (raw_cmd->reply_count > MAX_REPLIES)
3101 raw_cmd->reply_count = 0;
3102 for (i = 0; i < raw_cmd->reply_count; i++)
3103 raw_cmd->reply[i] = reply_buffer[i];
3104
3105 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3106 unsigned long flags;
3107 flags = claim_dma_lock();
3108 raw_cmd->length = fd_get_dma_residue();
3109 release_dma_lock(flags);
3110 }
3111
3112 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3113 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3114 raw_cmd->flags |= FD_RAW_FAILURE;
3115
3116 if (disk_change(current_drive))
3117 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3118 else
3119 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3120 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3121 motor_off_callback(current_drive);
3122
3123 if (raw_cmd->next &&
3124 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3125 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3126 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3127 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3128 raw_cmd = raw_cmd->next;
3129 return;
3130 }
3131 }
3132 generic_done(flag);
3133}
3134
3135static struct cont_t raw_cmd_cont = {
3136 .interrupt = success_and_wakeup,
3137 .redo = floppy_start,
3138 .error = generic_failure,
3139 .done = raw_cmd_done
3140};
3141
3142static inline int raw_cmd_copyout(int cmd, char __user *param,
3143 struct floppy_raw_cmd *ptr)
3144{
3145 int ret;
3146
3147 while (ptr) {
3148 COPYOUT(*ptr);
3149 param += sizeof(struct floppy_raw_cmd);
3150 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003151 if (ptr->length >= 0 &&
3152 ptr->length <= ptr->buffer_length) {
3153 long length = ptr->buffer_length - ptr->length;
3154 ECALL(fd_copyout(ptr->data, ptr->kernel_data,
3155 length));
3156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 }
3158 ptr = ptr->next;
3159 }
3160 return 0;
3161}
3162
3163static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3164{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003165 struct floppy_raw_cmd *next;
3166 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167
3168 this = *ptr;
3169 *ptr = NULL;
3170 while (this) {
3171 if (this->buffer_length) {
3172 fd_dma_mem_free((unsigned long)this->kernel_data,
3173 this->buffer_length);
3174 this->buffer_length = 0;
3175 }
3176 next = this->next;
3177 kfree(this);
3178 this = next;
3179 }
3180}
3181
3182static inline int raw_cmd_copyin(int cmd, char __user *param,
3183 struct floppy_raw_cmd **rcmd)
3184{
3185 struct floppy_raw_cmd *ptr;
3186 int ret;
3187 int i;
3188
3189 *rcmd = NULL;
3190 while (1) {
3191 ptr = (struct floppy_raw_cmd *)
3192 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3193 if (!ptr)
3194 return -ENOMEM;
3195 *rcmd = ptr;
3196 COPYIN(*ptr);
3197 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 }
3226 if (ptr->flags & FD_RAW_WRITE)
3227 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3228 ptr->length));
3229 rcmd = &(ptr->next);
3230 if (!(ptr->flags & FD_RAW_MORE))
3231 return 0;
3232 ptr->rate &= 0x43;
3233 }
3234}
3235
3236static int raw_cmd_ioctl(int cmd, void __user *param)
3237{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003239 int drive;
3240 int ret2;
3241 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
3243 if (FDCS->rawcmd <= 1)
3244 FDCS->rawcmd = 1;
3245 for (drive = 0; drive < N_DRIVE; drive++) {
3246 if (FDC(drive) != fdc)
3247 continue;
3248 if (drive == current_drive) {
3249 if (UDRS->fd_ref > 1) {
3250 FDCS->rawcmd = 2;
3251 break;
3252 }
3253 } else if (UDRS->fd_ref) {
3254 FDCS->rawcmd = 2;
3255 break;
3256 }
3257 }
3258
3259 if (FDCS->reset)
3260 return -EIO;
3261
3262 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3263 if (ret) {
3264 raw_cmd_free(&my_raw_cmd);
3265 return ret;
3266 }
3267
3268 raw_cmd = my_raw_cmd;
3269 cont = &raw_cmd_cont;
3270 ret = wait_til_done(floppy_start, 1);
Joe Perches87f530d2010-03-10 15:20:54 -08003271 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272
3273 if (ret != -EINTR && FDCS->reset)
3274 ret = -EIO;
3275
3276 DRS->track = NO_TRACK;
3277
3278 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3279 if (!ret)
3280 ret = ret2;
3281 raw_cmd_free(&my_raw_cmd);
3282 return ret;
3283}
3284
3285static int invalidate_drive(struct block_device *bdev)
3286{
3287 /* invalidate the buffer track to force a reread */
3288 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3289 process_fd_request();
3290 check_disk_change(bdev);
3291 return 0;
3292}
3293
3294static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3295 int drive, int type, struct block_device *bdev)
3296{
3297 int cnt;
3298
3299 /* sanity checking for parameters. */
3300 if (g->sect <= 0 ||
3301 g->head <= 0 ||
3302 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3303 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003304 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return -EINVAL;
3306 if (type) {
3307 if (!capable(CAP_SYS_ADMIN))
3308 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003309 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003310 if (lock_fdc(drive, 1)) {
3311 mutex_unlock(&open_lock);
3312 return -EINTR;
3313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 floppy_type[type] = *g;
3315 floppy_type[type].name = "user format";
3316 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3317 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3318 floppy_type[type].size + 1;
3319 process_fd_request();
3320 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3321 struct block_device *bdev = opened_bdev[cnt];
3322 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3323 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003324 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003326 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 } else {
3328 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003329
3330 if (lock_fdc(drive, 1))
3331 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 if (cmd != FDDEFPRM)
3333 /* notice a disk change immediately, else
3334 * we lose our settings immediately*/
3335 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3336 oldStretch = g->stretch;
3337 user_params[drive] = *g;
3338 if (buffer_drive == drive)
3339 SUPBOUND(buffer_max, user_params[drive].sect);
3340 current_type[drive] = &user_params[drive];
3341 floppy_sizes[drive] = user_params[drive].size;
3342 if (cmd == FDDEFPRM)
3343 DRS->keep_data = -1;
3344 else
3345 DRS->keep_data = 1;
3346 /* invalidation. Invalidate only when needed, i.e.
3347 * when there are already sectors in the buffer cache
3348 * whose number will change. This is useful, because
3349 * mtools often changes the geometry of the disk after
3350 * looking at the boot block */
3351 if (DRS->maxblock > user_params[drive].sect ||
3352 DRS->maxtrack ||
3353 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003354 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 invalidate_drive(bdev);
3356 else
3357 process_fd_request();
3358 }
3359 return 0;
3360}
3361
3362/* handle obsolete ioctl's */
3363static int ioctl_table[] = {
3364 FDCLRPRM,
3365 FDSETPRM,
3366 FDDEFPRM,
3367 FDGETPRM,
3368 FDMSGON,
3369 FDMSGOFF,
3370 FDFMTBEG,
3371 FDFMTTRK,
3372 FDFMTEND,
3373 FDSETEMSGTRESH,
3374 FDFLUSH,
3375 FDSETMAXERRS,
3376 FDGETMAXERRS,
3377 FDGETDRVTYP,
3378 FDSETDRVPRM,
3379 FDGETDRVPRM,
3380 FDGETDRVSTAT,
3381 FDPOLLDRVSTAT,
3382 FDRESET,
3383 FDGETFDCSTAT,
3384 FDWERRORCLR,
3385 FDWERRORGET,
3386 FDRAWCMD,
3387 FDEJECT,
3388 FDTWADDLE
3389};
3390
3391static inline int normalize_ioctl(int *cmd, int *size)
3392{
3393 int i;
3394
3395 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3396 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3397 *size = _IOC_SIZE(*cmd);
3398 *cmd = ioctl_table[i];
3399 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003400 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 return -EFAULT;
3402 }
3403 return 0;
3404 }
3405 }
3406 return -EINVAL;
3407}
3408
3409static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3410{
3411 if (type)
3412 *g = &floppy_type[type];
3413 else {
Joe Perches52a0d612010-03-10 15:20:53 -08003414 if (lock_fdc(drive, 0))
3415 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 CALL(poll_drive(0, 0));
3417 process_fd_request();
3418 *g = current_type[drive];
3419 }
3420 if (!*g)
3421 return -ENODEV;
3422 return 0;
3423}
3424
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003425static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3426{
3427 int drive = (long)bdev->bd_disk->private_data;
3428 int type = ITYPE(drive_state[drive].fd_device);
3429 struct floppy_struct *g;
3430 int ret;
3431
3432 ret = get_floppy_geometry(drive, type, &g);
3433 if (ret)
3434 return ret;
3435
3436 geo->heads = g->head;
3437 geo->sectors = g->sect;
3438 geo->cylinders = g->track;
3439 return 0;
3440}
3441
Al Viroa4af9b42008-03-02 09:27:55 -05003442static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 unsigned long param)
3444{
Al Viroa4af9b42008-03-02 09:27:55 -05003445#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
Al Viroa4af9b42008-03-02 09:27:55 -05003447 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003448 int type = ITYPE(UDRS->fd_device);
3449 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 int ret;
3451 int size;
3452 union inparam {
3453 struct floppy_struct g; /* geometry */
3454 struct format_descr f;
3455 struct floppy_max_errors max_errors;
3456 struct floppy_drive_params dp;
3457 } inparam; /* parameters coming from user space */
3458 const char *outparam; /* parameters passed back to user space */
3459
3460 /* convert compatibility eject ioctls into floppy eject ioctl.
3461 * We do this in order to provide a means to eject floppy disks before
3462 * installing the new fdutils package */
3463 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003464 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 DPRINT("obsolete eject ioctl\n");
3466 DPRINT("please use floppycontrol --eject\n");
3467 cmd = FDEJECT;
3468 }
3469
Joe Perchesa81ee542010-03-10 15:20:46 -08003470 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 return -EINVAL;
3472
Joe Perchesa81ee542010-03-10 15:20:46 -08003473 /* convert the old style command into a new style command */
3474 ECALL(normalize_ioctl(&cmd, &size));
3475
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 /* permission checks */
3477 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3478 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3479 return -EPERM;
3480
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003481 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3482 return -EINVAL;
3483
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003485 memset(&inparam, 0, sizeof(inparam));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 if (_IOC_DIR(cmd) & _IOC_WRITE)
Joe Perchesda273652010-03-10 15:20:52 -08003487 ECALL(fd_copyin((void __user *)param, &inparam, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488
Joe Perchesda273652010-03-10 15:20:52 -08003489 switch (cmd) {
3490 case FDEJECT:
3491 if (UDRS->fd_ref != 1)
3492 /* somebody else has this drive open */
3493 return -EBUSY;
Joe Perches52a0d612010-03-10 15:20:53 -08003494 if (lock_fdc(drive, 1))
3495 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496
Joe Perchesda273652010-03-10 15:20:52 -08003497 /* do the actual eject. Fails on
3498 * non-Sparc architectures */
3499 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
Joe Perchese0298532010-03-10 15:20:55 -08003501 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3502 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003503 process_fd_request();
3504 return ret;
3505 case FDCLRPRM:
Joe Perches52a0d612010-03-10 15:20:53 -08003506 if (lock_fdc(drive, 1))
3507 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003508 current_type[drive] = NULL;
3509 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3510 UDRS->keep_data = 0;
3511 return invalidate_drive(bdev);
3512 case FDSETPRM:
3513 case FDDEFPRM:
3514 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3515 case FDGETPRM:
3516 ECALL(get_floppy_geometry(drive, type,
3517 (struct floppy_struct **)
3518 &outparam));
3519 break;
3520 case FDMSGON:
3521 UDP->flags |= FTD_MSG;
3522 return 0;
3523 case FDMSGOFF:
3524 UDP->flags &= ~FTD_MSG;
3525 return 0;
3526 case FDFMTBEG:
Joe Perches52a0d612010-03-10 15:20:53 -08003527 if (lock_fdc(drive, 1))
3528 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003529 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3530 ret = UDRS->flags;
3531 process_fd_request();
3532 if (ret & FD_VERIFY)
3533 return -ENODEV;
3534 if (!(ret & FD_DISK_WRITABLE))
3535 return -EROFS;
3536 return 0;
3537 case FDFMTTRK:
3538 if (UDRS->fd_ref != 1)
3539 return -EBUSY;
3540 return do_format(drive, &inparam.f);
3541 case FDFMTEND:
3542 case FDFLUSH:
Joe Perches52a0d612010-03-10 15:20:53 -08003543 if (lock_fdc(drive, 1))
3544 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003545 return invalidate_drive(bdev);
3546 case FDSETEMSGTRESH:
3547 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3548 return 0;
3549 case FDGETMAXERRS:
3550 outparam = (const char *)&UDP->max_errors;
3551 break;
3552 case FDSETMAXERRS:
3553 UDP->max_errors = inparam.max_errors;
3554 break;
3555 case FDGETDRVTYP:
3556 outparam = drive_name(type, drive);
3557 SUPBOUND(size, strlen(outparam) + 1);
3558 break;
3559 case FDSETDRVPRM:
3560 *UDP = inparam.dp;
3561 break;
3562 case FDGETDRVPRM:
3563 outparam = (const char *)UDP;
3564 break;
3565 case FDPOLLDRVSTAT:
Joe Perches52a0d612010-03-10 15:20:53 -08003566 if (lock_fdc(drive, 1))
3567 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003568 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3569 process_fd_request();
3570 /* fall through */
3571 case FDGETDRVSTAT:
3572 outparam = (const char *)UDRS;
3573 break;
3574 case FDRESET:
3575 return user_reset_fdc(drive, (int)param, 1);
3576 case FDGETFDCSTAT:
3577 outparam = (const char *)UFDCS;
3578 break;
3579 case FDWERRORCLR:
3580 memset(UDRWE, 0, sizeof(*UDRWE));
3581 return 0;
3582 case FDWERRORGET:
3583 outparam = (const char *)UDRWE;
3584 break;
3585 case FDRAWCMD:
3586 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 return -EINVAL;
Joe Perches52a0d612010-03-10 15:20:53 -08003588 if (lock_fdc(drive, 1))
3589 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003590 set_floppy(drive);
3591 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3592 process_fd_request();
3593 return i;
3594 case FDTWADDLE:
Joe Perches52a0d612010-03-10 15:20:53 -08003595 if (lock_fdc(drive, 1))
3596 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003597 twaddle();
3598 process_fd_request();
3599 return 0;
3600 default:
3601 return -EINVAL;
3602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
3604 if (_IOC_DIR(cmd) & _IOC_READ)
3605 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003606
3607 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608}
3609
3610static void __init config_types(void)
3611{
Joe Perchesb46df352010-03-10 15:20:46 -08003612 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 int drive;
3614
3615 /* read drive info out of physical CMOS */
3616 drive = 0;
3617 if (!UDP->cmos)
3618 UDP->cmos = FLOPPY0_TYPE;
3619 drive = 1;
3620 if (!UDP->cmos && FLOPPY1_TYPE)
3621 UDP->cmos = FLOPPY1_TYPE;
3622
Jesper Juhl06f748c2007-10-16 23:30:57 -07003623 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624
3625 for (drive = 0; drive < N_DRIVE; drive++) {
3626 unsigned int type = UDP->cmos;
3627 struct floppy_drive_params *params;
3628 const char *name = NULL;
3629 static char temparea[32];
3630
Tobias Klauser945f3902006-01-08 01:05:11 -08003631 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 params = &default_drive_params[type].params;
3633 if (type) {
3634 name = default_drive_params[type].name;
3635 allowed_drive_mask |= 1 << drive;
3636 } else
3637 allowed_drive_mask &= ~(1 << drive);
3638 } else {
3639 params = &default_drive_params[0].params;
3640 sprintf(temparea, "unknown type %d (usb?)", type);
3641 name = temparea;
3642 }
3643 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003644 const char *prepend;
3645 if (!has_drive) {
3646 prepend = "";
3647 has_drive = true;
3648 pr_info("Floppy drive(s):");
3649 } else {
3650 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 }
Joe Perchesb46df352010-03-10 15:20:46 -08003652
3653 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 }
3655 *UDP = *params;
3656 }
Joe Perchesb46df352010-03-10 15:20:46 -08003657
3658 if (has_drive)
3659 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660}
3661
Al Viroa4af9b42008-03-02 09:27:55 -05003662static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663{
Al Viroa4af9b42008-03-02 09:27:55 -05003664 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003666 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 if (UDRS->fd_ref < 0)
3668 UDRS->fd_ref = 0;
3669 else if (!UDRS->fd_ref--) {
3670 DPRINT("floppy_release with fd_ref == 0");
3671 UDRS->fd_ref = 0;
3672 }
3673 if (!UDRS->fd_ref)
3674 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003675 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003676
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 return 0;
3678}
3679
3680/*
3681 * floppy_open check for aliasing (/dev/fd0 can be the same as
3682 * /dev/PS0 etc), and disallows simultaneous access to the same
3683 * drive with different device numbers.
3684 */
Al Viroa4af9b42008-03-02 09:27:55 -05003685static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686{
Al Viroa4af9b42008-03-02 09:27:55 -05003687 int drive = (long)bdev->bd_disk->private_data;
3688 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 int try;
3690 int res = -EBUSY;
3691 char *tmp;
3692
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003693 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003695 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 goto out2;
3697
3698 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003699 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3700 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 }
3702
Al Viroa4af9b42008-03-02 09:27:55 -05003703 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 goto out2;
3705
Al Viroa4af9b42008-03-02 09:27:55 -05003706 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 UDRS->fd_ref = -1;
3708 else
3709 UDRS->fd_ref++;
3710
Al Viroa4af9b42008-03-02 09:27:55 -05003711 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712
3713 res = -ENXIO;
3714
3715 if (!floppy_track_buffer) {
3716 /* if opening an ED drive, reserve a big buffer,
3717 * else reserve a small one */
3718 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3719 try = 64; /* Only 48 actually useful */
3720 else
3721 try = 32; /* Only 24 actually useful */
3722
3723 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3724 if (!tmp && !floppy_track_buffer) {
3725 try >>= 1; /* buffer only one side */
3726 INFBOUND(try, 16);
3727 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3728 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003729 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 if (!tmp && !floppy_track_buffer) {
3732 DPRINT("Unable to allocate DMA memory\n");
3733 goto out;
3734 }
3735 if (floppy_track_buffer) {
3736 if (tmp)
3737 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3738 } else {
3739 buffer_min = buffer_max = -1;
3740 floppy_track_buffer = tmp;
3741 max_buffer_sectors = try;
3742 }
3743 }
3744
Al Viroa4af9b42008-03-02 09:27:55 -05003745 new_dev = MINOR(bdev->bd_dev);
3746 UDRS->fd_device = new_dev;
3747 set_capacity(disks[drive], floppy_sizes[new_dev]);
3748 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 if (buffer_drive == drive)
3750 buffer_track = -1;
3751 }
3752
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 if (UFDCS->rawcmd == 1)
3754 UFDCS->rawcmd = 2;
3755
Al Viroa4af9b42008-03-02 09:27:55 -05003756 if (!(mode & FMODE_NDELAY)) {
3757 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003759 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003760 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 goto out;
3762 }
3763 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003764 if ((mode & FMODE_WRITE) &&
3765 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 goto out;
3767 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003768 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 return 0;
3770out:
3771 if (UDRS->fd_ref < 0)
3772 UDRS->fd_ref = 0;
3773 else
3774 UDRS->fd_ref--;
3775 if (!UDRS->fd_ref)
3776 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003778 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 return res;
3780}
3781
3782/*
3783 * Check if the disk has been changed or if a change has been faked.
3784 */
3785static int check_floppy_change(struct gendisk *disk)
3786{
3787 int drive = (long)disk->private_data;
3788
Joe Perchese0298532010-03-10 15:20:55 -08003789 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3790 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 return 1;
3792
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003793 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 lock_fdc(drive, 0);
3795 poll_drive(0, 0);
3796 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 }
3798
Joe Perchese0298532010-03-10 15:20:55 -08003799 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3800 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 test_bit(drive, &fake_change) ||
3802 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3803 return 1;
3804 return 0;
3805}
3806
3807/*
3808 * This implements "read block 0" for floppy_revalidate().
3809 * Needed for format autodetection, checking whether there is
3810 * a disk in the drive, and whether that disk is writable.
3811 */
3812
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003813static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816}
3817
3818static int __floppy_read_block_0(struct block_device *bdev)
3819{
3820 struct bio bio;
3821 struct bio_vec bio_vec;
3822 struct completion complete;
3823 struct page *page;
3824 size_t size;
3825
3826 page = alloc_page(GFP_NOIO);
3827 if (!page) {
3828 process_fd_request();
3829 return -ENOMEM;
3830 }
3831
3832 size = bdev->bd_block_size;
3833 if (!size)
3834 size = 1024;
3835
3836 bio_init(&bio);
3837 bio.bi_io_vec = &bio_vec;
3838 bio_vec.bv_page = page;
3839 bio_vec.bv_len = size;
3840 bio_vec.bv_offset = 0;
3841 bio.bi_vcnt = 1;
3842 bio.bi_idx = 0;
3843 bio.bi_size = size;
3844 bio.bi_bdev = bdev;
3845 bio.bi_sector = 0;
3846 init_completion(&complete);
3847 bio.bi_private = &complete;
3848 bio.bi_end_io = floppy_rb0_complete;
3849
3850 submit_bio(READ, &bio);
3851 generic_unplug_device(bdev_get_queue(bdev));
3852 process_fd_request();
3853 wait_for_completion(&complete);
3854
3855 __free_page(page);
3856
3857 return 0;
3858}
3859
3860/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3861 * the bootblock (block 0). "Autodetection" is also needed to check whether
3862 * there is a disk in the drive at all... Thus we also do it for fixed
3863 * geometry formats */
3864static int floppy_revalidate(struct gendisk *disk)
3865{
3866 int drive = (long)disk->private_data;
3867#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3868 int cf;
3869 int res = 0;
3870
Joe Perchese0298532010-03-10 15:20:55 -08003871 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3872 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
3873 test_bit(drive, &fake_change) || NO_GEOM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003875 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 return -EFAULT;
3877 }
3878 lock_fdc(drive, 0);
Joe Perchese0298532010-03-10 15:20:55 -08003879 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3880 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3882 process_fd_request(); /*already done by another thread */
3883 return 0;
3884 }
3885 UDRS->maxblock = 0;
3886 UDRS->maxtrack = 0;
3887 if (buffer_drive == drive)
3888 buffer_track = -1;
3889 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003890 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 if (cf)
3892 UDRS->generation++;
3893 if (NO_GEOM) {
3894 /* auto-sensing */
3895 res = __floppy_read_block_0(opened_bdev[drive]);
3896 } else {
3897 if (cf)
3898 poll_drive(0, FD_RAW_NEED_DISK);
3899 process_fd_request();
3900 }
3901 }
3902 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3903 return res;
3904}
3905
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003906static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003907 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003908 .open = floppy_open,
3909 .release = floppy_release,
3910 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003911 .getgeo = fd_getgeo,
3912 .media_changed = check_floppy_change,
3913 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916/*
3917 * Floppy Driver initialization
3918 * =============================
3919 */
3920
3921/* Determine the floppy disk controller type */
3922/* This routine was written by David C. Niemi */
3923static char __init get_fdc_version(void)
3924{
3925 int r;
3926
3927 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3928 if (FDCS->reset)
3929 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003930 r = result();
3931 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 return FDC_NONE; /* No FDC present ??? */
3933 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003934 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3936 }
3937 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003938 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3939 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 return FDC_UNKNOWN;
3941 }
3942
3943 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003944 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3946 }
3947
3948 output_byte(FD_PERPENDICULAR);
3949 if (need_more_output() == MORE_OUTPUT) {
3950 output_byte(0);
3951 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003952 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 return FDC_82072A; /* 82072A as found on Sparcs. */
3954 }
3955
3956 output_byte(FD_UNLOCK);
3957 r = result();
3958 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003959 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003960 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 * LOCK/UNLOCK */
3962 }
3963 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003964 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3965 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 return FDC_UNKNOWN;
3967 }
3968 output_byte(FD_PARTID);
3969 r = result();
3970 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003971 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3972 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 return FDC_UNKNOWN;
3974 }
3975 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003976 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 return FDC_82077; /* Revised 82077AA passes all the tests */
3978 }
3979 switch (reply_buffer[0] >> 5) {
3980 case 0x0:
3981 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003982 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 return FDC_82078;
3984 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003985 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 return FDC_82078;
3987 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003988 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 return FDC_S82078B;
3990 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003991 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 return FDC_87306;
3993 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003994 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3995 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 return FDC_82078_UNKN;
3997 }
3998} /* get_fdc_version */
3999
4000/* lilo configuration */
4001
4002static void __init floppy_set_flags(int *ints, int param, int param2)
4003{
4004 int i;
4005
4006 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4007 if (param)
4008 default_drive_params[i].params.flags |= param2;
4009 else
4010 default_drive_params[i].params.flags &= ~param2;
4011 }
4012 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4013}
4014
4015static void __init daring(int *ints, int param, int param2)
4016{
4017 int i;
4018
4019 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4020 if (param) {
4021 default_drive_params[i].params.select_delay = 0;
4022 default_drive_params[i].params.flags |=
4023 FD_SILENT_DCL_CLEAR;
4024 } else {
4025 default_drive_params[i].params.select_delay =
4026 2 * HZ / 100;
4027 default_drive_params[i].params.flags &=
4028 ~FD_SILENT_DCL_CLEAR;
4029 }
4030 }
4031 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4032}
4033
4034static void __init set_cmos(int *ints, int dummy, int dummy2)
4035{
4036 int current_drive = 0;
4037
4038 if (ints[0] != 2) {
4039 DPRINT("wrong number of parameters for CMOS\n");
4040 return;
4041 }
4042 current_drive = ints[1];
4043 if (current_drive < 0 || current_drive >= 8) {
4044 DPRINT("bad drive for set_cmos\n");
4045 return;
4046 }
4047#if N_FDC > 1
4048 if (current_drive >= 4 && !FDC2)
4049 FDC2 = 0x370;
4050#endif
4051 DP->cmos = ints[2];
4052 DPRINT("setting CMOS code to %d\n", ints[2]);
4053}
4054
4055static struct param_table {
4056 const char *name;
4057 void (*fn) (int *ints, int param, int param2);
4058 int *var;
4059 int def_param;
4060 int param2;
4061} config_params[] __initdata = {
4062 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4063 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4064 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4065 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4066 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4067 {"daring", daring, NULL, 1, 0},
4068#if N_FDC > 1
4069 {"two_fdc", NULL, &FDC2, 0x370, 0},
4070 {"one_fdc", NULL, &FDC2, 0, 0},
4071#endif
4072 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4073 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4074 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4075 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4076 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4077 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4078 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4079 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4080 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4081 {"nofifo", NULL, &no_fifo, 0x20, 0},
4082 {"usefifo", NULL, &no_fifo, 0, 0},
4083 {"cmos", set_cmos, NULL, 0, 0},
4084 {"slow", NULL, &slow_floppy, 1, 0},
4085 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4086 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4087 {"L40SX", NULL, &print_unex, 0, 0}
4088
4089 EXTRA_FLOPPY_PARAMS
4090};
4091
4092static int __init floppy_setup(char *str)
4093{
4094 int i;
4095 int param;
4096 int ints[11];
4097
4098 str = get_options(str, ARRAY_SIZE(ints), ints);
4099 if (str) {
4100 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4101 if (strcmp(str, config_params[i].name) == 0) {
4102 if (ints[0])
4103 param = ints[1];
4104 else
4105 param = config_params[i].def_param;
4106 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004107 config_params[i].fn(ints, param,
4108 config_params[i].
4109 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 if (config_params[i].var) {
4111 DPRINT("%s=%d\n", str, param);
4112 *config_params[i].var = param;
4113 }
4114 return 1;
4115 }
4116 }
4117 }
4118 if (str) {
4119 DPRINT("unknown floppy option [%s]\n", str);
4120
4121 DPRINT("allowed options are:");
4122 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004123 pr_cont(" %s", config_params[i].name);
4124 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 } else
4126 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004127 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 return 0;
4129}
4130
4131static int have_no_fdc = -ENODEV;
4132
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004133static ssize_t floppy_cmos_show(struct device *dev,
4134 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004135{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004136 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004137 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004138
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004139 drive = p->id;
4140 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004141}
Joe Perches48c8cee2010-03-10 15:20:45 -08004142
4143DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004144
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145static void floppy_device_release(struct device *dev)
4146{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147}
4148
Frans Popc90cd332009-07-25 22:24:54 +02004149static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004150{
4151 int fdc;
4152
4153 for (fdc = 0; fdc < N_FDC; fdc++)
4154 if (FDCS->address != -1)
4155 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4156
4157 return 0;
4158}
4159
Alexey Dobriyan47145212009-12-14 18:00:08 -08004160static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004161 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004162 .restore = floppy_resume,
4163};
4164
4165static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004166 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004167 .name = "floppy",
4168 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004169 },
4170};
4171
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004172static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173
4174static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4175{
4176 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4177 if (drive >= N_DRIVE ||
4178 !(allowed_drive_mask & (1 << drive)) ||
4179 fdc_state[FDC(drive)].version == FDC_NONE)
4180 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004181 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 return NULL;
4183 *part = 0;
4184 return get_disk(disks[drive]);
4185}
4186
4187static int __init floppy_init(void)
4188{
4189 int i, unit, drive;
4190 int err, dr;
4191
Kumar Gala68e1ee62008-09-22 14:41:31 -07004192#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004193 if (check_legacy_ioport(FDC1))
4194 return -ENODEV;
4195#endif
4196
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 raw_cmd = NULL;
4198
4199 for (dr = 0; dr < N_DRIVE; dr++) {
4200 disks[dr] = alloc_disk(1);
4201 if (!disks[dr]) {
4202 err = -ENOMEM;
4203 goto out_put_disk;
4204 }
4205
4206 disks[dr]->major = FLOPPY_MAJOR;
4207 disks[dr]->first_minor = TOMINOR(dr);
4208 disks[dr]->fops = &floppy_fops;
4209 sprintf(disks[dr]->disk_name, "fd%d", dr);
4210
4211 init_timer(&motor_off_timer[dr]);
4212 motor_off_timer[dr].data = dr;
4213 motor_off_timer[dr].function = motor_off_callback;
4214 }
4215
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 err = register_blkdev(FLOPPY_MAJOR, "fd");
4217 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004218 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004220 err = platform_driver_register(&floppy_driver);
4221 if (err)
4222 goto out_unreg_blkdev;
4223
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4225 if (!floppy_queue) {
4226 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004227 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004229 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230
4231 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4232 floppy_find, NULL, NULL);
4233
4234 for (i = 0; i < 256; i++)
4235 if (ITYPE(i))
4236 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4237 else
4238 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4239
4240 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4241 config_types();
4242
4243 for (i = 0; i < N_FDC; i++) {
4244 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004245 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 FDCS->dtr = -1;
4247 FDCS->dor = 0x4;
4248#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004249 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250#ifdef __mc68000__
4251 if (MACH_IS_SUN3X)
4252#endif
4253 FDCS->version = FDC_82072A;
4254#endif
4255 }
4256
4257 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 fdc_state[0].address = FDC1;
4259 if (fdc_state[0].address == -1) {
4260 del_timer(&fd_timeout);
4261 err = -ENODEV;
4262 goto out_unreg_region;
4263 }
4264#if N_FDC > 1
4265 fdc_state[1].address = FDC2;
4266#endif
4267
4268 fdc = 0; /* reset fdc in case of unexpected interrupt */
4269 err = floppy_grab_irq_and_dma();
4270 if (err) {
4271 del_timer(&fd_timeout);
4272 err = -EBUSY;
4273 goto out_unreg_region;
4274 }
4275
4276 /* initialise drive state */
4277 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004278 memset(UDRS, 0, sizeof(*UDRS));
4279 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004280 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4281 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4282 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 UDRS->fd_device = -1;
4284 floppy_track_buffer = NULL;
4285 max_buffer_sectors = 0;
4286 }
4287 /*
4288 * Small 10 msec delay to let through any interrupt that
4289 * initialization might have triggered, to not
4290 * confuse detection:
4291 */
4292 msleep(10);
4293
4294 for (i = 0; i < N_FDC; i++) {
4295 fdc = i;
4296 FDCS->driver_version = FD_DRIVER_VERSION;
4297 for (unit = 0; unit < 4; unit++)
4298 FDCS->track[unit] = 0;
4299 if (FDCS->address == -1)
4300 continue;
4301 FDCS->rawcmd = 2;
4302 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4303 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004304 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 FDCS->address = -1;
4306 FDCS->version = FDC_NONE;
4307 continue;
4308 }
4309 /* Try to determine the floppy controller type */
4310 FDCS->version = get_fdc_version();
4311 if (FDCS->version == FDC_NONE) {
4312 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004313 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 FDCS->address = -1;
4315 continue;
4316 }
4317 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4318 can_use_virtual_dma = 0;
4319
4320 have_no_fdc = 0;
4321 /* Not all FDCs seem to be able to handle the version command
4322 * properly, so force a reset for the standard FDC clones,
4323 * to avoid interrupt garbage.
4324 */
4325 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4326 }
4327 fdc = 0;
4328 del_timer(&fd_timeout);
4329 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 initialising = 0;
4331 if (have_no_fdc) {
4332 DPRINT("no floppy controllers found\n");
4333 err = have_no_fdc;
4334 goto out_flush_work;
4335 }
4336
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 for (drive = 0; drive < N_DRIVE; drive++) {
4338 if (!(allowed_drive_mask & (1 << drive)))
4339 continue;
4340 if (fdc_state[FDC(drive)].version == FDC_NONE)
4341 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004342
4343 floppy_device[drive].name = floppy_device_name;
4344 floppy_device[drive].id = drive;
4345 floppy_device[drive].dev.release = floppy_device_release;
4346
4347 err = platform_device_register(&floppy_device[drive]);
4348 if (err)
4349 goto out_flush_work;
4350
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004351 err = device_create_file(&floppy_device[drive].dev,
4352 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004353 if (err)
4354 goto out_unreg_platform_dev;
4355
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 /* to be cleaned up... */
4357 disks[drive]->private_data = (void *)(long)drive;
4358 disks[drive]->queue = floppy_queue;
4359 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004360 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 add_disk(disks[drive]);
4362 }
4363
4364 return 0;
4365
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004366out_unreg_platform_dev:
4367 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368out_flush_work:
4369 flush_scheduled_work();
4370 if (usage_count)
4371 floppy_release_irq_and_dma();
4372out_unreg_region:
4373 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4374 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004375out_unreg_driver:
4376 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377out_unreg_blkdev:
4378 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379out_put_disk:
4380 while (dr--) {
4381 del_timer(&motor_off_timer[dr]);
4382 put_disk(disks[dr]);
4383 }
4384 return err;
4385}
4386
4387static DEFINE_SPINLOCK(floppy_usage_lock);
4388
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004389static const struct io_region {
4390 int offset;
4391 int size;
4392} io_regions[] = {
4393 { 2, 1 },
4394 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4395 { 4, 2 },
4396 /* address + 6 is reserved, and may be taken by IDE.
4397 * Unfortunately, Adaptec doesn't know this :-(, */
4398 { 7, 1 },
4399};
4400
4401static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4402{
4403 while (p != io_regions) {
4404 p--;
4405 release_region(FDCS->address + p->offset, p->size);
4406 }
4407}
4408
4409#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4410
4411static int floppy_request_regions(int fdc)
4412{
4413 const struct io_region *p;
4414
4415 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004416 if (!request_region(FDCS->address + p->offset,
4417 p->size, "floppy")) {
4418 DPRINT("Floppy io-port 0x%04lx in use\n",
4419 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004420 floppy_release_allocated_regions(fdc, p);
4421 return -EBUSY;
4422 }
4423 }
4424 return 0;
4425}
4426
4427static void floppy_release_regions(int fdc)
4428{
4429 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4430}
4431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432static int floppy_grab_irq_and_dma(void)
4433{
4434 unsigned long flags;
4435
4436 spin_lock_irqsave(&floppy_usage_lock, flags);
4437 if (usage_count++) {
4438 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4439 return 0;
4440 }
4441 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004442
4443 /*
4444 * We might have scheduled a free_irq(), wait it to
4445 * drain first:
4446 */
4447 flush_scheduled_work();
4448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 if (fd_request_irq()) {
4450 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4451 FLOPPY_IRQ);
4452 spin_lock_irqsave(&floppy_usage_lock, flags);
4453 usage_count--;
4454 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4455 return -1;
4456 }
4457 if (fd_request_dma()) {
4458 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4459 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004460 if (can_use_virtual_dma & 2)
4461 use_virtual_dma = can_use_virtual_dma = 1;
4462 if (!(can_use_virtual_dma & 1)) {
4463 fd_free_irq();
4464 spin_lock_irqsave(&floppy_usage_lock, flags);
4465 usage_count--;
4466 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4467 return -1;
4468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 }
4470
4471 for (fdc = 0; fdc < N_FDC; fdc++) {
4472 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004473 if (floppy_request_regions(fdc))
4474 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 }
4476 }
4477 for (fdc = 0; fdc < N_FDC; fdc++) {
4478 if (FDCS->address != -1) {
4479 reset_fdc_info(1);
4480 fd_outb(FDCS->dor, FD_DOR);
4481 }
4482 }
4483 fdc = 0;
4484 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4485
4486 for (fdc = 0; fdc < N_FDC; fdc++)
4487 if (FDCS->address != -1)
4488 fd_outb(FDCS->dor, FD_DOR);
4489 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004490 * The driver will try and free resources and relies on us
4491 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 */
4493 fdc = 0;
4494 irqdma_allocated = 1;
4495 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004496cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 fd_free_irq();
4498 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004499 while (--fdc >= 0)
4500 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 spin_lock_irqsave(&floppy_usage_lock, flags);
4502 usage_count--;
4503 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4504 return -1;
4505}
4506
4507static void floppy_release_irq_and_dma(void)
4508{
4509 int old_fdc;
4510#ifdef FLOPPY_SANITY_CHECK
4511#ifndef __sparc__
4512 int drive;
4513#endif
4514#endif
4515 long tmpsize;
4516 unsigned long tmpaddr;
4517 unsigned long flags;
4518
4519 spin_lock_irqsave(&floppy_usage_lock, flags);
4520 if (--usage_count) {
4521 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4522 return;
4523 }
4524 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4525 if (irqdma_allocated) {
4526 fd_disable_dma();
4527 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004528 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 irqdma_allocated = 0;
4530 }
4531 set_dor(0, ~0, 8);
4532#if N_FDC > 1
4533 set_dor(1, ~8, 0);
4534#endif
4535 floppy_enable_hlt();
4536
4537 if (floppy_track_buffer && max_buffer_sectors) {
4538 tmpsize = max_buffer_sectors * 1024;
4539 tmpaddr = (unsigned long)floppy_track_buffer;
4540 floppy_track_buffer = NULL;
4541 max_buffer_sectors = 0;
4542 buffer_min = buffer_max = -1;
4543 fd_dma_mem_free(tmpaddr, tmpsize);
4544 }
4545#ifdef FLOPPY_SANITY_CHECK
4546#ifndef __sparc__
4547 for (drive = 0; drive < N_FDC * 4; drive++)
4548 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004549 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550#endif
4551
4552 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004553 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004555 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004556 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004557 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558#endif
4559 old_fdc = fdc;
4560 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004561 if (FDCS->address != -1)
4562 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 fdc = old_fdc;
4564}
4565
4566#ifdef MODULE
4567
4568static char *floppy;
4569
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570static void __init parse_floppy_cfg_string(char *cfg)
4571{
4572 char *ptr;
4573
4574 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004575 ptr = cfg;
4576 while (*cfg && *cfg != ' ' && *cfg != '\t')
4577 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 if (*cfg) {
4579 *cfg = '\0';
4580 cfg++;
4581 }
4582 if (*ptr)
4583 floppy_setup(ptr);
4584 }
4585}
4586
Jon Schindler7afea3b2008-04-29 00:59:21 -07004587static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588{
4589 if (floppy)
4590 parse_floppy_cfg_string(floppy);
4591 return floppy_init();
4592}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004593module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594
Jon Schindler7afea3b2008-04-29 00:59:21 -07004595static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596{
4597 int drive;
4598
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4600 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004601 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602
4603 for (drive = 0; drive < N_DRIVE; drive++) {
4604 del_timer_sync(&motor_off_timer[drive]);
4605
4606 if ((allowed_drive_mask & (1 << drive)) &&
4607 fdc_state[FDC(drive)].version != FDC_NONE) {
4608 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004609 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4610 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 }
4612 put_disk(disks[drive]);
4613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614
4615 del_timer_sync(&fd_timeout);
4616 del_timer_sync(&fd_timer);
4617 blk_cleanup_queue(floppy_queue);
4618
4619 if (usage_count)
4620 floppy_release_irq_and_dma();
4621
4622 /* eject disk, if any */
4623 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624}
Joe Perches48c8cee2010-03-10 15:20:45 -08004625
Jon Schindler7afea3b2008-04-29 00:59:21 -07004626module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
4628module_param(floppy, charp, 0);
4629module_param(FLOPPY_IRQ, int, 0);
4630module_param(FLOPPY_DMA, int, 0);
4631MODULE_AUTHOR("Alain L. Knaff");
4632MODULE_SUPPORTED_DEVICE("fd");
4633MODULE_LICENSE("GPL");
4634
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004635/* This doesn't actually get used other than for module information */
4636static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004637 {"PNP0700", 0},
4638 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004639};
Joe Perches48c8cee2010-03-10 15:20:45 -08004640
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004641MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4642
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643#else
4644
4645__setup("floppy=", floppy_setup);
4646module_init(floppy_init)
4647#endif
4648
4649MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);