blob: dae637abeec3210a3ed864fb065cbcdec8d69983 [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
155/* do print messages for unexpected interrupts */
156static int print_unex = 1;
157#include <linux/module.h>
158#include <linux/sched.h>
159#include <linux/fs.h>
160#include <linux/kernel.h>
161#include <linux/timer.h>
162#include <linux/workqueue.h>
163#define FDPATCHES
164#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165#include <linux/fd.h>
166#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167#include <linux/errno.h>
168#include <linux/slab.h>
169#include <linux/mm.h>
170#include <linux/bio.h>
171#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800172#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173#include <linux/fcntl.h>
174#include <linux/delay.h>
175#include <linux/mc146818rtc.h> /* CMOS defines */
176#include <linux/ioport.h>
177#include <linux/interrupt.h>
178#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100179#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700180#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800182#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800183#include <linux/io.h>
184#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186/*
187 * PS/2 floppies have much slower step rates than regular floppies.
188 * It's been recommended that take about 1/4 of the default speed
189 * in some more extreme cases.
190 */
191static int slow_floppy;
192
193#include <asm/dma.h>
194#include <asm/irq.h>
195#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197static int FLOPPY_IRQ = 6;
198static int FLOPPY_DMA = 2;
199static int can_use_virtual_dma = 2;
200/* =======
201 * can use virtual DMA:
202 * 0 = use of virtual DMA disallowed by config
203 * 1 = use of virtual DMA prescribed by config
204 * 2 = no virtual DMA preference configured. By default try hard DMA,
205 * but fall back on virtual DMA when not enough memory available
206 */
207
208static int use_virtual_dma;
209/* =======
210 * use virtual DMA
211 * 0 using hard DMA
212 * 1 using virtual DMA
213 * This variable is set to virtual when a DMA mem problem arises, and
214 * reset back in floppy_grab_irq_and_dma.
215 * It is not safe to reset it in other circumstances, because the floppy
216 * driver may have several buffers in use at once, and we do currently not
217 * record each buffers capabilities
218 */
219
220static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100223irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226#define K_64 0x10000 /* 64KB */
227
228/* the following is the mask of allowed drives. By default units 2 and
229 * 3 of both floppy controllers are disabled, because switching on the
230 * motor of these drives causes system hangs on some PCI computers. drive
231 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
232 * a drive is allowed.
233 *
234 * NOTE: This must come before we include the arch floppy header because
235 * some ports reference this variable from there. -DaveM
236 */
237
238static int allowed_drive_mask = 0x33;
239
240#include <asm/floppy.h>
241
242static int irqdma_allocated;
243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244#define DEVICE_NAME "floppy"
245
246#include <linux/blkdev.h>
247#include <linux/blkpg.h>
248#include <linux/cdrom.h> /* for the compatibility eject ioctl */
249#include <linux/completion.h>
250
251static struct request *current_req;
252static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800253static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255#ifndef fd_get_dma_residue
256#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
257#endif
258
259/* Dma Memory related stuff */
260
261#ifndef fd_dma_mem_free
262#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
263#endif
264
265#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800266#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267#endif
268
269static inline void fallback_on_nodma_alloc(char **addr, size_t l)
270{
271#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
272 if (*addr)
273 return; /* we have the memory */
274 if (can_use_virtual_dma != 2)
275 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800276 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 *addr = (char *)nodma_mem_alloc(l);
278#else
279 return;
280#endif
281}
282
283/* End dma memory related stuff */
284
285static unsigned long fake_change;
286static int initialising = 1;
287
Joe Perches48c8cee2010-03-10 15:20:45 -0800288#define ITYPE(x) (((x) >> 2) & 0x1f)
289#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
290#define UNIT(x) ((x) & 0x03) /* drive on fdc */
291#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700292 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Joe Perches48c8cee2010-03-10 15:20:45 -0800295#define DP (&drive_params[current_drive])
296#define DRS (&drive_state[current_drive])
297#define DRWE (&write_errors[current_drive])
298#define FDCS (&fdc_state[fdc])
299#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
300#define SETF(x) set_bit(x##_BIT, &DRS->flags)
301#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Joe Perches48c8cee2010-03-10 15:20:45 -0800303#define UDP (&drive_params[drive])
304#define UDRS (&drive_state[drive])
305#define UDRWE (&write_errors[drive])
306#define UFDCS (&fdc_state[FDC(drive)])
307#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
308#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
309#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Joe Perches48c8cee2010-03-10 15:20:45 -0800311#define DPRINT(format, args...) \
Joe Perchesb46df352010-03-10 15:20:46 -0800312 pr_info(DEVICE_NAME "%d: " format, current_drive, ##args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Joe Perches48c8cee2010-03-10 15:20:45 -0800314#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
315#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
316
317#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800320#define COMMAND (raw_cmd->cmd[0])
321#define DR_SELECT (raw_cmd->cmd[1])
322#define TRACK (raw_cmd->cmd[2])
323#define HEAD (raw_cmd->cmd[3])
324#define SECTOR (raw_cmd->cmd[4])
325#define SIZECODE (raw_cmd->cmd[5])
326#define SECT_PER_TRACK (raw_cmd->cmd[6])
327#define GAP (raw_cmd->cmd[7])
328#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329#define NR_RW 9
330
331/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800332#define F_SIZECODE (raw_cmd->cmd[2])
333#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
334#define F_GAP (raw_cmd->cmd[4])
335#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336#define NR_F 6
337
338/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800339 * Maximum disk size (in kilobytes).
340 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 * [Now it is rather a minimum]
342 */
343#define MAX_DISK_SIZE 4 /* 3984 */
344
345/*
346 * globals used by 'result()'
347 */
348#define MAX_REPLIES 16
349static unsigned char reply_buffer[MAX_REPLIES];
350static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800351#define ST0 (reply_buffer[0])
352#define ST1 (reply_buffer[1])
353#define ST2 (reply_buffer[2])
354#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
355#define R_TRACK (reply_buffer[3])
356#define R_HEAD (reply_buffer[4])
357#define R_SECTOR (reply_buffer[5])
358#define R_SIZECODE (reply_buffer[6])
359
360#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362/*
363 * this struct defines the different floppy drive types.
364 */
365static struct {
366 struct floppy_drive_params params;
367 const char *name; /* name printed while booting */
368} default_drive_params[] = {
369/* NOTE: the time values in jiffies should be in msec!
370 CMOS drive type
371 | Maximum data rate supported by drive type
372 | | Head load time, msec
373 | | | Head unload time, msec (not used)
374 | | | | Step rate interval, usec
375 | | | | | Time needed for spinup time (jiffies)
376 | | | | | | Timeout for spinning down (jiffies)
377 | | | | | | | Spindown offset (where disk stops)
378 | | | | | | | | Select delay
379 | | | | | | | | | RPS
380 | | | | | | | | | | Max number of tracks
381 | | | | | | | | | | | Interrupt timeout
382 | | | | | | | | | | | | Max nonintlv. sectors
383 | | | | | | | | | | | | | -Max Errors- flags */
384{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
385 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
386
387{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
388 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
389
390{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
391 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
392
393{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
394 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
395
396{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
397 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
398
399{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
400 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
401
402{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
403 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
404/* | --autodetected formats--- | | |
405 * read_track | | Name printed when booting
406 * | Native format
407 * Frequency of disk change checks */
408};
409
410static struct floppy_drive_params drive_params[N_DRIVE];
411static struct floppy_drive_struct drive_state[N_DRIVE];
412static struct floppy_write_errors write_errors[N_DRIVE];
413static struct timer_list motor_off_timer[N_DRIVE];
414static struct gendisk *disks[N_DRIVE];
415static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800416static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
418
419/*
420 * This struct defines the different floppy types.
421 *
422 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
423 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
424 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
425 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
426 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
427 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
428 * side 0 is on physical side 0 (but with the misnamed sector IDs).
429 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700430 * 'options'.
431 *
432 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
433 * The LSB (bit 2) is flipped. For most disks, the first sector
434 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
435 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
436 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
437 *
438 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 */
440/*
441 Size
442 | Sectors per track
443 | | Head
444 | | | Tracks
445 | | | | Stretch
446 | | | | | Gap 1 size
447 | | | | | | Data rate, | 0x40 for perp
448 | | | | | | | Spec1 (stepping rate, head unload
449 | | | | | | | | /fmt gap (gap2) */
450static struct floppy_struct floppy_type[32] = {
451 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
452 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
453 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
454 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
455 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
456 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
457 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
458 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
459 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
460 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
461
462 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
463 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
464 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
465 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
466 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
467 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
468 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
469 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
470 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
471 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
472
473 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
474 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
475 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
476 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
477 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
478 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
479 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
480 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
481 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
485 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
486};
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488#define SECTSIZE (_FD_SECTSIZE(*floppy))
489
490/* Auto-detection: Disk type used until the next media change occurs. */
491static struct floppy_struct *current_type[N_DRIVE];
492
493/*
494 * User-provided type information. current_type points to
495 * the respective entry of this array.
496 */
497static struct floppy_struct user_params[N_DRIVE];
498
499static sector_t floppy_sizes[256];
500
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200501static char floppy_device_name[] = "floppy";
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503/*
504 * The driver is trying to determine the correct media format
505 * while probing is set. rw_interrupt() clears it after a
506 * successful access.
507 */
508static int probing;
509
510/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800511#define FD_COMMAND_NONE -1
512#define FD_COMMAND_ERROR 2
513#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515static volatile int command_status = FD_COMMAND_NONE;
516static unsigned long fdc_busy;
517static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
518static DECLARE_WAIT_QUEUE_HEAD(command_done);
519
520#define NO_SIGNAL (!interruptible || !signal_pending(current))
Joe Perches48c8cee2010-03-10 15:20:45 -0800521#define CALL(x) if ((x) == -EINTR) return -EINTR
522#define ECALL(x) if ((ret = (x))) return ret;
523#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
524#define WAIT(x) _WAIT((x),interruptible)
525#define IWAIT(x) _WAIT((x),1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527/* Errors during formatting are counted here. */
528static int format_errors;
529
530/* Format request descriptor. */
531static struct format_descr format_req;
532
533/*
534 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
535 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
536 * H is head unload time (1=16ms, 2=32ms, etc)
537 */
538
539/*
540 * Track buffer
541 * Because these are written to by the DMA controller, they must
542 * not contain a 64k byte boundary crossing, or data will be
543 * corrupted/lost.
544 */
545static char *floppy_track_buffer;
546static int max_buffer_sectors;
547
548static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700549typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800551 void (*interrupt)(void);
552 /* this is called after the interrupt of the
553 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700554 void (*redo)(void); /* this is called to retry the operation */
555 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 done_f done; /* this is called to say if the operation has
557 * succeeded/failed */
558} *cont;
559
560static void floppy_ready(void);
561static void floppy_start(void);
562static void process_fd_request(void);
563static void recalibrate_floppy(void);
564static void floppy_shutdown(unsigned long);
565
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800566static int floppy_request_regions(int);
567static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568static int floppy_grab_irq_and_dma(void);
569static void floppy_release_irq_and_dma(void);
570
571/*
572 * The "reset" variable should be tested whenever an interrupt is scheduled,
573 * after the commands have been sent. This is to ensure that the driver doesn't
574 * get wedged when the interrupt doesn't come because of a failed command.
575 * reset doesn't need to be tested before sending commands, because
576 * output_byte is automatically disabled when reset is set.
577 */
578#define CHECK_RESET { if (FDCS->reset){ reset_fdc(); return; } }
579static 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
638typedef 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);
689 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 }
692 timeout_message = message;
693}
694
695static void reschedule_timeout(int drive, const char *message, int marg)
696{
697 unsigned long flags;
698
699 spin_lock_irqsave(&floppy_lock, flags);
700 __reschedule_timeout(drive, message, marg);
701 spin_unlock_irqrestore(&floppy_lock, flags);
702}
703
Joe Perches48c8cee2010-03-10 15:20:45 -0800704#define INFBOUND(a, b) (a) = max_t(int, a, b)
705#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707/*
708 * Bottom half floppy driver.
709 * ==========================
710 *
711 * This part of the file contains the code talking directly to the hardware,
712 * and also the main service loop (seek-configure-spinup-command)
713 */
714
715/*
716 * disk change.
717 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
718 * and the last_checked date.
719 *
720 * last_checked is the date of the last check which showed 'no disk change'
721 * FD_DISK_CHANGE is set under two conditions:
722 * 1. The floppy has been changed after some i/o to that floppy already
723 * took place.
724 * 2. No floppy disk is in the drive. This is done in order to ensure that
725 * requests are quickly flushed in case there is no disk in the drive. It
726 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
727 * the drive.
728 *
729 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
730 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
731 * each seek. If a disk is present, the disk change line should also be
732 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
733 * change line is set, this means either that no disk is in the drive, or
734 * that it has been removed since the last seek.
735 *
736 * This means that we really have a third possibility too:
737 * The floppy has been changed after the last seek.
738 */
739
740static int disk_change(int drive)
741{
742 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800745 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 DPRINT("WARNING disk change called early\n");
747 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
748 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
749 DPRINT("probing disk change on unselected drive\n");
750 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
751 (unsigned int)FDCS->dor);
752 }
753#endif
754
755#ifdef DCL_DEBUG
756 if (UDP->flags & FD_DEBUG) {
757 DPRINT("checking disk change line for drive %d\n", drive);
758 DPRINT("jiffies=%lu\n", jiffies);
759 DPRINT("disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
760 DPRINT("flags=%lx\n", UDRS->flags);
761 }
762#endif
763 if (UDP->flags & FD_BROKEN_DCL)
764 return UTESTF(FD_DISK_CHANGED);
765 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
766 USETF(FD_VERIFY); /* verify write protection */
767 if (UDRS->maxblock) {
768 /* mark it changed */
769 USETF(FD_DISK_CHANGED);
770 }
771
772 /* invalidate its geometry */
773 if (UDRS->keep_data >= 0) {
774 if ((UDP->flags & FTD_MSG) &&
775 current_type[drive] != NULL)
776 DPRINT("Disk type is undefined after "
777 "disk change\n");
778 current_type[drive] = NULL;
779 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
780 }
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return 1;
783 } else {
784 UDRS->last_checked = jiffies;
785 UCLEARF(FD_DISK_NEWCHANGE);
786 }
787 return 0;
788}
789
790static inline int is_selected(int dor, int unit)
791{
792 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
793}
794
795static int set_dor(int fdc, char mask, char data)
796{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700797 unsigned char unit;
798 unsigned char drive;
799 unsigned char newdor;
800 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
802 if (FDCS->address == -1)
803 return -1;
804
805 olddor = FDCS->dor;
806 newdor = (olddor & mask) | data;
807 if (newdor != olddor) {
808 unit = olddor & 0x3;
809 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
810 drive = REVDRIVE(fdc, unit);
811#ifdef DCL_DEBUG
812 if (UDP->flags & FD_DEBUG) {
813 DPRINT("calling disk change from set_dor\n");
814 }
815#endif
816 disk_change(drive);
817 }
818 FDCS->dor = newdor;
819 fd_outb(newdor, FD_DOR);
820
821 unit = newdor & 0x3;
822 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
823 drive = REVDRIVE(fdc, unit);
824 UDRS->select_date = jiffies;
825 }
826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 return olddor;
828}
829
830static void twaddle(void)
831{
832 if (DP->select_delay)
833 return;
834 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
835 fd_outb(FDCS->dor, FD_DOR);
836 DRS->select_date = jiffies;
837}
838
839/* reset all driver information about the current fdc. This is needed after
840 * a reset, and after a raw command. */
841static void reset_fdc_info(int mode)
842{
843 int drive;
844
845 FDCS->spec1 = FDCS->spec2 = -1;
846 FDCS->need_configure = 1;
847 FDCS->perp_mode = 1;
848 FDCS->rawcmd = 0;
849 for (drive = 0; drive < N_DRIVE; drive++)
850 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
851 UDRS->track = NEED_2_RECAL;
852}
853
854/* selects the fdc and drive, and enables the fdc's input/dma. */
855static void set_fdc(int drive)
856{
857 if (drive >= 0 && drive < N_DRIVE) {
858 fdc = FDC(drive);
859 current_drive = drive;
860 }
861 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800862 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return;
864 }
865 set_dor(fdc, ~0, 8);
866#if N_FDC > 1
867 set_dor(1 - fdc, ~8, 0);
868#endif
869 if (FDCS->rawcmd == 2)
870 reset_fdc_info(1);
871 if (fd_inb(FD_STATUS) != STATUS_READY)
872 FDCS->reset = 1;
873}
874
875/* locks the driver */
876static int _lock_fdc(int drive, int interruptible, int line)
877{
878 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800879 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 line);
881 return -1;
882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 if (test_and_set_bit(0, &fdc_busy)) {
885 DECLARE_WAITQUEUE(wait, current);
886 add_wait_queue(&fdc_wait, &wait);
887
888 for (;;) {
889 set_current_state(TASK_INTERRUPTIBLE);
890
891 if (!test_and_set_bit(0, &fdc_busy))
892 break;
893
894 schedule();
895
896 if (!NO_SIGNAL) {
897 remove_wait_queue(&fdc_wait, &wait);
898 return -EINTR;
899 }
900 }
901
902 set_current_state(TASK_RUNNING);
903 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700904 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
906 command_status = FD_COMMAND_NONE;
907
908 __reschedule_timeout(drive, "lock fdc", 0);
909 set_fdc(drive);
910 return 0;
911}
912
Joe Perches48c8cee2010-03-10 15:20:45 -0800913#define lock_fdc(drive, interruptible) \
914 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Joe Perches48c8cee2010-03-10 15:20:45 -0800916#define LOCK_FDC(drive, interruptible) \
917 if (lock_fdc(drive, interruptible)) \
918 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920/* unlocks the driver */
921static inline void unlock_fdc(void)
922{
923 unsigned long flags;
924
925 raw_cmd = NULL;
926 if (!test_bit(0, &fdc_busy))
927 DPRINT("FDC access conflict!\n");
928
929 if (do_floppy)
930 DPRINT("device interrupt still active at FDC release: %p!\n",
931 do_floppy);
932 command_status = FD_COMMAND_NONE;
933 spin_lock_irqsave(&floppy_lock, flags);
934 del_timer(&fd_timeout);
935 cont = NULL;
936 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900937 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 do_fd_request(floppy_queue);
939 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 wake_up(&fdc_wait);
941}
942
943/* switches the motor off after a given timeout */
944static void motor_off_callback(unsigned long nr)
945{
946 unsigned char mask = ~(0x10 << UNIT(nr));
947
948 set_dor(FDC(nr), mask, 0);
949}
950
951/* schedules motor off */
952static void floppy_off(unsigned int drive)
953{
954 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700955 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 if (!(FDCS->dor & (0x10 << UNIT(drive))))
958 return;
959
960 del_timer(motor_off_timer + drive);
961
962 /* make spindle stop in a position which minimizes spinup time
963 * next time */
964 if (UDP->rps) {
965 delta = jiffies - UDRS->first_read_date + HZ -
966 UDP->spindown_offset;
967 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
968 motor_off_timer[drive].expires =
969 jiffies + UDP->spindown - delta;
970 }
971 add_timer(motor_off_timer + drive);
972}
973
974/*
975 * cycle through all N_DRIVE floppy drives, for disk change testing.
976 * stopping at current drive. This is done before any long operation, to
977 * be sure to have up to date disk change information.
978 */
979static void scandrives(void)
980{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700981 int i;
982 int drive;
983 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 if (DP->select_delay)
986 return;
987
988 saved_drive = current_drive;
989 for (i = 0; i < N_DRIVE; i++) {
990 drive = (saved_drive + i + 1) % N_DRIVE;
991 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
992 continue; /* skip closed drives */
993 set_fdc(drive);
994 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
995 (0x10 << UNIT(drive))))
996 /* switch the motor off again, if it was off to
997 * begin with */
998 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
999 }
1000 set_fdc(saved_drive);
1001}
1002
1003static void empty(void)
1004{
1005}
1006
David Howells65f27f32006-11-22 14:55:48 +00001007static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Joe Perches48c8cee2010-03-10 15:20:45 -08001009static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010{
David Howells65f27f32006-11-22 14:55:48 +00001011 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 schedule_work(&floppy_work);
1013}
1014
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001015static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
1017static void cancel_activity(void)
1018{
1019 unsigned long flags;
1020
1021 spin_lock_irqsave(&floppy_lock, flags);
1022 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001023 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 del_timer(&fd_timer);
1025 spin_unlock_irqrestore(&floppy_lock, flags);
1026}
1027
1028/* this function makes sure that the disk stays in the drive during the
1029 * transfer */
1030static void fd_watchdog(void)
1031{
1032#ifdef DCL_DEBUG
1033 if (DP->flags & FD_DEBUG) {
1034 DPRINT("calling disk change from watchdog\n");
1035 }
1036#endif
1037
1038 if (disk_change(current_drive)) {
1039 DPRINT("disk removed during i/o\n");
1040 cancel_activity();
1041 cont->done(0);
1042 reset_fdc();
1043 } else {
1044 del_timer(&fd_timer);
1045 fd_timer.function = (timeout_fn) fd_watchdog;
1046 fd_timer.expires = jiffies + HZ / 10;
1047 add_timer(&fd_timer);
1048 }
1049}
1050
1051static void main_command_interrupt(void)
1052{
1053 del_timer(&fd_timer);
1054 cont->interrupt();
1055}
1056
1057/* waits for a delay (spinup or select) to pass */
1058static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1059{
1060 if (FDCS->reset) {
1061 reset_fdc(); /* do the reset during sleep to win time
1062 * if we don't need to sleep, it's a good
1063 * occasion anyways */
1064 return 1;
1065 }
1066
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001067 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 del_timer(&fd_timer);
1069 fd_timer.function = function;
1070 fd_timer.expires = delay;
1071 add_timer(&fd_timer);
1072 return 1;
1073 }
1074 return 0;
1075}
1076
1077static DEFINE_SPINLOCK(floppy_hlt_lock);
1078static int hlt_disabled;
1079static void floppy_disable_hlt(void)
1080{
1081 unsigned long flags;
1082
1083 spin_lock_irqsave(&floppy_hlt_lock, flags);
1084 if (!hlt_disabled) {
1085 hlt_disabled = 1;
1086#ifdef HAVE_DISABLE_HLT
1087 disable_hlt();
1088#endif
1089 }
1090 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1091}
1092
1093static void floppy_enable_hlt(void)
1094{
1095 unsigned long flags;
1096
1097 spin_lock_irqsave(&floppy_hlt_lock, flags);
1098 if (hlt_disabled) {
1099 hlt_disabled = 0;
1100#ifdef HAVE_DISABLE_HLT
1101 enable_hlt();
1102#endif
1103 }
1104 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1105}
1106
1107static void setup_DMA(void)
1108{
1109 unsigned long f;
1110
1111#ifdef FLOPPY_SANITY_CHECK
1112 if (raw_cmd->length == 0) {
1113 int i;
1114
Joe Perchesb46df352010-03-10 15:20:46 -08001115 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001117 pr_cont("%x,", raw_cmd->cmd[i]);
1118 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 cont->done(0);
1120 FDCS->reset = 1;
1121 return;
1122 }
1123 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001124 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 cont->done(0);
1126 FDCS->reset = 1;
1127 return;
1128 }
1129#endif
1130 f = claim_dma_lock();
1131 fd_disable_dma();
1132#ifdef fd_dma_setup
1133 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1134 (raw_cmd->flags & FD_RAW_READ) ?
1135 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1136 release_dma_lock(f);
1137 cont->done(0);
1138 FDCS->reset = 1;
1139 return;
1140 }
1141 release_dma_lock(f);
1142#else
1143 fd_clear_dma_ff();
1144 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1145 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1146 DMA_MODE_READ : DMA_MODE_WRITE);
1147 fd_set_dma_addr(raw_cmd->kernel_data);
1148 fd_set_dma_count(raw_cmd->length);
1149 virtual_dma_port = FDCS->address;
1150 fd_enable_dma();
1151 release_dma_lock(f);
1152#endif
1153 floppy_disable_hlt();
1154}
1155
1156static void show_floppy(void);
1157
1158/* waits until the fdc becomes ready */
1159static int wait_til_ready(void)
1160{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001161 int status;
1162 int counter;
1163
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 if (FDCS->reset)
1165 return -1;
1166 for (counter = 0; counter < 10000; counter++) {
1167 status = fd_inb(FD_STATUS);
1168 if (status & STATUS_READY)
1169 return status;
1170 }
1171 if (!initialising) {
1172 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1173 show_floppy();
1174 }
1175 FDCS->reset = 1;
1176 return -1;
1177}
1178
1179/* sends a command byte to the fdc */
1180static int output_byte(char byte)
1181{
1182 int status;
1183
1184 if ((status = wait_til_ready()) < 0)
1185 return -1;
1186 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1187 fd_outb(byte, FD_DATA);
1188#ifdef FLOPPY_SANITY_CHECK
1189 output_log[output_log_pos].data = byte;
1190 output_log[output_log_pos].status = status;
1191 output_log[output_log_pos].jiffies = jiffies;
1192 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1193#endif
1194 return 0;
1195 }
1196 FDCS->reset = 1;
1197 if (!initialising) {
1198 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1199 byte, fdc, status);
1200 show_floppy();
1201 }
1202 return -1;
1203}
1204
1205#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
1206
1207/* gets the response from the fdc */
1208static int result(void)
1209{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001210 int i;
1211 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 for (i = 0; i < MAX_REPLIES; i++) {
1214 if ((status = wait_til_ready()) < 0)
1215 break;
1216 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1217 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1218#ifdef FLOPPY_SANITY_CHECK
1219 resultjiffies = jiffies;
1220 resultsize = i;
1221#endif
1222 return i;
1223 }
1224 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1225 reply_buffer[i] = fd_inb(FD_DATA);
1226 else
1227 break;
1228 }
1229 if (!initialising) {
1230 DPRINT
1231 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1232 fdc, status, i);
1233 show_floppy();
1234 }
1235 FDCS->reset = 1;
1236 return -1;
1237}
1238
1239#define MORE_OUTPUT -2
1240/* does the fdc need more output? */
1241static int need_more_output(void)
1242{
1243 int status;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001244
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 if ((status = wait_til_ready()) < 0)
1246 return -1;
1247 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1248 return MORE_OUTPUT;
1249 return result();
1250}
1251
1252/* Set perpendicular mode as required, based on data rate, if supported.
1253 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1254 */
1255static inline void perpendicular_mode(void)
1256{
1257 unsigned char perp_mode;
1258
1259 if (raw_cmd->rate & 0x40) {
1260 switch (raw_cmd->rate & 3) {
1261 case 0:
1262 perp_mode = 2;
1263 break;
1264 case 3:
1265 perp_mode = 3;
1266 break;
1267 default:
1268 DPRINT("Invalid data rate for perpendicular mode!\n");
1269 cont->done(0);
1270 FDCS->reset = 1; /* convenient way to return to
1271 * redo without to much hassle (deep
1272 * stack et al. */
1273 return;
1274 }
1275 } else
1276 perp_mode = 0;
1277
1278 if (FDCS->perp_mode == perp_mode)
1279 return;
1280 if (FDCS->version >= FDC_82077_ORIG) {
1281 output_byte(FD_PERPENDICULAR);
1282 output_byte(perp_mode);
1283 FDCS->perp_mode = perp_mode;
1284 } else if (perp_mode) {
1285 DPRINT("perpendicular mode not supported by this FDC.\n");
1286 }
1287} /* perpendicular_mode */
1288
1289static int fifo_depth = 0xa;
1290static int no_fifo;
1291
1292static int fdc_configure(void)
1293{
1294 /* Turn on FIFO */
1295 output_byte(FD_CONFIGURE);
1296 if (need_more_output() != MORE_OUTPUT)
1297 return 0;
1298 output_byte(0);
1299 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1300 output_byte(0); /* pre-compensation from track
1301 0 upwards */
1302 return 1;
1303}
1304
1305#define NOMINAL_DTR 500
1306
1307/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1308 * head load time, and DMA disable flag to values needed by floppy.
1309 *
1310 * The value "dtr" is the data transfer rate in Kbps. It is needed
1311 * to account for the data rate-based scaling done by the 82072 and 82077
1312 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1313 * 8272a).
1314 *
1315 * Note that changing the data transfer rate has a (probably deleterious)
1316 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1317 * fdc_specify is called again after each data transfer rate
1318 * change.
1319 *
1320 * srt: 1000 to 16000 in microseconds
1321 * hut: 16 to 240 milliseconds
1322 * hlt: 2 to 254 milliseconds
1323 *
1324 * These values are rounded up to the next highest available delay time.
1325 */
1326static void fdc_specify(void)
1327{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001328 unsigned char spec1;
1329 unsigned char spec2;
1330 unsigned long srt;
1331 unsigned long hlt;
1332 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 unsigned long dtr = NOMINAL_DTR;
1334 unsigned long scale_dtr = NOMINAL_DTR;
1335 int hlt_max_code = 0x7f;
1336 int hut_max_code = 0xf;
1337
1338 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1339 fdc_configure();
1340 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 }
1342
1343 switch (raw_cmd->rate & 0x03) {
1344 case 3:
1345 dtr = 1000;
1346 break;
1347 case 1:
1348 dtr = 300;
1349 if (FDCS->version >= FDC_82078) {
1350 /* chose the default rate table, not the one
1351 * where 1 = 2 Mbps */
1352 output_byte(FD_DRIVESPEC);
1353 if (need_more_output() == MORE_OUTPUT) {
1354 output_byte(UNIT(current_drive));
1355 output_byte(0xc0);
1356 }
1357 }
1358 break;
1359 case 2:
1360 dtr = 250;
1361 break;
1362 }
1363
1364 if (FDCS->version >= FDC_82072) {
1365 scale_dtr = dtr;
1366 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1367 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1368 }
1369
1370 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001371 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 if (slow_floppy) {
1373 srt = srt / 4;
1374 }
1375 SUPBOUND(srt, 0xf);
1376 INFBOUND(srt, 0);
1377
Julia Lawall061837b2008-09-22 14:57:16 -07001378 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 if (hlt < 0x01)
1380 hlt = 0x01;
1381 else if (hlt > 0x7f)
1382 hlt = hlt_max_code;
1383
Julia Lawall061837b2008-09-22 14:57:16 -07001384 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if (hut < 0x1)
1386 hut = 0x1;
1387 else if (hut > 0xf)
1388 hut = hut_max_code;
1389
1390 spec1 = (srt << 4) | hut;
1391 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1392
1393 /* If these parameters did not change, just return with success */
1394 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1395 /* Go ahead and set spec1 and spec2 */
1396 output_byte(FD_SPECIFY);
1397 output_byte(FDCS->spec1 = spec1);
1398 output_byte(FDCS->spec2 = spec2);
1399 }
1400} /* fdc_specify */
1401
1402/* Set the FDC's data transfer rate on behalf of the specified drive.
1403 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1404 * of the specify command (i.e. using the fdc_specify function).
1405 */
1406static int fdc_dtr(void)
1407{
1408 /* If data rate not already set to desired value, set it. */
1409 if ((raw_cmd->rate & 3) == FDCS->dtr)
1410 return 0;
1411
1412 /* Set dtr */
1413 fd_outb(raw_cmd->rate & 3, FD_DCR);
1414
1415 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1416 * need a stabilization period of several milliseconds to be
1417 * enforced after data rate changes before R/W operations.
1418 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1419 */
1420 FDCS->dtr = raw_cmd->rate & 3;
1421 return (fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1422 (timeout_fn) floppy_ready));
1423} /* fdc_dtr */
1424
1425static void tell_sector(void)
1426{
Joe Perchesb46df352010-03-10 15:20:46 -08001427 pr_cont(": track %d, head %d, sector %d, size %d",
1428 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429} /* tell_sector */
1430
Joe Perchesb46df352010-03-10 15:20:46 -08001431static void print_errors(void)
1432{
1433 DPRINT("");
1434 if (ST0 & ST0_ECE) {
1435 pr_cont("Recalibrate failed!");
1436 } else if (ST2 & ST2_CRC) {
1437 pr_cont("data CRC error");
1438 tell_sector();
1439 } else if (ST1 & ST1_CRC) {
1440 pr_cont("CRC error");
1441 tell_sector();
1442 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1443 (ST2 & ST2_MAM)) {
1444 if (!probing) {
1445 pr_cont("sector not found");
1446 tell_sector();
1447 } else
1448 pr_cont("probe failed...");
1449 } else if (ST2 & ST2_WC) { /* seek error */
1450 pr_cont("wrong cylinder");
1451 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1452 pr_cont("bad cylinder");
1453 } else {
1454 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1455 ST0, ST1, ST2);
1456 tell_sector();
1457 }
1458 pr_cont("\n");
1459}
1460
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461/*
1462 * OK, this error interpreting routine is called after a
1463 * DMA read/write has succeeded
1464 * or failed, so we check the results, and copy any buffers.
1465 * hhb: Added better error reporting.
1466 * ak: Made this into a separate routine.
1467 */
1468static int interpret_errors(void)
1469{
1470 char bad;
1471
1472 if (inr != 7) {
1473 DPRINT("-- FDC reply error");
1474 FDCS->reset = 1;
1475 return 1;
1476 }
1477
1478 /* check IC to find cause of interrupt */
1479 switch (ST0 & ST0_INTR) {
1480 case 0x40: /* error occurred during command execution */
1481 if (ST1 & ST1_EOC)
1482 return 0; /* occurs with pseudo-DMA */
1483 bad = 1;
1484 if (ST1 & ST1_WP) {
1485 DPRINT("Drive is write protected\n");
1486 CLEARF(FD_DISK_WRITABLE);
1487 cont->done(0);
1488 bad = 2;
1489 } else if (ST1 & ST1_ND) {
1490 SETF(FD_NEED_TWADDLE);
1491 } else if (ST1 & ST1_OR) {
1492 if (DP->flags & FTD_MSG)
1493 DPRINT("Over/Underrun - retrying\n");
1494 bad = 0;
1495 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001496 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 }
1498 if (ST2 & ST2_WC || ST2 & ST2_BC)
1499 /* wrong cylinder => recal */
1500 DRS->track = NEED_2_RECAL;
1501 return bad;
1502 case 0x80: /* invalid command given */
1503 DPRINT("Invalid FDC command given!\n");
1504 cont->done(0);
1505 return 2;
1506 case 0xc0:
1507 DPRINT("Abnormal termination caused by polling\n");
1508 cont->error();
1509 return 2;
1510 default: /* (0) Normal command termination */
1511 return 0;
1512 }
1513}
1514
1515/*
1516 * This routine is called when everything should be correctly set up
1517 * for the transfer (i.e. floppy motor is on, the correct floppy is
1518 * selected, and the head is sitting on the right track).
1519 */
1520static void setup_rw_floppy(void)
1521{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001522 int i;
1523 int r;
1524 int flags;
1525 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 unsigned long ready_date;
1527 timeout_fn function;
1528
1529 flags = raw_cmd->flags;
1530 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1531 flags |= FD_RAW_INTR;
1532
1533 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1534 ready_date = DRS->spinup_date + DP->spinup;
1535 /* If spinup will take a long time, rerun scandrives
1536 * again just before spinup completion. Beware that
1537 * after scandrives, we must again wait for selection.
1538 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001539 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 ready_date -= DP->select_delay;
1541 function = (timeout_fn) floppy_start;
1542 } else
1543 function = (timeout_fn) setup_rw_floppy;
1544
1545 /* wait until the floppy is spinning fast enough */
1546 if (fd_wait_for_completion(ready_date, function))
1547 return;
1548 }
1549 dflags = DRS->flags;
1550
1551 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1552 setup_DMA();
1553
1554 if (flags & FD_RAW_INTR)
1555 do_floppy = main_command_interrupt;
1556
1557 r = 0;
1558 for (i = 0; i < raw_cmd->cmd_count; i++)
1559 r |= output_byte(raw_cmd->cmd[i]);
1560
1561 debugt("rw_command: ");
1562
1563 if (r) {
1564 cont->error();
1565 reset_fdc();
1566 return;
1567 }
1568
1569 if (!(flags & FD_RAW_INTR)) {
1570 inr = result();
1571 cont->interrupt();
1572 } else if (flags & FD_RAW_NEED_DISK)
1573 fd_watchdog();
1574}
1575
1576static int blind_seek;
1577
1578/*
1579 * This is the routine called after every seek (or recalibrate) interrupt
1580 * from the floppy controller.
1581 */
1582static void seek_interrupt(void)
1583{
1584 debugt("seek interrupt:");
1585 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1586 DPRINT("seek failed\n");
1587 DRS->track = NEED_2_RECAL;
1588 cont->error();
1589 cont->redo();
1590 return;
1591 }
1592 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
1593#ifdef DCL_DEBUG
1594 if (DP->flags & FD_DEBUG) {
Joe Perchesb46df352010-03-10 15:20:46 -08001595 DPRINT("clearing NEWCHANGE flag because of effective seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 DPRINT("jiffies=%lu\n", jiffies);
1597 }
1598#endif
1599 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1600 DRS->select_date = jiffies;
1601 }
1602 DRS->track = ST1;
1603 floppy_ready();
1604}
1605
1606static void check_wp(void)
1607{
1608 if (TESTF(FD_VERIFY)) {
1609 /* check write protection */
1610 output_byte(FD_GETSTATUS);
1611 output_byte(UNIT(current_drive));
1612 if (result() != 1) {
1613 FDCS->reset = 1;
1614 return;
1615 }
1616 CLEARF(FD_VERIFY);
1617 CLEARF(FD_NEED_TWADDLE);
1618#ifdef DCL_DEBUG
1619 if (DP->flags & FD_DEBUG) {
1620 DPRINT("checking whether disk is write protected\n");
1621 DPRINT("wp=%x\n", ST3 & 0x40);
1622 }
1623#endif
1624 if (!(ST3 & 0x40))
1625 SETF(FD_DISK_WRITABLE);
1626 else
1627 CLEARF(FD_DISK_WRITABLE);
1628 }
1629}
1630
1631static void seek_floppy(void)
1632{
1633 int track;
1634
1635 blind_seek = 0;
1636
1637#ifdef DCL_DEBUG
1638 if (DP->flags & FD_DEBUG) {
1639 DPRINT("calling disk change from seek\n");
1640 }
1641#endif
1642
1643 if (!TESTF(FD_DISK_NEWCHANGE) &&
1644 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1645 /* the media changed flag should be cleared after the seek.
1646 * If it isn't, this means that there is really no disk in
1647 * the drive.
1648 */
1649 SETF(FD_DISK_CHANGED);
1650 cont->done(0);
1651 cont->redo();
1652 return;
1653 }
1654 if (DRS->track <= NEED_1_RECAL) {
1655 recalibrate_floppy();
1656 return;
1657 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1658 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1659 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1660 /* we seek to clear the media-changed condition. Does anybody
1661 * know a more elegant way, which works on all drives? */
1662 if (raw_cmd->track)
1663 track = raw_cmd->track - 1;
1664 else {
1665 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1666 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1667 blind_seek = 1;
1668 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1669 }
1670 track = 1;
1671 }
1672 } else {
1673 check_wp();
1674 if (raw_cmd->track != DRS->track &&
1675 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1676 track = raw_cmd->track;
1677 else {
1678 setup_rw_floppy();
1679 return;
1680 }
1681 }
1682
1683 do_floppy = seek_interrupt;
1684 output_byte(FD_SEEK);
1685 output_byte(UNIT(current_drive));
1686 LAST_OUT(track);
1687 debugt("seek command:");
1688}
1689
1690static void recal_interrupt(void)
1691{
1692 debugt("recal interrupt:");
1693 if (inr != 2)
1694 FDCS->reset = 1;
1695 else if (ST0 & ST0_ECE) {
1696 switch (DRS->track) {
1697 case NEED_1_RECAL:
1698 debugt("recal interrupt need 1 recal:");
1699 /* after a second recalibrate, we still haven't
1700 * reached track 0. Probably no drive. Raise an
1701 * error, as failing immediately might upset
1702 * computers possessed by the Devil :-) */
1703 cont->error();
1704 cont->redo();
1705 return;
1706 case NEED_2_RECAL:
1707 debugt("recal interrupt need 2 recal:");
1708 /* If we already did a recalibrate,
1709 * and we are not at track 0, this
1710 * means we have moved. (The only way
1711 * not to move at recalibration is to
1712 * be already at track 0.) Clear the
1713 * new change flag */
1714#ifdef DCL_DEBUG
Joe Perchesb46df352010-03-10 15:20:46 -08001715 if (DP->flags & FD_DEBUG)
1716 DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717#endif
1718
1719 CLEARF(FD_DISK_NEWCHANGE);
1720 DRS->select_date = jiffies;
1721 /* fall through */
1722 default:
1723 debugt("recal interrupt default:");
1724 /* Recalibrate moves the head by at
1725 * most 80 steps. If after one
1726 * recalibrate we don't have reached
1727 * track 0, this might mean that we
1728 * started beyond track 80. Try
1729 * again. */
1730 DRS->track = NEED_1_RECAL;
1731 break;
1732 }
1733 } else
1734 DRS->track = ST1;
1735 floppy_ready();
1736}
1737
1738static void print_result(char *message, int inr)
1739{
1740 int i;
1741
1742 DPRINT("%s ", message);
1743 if (inr >= 0)
1744 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001745 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1746 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747}
1748
1749/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001750irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 int do_print;
1753 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001754 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 lasthandler = handler;
1757 interruptjiffies = jiffies;
1758
1759 f = claim_dma_lock();
1760 fd_disable_dma();
1761 release_dma_lock(f);
1762
1763 floppy_enable_hlt();
1764 do_floppy = NULL;
1765 if (fdc >= N_FDC || FDCS->address == -1) {
1766 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001767 pr_info("DOR0=%x\n", fdc_state[0].dor);
1768 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1769 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 is_alive("bizarre fdc");
1771 return IRQ_NONE;
1772 }
1773
1774 FDCS->reset = 0;
1775 /* We have to clear the reset flag here, because apparently on boxes
1776 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1777 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1778 * emission of the SENSEI's.
1779 * It is OK to emit floppy commands because we are in an interrupt
1780 * handler here, and thus we have to fear no interference of other
1781 * activity.
1782 */
1783
1784 do_print = !handler && print_unex && !initialising;
1785
1786 inr = result();
1787 if (do_print)
1788 print_result("unexpected interrupt", inr);
1789 if (inr == 0) {
1790 int max_sensei = 4;
1791 do {
1792 output_byte(FD_SENSEI);
1793 inr = result();
1794 if (do_print)
1795 print_result("sensei", inr);
1796 max_sensei--;
1797 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1798 && max_sensei);
1799 }
1800 if (!handler) {
1801 FDCS->reset = 1;
1802 return IRQ_NONE;
1803 }
1804 schedule_bh(handler);
1805 is_alive("normal interrupt end");
1806
1807 /* FIXME! Was it really for us? */
1808 return IRQ_HANDLED;
1809}
1810
1811static void recalibrate_floppy(void)
1812{
1813 debugt("recalibrate floppy:");
1814 do_floppy = recal_interrupt;
1815 output_byte(FD_RECALIBRATE);
1816 LAST_OUT(UNIT(current_drive));
1817}
1818
1819/*
1820 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1821 */
1822static void reset_interrupt(void)
1823{
1824 debugt("reset interrupt:");
1825 result(); /* get the status ready for set_fdc */
1826 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001827 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 cont->error(); /* a reset just after a reset. BAD! */
1829 }
1830 cont->redo();
1831}
1832
1833/*
1834 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1835 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1836 */
1837static void reset_fdc(void)
1838{
1839 unsigned long flags;
1840
1841 do_floppy = reset_interrupt;
1842 FDCS->reset = 0;
1843 reset_fdc_info(0);
1844
1845 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1846 /* Irrelevant for systems with true DMA (i386). */
1847
1848 flags = claim_dma_lock();
1849 fd_disable_dma();
1850 release_dma_lock(flags);
1851
1852 if (FDCS->version >= FDC_82072A)
1853 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1854 else {
1855 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1856 udelay(FD_RESET_DELAY);
1857 fd_outb(FDCS->dor, FD_DOR);
1858 }
1859}
1860
1861static void show_floppy(void)
1862{
1863 int i;
1864
Joe Perchesb46df352010-03-10 15:20:46 -08001865 pr_info("\n");
1866 pr_info("floppy driver state\n");
1867 pr_info("-------------------\n");
1868 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1869 jiffies, interruptjiffies, jiffies - interruptjiffies,
1870 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
1872#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001873 pr_info("timeout_message=%s\n", timeout_message);
1874 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001876 pr_info("%2x %2x %lu\n",
1877 output_log[(i + output_log_pos) % OLOGSIZE].data,
1878 output_log[(i + output_log_pos) % OLOGSIZE].status,
1879 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1880 pr_info("last result at %lu\n", resultjiffies);
1881 pr_info("last redo_fd_request at %lu\n", lastredo);
1882 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1883 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884#endif
1885
Joe Perchesb46df352010-03-10 15:20:46 -08001886 pr_info("status=%x\n", fd_inb(FD_STATUS));
1887 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001889 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001890 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001891 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001893 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001895 pr_info("timer_function=%p\n", fd_timeout.function);
1896 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1897 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
Joe Perchesb46df352010-03-10 15:20:46 -08001899 pr_info("cont=%p\n", cont);
1900 pr_info("current_req=%p\n", current_req);
1901 pr_info("command_status=%d\n", command_status);
1902 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903}
1904
1905static void floppy_shutdown(unsigned long data)
1906{
1907 unsigned long flags;
1908
1909 if (!initialising)
1910 show_floppy();
1911 cancel_activity();
1912
1913 floppy_enable_hlt();
1914
1915 flags = claim_dma_lock();
1916 fd_disable_dma();
1917 release_dma_lock(flags);
1918
1919 /* avoid dma going to a random drive after shutdown */
1920
1921 if (!initialising)
1922 DPRINT("floppy timeout called\n");
1923 FDCS->reset = 1;
1924 if (cont) {
1925 cont->done(0);
1926 cont->redo(); /* this will recall reset when needed */
1927 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001928 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 process_fd_request();
1930 }
1931 is_alive("floppy shutdown");
1932}
1933
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001935static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001937 int mask;
1938 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
1940 mask = 0xfc;
1941 data = UNIT(current_drive);
1942 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1943 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1944 set_debugt();
1945 /* no read since this drive is running */
1946 DRS->first_read_date = 0;
1947 /* note motor start time if motor is not yet running */
1948 DRS->spinup_date = jiffies;
1949 data |= (0x10 << UNIT(current_drive));
1950 }
1951 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1952 mask &= ~(0x10 << UNIT(current_drive));
1953
1954 /* starts motor and selects floppy */
1955 del_timer(motor_off_timer + current_drive);
1956 set_dor(fdc, mask, data);
1957
1958 /* wait_for_completion also schedules reset if needed. */
1959 return (fd_wait_for_completion(DRS->select_date + DP->select_delay,
1960 (timeout_fn) function));
1961}
1962
1963static void floppy_ready(void)
1964{
1965 CHECK_RESET;
1966 if (start_motor(floppy_ready))
1967 return;
1968 if (fdc_dtr())
1969 return;
1970
1971#ifdef DCL_DEBUG
1972 if (DP->flags & FD_DEBUG) {
1973 DPRINT("calling disk change from floppy_ready\n");
1974 }
1975#endif
1976 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1977 disk_change(current_drive) && !DP->select_delay)
1978 twaddle(); /* this clears the dcl on certain drive/controller
1979 * combinations */
1980
1981#ifdef fd_chose_dma_mode
1982 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1983 unsigned long flags = claim_dma_lock();
1984 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1985 release_dma_lock(flags);
1986 }
1987#endif
1988
1989 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1990 perpendicular_mode();
1991 fdc_specify(); /* must be done here because of hut, hlt ... */
1992 seek_floppy();
1993 } else {
1994 if ((raw_cmd->flags & FD_RAW_READ) ||
1995 (raw_cmd->flags & FD_RAW_WRITE))
1996 fdc_specify();
1997 setup_rw_floppy();
1998 }
1999}
2000
2001static void floppy_start(void)
2002{
2003 reschedule_timeout(current_reqD, "floppy start", 0);
2004
2005 scandrives();
2006#ifdef DCL_DEBUG
2007 if (DP->flags & FD_DEBUG) {
2008 DPRINT("setting NEWCHANGE in floppy_start\n");
2009 }
2010#endif
2011 SETF(FD_DISK_NEWCHANGE);
2012 floppy_ready();
2013}
2014
2015/*
2016 * ========================================================================
2017 * here ends the bottom half. Exported routines are:
2018 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2019 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2020 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2021 * and set_dor.
2022 * ========================================================================
2023 */
2024/*
2025 * General purpose continuations.
2026 * ==============================
2027 */
2028
2029static void do_wakeup(void)
2030{
2031 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2032 cont = NULL;
2033 command_status += 2;
2034 wake_up(&command_done);
2035}
2036
2037static struct cont_t wakeup_cont = {
2038 .interrupt = empty,
2039 .redo = do_wakeup,
2040 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002041 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042};
2043
2044static struct cont_t intr_cont = {
2045 .interrupt = empty,
2046 .redo = process_fd_request,
2047 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002048 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049};
2050
Jesper Juhl06f748c2007-10-16 23:30:57 -07002051static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052{
2053 int ret;
2054
2055 schedule_bh(handler);
2056
2057 if (command_status < 2 && NO_SIGNAL) {
2058 DECLARE_WAITQUEUE(wait, current);
2059
2060 add_wait_queue(&command_done, &wait);
2061 for (;;) {
2062 set_current_state(interruptible ?
2063 TASK_INTERRUPTIBLE :
2064 TASK_UNINTERRUPTIBLE);
2065
2066 if (command_status >= 2 || !NO_SIGNAL)
2067 break;
2068
2069 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 schedule();
2071 }
2072
2073 set_current_state(TASK_RUNNING);
2074 remove_wait_queue(&command_done, &wait);
2075 }
2076
2077 if (command_status < 2) {
2078 cancel_activity();
2079 cont = &intr_cont;
2080 reset_fdc();
2081 return -EINTR;
2082 }
2083
2084 if (FDCS->reset)
2085 command_status = FD_COMMAND_ERROR;
2086 if (command_status == FD_COMMAND_OKAY)
2087 ret = 0;
2088 else
2089 ret = -EIO;
2090 command_status = FD_COMMAND_NONE;
2091 return ret;
2092}
2093
2094static void generic_done(int result)
2095{
2096 command_status = result;
2097 cont = &wakeup_cont;
2098}
2099
2100static void generic_success(void)
2101{
2102 cont->done(1);
2103}
2104
2105static void generic_failure(void)
2106{
2107 cont->done(0);
2108}
2109
2110static void success_and_wakeup(void)
2111{
2112 generic_success();
2113 cont->redo();
2114}
2115
2116/*
2117 * formatting and rw support.
2118 * ==========================
2119 */
2120
2121static int next_valid_format(void)
2122{
2123 int probed_format;
2124
2125 probed_format = DRS->probed_format;
2126 while (1) {
2127 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2128 DRS->probed_format = 0;
2129 return 1;
2130 }
2131 if (floppy_type[DP->autodetect[probed_format]].sect) {
2132 DRS->probed_format = probed_format;
2133 return 0;
2134 }
2135 probed_format++;
2136 }
2137}
2138
2139static void bad_flp_intr(void)
2140{
2141 int err_count;
2142
2143 if (probing) {
2144 DRS->probed_format++;
2145 if (!next_valid_format())
2146 return;
2147 }
2148 err_count = ++(*errors);
2149 INFBOUND(DRWE->badness, err_count);
2150 if (err_count > DP->max_errors.abort)
2151 cont->done(0);
2152 if (err_count > DP->max_errors.reset)
2153 FDCS->reset = 1;
2154 else if (err_count > DP->max_errors.recal)
2155 DRS->track = NEED_2_RECAL;
2156}
2157
2158static void set_floppy(int drive)
2159{
2160 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002161
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 if (type)
2163 _floppy = floppy_type + type;
2164 else
2165 _floppy = current_type[drive];
2166}
2167
2168/*
2169 * formatting support.
2170 * ===================
2171 */
2172static void format_interrupt(void)
2173{
2174 switch (interpret_errors()) {
2175 case 1:
2176 cont->error();
2177 case 2:
2178 break;
2179 case 0:
2180 cont->done(1);
2181 }
2182 cont->redo();
2183}
2184
2185#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002186#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002188
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189static void setup_format_params(int track)
2190{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002191 int n;
2192 int il;
2193 int count;
2194 int head_shift;
2195 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 struct fparm {
2197 unsigned char track, head, sect, size;
2198 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
2200 raw_cmd = &default_raw_cmd;
2201 raw_cmd->track = track;
2202
Joe Perches48c8cee2010-03-10 15:20:45 -08002203 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2204 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 raw_cmd->rate = _floppy->rate & 0x43;
2206 raw_cmd->cmd_count = NR_F;
2207 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2208 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2209 F_SIZECODE = FD_SIZECODE(_floppy);
2210 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2211 F_GAP = _floppy->fmt_gap;
2212 F_FILL = FD_FILL_BYTE;
2213
2214 raw_cmd->kernel_data = floppy_track_buffer;
2215 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2216
2217 /* allow for about 30ms for data transport per track */
2218 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2219
2220 /* a ``cylinder'' is two tracks plus a little stepping time */
2221 track_shift = 2 * head_shift + 3;
2222
2223 /* position of logical sector 1 on this track */
2224 n = (track_shift * format_req.track + head_shift * format_req.head)
2225 % F_SECT_PER_TRACK;
2226
2227 /* determine interleave */
2228 il = 1;
2229 if (_floppy->fmt_gap < 0x22)
2230 il++;
2231
2232 /* initialize field */
2233 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2234 here[count].track = format_req.track;
2235 here[count].head = format_req.head;
2236 here[count].sect = 0;
2237 here[count].size = F_SIZECODE;
2238 }
2239 /* place logical sectors */
2240 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2241 here[n].sect = count;
2242 n = (n + il) % F_SECT_PER_TRACK;
2243 if (here[n].sect) { /* sector busy, find next free sector */
2244 ++n;
2245 if (n >= F_SECT_PER_TRACK) {
2246 n -= F_SECT_PER_TRACK;
2247 while (here[n].sect)
2248 ++n;
2249 }
2250 }
2251 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002252 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002254 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 }
2256}
2257
2258static void redo_format(void)
2259{
2260 buffer_track = -1;
2261 setup_format_params(format_req.track << STRETCH(_floppy));
2262 floppy_start();
2263 debugt("queue format request");
2264}
2265
2266static struct cont_t format_cont = {
2267 .interrupt = format_interrupt,
2268 .redo = redo_format,
2269 .error = bad_flp_intr,
2270 .done = generic_done
2271};
2272
2273static int do_format(int drive, struct format_descr *tmp_format_req)
2274{
2275 int ret;
2276
2277 LOCK_FDC(drive, 1);
2278 set_floppy(drive);
2279 if (!_floppy ||
2280 _floppy->track > DP->tracks ||
2281 tmp_format_req->track >= _floppy->track ||
2282 tmp_format_req->head >= _floppy->head ||
2283 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2284 !_floppy->fmt_gap) {
2285 process_fd_request();
2286 return -EINVAL;
2287 }
2288 format_req = *tmp_format_req;
2289 format_errors = 0;
2290 cont = &format_cont;
2291 errors = &format_errors;
2292 IWAIT(redo_format);
2293 process_fd_request();
2294 return ret;
2295}
2296
2297/*
2298 * Buffer read/write and support
2299 * =============================
2300 */
2301
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002302static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303{
2304 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002305 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002308 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002309 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002310 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
2313 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002314 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 current_req = NULL;
2316}
2317
2318/* new request_done. Can handle physical sectors which are smaller than a
2319 * logical buffer */
2320static void request_done(int uptodate)
2321{
2322 struct request_queue *q = floppy_queue;
2323 struct request *req = current_req;
2324 unsigned long flags;
2325 int block;
2326
2327 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002328 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
2330 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002331 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 return;
2333 }
2334
2335 if (uptodate) {
2336 /* maintain values for invalidation on geometry
2337 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002338 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 INFBOUND(DRS->maxblock, block);
2340 if (block > _floppy->sect)
2341 DRS->maxtrack = 1;
2342
2343 /* unlock chained buffers */
2344 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002345 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 spin_unlock_irqrestore(q->queue_lock, flags);
2347 } else {
2348 if (rq_data_dir(req) == WRITE) {
2349 /* record write error information */
2350 DRWE->write_errors++;
2351 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002352 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 DRWE->first_error_generation = DRS->generation;
2354 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002355 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 DRWE->last_error_generation = DRS->generation;
2357 }
2358 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002359 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 spin_unlock_irqrestore(q->queue_lock, flags);
2361 }
2362}
2363
2364/* Interrupt handler evaluating the result of the r/w operation */
2365static void rw_interrupt(void)
2366{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002367 int eoc;
2368 int ssize;
2369 int heads;
2370 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
2372 if (R_HEAD >= 2) {
2373 /* some Toshiba floppy controllers occasionnally seem to
2374 * return bogus interrupts after read/write operations, which
2375 * can be recognized by a bad head number (>= 2) */
2376 return;
2377 }
2378
2379 if (!DRS->first_read_date)
2380 DRS->first_read_date = jiffies;
2381
2382 nr_sectors = 0;
2383 CODE2SIZE;
2384
2385 if (ST1 & ST1_EOC)
2386 eoc = 1;
2387 else
2388 eoc = 0;
2389
2390 if (COMMAND & 0x80)
2391 heads = 2;
2392 else
2393 heads = 1;
2394
2395 nr_sectors = (((R_TRACK - TRACK) * heads +
2396 R_HEAD - HEAD) * SECT_PER_TRACK +
2397 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2398
2399#ifdef FLOPPY_SANITY_CHECK
2400 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002401 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 DPRINT("long rw: %x instead of %lx\n",
2403 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002404 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2405 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2406 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2407 pr_info("heads=%d eoc=%d\n", heads, eoc);
2408 pr_info("spt=%d st=%d ss=%d\n",
2409 SECT_PER_TRACK, fsector_t, ssize);
2410 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 }
2412#endif
2413
2414 nr_sectors -= in_sector_offset;
2415 INFBOUND(nr_sectors, 0);
2416 SUPBOUND(current_count_sectors, nr_sectors);
2417
2418 switch (interpret_errors()) {
2419 case 2:
2420 cont->redo();
2421 return;
2422 case 1:
2423 if (!current_count_sectors) {
2424 cont->error();
2425 cont->redo();
2426 return;
2427 }
2428 break;
2429 case 0:
2430 if (!current_count_sectors) {
2431 cont->redo();
2432 return;
2433 }
2434 current_type[current_drive] = _floppy;
2435 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2436 break;
2437 }
2438
2439 if (probing) {
2440 if (DP->flags & FTD_MSG)
2441 DPRINT("Auto-detected floppy type %s in fd%d\n",
2442 _floppy->name, current_drive);
2443 current_type[current_drive] = _floppy;
2444 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2445 probing = 0;
2446 }
2447
2448 if (CT(COMMAND) != FD_READ ||
2449 raw_cmd->kernel_data == current_req->buffer) {
2450 /* transfer directly from buffer */
2451 cont->done(1);
2452 } else if (CT(COMMAND) == FD_READ) {
2453 buffer_track = raw_cmd->track;
2454 buffer_drive = current_drive;
2455 INFBOUND(buffer_max, nr_sectors + fsector_t);
2456 }
2457 cont->redo();
2458}
2459
2460/* Compute maximal contiguous buffer size. */
2461static int buffer_chain_size(void)
2462{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002464 int size;
2465 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 char *base;
2467
2468 base = bio_data(current_req->bio);
2469 size = 0;
2470
NeilBrown5705f702007-09-25 12:35:59 +02002471 rq_for_each_segment(bv, current_req, iter) {
2472 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2473 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
NeilBrown5705f702007-09-25 12:35:59 +02002475 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 }
2477
2478 return size >> 9;
2479}
2480
2481/* Compute the maximal transfer size */
2482static int transfer_size(int ssize, int max_sector, int max_size)
2483{
2484 SUPBOUND(max_sector, fsector_t + max_size);
2485
2486 /* alignment */
2487 max_sector -= (max_sector % _floppy->sect) % ssize;
2488
2489 /* transfer size, beginning not aligned */
2490 current_count_sectors = max_sector - fsector_t;
2491
2492 return max_sector;
2493}
2494
2495/*
2496 * Move data from/to the track buffer to/from the buffer cache.
2497 */
2498static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2499{
2500 int remaining; /* number of transferred 512-byte sectors */
2501 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002502 char *buffer;
2503 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002504 int size;
2505 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506
2507 max_sector = transfer_size(ssize,
2508 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002509 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002512 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002514 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 remaining = current_count_sectors << 9;
2517#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002518 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002520 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2521 pr_info("remaining=%d\n", remaining >> 9);
2522 pr_info("current_req->nr_sectors=%u\n",
2523 blk_rq_sectors(current_req));
2524 pr_info("current_req->current_nr_sectors=%u\n",
2525 blk_rq_cur_sectors(current_req));
2526 pr_info("max_sector=%d\n", max_sector);
2527 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 }
2529#endif
2530
2531 buffer_max = max(max_sector, buffer_max);
2532
2533 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2534
Tejun Heo1011c1b2009-05-07 22:24:45 +09002535 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
NeilBrown5705f702007-09-25 12:35:59 +02002537 rq_for_each_segment(bv, current_req, iter) {
2538 if (!remaining)
2539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
NeilBrown5705f702007-09-25 12:35:59 +02002541 size = bv->bv_len;
2542 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543
NeilBrown5705f702007-09-25 12:35:59 +02002544 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002546 if (dma_buffer + size >
2547 floppy_track_buffer + (max_buffer_sectors << 10) ||
2548 dma_buffer < floppy_track_buffer) {
2549 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002550 (int)((floppy_track_buffer - dma_buffer) >> 9));
2551 pr_info("fsector_t=%d buffer_min=%d\n",
2552 fsector_t, buffer_min);
2553 pr_info("current_count_sectors=%ld\n",
2554 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002556 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002557 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002558 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002559 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 }
NeilBrown5705f702007-09-25 12:35:59 +02002561 if (((unsigned long)buffer) % 512)
2562 DPRINT("%p buffer not aligned\n", buffer);
2563#endif
2564 if (CT(COMMAND) == FD_READ)
2565 memcpy(buffer, dma_buffer, size);
2566 else
2567 memcpy(dma_buffer, buffer, size);
2568
2569 remaining -= size;
2570 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 }
2572#ifdef FLOPPY_SANITY_CHECK
2573 if (remaining) {
2574 if (remaining > 0)
2575 max_sector -= remaining >> 9;
2576 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2577 }
2578#endif
2579}
2580
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581/* work around a bug in pseudo DMA
2582 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2583 * sending data. Hence we need a different way to signal the
2584 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2585 * does not work with MT, hence we can only transfer one head at
2586 * a time
2587 */
2588static void virtualdmabug_workaround(void)
2589{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002590 int hard_sectors;
2591 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
2593 if (CT(COMMAND) == FD_WRITE) {
2594 COMMAND &= ~0x80; /* switch off multiple track mode */
2595
2596 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2597 end_sector = SECTOR + hard_sectors - 1;
2598#ifdef FLOPPY_SANITY_CHECK
2599 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002600 pr_info("too many sectors %d > %d\n",
2601 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 return;
2603 }
2604#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002605 SECT_PER_TRACK = end_sector;
2606 /* make sure SECT_PER_TRACK
2607 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 }
2609}
2610
2611/*
2612 * Formulate a read/write request.
2613 * this routine decides where to load the data (directly to buffer, or to
2614 * tmp floppy area), how much data to load (the size of the buffer, the whole
2615 * track, or a single sector)
2616 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2617 * allocation on the fly, it should be done here. No other part should need
2618 * modification.
2619 */
2620
2621static int make_raw_rw_request(void)
2622{
2623 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002624 int max_sector;
2625 int max_size;
2626 int tracksize;
2627 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002630 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 return 0;
2632 }
2633
2634 set_fdc((long)current_req->rq_disk->private_data);
2635
2636 raw_cmd = &default_raw_cmd;
2637 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2638 FD_RAW_NEED_SEEK;
2639 raw_cmd->cmd_count = NR_RW;
2640 if (rq_data_dir(current_req) == READ) {
2641 raw_cmd->flags |= FD_RAW_READ;
2642 COMMAND = FM_MODE(_floppy, FD_READ);
2643 } else if (rq_data_dir(current_req) == WRITE) {
2644 raw_cmd->flags |= FD_RAW_WRITE;
2645 COMMAND = FM_MODE(_floppy, FD_WRITE);
2646 } else {
2647 DPRINT("make_raw_rw_request: unknown command\n");
2648 return 0;
2649 }
2650
2651 max_sector = _floppy->sect * _floppy->head;
2652
Tejun Heo83096eb2009-05-07 22:24:39 +09002653 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2654 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002656 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 current_count_sectors = 1;
2658 return 1;
2659 } else
2660 return 0;
2661 }
2662 HEAD = fsector_t / _floppy->sect;
2663
Keith Wansbrough9e491842008-09-22 14:57:17 -07002664 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2666 max_sector = _floppy->sect;
2667
2668 /* 2M disks have phantom sectors on the first track */
2669 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2670 max_sector = 2 * _floppy->sect / 3;
2671 if (fsector_t >= max_sector) {
2672 current_count_sectors =
2673 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002674 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 return 1;
2676 }
2677 SIZECODE = 2;
2678 } else
2679 SIZECODE = FD_SIZECODE(_floppy);
2680 raw_cmd->rate = _floppy->rate & 0x43;
2681 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2682 raw_cmd->rate = 1;
2683
2684 if (SIZECODE)
2685 SIZECODE2 = 0xff;
2686 else
2687 SIZECODE2 = 0x80;
2688 raw_cmd->track = TRACK << STRETCH(_floppy);
2689 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2690 GAP = _floppy->gap;
2691 CODE2SIZE;
2692 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2693 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002694 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
2696 /* tracksize describes the size which can be filled up with sectors
2697 * of size ssize.
2698 */
2699 tracksize = _floppy->sect - _floppy->sect % ssize;
2700 if (tracksize < _floppy->sect) {
2701 SECT_PER_TRACK++;
2702 if (tracksize <= fsector_t % _floppy->sect)
2703 SECTOR--;
2704
2705 /* if we are beyond tracksize, fill up using smaller sectors */
2706 while (tracksize <= fsector_t % _floppy->sect) {
2707 while (tracksize + ssize > _floppy->sect) {
2708 SIZECODE--;
2709 ssize >>= 1;
2710 }
2711 SECTOR++;
2712 SECT_PER_TRACK++;
2713 tracksize += ssize;
2714 }
2715 max_sector = HEAD * _floppy->sect + tracksize;
2716 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2717 max_sector = _floppy->sect;
2718 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2719 /* for virtual DMA bug workaround */
2720 max_sector = _floppy->sect;
2721 }
2722
2723 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2724 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002725 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 if ((raw_cmd->track == buffer_track) &&
2727 (current_drive == buffer_drive) &&
2728 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2729 /* data already in track buffer */
2730 if (CT(COMMAND) == FD_READ) {
2731 copy_buffer(1, max_sector, buffer_max);
2732 return 1;
2733 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002734 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 if (CT(COMMAND) == FD_WRITE) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002736 if (fsector_t + blk_rq_sectors(current_req) > ssize &&
2737 fsector_t + blk_rq_sectors(current_req) < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 max_size = ssize + ssize;
2739 else
2740 max_size = ssize;
2741 }
2742 raw_cmd->flags &= ~FD_RAW_WRITE;
2743 raw_cmd->flags |= FD_RAW_READ;
2744 COMMAND = FM_MODE(_floppy, FD_READ);
2745 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2746 unsigned long dma_limit;
2747 int direct, indirect;
2748
2749 indirect =
2750 transfer_size(ssize, max_sector,
2751 max_buffer_sectors * 2) - fsector_t;
2752
2753 /*
2754 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2755 * on a 64 bit machine!
2756 */
2757 max_size = buffer_chain_size();
2758 dma_limit =
2759 (MAX_DMA_ADDRESS -
2760 ((unsigned long)current_req->buffer)) >> 9;
2761 if ((unsigned long)max_size > dma_limit) {
2762 max_size = dma_limit;
2763 }
2764 /* 64 kb boundaries */
2765 if (CROSS_64KB(current_req->buffer, max_size << 9))
2766 max_size = (K_64 -
2767 ((unsigned long)current_req->buffer) %
2768 K_64) >> 9;
2769 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2770 /*
2771 * We try to read tracks, but if we get too many errors, we
2772 * go back to reading just one sector at a time.
2773 *
2774 * This means we should be able to read a sector even if there
2775 * are other bad sectors on this track.
2776 */
2777 if (!direct ||
2778 (indirect * 2 > direct * 3 &&
Jesper Juhlaee90412007-10-16 23:30:58 -07002779 *errors < DP->max_errors.read_track && ((!probing
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 || (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002781 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 } else {
2783 raw_cmd->kernel_data = current_req->buffer;
2784 raw_cmd->length = current_count_sectors << 9;
2785 if (raw_cmd->length == 0) {
2786 DPRINT
2787 ("zero dma transfer attempted from make_raw_request\n");
2788 DPRINT("indirect=%d direct=%d fsector_t=%d",
2789 indirect, direct, fsector_t);
2790 return 0;
2791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 virtualdmabug_workaround();
2793 return 2;
2794 }
2795 }
2796
2797 if (CT(COMMAND) == FD_READ)
2798 max_size = max_sector; /* unbounded */
2799
2800 /* claim buffer track if needed */
2801 if (buffer_track != raw_cmd->track || /* bad track */
2802 buffer_drive != current_drive || /* bad drive */
2803 fsector_t > buffer_max ||
2804 fsector_t < buffer_min ||
2805 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002806 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 max_sector > 2 * max_buffer_sectors + buffer_min &&
2808 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
2809 /* not enough space */
2810 ) {
2811 buffer_track = -1;
2812 buffer_drive = current_drive;
2813 buffer_max = buffer_min = aligned_sector_t;
2814 }
2815 raw_cmd->kernel_data = floppy_track_buffer +
2816 ((aligned_sector_t - buffer_min) << 9);
2817
2818 if (CT(COMMAND) == FD_WRITE) {
2819 /* copy write buffer to track buffer.
2820 * if we get here, we know that the write
2821 * is either aligned or the data already in the buffer
2822 * (buffer will be overwritten) */
2823#ifdef FLOPPY_SANITY_CHECK
2824 if (in_sector_offset && buffer_track == -1)
2825 DPRINT("internal error offset !=0 on write\n");
2826#endif
2827 buffer_track = raw_cmd->track;
2828 buffer_drive = current_drive;
2829 copy_buffer(ssize, max_sector,
2830 2 * max_buffer_sectors + buffer_min);
2831 } else
2832 transfer_size(ssize, max_sector,
2833 2 * max_buffer_sectors + buffer_min -
2834 aligned_sector_t);
2835
2836 /* round up current_count_sectors to get dma xfer size */
2837 raw_cmd->length = in_sector_offset + current_count_sectors;
2838 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2839 raw_cmd->length <<= 9;
2840#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 if ((raw_cmd->length < current_count_sectors << 9) ||
2842 (raw_cmd->kernel_data != current_req->buffer &&
2843 CT(COMMAND) == FD_WRITE &&
2844 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2845 aligned_sector_t < buffer_min)) ||
2846 raw_cmd->length % (128 << SIZECODE) ||
2847 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2848 DPRINT("fractionary current count b=%lx s=%lx\n",
2849 raw_cmd->length, current_count_sectors);
2850 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002851 pr_info("addr=%d, length=%ld\n",
2852 (int)((raw_cmd->kernel_data -
2853 floppy_track_buffer) >> 9),
2854 current_count_sectors);
2855 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2856 fsector_t, aligned_sector_t, max_sector, max_size);
2857 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2858 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2859 COMMAND, SECTOR, HEAD, TRACK);
2860 pr_info("buffer drive=%d\n", buffer_drive);
2861 pr_info("buffer track=%d\n", buffer_track);
2862 pr_info("buffer_min=%d\n", buffer_min);
2863 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 return 0;
2865 }
2866
2867 if (raw_cmd->kernel_data != current_req->buffer) {
2868 if (raw_cmd->kernel_data < floppy_track_buffer ||
2869 current_count_sectors < 0 ||
2870 raw_cmd->length < 0 ||
2871 raw_cmd->kernel_data + raw_cmd->length >
2872 floppy_track_buffer + (max_buffer_sectors << 10)) {
2873 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002874 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2875 fsector_t, buffer_min, raw_cmd->length >> 9);
2876 pr_info("current_count_sectors=%ld\n",
2877 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002879 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002881 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 return 0;
2883 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002884 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002885 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 DPRINT("buffer overrun in direct transfer\n");
2887 return 0;
2888 } else if (raw_cmd->length < current_count_sectors << 9) {
2889 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002890 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2891 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 }
2893 if (raw_cmd->length == 0) {
2894 DPRINT("zero dma transfer attempted from make_raw_request\n");
2895 return 0;
2896 }
2897#endif
2898
2899 virtualdmabug_workaround();
2900 return 2;
2901}
2902
2903static void redo_fd_request(void)
2904{
2905#define REPEAT {request_done(0); continue; }
2906 int drive;
2907 int tmp;
2908
2909 lastredo = jiffies;
2910 if (current_drive < N_DRIVE)
2911 floppy_off(current_drive);
2912
2913 for (;;) {
2914 if (!current_req) {
2915 struct request *req;
2916
2917 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002918 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 spin_unlock_irq(floppy_queue->queue_lock);
2920 if (!req) {
2921 do_floppy = NULL;
2922 unlock_fdc();
2923 return;
2924 }
2925 current_req = req;
2926 }
2927 drive = (long)current_req->rq_disk->private_data;
2928 set_fdc(drive);
2929 reschedule_timeout(current_reqD, "redo fd request", 0);
2930
2931 set_floppy(drive);
2932 raw_cmd = &default_raw_cmd;
2933 raw_cmd->flags = 0;
2934 if (start_motor(redo_fd_request))
2935 return;
2936 disk_change(current_drive);
2937 if (test_bit(current_drive, &fake_change) ||
2938 TESTF(FD_DISK_CHANGED)) {
2939 DPRINT("disk absent or changed during operation\n");
2940 REPEAT;
2941 }
2942 if (!_floppy) { /* Autodetection */
2943 if (!probing) {
2944 DRS->probed_format = 0;
2945 if (next_valid_format()) {
2946 DPRINT("no autodetectable formats\n");
2947 _floppy = NULL;
2948 REPEAT;
2949 }
2950 }
2951 probing = 1;
2952 _floppy =
2953 floppy_type + DP->autodetect[DRS->probed_format];
2954 } else
2955 probing = 0;
2956 errors = &(current_req->errors);
2957 tmp = make_raw_rw_request();
2958 if (tmp < 2) {
2959 request_done(tmp);
2960 continue;
2961 }
2962
2963 if (TESTF(FD_NEED_TWADDLE))
2964 twaddle();
2965 schedule_bh(floppy_start);
2966 debugt("queue fd request");
2967 return;
2968 }
2969#undef REPEAT
2970}
2971
2972static struct cont_t rw_cont = {
2973 .interrupt = rw_interrupt,
2974 .redo = redo_fd_request,
2975 .error = bad_flp_intr,
2976 .done = request_done
2977};
2978
2979static void process_fd_request(void)
2980{
2981 cont = &rw_cont;
2982 schedule_bh(redo_fd_request);
2983}
2984
Jens Axboe165125e2007-07-24 09:28:11 +02002985static void do_fd_request(struct request_queue * q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
2987 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002988 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 return;
2990 }
2991
2992 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002993 pr_info("warning: usage count=0, current_req=%p exiting\n",
2994 current_req);
2995 pr_info("sect=%ld type=%x flags=%x\n",
2996 (long)blk_rq_pos(current_req), current_req->cmd_type,
2997 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 return;
2999 }
3000 if (test_bit(0, &fdc_busy)) {
3001 /* fdc busy, this new request will be treated when the
3002 current one is done */
3003 is_alive("do fd request, old request running");
3004 return;
3005 }
3006 lock_fdc(MAXTIMEOUT, 0);
3007 process_fd_request();
3008 is_alive("do fd request");
3009}
3010
3011static struct cont_t poll_cont = {
3012 .interrupt = success_and_wakeup,
3013 .redo = floppy_ready,
3014 .error = generic_failure,
3015 .done = generic_done
3016};
3017
3018static int poll_drive(int interruptible, int flag)
3019{
3020 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003021
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 /* no auto-sense, just clear dcl */
3023 raw_cmd = &default_raw_cmd;
3024 raw_cmd->flags = flag;
3025 raw_cmd->track = 0;
3026 raw_cmd->cmd_count = 0;
3027 cont = &poll_cont;
3028#ifdef DCL_DEBUG
3029 if (DP->flags & FD_DEBUG) {
3030 DPRINT("setting NEWCHANGE in poll_drive\n");
3031 }
3032#endif
3033 SETF(FD_DISK_NEWCHANGE);
3034 WAIT(floppy_ready);
3035 return ret;
3036}
3037
3038/*
3039 * User triggered reset
3040 * ====================
3041 */
3042
3043static void reset_intr(void)
3044{
Joe Perchesb46df352010-03-10 15:20:46 -08003045 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046}
3047
3048static struct cont_t reset_cont = {
3049 .interrupt = reset_intr,
3050 .redo = success_and_wakeup,
3051 .error = generic_failure,
3052 .done = generic_done
3053};
3054
3055static int user_reset_fdc(int drive, int arg, int interruptible)
3056{
3057 int ret;
3058
3059 ret = 0;
3060 LOCK_FDC(drive, interruptible);
3061 if (arg == FD_RESET_ALWAYS)
3062 FDCS->reset = 1;
3063 if (FDCS->reset) {
3064 cont = &reset_cont;
3065 WAIT(reset_fdc);
3066 }
3067 process_fd_request();
3068 return ret;
3069}
3070
3071/*
3072 * Misc Ioctl's and support
3073 * ========================
3074 */
3075static inline int fd_copyout(void __user *param, const void *address,
3076 unsigned long size)
3077{
3078 return copy_to_user(param, address, size) ? -EFAULT : 0;
3079}
3080
Joe Perches48c8cee2010-03-10 15:20:45 -08003081static inline int fd_copyin(void __user *param, void *address,
3082 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083{
3084 return copy_from_user(address, param, size) ? -EFAULT : 0;
3085}
3086
Joe Perches48c8cee2010-03-10 15:20:45 -08003087#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3088 ? -EFAULT : 0)
3089#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3090 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
Joe Perches48c8cee2010-03-10 15:20:45 -08003092#define COPYOUT(x) ECALL(_COPYOUT(x))
3093#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
3095static inline const char *drive_name(int type, int drive)
3096{
3097 struct floppy_struct *floppy;
3098
3099 if (type)
3100 floppy = floppy_type + type;
3101 else {
3102 if (UDP->native_format)
3103 floppy = floppy_type + UDP->native_format;
3104 else
3105 return "(null)";
3106 }
3107 if (floppy->name)
3108 return floppy->name;
3109 else
3110 return "(null)";
3111}
3112
3113/* raw commands */
3114static void raw_cmd_done(int flag)
3115{
3116 int i;
3117
3118 if (!flag) {
3119 raw_cmd->flags |= FD_RAW_FAILURE;
3120 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3121 } else {
3122 raw_cmd->reply_count = inr;
3123 if (raw_cmd->reply_count > MAX_REPLIES)
3124 raw_cmd->reply_count = 0;
3125 for (i = 0; i < raw_cmd->reply_count; i++)
3126 raw_cmd->reply[i] = reply_buffer[i];
3127
3128 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3129 unsigned long flags;
3130 flags = claim_dma_lock();
3131 raw_cmd->length = fd_get_dma_residue();
3132 release_dma_lock(flags);
3133 }
3134
3135 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3136 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3137 raw_cmd->flags |= FD_RAW_FAILURE;
3138
3139 if (disk_change(current_drive))
3140 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3141 else
3142 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3143 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3144 motor_off_callback(current_drive);
3145
3146 if (raw_cmd->next &&
3147 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3148 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3149 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3150 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3151 raw_cmd = raw_cmd->next;
3152 return;
3153 }
3154 }
3155 generic_done(flag);
3156}
3157
3158static struct cont_t raw_cmd_cont = {
3159 .interrupt = success_and_wakeup,
3160 .redo = floppy_start,
3161 .error = generic_failure,
3162 .done = raw_cmd_done
3163};
3164
3165static inline int raw_cmd_copyout(int cmd, char __user *param,
3166 struct floppy_raw_cmd *ptr)
3167{
3168 int ret;
3169
3170 while (ptr) {
3171 COPYOUT(*ptr);
3172 param += sizeof(struct floppy_raw_cmd);
3173 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
3174 if (ptr->length >= 0
3175 && ptr->length <= ptr->buffer_length)
3176 ECALL(fd_copyout
3177 (ptr->data, ptr->kernel_data,
3178 ptr->buffer_length - ptr->length));
3179 }
3180 ptr = ptr->next;
3181 }
3182 return 0;
3183}
3184
3185static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3186{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003187 struct floppy_raw_cmd *next;
3188 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
3190 this = *ptr;
3191 *ptr = NULL;
3192 while (this) {
3193 if (this->buffer_length) {
3194 fd_dma_mem_free((unsigned long)this->kernel_data,
3195 this->buffer_length);
3196 this->buffer_length = 0;
3197 }
3198 next = this->next;
3199 kfree(this);
3200 this = next;
3201 }
3202}
3203
3204static inline int raw_cmd_copyin(int cmd, char __user *param,
3205 struct floppy_raw_cmd **rcmd)
3206{
3207 struct floppy_raw_cmd *ptr;
3208 int ret;
3209 int i;
3210
3211 *rcmd = NULL;
3212 while (1) {
3213 ptr = (struct floppy_raw_cmd *)
3214 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3215 if (!ptr)
3216 return -ENOMEM;
3217 *rcmd = ptr;
3218 COPYIN(*ptr);
3219 ptr->next = NULL;
3220 ptr->buffer_length = 0;
3221 param += sizeof(struct floppy_raw_cmd);
3222 if (ptr->cmd_count > 33)
3223 /* the command may now also take up the space
3224 * initially intended for the reply & the
3225 * reply count. Needed for long 82078 commands
3226 * such as RESTORE, which takes ... 17 command
3227 * bytes. Murphy's law #137: When you reserve
3228 * 16 bytes for a structure, you'll one day
3229 * discover that you really need 17...
3230 */
3231 return -EINVAL;
3232
3233 for (i = 0; i < 16; i++)
3234 ptr->reply[i] = 0;
3235 ptr->resultcode = 0;
3236 ptr->kernel_data = NULL;
3237
3238 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3239 if (ptr->length <= 0)
3240 return -EINVAL;
3241 ptr->kernel_data =
3242 (char *)fd_dma_mem_alloc(ptr->length);
3243 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3244 if (!ptr->kernel_data)
3245 return -ENOMEM;
3246 ptr->buffer_length = ptr->length;
3247 }
3248 if (ptr->flags & FD_RAW_WRITE)
3249 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3250 ptr->length));
3251 rcmd = &(ptr->next);
3252 if (!(ptr->flags & FD_RAW_MORE))
3253 return 0;
3254 ptr->rate &= 0x43;
3255 }
3256}
3257
3258static int raw_cmd_ioctl(int cmd, void __user *param)
3259{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003261 int drive;
3262 int ret2;
3263 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264
3265 if (FDCS->rawcmd <= 1)
3266 FDCS->rawcmd = 1;
3267 for (drive = 0; drive < N_DRIVE; drive++) {
3268 if (FDC(drive) != fdc)
3269 continue;
3270 if (drive == current_drive) {
3271 if (UDRS->fd_ref > 1) {
3272 FDCS->rawcmd = 2;
3273 break;
3274 }
3275 } else if (UDRS->fd_ref) {
3276 FDCS->rawcmd = 2;
3277 break;
3278 }
3279 }
3280
3281 if (FDCS->reset)
3282 return -EIO;
3283
3284 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3285 if (ret) {
3286 raw_cmd_free(&my_raw_cmd);
3287 return ret;
3288 }
3289
3290 raw_cmd = my_raw_cmd;
3291 cont = &raw_cmd_cont;
3292 ret = wait_til_done(floppy_start, 1);
3293#ifdef DCL_DEBUG
3294 if (DP->flags & FD_DEBUG) {
3295 DPRINT("calling disk change from raw_cmd ioctl\n");
3296 }
3297#endif
3298
3299 if (ret != -EINTR && FDCS->reset)
3300 ret = -EIO;
3301
3302 DRS->track = NO_TRACK;
3303
3304 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3305 if (!ret)
3306 ret = ret2;
3307 raw_cmd_free(&my_raw_cmd);
3308 return ret;
3309}
3310
3311static int invalidate_drive(struct block_device *bdev)
3312{
3313 /* invalidate the buffer track to force a reread */
3314 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3315 process_fd_request();
3316 check_disk_change(bdev);
3317 return 0;
3318}
3319
3320static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3321 int drive, int type, struct block_device *bdev)
3322{
3323 int cnt;
3324
3325 /* sanity checking for parameters. */
3326 if (g->sect <= 0 ||
3327 g->head <= 0 ||
3328 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3329 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003330 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 return -EINVAL;
3332 if (type) {
3333 if (!capable(CAP_SYS_ADMIN))
3334 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003335 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003336 if (lock_fdc(drive, 1)) {
3337 mutex_unlock(&open_lock);
3338 return -EINTR;
3339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 floppy_type[type] = *g;
3341 floppy_type[type].name = "user format";
3342 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3343 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3344 floppy_type[type].size + 1;
3345 process_fd_request();
3346 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3347 struct block_device *bdev = opened_bdev[cnt];
3348 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3349 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003350 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003352 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 } else {
3354 int oldStretch;
3355 LOCK_FDC(drive, 1);
3356 if (cmd != FDDEFPRM)
3357 /* notice a disk change immediately, else
3358 * we lose our settings immediately*/
3359 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3360 oldStretch = g->stretch;
3361 user_params[drive] = *g;
3362 if (buffer_drive == drive)
3363 SUPBOUND(buffer_max, user_params[drive].sect);
3364 current_type[drive] = &user_params[drive];
3365 floppy_sizes[drive] = user_params[drive].size;
3366 if (cmd == FDDEFPRM)
3367 DRS->keep_data = -1;
3368 else
3369 DRS->keep_data = 1;
3370 /* invalidation. Invalidate only when needed, i.e.
3371 * when there are already sectors in the buffer cache
3372 * whose number will change. This is useful, because
3373 * mtools often changes the geometry of the disk after
3374 * looking at the boot block */
3375 if (DRS->maxblock > user_params[drive].sect ||
3376 DRS->maxtrack ||
3377 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003378 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 invalidate_drive(bdev);
3380 else
3381 process_fd_request();
3382 }
3383 return 0;
3384}
3385
3386/* handle obsolete ioctl's */
3387static int ioctl_table[] = {
3388 FDCLRPRM,
3389 FDSETPRM,
3390 FDDEFPRM,
3391 FDGETPRM,
3392 FDMSGON,
3393 FDMSGOFF,
3394 FDFMTBEG,
3395 FDFMTTRK,
3396 FDFMTEND,
3397 FDSETEMSGTRESH,
3398 FDFLUSH,
3399 FDSETMAXERRS,
3400 FDGETMAXERRS,
3401 FDGETDRVTYP,
3402 FDSETDRVPRM,
3403 FDGETDRVPRM,
3404 FDGETDRVSTAT,
3405 FDPOLLDRVSTAT,
3406 FDRESET,
3407 FDGETFDCSTAT,
3408 FDWERRORCLR,
3409 FDWERRORGET,
3410 FDRAWCMD,
3411 FDEJECT,
3412 FDTWADDLE
3413};
3414
3415static inline int normalize_ioctl(int *cmd, int *size)
3416{
3417 int i;
3418
3419 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3420 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3421 *size = _IOC_SIZE(*cmd);
3422 *cmd = ioctl_table[i];
3423 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003424 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 return -EFAULT;
3426 }
3427 return 0;
3428 }
3429 }
3430 return -EINVAL;
3431}
3432
3433static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3434{
3435 if (type)
3436 *g = &floppy_type[type];
3437 else {
3438 LOCK_FDC(drive, 0);
3439 CALL(poll_drive(0, 0));
3440 process_fd_request();
3441 *g = current_type[drive];
3442 }
3443 if (!*g)
3444 return -ENODEV;
3445 return 0;
3446}
3447
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003448static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3449{
3450 int drive = (long)bdev->bd_disk->private_data;
3451 int type = ITYPE(drive_state[drive].fd_device);
3452 struct floppy_struct *g;
3453 int ret;
3454
3455 ret = get_floppy_geometry(drive, type, &g);
3456 if (ret)
3457 return ret;
3458
3459 geo->heads = g->head;
3460 geo->sectors = g->sect;
3461 geo->cylinders = g->track;
3462 return 0;
3463}
3464
Al Viroa4af9b42008-03-02 09:27:55 -05003465static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 unsigned long param)
3467{
Al Viroa4af9b42008-03-02 09:27:55 -05003468#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469#define OUT(c,x) case c: outparam = (const char *) (x); break
3470#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
3471
Al Viroa4af9b42008-03-02 09:27:55 -05003472 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003473 int type = ITYPE(UDRS->fd_device);
3474 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 int ret;
3476 int size;
3477 union inparam {
3478 struct floppy_struct g; /* geometry */
3479 struct format_descr f;
3480 struct floppy_max_errors max_errors;
3481 struct floppy_drive_params dp;
3482 } inparam; /* parameters coming from user space */
3483 const char *outparam; /* parameters passed back to user space */
3484
3485 /* convert compatibility eject ioctls into floppy eject ioctl.
3486 * We do this in order to provide a means to eject floppy disks before
3487 * installing the new fdutils package */
3488 if (cmd == CDROMEJECT || /* CD-ROM eject */
3489 cmd == 0x6470 /* SunOS floppy eject */ ) {
3490 DPRINT("obsolete eject ioctl\n");
3491 DPRINT("please use floppycontrol --eject\n");
3492 cmd = FDEJECT;
3493 }
3494
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 /* convert the old style command into a new style command */
3496 if ((cmd & 0xff00) == 0x0200) {
3497 ECALL(normalize_ioctl(&cmd, &size));
3498 } else
3499 return -EINVAL;
3500
3501 /* permission checks */
3502 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3503 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3504 return -EPERM;
3505
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003506 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3507 return -EINVAL;
3508
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 /* copyin */
3510 CLEARSTRUCT(&inparam);
3511 if (_IOC_DIR(cmd) & _IOC_WRITE)
3512 ECALL(fd_copyin((void __user *)param, &inparam, size))
3513
3514 switch (cmd) {
3515 case FDEJECT:
3516 if (UDRS->fd_ref != 1)
3517 /* somebody else has this drive open */
3518 return -EBUSY;
3519 LOCK_FDC(drive, 1);
3520
3521 /* do the actual eject. Fails on
3522 * non-Sparc architectures */
3523 ret = fd_eject(UNIT(drive));
3524
3525 USETF(FD_DISK_CHANGED);
3526 USETF(FD_VERIFY);
3527 process_fd_request();
3528 return ret;
3529 case FDCLRPRM:
3530 LOCK_FDC(drive, 1);
3531 current_type[drive] = NULL;
3532 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3533 UDRS->keep_data = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003534 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 case FDSETPRM:
3536 case FDDEFPRM:
3537 return set_geometry(cmd, &inparam.g,
Al Viroa4af9b42008-03-02 09:27:55 -05003538 drive, type, bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 case FDGETPRM:
3540 ECALL(get_floppy_geometry(drive, type,
3541 (struct floppy_struct **)
3542 &outparam));
3543 break;
3544
3545 case FDMSGON:
3546 UDP->flags |= FTD_MSG;
3547 return 0;
3548 case FDMSGOFF:
3549 UDP->flags &= ~FTD_MSG;
3550 return 0;
3551
3552 case FDFMTBEG:
3553 LOCK_FDC(drive, 1);
3554 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3555 ret = UDRS->flags;
3556 process_fd_request();
3557 if (ret & FD_VERIFY)
3558 return -ENODEV;
3559 if (!(ret & FD_DISK_WRITABLE))
3560 return -EROFS;
3561 return 0;
3562 case FDFMTTRK:
3563 if (UDRS->fd_ref != 1)
3564 return -EBUSY;
3565 return do_format(drive, &inparam.f);
3566 case FDFMTEND:
3567 case FDFLUSH:
3568 LOCK_FDC(drive, 1);
Al Viroa4af9b42008-03-02 09:27:55 -05003569 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
3571 case FDSETEMSGTRESH:
3572 UDP->max_errors.reporting =
3573 (unsigned short)(param & 0x0f);
3574 return 0;
3575 OUT(FDGETMAXERRS, &UDP->max_errors);
3576 IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
3577
3578 case FDGETDRVTYP:
3579 outparam = drive_name(type, drive);
3580 SUPBOUND(size, strlen(outparam) + 1);
3581 break;
3582
3583 IN(FDSETDRVPRM, UDP, dp);
3584 OUT(FDGETDRVPRM, UDP);
3585
3586 case FDPOLLDRVSTAT:
3587 LOCK_FDC(drive, 1);
3588 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3589 process_fd_request();
3590 /* fall through */
3591 OUT(FDGETDRVSTAT, UDRS);
3592
3593 case FDRESET:
3594 return user_reset_fdc(drive, (int)param, 1);
3595
3596 OUT(FDGETFDCSTAT, UFDCS);
3597
3598 case FDWERRORCLR:
3599 CLEARSTRUCT(UDRWE);
3600 return 0;
3601 OUT(FDWERRORGET, UDRWE);
3602
3603 case FDRAWCMD:
3604 if (type)
3605 return -EINVAL;
3606 LOCK_FDC(drive, 1);
3607 set_floppy(drive);
3608 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3609 process_fd_request();
3610 return i;
3611
3612 case FDTWADDLE:
3613 LOCK_FDC(drive, 1);
3614 twaddle();
3615 process_fd_request();
3616 return 0;
3617
3618 default:
3619 return -EINVAL;
3620 }
3621
3622 if (_IOC_DIR(cmd) & _IOC_READ)
3623 return fd_copyout((void __user *)param, outparam, size);
3624 else
3625 return 0;
3626#undef OUT
3627#undef IN
3628}
3629
3630static void __init config_types(void)
3631{
Joe Perchesb46df352010-03-10 15:20:46 -08003632 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 int drive;
3634
3635 /* read drive info out of physical CMOS */
3636 drive = 0;
3637 if (!UDP->cmos)
3638 UDP->cmos = FLOPPY0_TYPE;
3639 drive = 1;
3640 if (!UDP->cmos && FLOPPY1_TYPE)
3641 UDP->cmos = FLOPPY1_TYPE;
3642
Jesper Juhl06f748c2007-10-16 23:30:57 -07003643 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644
3645 for (drive = 0; drive < N_DRIVE; drive++) {
3646 unsigned int type = UDP->cmos;
3647 struct floppy_drive_params *params;
3648 const char *name = NULL;
3649 static char temparea[32];
3650
Tobias Klauser945f3902006-01-08 01:05:11 -08003651 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 params = &default_drive_params[type].params;
3653 if (type) {
3654 name = default_drive_params[type].name;
3655 allowed_drive_mask |= 1 << drive;
3656 } else
3657 allowed_drive_mask &= ~(1 << drive);
3658 } else {
3659 params = &default_drive_params[0].params;
3660 sprintf(temparea, "unknown type %d (usb?)", type);
3661 name = temparea;
3662 }
3663 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003664 const char *prepend;
3665 if (!has_drive) {
3666 prepend = "";
3667 has_drive = true;
3668 pr_info("Floppy drive(s):");
3669 } else {
3670 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 }
Joe Perchesb46df352010-03-10 15:20:46 -08003672
3673 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 }
3675 *UDP = *params;
3676 }
Joe Perchesb46df352010-03-10 15:20:46 -08003677
3678 if (has_drive)
3679 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680}
3681
Al Viroa4af9b42008-03-02 09:27:55 -05003682static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683{
Al Viroa4af9b42008-03-02 09:27:55 -05003684 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003686 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 if (UDRS->fd_ref < 0)
3688 UDRS->fd_ref = 0;
3689 else if (!UDRS->fd_ref--) {
3690 DPRINT("floppy_release with fd_ref == 0");
3691 UDRS->fd_ref = 0;
3692 }
3693 if (!UDRS->fd_ref)
3694 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003695 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003696
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 return 0;
3698}
3699
3700/*
3701 * floppy_open check for aliasing (/dev/fd0 can be the same as
3702 * /dev/PS0 etc), and disallows simultaneous access to the same
3703 * drive with different device numbers.
3704 */
Al Viroa4af9b42008-03-02 09:27:55 -05003705static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706{
Al Viroa4af9b42008-03-02 09:27:55 -05003707 int drive = (long)bdev->bd_disk->private_data;
3708 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 int try;
3710 int res = -EBUSY;
3711 char *tmp;
3712
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003713 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003715 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 goto out2;
3717
3718 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3719 USETF(FD_DISK_CHANGED);
3720 USETF(FD_VERIFY);
3721 }
3722
Al Viroa4af9b42008-03-02 09:27:55 -05003723 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 goto out2;
3725
Al Viroa4af9b42008-03-02 09:27:55 -05003726 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 UDRS->fd_ref = -1;
3728 else
3729 UDRS->fd_ref++;
3730
Al Viroa4af9b42008-03-02 09:27:55 -05003731 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
3733 res = -ENXIO;
3734
3735 if (!floppy_track_buffer) {
3736 /* if opening an ED drive, reserve a big buffer,
3737 * else reserve a small one */
3738 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3739 try = 64; /* Only 48 actually useful */
3740 else
3741 try = 32; /* Only 24 actually useful */
3742
3743 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3744 if (!tmp && !floppy_track_buffer) {
3745 try >>= 1; /* buffer only one side */
3746 INFBOUND(try, 16);
3747 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3748 }
3749 if (!tmp && !floppy_track_buffer) {
3750 fallback_on_nodma_alloc(&tmp, 2048 * try);
3751 }
3752 if (!tmp && !floppy_track_buffer) {
3753 DPRINT("Unable to allocate DMA memory\n");
3754 goto out;
3755 }
3756 if (floppy_track_buffer) {
3757 if (tmp)
3758 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3759 } else {
3760 buffer_min = buffer_max = -1;
3761 floppy_track_buffer = tmp;
3762 max_buffer_sectors = try;
3763 }
3764 }
3765
Al Viroa4af9b42008-03-02 09:27:55 -05003766 new_dev = MINOR(bdev->bd_dev);
3767 UDRS->fd_device = new_dev;
3768 set_capacity(disks[drive], floppy_sizes[new_dev]);
3769 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 if (buffer_drive == drive)
3771 buffer_track = -1;
3772 }
3773
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 if (UFDCS->rawcmd == 1)
3775 UFDCS->rawcmd = 2;
3776
Al Viroa4af9b42008-03-02 09:27:55 -05003777 if (!(mode & FMODE_NDELAY)) {
3778 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003780 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 if (UTESTF(FD_DISK_CHANGED))
3782 goto out;
3783 }
3784 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003785 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 goto out;
3787 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003788 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 return 0;
3790out:
3791 if (UDRS->fd_ref < 0)
3792 UDRS->fd_ref = 0;
3793 else
3794 UDRS->fd_ref--;
3795 if (!UDRS->fd_ref)
3796 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003798 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 return res;
3800}
3801
3802/*
3803 * Check if the disk has been changed or if a change has been faked.
3804 */
3805static int check_floppy_change(struct gendisk *disk)
3806{
3807 int drive = (long)disk->private_data;
3808
3809 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3810 return 1;
3811
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003812 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 lock_fdc(drive, 0);
3814 poll_drive(0, 0);
3815 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 }
3817
3818 if (UTESTF(FD_DISK_CHANGED) ||
3819 UTESTF(FD_VERIFY) ||
3820 test_bit(drive, &fake_change) ||
3821 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3822 return 1;
3823 return 0;
3824}
3825
3826/*
3827 * This implements "read block 0" for floppy_revalidate().
3828 * Needed for format autodetection, checking whether there is
3829 * a disk in the drive, and whether that disk is writable.
3830 */
3831
NeilBrown6712ecf2007-09-27 12:47:43 +02003832static void floppy_rb0_complete(struct bio *bio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 int err)
3834{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836}
3837
3838static int __floppy_read_block_0(struct block_device *bdev)
3839{
3840 struct bio bio;
3841 struct bio_vec bio_vec;
3842 struct completion complete;
3843 struct page *page;
3844 size_t size;
3845
3846 page = alloc_page(GFP_NOIO);
3847 if (!page) {
3848 process_fd_request();
3849 return -ENOMEM;
3850 }
3851
3852 size = bdev->bd_block_size;
3853 if (!size)
3854 size = 1024;
3855
3856 bio_init(&bio);
3857 bio.bi_io_vec = &bio_vec;
3858 bio_vec.bv_page = page;
3859 bio_vec.bv_len = size;
3860 bio_vec.bv_offset = 0;
3861 bio.bi_vcnt = 1;
3862 bio.bi_idx = 0;
3863 bio.bi_size = size;
3864 bio.bi_bdev = bdev;
3865 bio.bi_sector = 0;
3866 init_completion(&complete);
3867 bio.bi_private = &complete;
3868 bio.bi_end_io = floppy_rb0_complete;
3869
3870 submit_bio(READ, &bio);
3871 generic_unplug_device(bdev_get_queue(bdev));
3872 process_fd_request();
3873 wait_for_completion(&complete);
3874
3875 __free_page(page);
3876
3877 return 0;
3878}
3879
3880/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3881 * the bootblock (block 0). "Autodetection" is also needed to check whether
3882 * there is a disk in the drive at all... Thus we also do it for fixed
3883 * geometry formats */
3884static int floppy_revalidate(struct gendisk *disk)
3885{
3886 int drive = (long)disk->private_data;
3887#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3888 int cf;
3889 int res = 0;
3890
3891 if (UTESTF(FD_DISK_CHANGED) ||
3892 UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
3893 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003894 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 return -EFAULT;
3896 }
3897 lock_fdc(drive, 0);
3898 cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
3899 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3900 process_fd_request(); /*already done by another thread */
3901 return 0;
3902 }
3903 UDRS->maxblock = 0;
3904 UDRS->maxtrack = 0;
3905 if (buffer_drive == drive)
3906 buffer_track = -1;
3907 clear_bit(drive, &fake_change);
3908 UCLEARF(FD_DISK_CHANGED);
3909 if (cf)
3910 UDRS->generation++;
3911 if (NO_GEOM) {
3912 /* auto-sensing */
3913 res = __floppy_read_block_0(opened_bdev[drive]);
3914 } else {
3915 if (cf)
3916 poll_drive(0, FD_RAW_NEED_DISK);
3917 process_fd_request();
3918 }
3919 }
3920 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3921 return res;
3922}
3923
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003924static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003925 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003926 .open = floppy_open,
3927 .release = floppy_release,
3928 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003929 .getgeo = fd_getgeo,
3930 .media_changed = check_floppy_change,
3931 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934/*
3935 * Floppy Driver initialization
3936 * =============================
3937 */
3938
3939/* Determine the floppy disk controller type */
3940/* This routine was written by David C. Niemi */
3941static char __init get_fdc_version(void)
3942{
3943 int r;
3944
3945 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3946 if (FDCS->reset)
3947 return FDC_NONE;
3948 if ((r = result()) <= 0x00)
3949 return FDC_NONE; /* No FDC present ??? */
3950 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003951 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3953 }
3954 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003955 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3956 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 return FDC_UNKNOWN;
3958 }
3959
3960 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003961 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3963 }
3964
3965 output_byte(FD_PERPENDICULAR);
3966 if (need_more_output() == MORE_OUTPUT) {
3967 output_byte(0);
3968 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003969 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 return FDC_82072A; /* 82072A as found on Sparcs. */
3971 }
3972
3973 output_byte(FD_UNLOCK);
3974 r = result();
3975 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003976 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
3978 * LOCK/UNLOCK */
3979 }
3980 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003981 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3982 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 return FDC_UNKNOWN;
3984 }
3985 output_byte(FD_PARTID);
3986 r = result();
3987 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003988 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3989 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 return FDC_UNKNOWN;
3991 }
3992 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003993 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 return FDC_82077; /* Revised 82077AA passes all the tests */
3995 }
3996 switch (reply_buffer[0] >> 5) {
3997 case 0x0:
3998 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003999 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 return FDC_82078;
4001 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004002 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 return FDC_82078;
4004 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004005 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 return FDC_S82078B;
4007 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004008 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 return FDC_87306;
4010 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004011 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4012 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 return FDC_82078_UNKN;
4014 }
4015} /* get_fdc_version */
4016
4017/* lilo configuration */
4018
4019static void __init floppy_set_flags(int *ints, int param, int param2)
4020{
4021 int i;
4022
4023 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4024 if (param)
4025 default_drive_params[i].params.flags |= param2;
4026 else
4027 default_drive_params[i].params.flags &= ~param2;
4028 }
4029 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4030}
4031
4032static void __init daring(int *ints, int param, int param2)
4033{
4034 int i;
4035
4036 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4037 if (param) {
4038 default_drive_params[i].params.select_delay = 0;
4039 default_drive_params[i].params.flags |=
4040 FD_SILENT_DCL_CLEAR;
4041 } else {
4042 default_drive_params[i].params.select_delay =
4043 2 * HZ / 100;
4044 default_drive_params[i].params.flags &=
4045 ~FD_SILENT_DCL_CLEAR;
4046 }
4047 }
4048 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4049}
4050
4051static void __init set_cmos(int *ints, int dummy, int dummy2)
4052{
4053 int current_drive = 0;
4054
4055 if (ints[0] != 2) {
4056 DPRINT("wrong number of parameters for CMOS\n");
4057 return;
4058 }
4059 current_drive = ints[1];
4060 if (current_drive < 0 || current_drive >= 8) {
4061 DPRINT("bad drive for set_cmos\n");
4062 return;
4063 }
4064#if N_FDC > 1
4065 if (current_drive >= 4 && !FDC2)
4066 FDC2 = 0x370;
4067#endif
4068 DP->cmos = ints[2];
4069 DPRINT("setting CMOS code to %d\n", ints[2]);
4070}
4071
4072static struct param_table {
4073 const char *name;
4074 void (*fn) (int *ints, int param, int param2);
4075 int *var;
4076 int def_param;
4077 int param2;
4078} config_params[] __initdata = {
4079 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4080 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4081 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4082 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4083 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4084 {"daring", daring, NULL, 1, 0},
4085#if N_FDC > 1
4086 {"two_fdc", NULL, &FDC2, 0x370, 0},
4087 {"one_fdc", NULL, &FDC2, 0, 0},
4088#endif
4089 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4090 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4091 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4092 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4093 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4094 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4095 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4096 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4097 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4098 {"nofifo", NULL, &no_fifo, 0x20, 0},
4099 {"usefifo", NULL, &no_fifo, 0, 0},
4100 {"cmos", set_cmos, NULL, 0, 0},
4101 {"slow", NULL, &slow_floppy, 1, 0},
4102 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4103 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4104 {"L40SX", NULL, &print_unex, 0, 0}
4105
4106 EXTRA_FLOPPY_PARAMS
4107};
4108
4109static int __init floppy_setup(char *str)
4110{
4111 int i;
4112 int param;
4113 int ints[11];
4114
4115 str = get_options(str, ARRAY_SIZE(ints), ints);
4116 if (str) {
4117 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4118 if (strcmp(str, config_params[i].name) == 0) {
4119 if (ints[0])
4120 param = ints[1];
4121 else
4122 param = config_params[i].def_param;
4123 if (config_params[i].fn)
4124 config_params[i].
4125 fn(ints, param,
4126 config_params[i].param2);
4127 if (config_params[i].var) {
4128 DPRINT("%s=%d\n", str, param);
4129 *config_params[i].var = param;
4130 }
4131 return 1;
4132 }
4133 }
4134 }
4135 if (str) {
4136 DPRINT("unknown floppy option [%s]\n", str);
4137
4138 DPRINT("allowed options are:");
4139 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004140 pr_cont(" %s", config_params[i].name);
4141 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 } else
4143 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004144 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 return 0;
4146}
4147
4148static int have_no_fdc = -ENODEV;
4149
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004150static ssize_t floppy_cmos_show(struct device *dev,
4151 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004152{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004153 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004154 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004155
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004156 drive = p->id;
4157 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004158}
Joe Perches48c8cee2010-03-10 15:20:45 -08004159
4160DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004161
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162static void floppy_device_release(struct device *dev)
4163{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164}
4165
Frans Popc90cd332009-07-25 22:24:54 +02004166static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004167{
4168 int fdc;
4169
4170 for (fdc = 0; fdc < N_FDC; fdc++)
4171 if (FDCS->address != -1)
4172 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4173
4174 return 0;
4175}
4176
Alexey Dobriyan47145212009-12-14 18:00:08 -08004177static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004178 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004179 .restore = floppy_resume,
4180};
4181
4182static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004183 .driver = {
4184 .name = "floppy",
Frans Popc90cd332009-07-25 22:24:54 +02004185 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004186 },
4187};
4188
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004189static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190
4191static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4192{
4193 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4194 if (drive >= N_DRIVE ||
4195 !(allowed_drive_mask & (1 << drive)) ||
4196 fdc_state[FDC(drive)].version == FDC_NONE)
4197 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004198 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 return NULL;
4200 *part = 0;
4201 return get_disk(disks[drive]);
4202}
4203
4204static int __init floppy_init(void)
4205{
4206 int i, unit, drive;
4207 int err, dr;
4208
Kumar Gala68e1ee62008-09-22 14:41:31 -07004209#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004210 if (check_legacy_ioport(FDC1))
4211 return -ENODEV;
4212#endif
4213
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 raw_cmd = NULL;
4215
4216 for (dr = 0; dr < N_DRIVE; dr++) {
4217 disks[dr] = alloc_disk(1);
4218 if (!disks[dr]) {
4219 err = -ENOMEM;
4220 goto out_put_disk;
4221 }
4222
4223 disks[dr]->major = FLOPPY_MAJOR;
4224 disks[dr]->first_minor = TOMINOR(dr);
4225 disks[dr]->fops = &floppy_fops;
4226 sprintf(disks[dr]->disk_name, "fd%d", dr);
4227
4228 init_timer(&motor_off_timer[dr]);
4229 motor_off_timer[dr].data = dr;
4230 motor_off_timer[dr].function = motor_off_callback;
4231 }
4232
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 err = register_blkdev(FLOPPY_MAJOR, "fd");
4234 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004235 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004237 err = platform_driver_register(&floppy_driver);
4238 if (err)
4239 goto out_unreg_blkdev;
4240
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4242 if (!floppy_queue) {
4243 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004244 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004246 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247
4248 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4249 floppy_find, NULL, NULL);
4250
4251 for (i = 0; i < 256; i++)
4252 if (ITYPE(i))
4253 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4254 else
4255 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4256
4257 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4258 config_types();
4259
4260 for (i = 0; i < N_FDC; i++) {
4261 fdc = i;
4262 CLEARSTRUCT(FDCS);
4263 FDCS->dtr = -1;
4264 FDCS->dor = 0x4;
4265#if defined(__sparc__) || defined(__mc68000__)
4266 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
4267#ifdef __mc68000__
4268 if (MACH_IS_SUN3X)
4269#endif
4270 FDCS->version = FDC_82072A;
4271#endif
4272 }
4273
4274 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 fdc_state[0].address = FDC1;
4276 if (fdc_state[0].address == -1) {
4277 del_timer(&fd_timeout);
4278 err = -ENODEV;
4279 goto out_unreg_region;
4280 }
4281#if N_FDC > 1
4282 fdc_state[1].address = FDC2;
4283#endif
4284
4285 fdc = 0; /* reset fdc in case of unexpected interrupt */
4286 err = floppy_grab_irq_and_dma();
4287 if (err) {
4288 del_timer(&fd_timeout);
4289 err = -EBUSY;
4290 goto out_unreg_region;
4291 }
4292
4293 /* initialise drive state */
4294 for (drive = 0; drive < N_DRIVE; drive++) {
4295 CLEARSTRUCT(UDRS);
4296 CLEARSTRUCT(UDRWE);
4297 USETF(FD_DISK_NEWCHANGE);
4298 USETF(FD_DISK_CHANGED);
4299 USETF(FD_VERIFY);
4300 UDRS->fd_device = -1;
4301 floppy_track_buffer = NULL;
4302 max_buffer_sectors = 0;
4303 }
4304 /*
4305 * Small 10 msec delay to let through any interrupt that
4306 * initialization might have triggered, to not
4307 * confuse detection:
4308 */
4309 msleep(10);
4310
4311 for (i = 0; i < N_FDC; i++) {
4312 fdc = i;
4313 FDCS->driver_version = FD_DRIVER_VERSION;
4314 for (unit = 0; unit < 4; unit++)
4315 FDCS->track[unit] = 0;
4316 if (FDCS->address == -1)
4317 continue;
4318 FDCS->rawcmd = 2;
4319 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4320 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004321 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 FDCS->address = -1;
4323 FDCS->version = FDC_NONE;
4324 continue;
4325 }
4326 /* Try to determine the floppy controller type */
4327 FDCS->version = get_fdc_version();
4328 if (FDCS->version == FDC_NONE) {
4329 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004330 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 FDCS->address = -1;
4332 continue;
4333 }
4334 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4335 can_use_virtual_dma = 0;
4336
4337 have_no_fdc = 0;
4338 /* Not all FDCs seem to be able to handle the version command
4339 * properly, so force a reset for the standard FDC clones,
4340 * to avoid interrupt garbage.
4341 */
4342 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4343 }
4344 fdc = 0;
4345 del_timer(&fd_timeout);
4346 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 initialising = 0;
4348 if (have_no_fdc) {
4349 DPRINT("no floppy controllers found\n");
4350 err = have_no_fdc;
4351 goto out_flush_work;
4352 }
4353
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 for (drive = 0; drive < N_DRIVE; drive++) {
4355 if (!(allowed_drive_mask & (1 << drive)))
4356 continue;
4357 if (fdc_state[FDC(drive)].version == FDC_NONE)
4358 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004359
4360 floppy_device[drive].name = floppy_device_name;
4361 floppy_device[drive].id = drive;
4362 floppy_device[drive].dev.release = floppy_device_release;
4363
4364 err = platform_device_register(&floppy_device[drive]);
4365 if (err)
4366 goto out_flush_work;
4367
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004368 err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
4369 if (err)
4370 goto out_unreg_platform_dev;
4371
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 /* to be cleaned up... */
4373 disks[drive]->private_data = (void *)(long)drive;
4374 disks[drive]->queue = floppy_queue;
4375 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004376 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 add_disk(disks[drive]);
4378 }
4379
4380 return 0;
4381
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004382out_unreg_platform_dev:
4383 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384out_flush_work:
4385 flush_scheduled_work();
4386 if (usage_count)
4387 floppy_release_irq_and_dma();
4388out_unreg_region:
4389 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4390 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004391out_unreg_driver:
4392 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393out_unreg_blkdev:
4394 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395out_put_disk:
4396 while (dr--) {
4397 del_timer(&motor_off_timer[dr]);
4398 put_disk(disks[dr]);
4399 }
4400 return err;
4401}
4402
4403static DEFINE_SPINLOCK(floppy_usage_lock);
4404
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004405static const struct io_region {
4406 int offset;
4407 int size;
4408} io_regions[] = {
4409 { 2, 1 },
4410 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4411 { 4, 2 },
4412 /* address + 6 is reserved, and may be taken by IDE.
4413 * Unfortunately, Adaptec doesn't know this :-(, */
4414 { 7, 1 },
4415};
4416
4417static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4418{
4419 while (p != io_regions) {
4420 p--;
4421 release_region(FDCS->address + p->offset, p->size);
4422 }
4423}
4424
4425#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4426
4427static int floppy_request_regions(int fdc)
4428{
4429 const struct io_region *p;
4430
4431 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
4432 if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
4433 DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
4434 floppy_release_allocated_regions(fdc, p);
4435 return -EBUSY;
4436 }
4437 }
4438 return 0;
4439}
4440
4441static void floppy_release_regions(int fdc)
4442{
4443 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4444}
4445
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446static int floppy_grab_irq_and_dma(void)
4447{
4448 unsigned long flags;
4449
4450 spin_lock_irqsave(&floppy_usage_lock, flags);
4451 if (usage_count++) {
4452 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4453 return 0;
4454 }
4455 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004456
4457 /*
4458 * We might have scheduled a free_irq(), wait it to
4459 * drain first:
4460 */
4461 flush_scheduled_work();
4462
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 if (fd_request_irq()) {
4464 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4465 FLOPPY_IRQ);
4466 spin_lock_irqsave(&floppy_usage_lock, flags);
4467 usage_count--;
4468 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4469 return -1;
4470 }
4471 if (fd_request_dma()) {
4472 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4473 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004474 if (can_use_virtual_dma & 2)
4475 use_virtual_dma = can_use_virtual_dma = 1;
4476 if (!(can_use_virtual_dma & 1)) {
4477 fd_free_irq();
4478 spin_lock_irqsave(&floppy_usage_lock, flags);
4479 usage_count--;
4480 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4481 return -1;
4482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 }
4484
4485 for (fdc = 0; fdc < N_FDC; fdc++) {
4486 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004487 if (floppy_request_regions(fdc))
4488 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 }
4490 }
4491 for (fdc = 0; fdc < N_FDC; fdc++) {
4492 if (FDCS->address != -1) {
4493 reset_fdc_info(1);
4494 fd_outb(FDCS->dor, FD_DOR);
4495 }
4496 }
4497 fdc = 0;
4498 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4499
4500 for (fdc = 0; fdc < N_FDC; fdc++)
4501 if (FDCS->address != -1)
4502 fd_outb(FDCS->dor, FD_DOR);
4503 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004504 * The driver will try and free resources and relies on us
4505 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 */
4507 fdc = 0;
4508 irqdma_allocated = 1;
4509 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004510cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 fd_free_irq();
4512 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004513 while (--fdc >= 0)
4514 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 spin_lock_irqsave(&floppy_usage_lock, flags);
4516 usage_count--;
4517 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4518 return -1;
4519}
4520
4521static void floppy_release_irq_and_dma(void)
4522{
4523 int old_fdc;
4524#ifdef FLOPPY_SANITY_CHECK
4525#ifndef __sparc__
4526 int drive;
4527#endif
4528#endif
4529 long tmpsize;
4530 unsigned long tmpaddr;
4531 unsigned long flags;
4532
4533 spin_lock_irqsave(&floppy_usage_lock, flags);
4534 if (--usage_count) {
4535 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4536 return;
4537 }
4538 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4539 if (irqdma_allocated) {
4540 fd_disable_dma();
4541 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004542 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 irqdma_allocated = 0;
4544 }
4545 set_dor(0, ~0, 8);
4546#if N_FDC > 1
4547 set_dor(1, ~8, 0);
4548#endif
4549 floppy_enable_hlt();
4550
4551 if (floppy_track_buffer && max_buffer_sectors) {
4552 tmpsize = max_buffer_sectors * 1024;
4553 tmpaddr = (unsigned long)floppy_track_buffer;
4554 floppy_track_buffer = NULL;
4555 max_buffer_sectors = 0;
4556 buffer_min = buffer_max = -1;
4557 fd_dma_mem_free(tmpaddr, tmpsize);
4558 }
4559#ifdef FLOPPY_SANITY_CHECK
4560#ifndef __sparc__
4561 for (drive = 0; drive < N_FDC * 4; drive++)
4562 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004563 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564#endif
4565
4566 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004567 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004569 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004570 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004571 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572#endif
4573 old_fdc = fdc;
4574 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004575 if (FDCS->address != -1)
4576 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 fdc = old_fdc;
4578}
4579
4580#ifdef MODULE
4581
4582static char *floppy;
4583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584static void __init parse_floppy_cfg_string(char *cfg)
4585{
4586 char *ptr;
4587
4588 while (*cfg) {
4589 for (ptr = cfg; *cfg && *cfg != ' ' && *cfg != '\t'; cfg++) ;
4590 if (*cfg) {
4591 *cfg = '\0';
4592 cfg++;
4593 }
4594 if (*ptr)
4595 floppy_setup(ptr);
4596 }
4597}
4598
Jon Schindler7afea3b2008-04-29 00:59:21 -07004599static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600{
4601 if (floppy)
4602 parse_floppy_cfg_string(floppy);
4603 return floppy_init();
4604}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004605module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606
Jon Schindler7afea3b2008-04-29 00:59:21 -07004607static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608{
4609 int drive;
4610
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4612 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004613 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614
4615 for (drive = 0; drive < N_DRIVE; drive++) {
4616 del_timer_sync(&motor_off_timer[drive]);
4617
4618 if ((allowed_drive_mask & (1 << drive)) &&
4619 fdc_state[FDC(drive)].version != FDC_NONE) {
4620 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004621 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4622 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 }
4624 put_disk(disks[drive]);
4625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626
4627 del_timer_sync(&fd_timeout);
4628 del_timer_sync(&fd_timer);
4629 blk_cleanup_queue(floppy_queue);
4630
4631 if (usage_count)
4632 floppy_release_irq_and_dma();
4633
4634 /* eject disk, if any */
4635 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636}
Joe Perches48c8cee2010-03-10 15:20:45 -08004637
Jon Schindler7afea3b2008-04-29 00:59:21 -07004638module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639
4640module_param(floppy, charp, 0);
4641module_param(FLOPPY_IRQ, int, 0);
4642module_param(FLOPPY_DMA, int, 0);
4643MODULE_AUTHOR("Alain L. Knaff");
4644MODULE_SUPPORTED_DEVICE("fd");
4645MODULE_LICENSE("GPL");
4646
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004647/* This doesn't actually get used other than for module information */
4648static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004649 {"PNP0700", 0},
4650 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004651};
Joe Perches48c8cee2010-03-10 15:20:45 -08004652
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004653MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4654
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655#else
4656
4657__setup("floppy=", floppy_setup);
4658module_init(floppy_init)
4659#endif
4660
4661MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);