blob: 48aefd9c5662522c6712185620f0874b3a5f4b2f [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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578static void reset_fdc(void);
579
580/*
581 * These are global variables, as that's the easiest way to give
582 * information to interrupts. They are the data used for the current
583 * request.
584 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800585#define NO_TRACK -1
586#define NEED_1_RECAL -2
587#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589static int usage_count;
590
591/* buffer related variables */
592static int buffer_track = -1;
593static int buffer_drive = -1;
594static int buffer_min = -1;
595static int buffer_max = -1;
596
597/* fdc related variables, should end up in a struct */
598static struct floppy_fdc_state fdc_state[N_FDC];
599static int fdc; /* current fdc */
600
601static struct floppy_struct *_floppy = floppy_type;
602static unsigned char current_drive;
603static long current_count_sectors;
604static unsigned char fsector_t; /* sector in track */
605static unsigned char in_sector_offset; /* offset within physical sector,
606 * expressed in units of 512 bytes */
607
608#ifndef fd_eject
609static inline int fd_eject(int drive)
610{
611 return -EINVAL;
612}
613#endif
614
615/*
616 * Debugging
617 * =========
618 */
619#ifdef DEBUGT
620static long unsigned debugtimer;
621
622static inline void set_debugt(void)
623{
624 debugtimer = jiffies;
625}
626
627static inline void debugt(const char *message)
628{
629 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800630 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632#else
633static inline void set_debugt(void) { }
634static inline void debugt(const char *message) { }
635#endif /* DEBUGT */
636
637typedef void (*timeout_fn) (unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700638static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640static const char *timeout_message;
641
642#ifdef FLOPPY_SANITY_CHECK
643static void is_alive(const char *message)
644{
645 /* this routine checks whether the floppy driver is "alive" */
646 if (test_bit(0, &fdc_busy) && command_status < 2
647 && !timer_pending(&fd_timeout)) {
648 DPRINT("timeout handler died: %s\n", message);
649 }
650}
651#endif
652
Joe Perches48c8cee2010-03-10 15:20:45 -0800653static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655#ifdef FLOPPY_SANITY_CHECK
656
657#define OLOGSIZE 20
658
Joe Perches48c8cee2010-03-10 15:20:45 -0800659static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660static unsigned long interruptjiffies;
661static unsigned long resultjiffies;
662static int resultsize;
663static unsigned long lastredo;
664
665static struct output_log {
666 unsigned char data;
667 unsigned char status;
668 unsigned long jiffies;
669} output_log[OLOGSIZE];
670
671static int output_log_pos;
672#endif
673
674#define current_reqD -1
675#define MAXTIMEOUT -2
676
677static void __reschedule_timeout(int drive, const char *message, int marg)
678{
679 if (drive == current_reqD)
680 drive = current_drive;
681 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700682 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 fd_timeout.expires = jiffies + 20UL * HZ;
684 drive = 0;
685 } else
686 fd_timeout.expires = jiffies + UDP->timeout;
687 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800688 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800689 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 timeout_message = message;
691}
692
693static void reschedule_timeout(int drive, const char *message, int marg)
694{
695 unsigned long flags;
696
697 spin_lock_irqsave(&floppy_lock, flags);
698 __reschedule_timeout(drive, message, marg);
699 spin_unlock_irqrestore(&floppy_lock, flags);
700}
701
Joe Perches48c8cee2010-03-10 15:20:45 -0800702#define INFBOUND(a, b) (a) = max_t(int, a, b)
703#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705/*
706 * Bottom half floppy driver.
707 * ==========================
708 *
709 * This part of the file contains the code talking directly to the hardware,
710 * and also the main service loop (seek-configure-spinup-command)
711 */
712
713/*
714 * disk change.
715 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
716 * and the last_checked date.
717 *
718 * last_checked is the date of the last check which showed 'no disk change'
719 * FD_DISK_CHANGE is set under two conditions:
720 * 1. The floppy has been changed after some i/o to that floppy already
721 * took place.
722 * 2. No floppy disk is in the drive. This is done in order to ensure that
723 * requests are quickly flushed in case there is no disk in the drive. It
724 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
725 * the drive.
726 *
727 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
728 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
729 * each seek. If a disk is present, the disk change line should also be
730 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
731 * change line is set, this means either that no disk is in the drive, or
732 * that it has been removed since the last seek.
733 *
734 * This means that we really have a third possibility too:
735 * The floppy has been changed after the last seek.
736 */
737
738static int disk_change(int drive)
739{
740 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800743 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 DPRINT("WARNING disk change called early\n");
745 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
746 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
747 DPRINT("probing disk change on unselected drive\n");
748 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
749 (unsigned int)FDCS->dor);
750 }
751#endif
752
753#ifdef DCL_DEBUG
754 if (UDP->flags & FD_DEBUG) {
755 DPRINT("checking disk change line for drive %d\n", drive);
756 DPRINT("jiffies=%lu\n", jiffies);
757 DPRINT("disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
758 DPRINT("flags=%lx\n", UDRS->flags);
759 }
760#endif
761 if (UDP->flags & FD_BROKEN_DCL)
762 return UTESTF(FD_DISK_CHANGED);
763 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
764 USETF(FD_VERIFY); /* verify write protection */
765 if (UDRS->maxblock) {
766 /* mark it changed */
767 USETF(FD_DISK_CHANGED);
768 }
769
770 /* invalidate its geometry */
771 if (UDRS->keep_data >= 0) {
772 if ((UDP->flags & FTD_MSG) &&
773 current_type[drive] != NULL)
774 DPRINT("Disk type is undefined after "
775 "disk change\n");
776 current_type[drive] = NULL;
777 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
778 }
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return 1;
781 } else {
782 UDRS->last_checked = jiffies;
783 UCLEARF(FD_DISK_NEWCHANGE);
784 }
785 return 0;
786}
787
788static inline int is_selected(int dor, int unit)
789{
790 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
791}
792
793static int set_dor(int fdc, char mask, char data)
794{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700795 unsigned char unit;
796 unsigned char drive;
797 unsigned char newdor;
798 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 if (FDCS->address == -1)
801 return -1;
802
803 olddor = FDCS->dor;
804 newdor = (olddor & mask) | data;
805 if (newdor != olddor) {
806 unit = olddor & 0x3;
807 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
808 drive = REVDRIVE(fdc, unit);
809#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -0800810 if (UDP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 DPRINT("calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812#endif
813 disk_change(drive);
814 }
815 FDCS->dor = newdor;
816 fd_outb(newdor, FD_DOR);
817
818 unit = newdor & 0x3;
819 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
820 drive = REVDRIVE(fdc, unit);
821 UDRS->select_date = jiffies;
822 }
823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return olddor;
825}
826
827static void twaddle(void)
828{
829 if (DP->select_delay)
830 return;
831 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
832 fd_outb(FDCS->dor, FD_DOR);
833 DRS->select_date = jiffies;
834}
835
836/* reset all driver information about the current fdc. This is needed after
837 * a reset, and after a raw command. */
838static void reset_fdc_info(int mode)
839{
840 int drive;
841
842 FDCS->spec1 = FDCS->spec2 = -1;
843 FDCS->need_configure = 1;
844 FDCS->perp_mode = 1;
845 FDCS->rawcmd = 0;
846 for (drive = 0; drive < N_DRIVE; drive++)
847 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
848 UDRS->track = NEED_2_RECAL;
849}
850
851/* selects the fdc and drive, and enables the fdc's input/dma. */
852static void set_fdc(int drive)
853{
854 if (drive >= 0 && drive < N_DRIVE) {
855 fdc = FDC(drive);
856 current_drive = drive;
857 }
858 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800859 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 return;
861 }
862 set_dor(fdc, ~0, 8);
863#if N_FDC > 1
864 set_dor(1 - fdc, ~8, 0);
865#endif
866 if (FDCS->rawcmd == 2)
867 reset_fdc_info(1);
868 if (fd_inb(FD_STATUS) != STATUS_READY)
869 FDCS->reset = 1;
870}
871
872/* locks the driver */
873static int _lock_fdc(int drive, int interruptible, int line)
874{
875 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800876 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 line);
878 return -1;
879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 if (test_and_set_bit(0, &fdc_busy)) {
882 DECLARE_WAITQUEUE(wait, current);
883 add_wait_queue(&fdc_wait, &wait);
884
885 for (;;) {
886 set_current_state(TASK_INTERRUPTIBLE);
887
888 if (!test_and_set_bit(0, &fdc_busy))
889 break;
890
891 schedule();
892
893 if (!NO_SIGNAL) {
894 remove_wait_queue(&fdc_wait, &wait);
895 return -EINTR;
896 }
897 }
898
899 set_current_state(TASK_RUNNING);
900 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700901 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
903 command_status = FD_COMMAND_NONE;
904
905 __reschedule_timeout(drive, "lock fdc", 0);
906 set_fdc(drive);
907 return 0;
908}
909
Joe Perches48c8cee2010-03-10 15:20:45 -0800910#define lock_fdc(drive, interruptible) \
911 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Joe Perches48c8cee2010-03-10 15:20:45 -0800913#define LOCK_FDC(drive, interruptible) \
914 if (lock_fdc(drive, interruptible)) \
915 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917/* unlocks the driver */
918static inline void unlock_fdc(void)
919{
920 unsigned long flags;
921
922 raw_cmd = NULL;
923 if (!test_bit(0, &fdc_busy))
924 DPRINT("FDC access conflict!\n");
925
926 if (do_floppy)
927 DPRINT("device interrupt still active at FDC release: %p!\n",
928 do_floppy);
929 command_status = FD_COMMAND_NONE;
930 spin_lock_irqsave(&floppy_lock, flags);
931 del_timer(&fd_timeout);
932 cont = NULL;
933 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900934 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 do_fd_request(floppy_queue);
936 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 wake_up(&fdc_wait);
938}
939
940/* switches the motor off after a given timeout */
941static void motor_off_callback(unsigned long nr)
942{
943 unsigned char mask = ~(0x10 << UNIT(nr));
944
945 set_dor(FDC(nr), mask, 0);
946}
947
948/* schedules motor off */
949static void floppy_off(unsigned int drive)
950{
951 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700952 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 if (!(FDCS->dor & (0x10 << UNIT(drive))))
955 return;
956
957 del_timer(motor_off_timer + drive);
958
959 /* make spindle stop in a position which minimizes spinup time
960 * next time */
961 if (UDP->rps) {
962 delta = jiffies - UDRS->first_read_date + HZ -
963 UDP->spindown_offset;
964 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
965 motor_off_timer[drive].expires =
966 jiffies + UDP->spindown - delta;
967 }
968 add_timer(motor_off_timer + drive);
969}
970
971/*
972 * cycle through all N_DRIVE floppy drives, for disk change testing.
973 * stopping at current drive. This is done before any long operation, to
974 * be sure to have up to date disk change information.
975 */
976static void scandrives(void)
977{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700978 int i;
979 int drive;
980 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 if (DP->select_delay)
983 return;
984
985 saved_drive = current_drive;
986 for (i = 0; i < N_DRIVE; i++) {
987 drive = (saved_drive + i + 1) % N_DRIVE;
988 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
989 continue; /* skip closed drives */
990 set_fdc(drive);
991 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
992 (0x10 << UNIT(drive))))
993 /* switch the motor off again, if it was off to
994 * begin with */
995 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
996 }
997 set_fdc(saved_drive);
998}
999
1000static void empty(void)
1001{
1002}
1003
David Howells65f27f32006-11-22 14:55:48 +00001004static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Joe Perches48c8cee2010-03-10 15:20:45 -08001006static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007{
David Howells65f27f32006-11-22 14:55:48 +00001008 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 schedule_work(&floppy_work);
1010}
1011
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001012static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014static void cancel_activity(void)
1015{
1016 unsigned long flags;
1017
1018 spin_lock_irqsave(&floppy_lock, flags);
1019 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001020 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 del_timer(&fd_timer);
1022 spin_unlock_irqrestore(&floppy_lock, flags);
1023}
1024
1025/* this function makes sure that the disk stays in the drive during the
1026 * transfer */
1027static void fd_watchdog(void)
1028{
1029#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001030 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 DPRINT("calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032#endif
1033
1034 if (disk_change(current_drive)) {
1035 DPRINT("disk removed during i/o\n");
1036 cancel_activity();
1037 cont->done(0);
1038 reset_fdc();
1039 } else {
1040 del_timer(&fd_timer);
1041 fd_timer.function = (timeout_fn) fd_watchdog;
1042 fd_timer.expires = jiffies + HZ / 10;
1043 add_timer(&fd_timer);
1044 }
1045}
1046
1047static void main_command_interrupt(void)
1048{
1049 del_timer(&fd_timer);
1050 cont->interrupt();
1051}
1052
1053/* waits for a delay (spinup or select) to pass */
1054static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1055{
1056 if (FDCS->reset) {
1057 reset_fdc(); /* do the reset during sleep to win time
1058 * if we don't need to sleep, it's a good
1059 * occasion anyways */
1060 return 1;
1061 }
1062
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001063 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 del_timer(&fd_timer);
1065 fd_timer.function = function;
1066 fd_timer.expires = delay;
1067 add_timer(&fd_timer);
1068 return 1;
1069 }
1070 return 0;
1071}
1072
1073static DEFINE_SPINLOCK(floppy_hlt_lock);
1074static int hlt_disabled;
1075static void floppy_disable_hlt(void)
1076{
1077 unsigned long flags;
1078
1079 spin_lock_irqsave(&floppy_hlt_lock, flags);
1080 if (!hlt_disabled) {
1081 hlt_disabled = 1;
1082#ifdef HAVE_DISABLE_HLT
1083 disable_hlt();
1084#endif
1085 }
1086 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1087}
1088
1089static void floppy_enable_hlt(void)
1090{
1091 unsigned long flags;
1092
1093 spin_lock_irqsave(&floppy_hlt_lock, flags);
1094 if (hlt_disabled) {
1095 hlt_disabled = 0;
1096#ifdef HAVE_DISABLE_HLT
1097 enable_hlt();
1098#endif
1099 }
1100 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1101}
1102
1103static void setup_DMA(void)
1104{
1105 unsigned long f;
1106
1107#ifdef FLOPPY_SANITY_CHECK
1108 if (raw_cmd->length == 0) {
1109 int i;
1110
Joe Perchesb46df352010-03-10 15:20:46 -08001111 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001113 pr_cont("%x,", raw_cmd->cmd[i]);
1114 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 cont->done(0);
1116 FDCS->reset = 1;
1117 return;
1118 }
1119 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001120 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 cont->done(0);
1122 FDCS->reset = 1;
1123 return;
1124 }
1125#endif
1126 f = claim_dma_lock();
1127 fd_disable_dma();
1128#ifdef fd_dma_setup
1129 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1130 (raw_cmd->flags & FD_RAW_READ) ?
1131 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1132 release_dma_lock(f);
1133 cont->done(0);
1134 FDCS->reset = 1;
1135 return;
1136 }
1137 release_dma_lock(f);
1138#else
1139 fd_clear_dma_ff();
1140 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1141 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1142 DMA_MODE_READ : DMA_MODE_WRITE);
1143 fd_set_dma_addr(raw_cmd->kernel_data);
1144 fd_set_dma_count(raw_cmd->length);
1145 virtual_dma_port = FDCS->address;
1146 fd_enable_dma();
1147 release_dma_lock(f);
1148#endif
1149 floppy_disable_hlt();
1150}
1151
1152static void show_floppy(void);
1153
1154/* waits until the fdc becomes ready */
1155static int wait_til_ready(void)
1156{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001157 int status;
1158 int counter;
1159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (FDCS->reset)
1161 return -1;
1162 for (counter = 0; counter < 10000; counter++) {
1163 status = fd_inb(FD_STATUS);
1164 if (status & STATUS_READY)
1165 return status;
1166 }
1167 if (!initialising) {
1168 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1169 show_floppy();
1170 }
1171 FDCS->reset = 1;
1172 return -1;
1173}
1174
1175/* sends a command byte to the fdc */
1176static int output_byte(char byte)
1177{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001178 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001180 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 return -1;
1182 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1183 fd_outb(byte, FD_DATA);
1184#ifdef FLOPPY_SANITY_CHECK
1185 output_log[output_log_pos].data = byte;
1186 output_log[output_log_pos].status = status;
1187 output_log[output_log_pos].jiffies = jiffies;
1188 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1189#endif
1190 return 0;
1191 }
1192 FDCS->reset = 1;
1193 if (!initialising) {
1194 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1195 byte, fdc, status);
1196 show_floppy();
1197 }
1198 return -1;
1199}
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201/* gets the response from the fdc */
1202static int result(void)
1203{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001204 int i;
1205 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
1207 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001208 status = wait_til_ready();
1209 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 break;
1211 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1212 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1213#ifdef FLOPPY_SANITY_CHECK
1214 resultjiffies = jiffies;
1215 resultsize = i;
1216#endif
1217 return i;
1218 }
1219 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1220 reply_buffer[i] = fd_inb(FD_DATA);
1221 else
1222 break;
1223 }
1224 if (!initialising) {
1225 DPRINT
1226 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1227 fdc, status, i);
1228 show_floppy();
1229 }
1230 FDCS->reset = 1;
1231 return -1;
1232}
1233
1234#define MORE_OUTPUT -2
1235/* does the fdc need more output? */
1236static int need_more_output(void)
1237{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001238 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001239
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001240 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 return -1;
1242 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1243 return MORE_OUTPUT;
1244 return result();
1245}
1246
1247/* Set perpendicular mode as required, based on data rate, if supported.
1248 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1249 */
1250static inline void perpendicular_mode(void)
1251{
1252 unsigned char perp_mode;
1253
1254 if (raw_cmd->rate & 0x40) {
1255 switch (raw_cmd->rate & 3) {
1256 case 0:
1257 perp_mode = 2;
1258 break;
1259 case 3:
1260 perp_mode = 3;
1261 break;
1262 default:
1263 DPRINT("Invalid data rate for perpendicular mode!\n");
1264 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001265 FDCS->reset = 1;
1266 /*
1267 * convenient way to return to
1268 * redo without too much hassle
1269 * (deep stack et al.)
1270 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 return;
1272 }
1273 } else
1274 perp_mode = 0;
1275
1276 if (FDCS->perp_mode == perp_mode)
1277 return;
1278 if (FDCS->version >= FDC_82077_ORIG) {
1279 output_byte(FD_PERPENDICULAR);
1280 output_byte(perp_mode);
1281 FDCS->perp_mode = perp_mode;
1282 } else if (perp_mode) {
1283 DPRINT("perpendicular mode not supported by this FDC.\n");
1284 }
1285} /* perpendicular_mode */
1286
1287static int fifo_depth = 0xa;
1288static int no_fifo;
1289
1290static int fdc_configure(void)
1291{
1292 /* Turn on FIFO */
1293 output_byte(FD_CONFIGURE);
1294 if (need_more_output() != MORE_OUTPUT)
1295 return 0;
1296 output_byte(0);
1297 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1298 output_byte(0); /* pre-compensation from track
1299 0 upwards */
1300 return 1;
1301}
1302
1303#define NOMINAL_DTR 500
1304
1305/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1306 * head load time, and DMA disable flag to values needed by floppy.
1307 *
1308 * The value "dtr" is the data transfer rate in Kbps. It is needed
1309 * to account for the data rate-based scaling done by the 82072 and 82077
1310 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1311 * 8272a).
1312 *
1313 * Note that changing the data transfer rate has a (probably deleterious)
1314 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1315 * fdc_specify is called again after each data transfer rate
1316 * change.
1317 *
1318 * srt: 1000 to 16000 in microseconds
1319 * hut: 16 to 240 milliseconds
1320 * hlt: 2 to 254 milliseconds
1321 *
1322 * These values are rounded up to the next highest available delay time.
1323 */
1324static void fdc_specify(void)
1325{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001326 unsigned char spec1;
1327 unsigned char spec2;
1328 unsigned long srt;
1329 unsigned long hlt;
1330 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 unsigned long dtr = NOMINAL_DTR;
1332 unsigned long scale_dtr = NOMINAL_DTR;
1333 int hlt_max_code = 0x7f;
1334 int hut_max_code = 0xf;
1335
1336 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1337 fdc_configure();
1338 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 }
1340
1341 switch (raw_cmd->rate & 0x03) {
1342 case 3:
1343 dtr = 1000;
1344 break;
1345 case 1:
1346 dtr = 300;
1347 if (FDCS->version >= FDC_82078) {
1348 /* chose the default rate table, not the one
1349 * where 1 = 2 Mbps */
1350 output_byte(FD_DRIVESPEC);
1351 if (need_more_output() == MORE_OUTPUT) {
1352 output_byte(UNIT(current_drive));
1353 output_byte(0xc0);
1354 }
1355 }
1356 break;
1357 case 2:
1358 dtr = 250;
1359 break;
1360 }
1361
1362 if (FDCS->version >= FDC_82072) {
1363 scale_dtr = dtr;
1364 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1365 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1366 }
1367
1368 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001369 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001370 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 SUPBOUND(srt, 0xf);
1374 INFBOUND(srt, 0);
1375
Julia Lawall061837b2008-09-22 14:57:16 -07001376 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 if (hlt < 0x01)
1378 hlt = 0x01;
1379 else if (hlt > 0x7f)
1380 hlt = hlt_max_code;
1381
Julia Lawall061837b2008-09-22 14:57:16 -07001382 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 if (hut < 0x1)
1384 hut = 0x1;
1385 else if (hut > 0xf)
1386 hut = hut_max_code;
1387
1388 spec1 = (srt << 4) | hut;
1389 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1390
1391 /* If these parameters did not change, just return with success */
1392 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1393 /* Go ahead and set spec1 and spec2 */
1394 output_byte(FD_SPECIFY);
1395 output_byte(FDCS->spec1 = spec1);
1396 output_byte(FDCS->spec2 = spec2);
1397 }
1398} /* fdc_specify */
1399
1400/* Set the FDC's data transfer rate on behalf of the specified drive.
1401 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1402 * of the specify command (i.e. using the fdc_specify function).
1403 */
1404static int fdc_dtr(void)
1405{
1406 /* If data rate not already set to desired value, set it. */
1407 if ((raw_cmd->rate & 3) == FDCS->dtr)
1408 return 0;
1409
1410 /* Set dtr */
1411 fd_outb(raw_cmd->rate & 3, FD_DCR);
1412
1413 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1414 * need a stabilization period of several milliseconds to be
1415 * enforced after data rate changes before R/W operations.
1416 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1417 */
1418 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001419 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1420 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421} /* fdc_dtr */
1422
1423static void tell_sector(void)
1424{
Joe Perchesb46df352010-03-10 15:20:46 -08001425 pr_cont(": track %d, head %d, sector %d, size %d",
1426 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427} /* tell_sector */
1428
Joe Perchesb46df352010-03-10 15:20:46 -08001429static void print_errors(void)
1430{
1431 DPRINT("");
1432 if (ST0 & ST0_ECE) {
1433 pr_cont("Recalibrate failed!");
1434 } else if (ST2 & ST2_CRC) {
1435 pr_cont("data CRC error");
1436 tell_sector();
1437 } else if (ST1 & ST1_CRC) {
1438 pr_cont("CRC error");
1439 tell_sector();
1440 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1441 (ST2 & ST2_MAM)) {
1442 if (!probing) {
1443 pr_cont("sector not found");
1444 tell_sector();
1445 } else
1446 pr_cont("probe failed...");
1447 } else if (ST2 & ST2_WC) { /* seek error */
1448 pr_cont("wrong cylinder");
1449 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1450 pr_cont("bad cylinder");
1451 } else {
1452 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1453 ST0, ST1, ST2);
1454 tell_sector();
1455 }
1456 pr_cont("\n");
1457}
1458
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459/*
1460 * OK, this error interpreting routine is called after a
1461 * DMA read/write has succeeded
1462 * or failed, so we check the results, and copy any buffers.
1463 * hhb: Added better error reporting.
1464 * ak: Made this into a separate routine.
1465 */
1466static int interpret_errors(void)
1467{
1468 char bad;
1469
1470 if (inr != 7) {
1471 DPRINT("-- FDC reply error");
1472 FDCS->reset = 1;
1473 return 1;
1474 }
1475
1476 /* check IC to find cause of interrupt */
1477 switch (ST0 & ST0_INTR) {
1478 case 0x40: /* error occurred during command execution */
1479 if (ST1 & ST1_EOC)
1480 return 0; /* occurs with pseudo-DMA */
1481 bad = 1;
1482 if (ST1 & ST1_WP) {
1483 DPRINT("Drive is write protected\n");
1484 CLEARF(FD_DISK_WRITABLE);
1485 cont->done(0);
1486 bad = 2;
1487 } else if (ST1 & ST1_ND) {
1488 SETF(FD_NEED_TWADDLE);
1489 } else if (ST1 & ST1_OR) {
1490 if (DP->flags & FTD_MSG)
1491 DPRINT("Over/Underrun - retrying\n");
1492 bad = 0;
1493 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001494 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 }
1496 if (ST2 & ST2_WC || ST2 & ST2_BC)
1497 /* wrong cylinder => recal */
1498 DRS->track = NEED_2_RECAL;
1499 return bad;
1500 case 0x80: /* invalid command given */
1501 DPRINT("Invalid FDC command given!\n");
1502 cont->done(0);
1503 return 2;
1504 case 0xc0:
1505 DPRINT("Abnormal termination caused by polling\n");
1506 cont->error();
1507 return 2;
1508 default: /* (0) Normal command termination */
1509 return 0;
1510 }
1511}
1512
1513/*
1514 * This routine is called when everything should be correctly set up
1515 * for the transfer (i.e. floppy motor is on, the correct floppy is
1516 * selected, and the head is sitting on the right track).
1517 */
1518static void setup_rw_floppy(void)
1519{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001520 int i;
1521 int r;
1522 int flags;
1523 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 unsigned long ready_date;
1525 timeout_fn function;
1526
1527 flags = raw_cmd->flags;
1528 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1529 flags |= FD_RAW_INTR;
1530
1531 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1532 ready_date = DRS->spinup_date + DP->spinup;
1533 /* If spinup will take a long time, rerun scandrives
1534 * again just before spinup completion. Beware that
1535 * after scandrives, we must again wait for selection.
1536 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001537 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 ready_date -= DP->select_delay;
1539 function = (timeout_fn) floppy_start;
1540 } else
1541 function = (timeout_fn) setup_rw_floppy;
1542
1543 /* wait until the floppy is spinning fast enough */
1544 if (fd_wait_for_completion(ready_date, function))
1545 return;
1546 }
1547 dflags = DRS->flags;
1548
1549 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1550 setup_DMA();
1551
1552 if (flags & FD_RAW_INTR)
1553 do_floppy = main_command_interrupt;
1554
1555 r = 0;
1556 for (i = 0; i < raw_cmd->cmd_count; i++)
1557 r |= output_byte(raw_cmd->cmd[i]);
1558
1559 debugt("rw_command: ");
1560
1561 if (r) {
1562 cont->error();
1563 reset_fdc();
1564 return;
1565 }
1566
1567 if (!(flags & FD_RAW_INTR)) {
1568 inr = result();
1569 cont->interrupt();
1570 } else if (flags & FD_RAW_NEED_DISK)
1571 fd_watchdog();
1572}
1573
1574static int blind_seek;
1575
1576/*
1577 * This is the routine called after every seek (or recalibrate) interrupt
1578 * from the floppy controller.
1579 */
1580static void seek_interrupt(void)
1581{
1582 debugt("seek interrupt:");
1583 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1584 DPRINT("seek failed\n");
1585 DRS->track = NEED_2_RECAL;
1586 cont->error();
1587 cont->redo();
1588 return;
1589 }
1590 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
1591#ifdef DCL_DEBUG
1592 if (DP->flags & FD_DEBUG) {
Joe Perchesb46df352010-03-10 15:20:46 -08001593 DPRINT("clearing NEWCHANGE flag because of effective seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 DPRINT("jiffies=%lu\n", jiffies);
1595 }
1596#endif
1597 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1598 DRS->select_date = jiffies;
1599 }
1600 DRS->track = ST1;
1601 floppy_ready();
1602}
1603
1604static void check_wp(void)
1605{
1606 if (TESTF(FD_VERIFY)) {
1607 /* check write protection */
1608 output_byte(FD_GETSTATUS);
1609 output_byte(UNIT(current_drive));
1610 if (result() != 1) {
1611 FDCS->reset = 1;
1612 return;
1613 }
1614 CLEARF(FD_VERIFY);
1615 CLEARF(FD_NEED_TWADDLE);
1616#ifdef DCL_DEBUG
1617 if (DP->flags & FD_DEBUG) {
1618 DPRINT("checking whether disk is write protected\n");
1619 DPRINT("wp=%x\n", ST3 & 0x40);
1620 }
1621#endif
1622 if (!(ST3 & 0x40))
1623 SETF(FD_DISK_WRITABLE);
1624 else
1625 CLEARF(FD_DISK_WRITABLE);
1626 }
1627}
1628
1629static void seek_floppy(void)
1630{
1631 int track;
1632
1633 blind_seek = 0;
1634
1635#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001636 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 DPRINT("calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638#endif
1639
1640 if (!TESTF(FD_DISK_NEWCHANGE) &&
1641 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1642 /* the media changed flag should be cleared after the seek.
1643 * If it isn't, this means that there is really no disk in
1644 * the drive.
1645 */
1646 SETF(FD_DISK_CHANGED);
1647 cont->done(0);
1648 cont->redo();
1649 return;
1650 }
1651 if (DRS->track <= NEED_1_RECAL) {
1652 recalibrate_floppy();
1653 return;
1654 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1655 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1656 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1657 /* we seek to clear the media-changed condition. Does anybody
1658 * know a more elegant way, which works on all drives? */
1659 if (raw_cmd->track)
1660 track = raw_cmd->track - 1;
1661 else {
1662 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1663 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1664 blind_seek = 1;
1665 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1666 }
1667 track = 1;
1668 }
1669 } else {
1670 check_wp();
1671 if (raw_cmd->track != DRS->track &&
1672 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1673 track = raw_cmd->track;
1674 else {
1675 setup_rw_floppy();
1676 return;
1677 }
1678 }
1679
1680 do_floppy = seek_interrupt;
1681 output_byte(FD_SEEK);
1682 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001683 if (output_byte(track) < 0) {
1684 reset_fdc();
1685 return;
1686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 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);
Joe Perches2300f902010-03-10 15:20:49 -08001816 if (output_byte(UNIT(current_drive)) < 0) {
1817 reset_fdc();
1818 return;
1819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820}
1821
1822/*
1823 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1824 */
1825static void reset_interrupt(void)
1826{
1827 debugt("reset interrupt:");
1828 result(); /* get the status ready for set_fdc */
1829 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001830 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 cont->error(); /* a reset just after a reset. BAD! */
1832 }
1833 cont->redo();
1834}
1835
1836/*
1837 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1838 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1839 */
1840static void reset_fdc(void)
1841{
1842 unsigned long flags;
1843
1844 do_floppy = reset_interrupt;
1845 FDCS->reset = 0;
1846 reset_fdc_info(0);
1847
1848 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1849 /* Irrelevant for systems with true DMA (i386). */
1850
1851 flags = claim_dma_lock();
1852 fd_disable_dma();
1853 release_dma_lock(flags);
1854
1855 if (FDCS->version >= FDC_82072A)
1856 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1857 else {
1858 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1859 udelay(FD_RESET_DELAY);
1860 fd_outb(FDCS->dor, FD_DOR);
1861 }
1862}
1863
1864static void show_floppy(void)
1865{
1866 int i;
1867
Joe Perchesb46df352010-03-10 15:20:46 -08001868 pr_info("\n");
1869 pr_info("floppy driver state\n");
1870 pr_info("-------------------\n");
1871 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1872 jiffies, interruptjiffies, jiffies - interruptjiffies,
1873 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001876 pr_info("timeout_message=%s\n", timeout_message);
1877 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001879 pr_info("%2x %2x %lu\n",
1880 output_log[(i + output_log_pos) % OLOGSIZE].data,
1881 output_log[(i + output_log_pos) % OLOGSIZE].status,
1882 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1883 pr_info("last result at %lu\n", resultjiffies);
1884 pr_info("last redo_fd_request at %lu\n", lastredo);
1885 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1886 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887#endif
1888
Joe Perchesb46df352010-03-10 15:20:46 -08001889 pr_info("status=%x\n", fd_inb(FD_STATUS));
1890 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001892 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001893 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001894 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001896 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001898 pr_info("timer_function=%p\n", fd_timeout.function);
1899 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1900 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 }
Joe Perchesb46df352010-03-10 15:20:46 -08001902 pr_info("cont=%p\n", cont);
1903 pr_info("current_req=%p\n", current_req);
1904 pr_info("command_status=%d\n", command_status);
1905 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906}
1907
1908static void floppy_shutdown(unsigned long data)
1909{
1910 unsigned long flags;
1911
1912 if (!initialising)
1913 show_floppy();
1914 cancel_activity();
1915
1916 floppy_enable_hlt();
1917
1918 flags = claim_dma_lock();
1919 fd_disable_dma();
1920 release_dma_lock(flags);
1921
1922 /* avoid dma going to a random drive after shutdown */
1923
1924 if (!initialising)
1925 DPRINT("floppy timeout called\n");
1926 FDCS->reset = 1;
1927 if (cont) {
1928 cont->done(0);
1929 cont->redo(); /* this will recall reset when needed */
1930 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001931 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 process_fd_request();
1933 }
1934 is_alive("floppy shutdown");
1935}
1936
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001938static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001940 int mask;
1941 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
1943 mask = 0xfc;
1944 data = UNIT(current_drive);
1945 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1946 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1947 set_debugt();
1948 /* no read since this drive is running */
1949 DRS->first_read_date = 0;
1950 /* note motor start time if motor is not yet running */
1951 DRS->spinup_date = jiffies;
1952 data |= (0x10 << UNIT(current_drive));
1953 }
1954 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1955 mask &= ~(0x10 << UNIT(current_drive));
1956
1957 /* starts motor and selects floppy */
1958 del_timer(motor_off_timer + current_drive);
1959 set_dor(fdc, mask, data);
1960
1961 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001962 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1963 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964}
1965
1966static void floppy_ready(void)
1967{
Joe Perches045f9832010-03-10 15:20:47 -08001968 if (FDCS->reset) {
1969 reset_fdc();
1970 return;
1971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 if (start_motor(floppy_ready))
1973 return;
1974 if (fdc_dtr())
1975 return;
1976
1977#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001978 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 DPRINT("calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980#endif
1981 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1982 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001983 twaddle(); /* this clears the dcl on certain
1984 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
1986#ifdef fd_chose_dma_mode
1987 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1988 unsigned long flags = claim_dma_lock();
1989 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1990 release_dma_lock(flags);
1991 }
1992#endif
1993
1994 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1995 perpendicular_mode();
1996 fdc_specify(); /* must be done here because of hut, hlt ... */
1997 seek_floppy();
1998 } else {
1999 if ((raw_cmd->flags & FD_RAW_READ) ||
2000 (raw_cmd->flags & FD_RAW_WRITE))
2001 fdc_specify();
2002 setup_rw_floppy();
2003 }
2004}
2005
2006static void floppy_start(void)
2007{
2008 reschedule_timeout(current_reqD, "floppy start", 0);
2009
2010 scandrives();
2011#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08002012 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 DPRINT("setting NEWCHANGE in floppy_start\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014#endif
2015 SETF(FD_DISK_NEWCHANGE);
2016 floppy_ready();
2017}
2018
2019/*
2020 * ========================================================================
2021 * here ends the bottom half. Exported routines are:
2022 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2023 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2024 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2025 * and set_dor.
2026 * ========================================================================
2027 */
2028/*
2029 * General purpose continuations.
2030 * ==============================
2031 */
2032
2033static void do_wakeup(void)
2034{
2035 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2036 cont = NULL;
2037 command_status += 2;
2038 wake_up(&command_done);
2039}
2040
2041static struct cont_t wakeup_cont = {
2042 .interrupt = empty,
2043 .redo = do_wakeup,
2044 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002045 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046};
2047
2048static struct cont_t intr_cont = {
2049 .interrupt = empty,
2050 .redo = process_fd_request,
2051 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002052 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053};
2054
Jesper Juhl06f748c2007-10-16 23:30:57 -07002055static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056{
2057 int ret;
2058
2059 schedule_bh(handler);
2060
2061 if (command_status < 2 && NO_SIGNAL) {
2062 DECLARE_WAITQUEUE(wait, current);
2063
2064 add_wait_queue(&command_done, &wait);
2065 for (;;) {
2066 set_current_state(interruptible ?
2067 TASK_INTERRUPTIBLE :
2068 TASK_UNINTERRUPTIBLE);
2069
2070 if (command_status >= 2 || !NO_SIGNAL)
2071 break;
2072
2073 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 schedule();
2075 }
2076
2077 set_current_state(TASK_RUNNING);
2078 remove_wait_queue(&command_done, &wait);
2079 }
2080
2081 if (command_status < 2) {
2082 cancel_activity();
2083 cont = &intr_cont;
2084 reset_fdc();
2085 return -EINTR;
2086 }
2087
2088 if (FDCS->reset)
2089 command_status = FD_COMMAND_ERROR;
2090 if (command_status == FD_COMMAND_OKAY)
2091 ret = 0;
2092 else
2093 ret = -EIO;
2094 command_status = FD_COMMAND_NONE;
2095 return ret;
2096}
2097
2098static void generic_done(int result)
2099{
2100 command_status = result;
2101 cont = &wakeup_cont;
2102}
2103
2104static void generic_success(void)
2105{
2106 cont->done(1);
2107}
2108
2109static void generic_failure(void)
2110{
2111 cont->done(0);
2112}
2113
2114static void success_and_wakeup(void)
2115{
2116 generic_success();
2117 cont->redo();
2118}
2119
2120/*
2121 * formatting and rw support.
2122 * ==========================
2123 */
2124
2125static int next_valid_format(void)
2126{
2127 int probed_format;
2128
2129 probed_format = DRS->probed_format;
2130 while (1) {
2131 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2132 DRS->probed_format = 0;
2133 return 1;
2134 }
2135 if (floppy_type[DP->autodetect[probed_format]].sect) {
2136 DRS->probed_format = probed_format;
2137 return 0;
2138 }
2139 probed_format++;
2140 }
2141}
2142
2143static void bad_flp_intr(void)
2144{
2145 int err_count;
2146
2147 if (probing) {
2148 DRS->probed_format++;
2149 if (!next_valid_format())
2150 return;
2151 }
2152 err_count = ++(*errors);
2153 INFBOUND(DRWE->badness, err_count);
2154 if (err_count > DP->max_errors.abort)
2155 cont->done(0);
2156 if (err_count > DP->max_errors.reset)
2157 FDCS->reset = 1;
2158 else if (err_count > DP->max_errors.recal)
2159 DRS->track = NEED_2_RECAL;
2160}
2161
2162static void set_floppy(int drive)
2163{
2164 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 if (type)
2167 _floppy = floppy_type + type;
2168 else
2169 _floppy = current_type[drive];
2170}
2171
2172/*
2173 * formatting support.
2174 * ===================
2175 */
2176static void format_interrupt(void)
2177{
2178 switch (interpret_errors()) {
2179 case 1:
2180 cont->error();
2181 case 2:
2182 break;
2183 case 0:
2184 cont->done(1);
2185 }
2186 cont->redo();
2187}
2188
2189#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002190#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002192
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193static void setup_format_params(int track)
2194{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002195 int n;
2196 int il;
2197 int count;
2198 int head_shift;
2199 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 struct fparm {
2201 unsigned char track, head, sect, size;
2202 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
2204 raw_cmd = &default_raw_cmd;
2205 raw_cmd->track = track;
2206
Joe Perches48c8cee2010-03-10 15:20:45 -08002207 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2208 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 raw_cmd->rate = _floppy->rate & 0x43;
2210 raw_cmd->cmd_count = NR_F;
2211 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2212 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2213 F_SIZECODE = FD_SIZECODE(_floppy);
2214 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2215 F_GAP = _floppy->fmt_gap;
2216 F_FILL = FD_FILL_BYTE;
2217
2218 raw_cmd->kernel_data = floppy_track_buffer;
2219 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2220
2221 /* allow for about 30ms for data transport per track */
2222 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2223
2224 /* a ``cylinder'' is two tracks plus a little stepping time */
2225 track_shift = 2 * head_shift + 3;
2226
2227 /* position of logical sector 1 on this track */
2228 n = (track_shift * format_req.track + head_shift * format_req.head)
2229 % F_SECT_PER_TRACK;
2230
2231 /* determine interleave */
2232 il = 1;
2233 if (_floppy->fmt_gap < 0x22)
2234 il++;
2235
2236 /* initialize field */
2237 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2238 here[count].track = format_req.track;
2239 here[count].head = format_req.head;
2240 here[count].sect = 0;
2241 here[count].size = F_SIZECODE;
2242 }
2243 /* place logical sectors */
2244 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2245 here[n].sect = count;
2246 n = (n + il) % F_SECT_PER_TRACK;
2247 if (here[n].sect) { /* sector busy, find next free sector */
2248 ++n;
2249 if (n >= F_SECT_PER_TRACK) {
2250 n -= F_SECT_PER_TRACK;
2251 while (here[n].sect)
2252 ++n;
2253 }
2254 }
2255 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002256 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002258 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 }
2260}
2261
2262static void redo_format(void)
2263{
2264 buffer_track = -1;
2265 setup_format_params(format_req.track << STRETCH(_floppy));
2266 floppy_start();
2267 debugt("queue format request");
2268}
2269
2270static struct cont_t format_cont = {
2271 .interrupt = format_interrupt,
2272 .redo = redo_format,
2273 .error = bad_flp_intr,
2274 .done = generic_done
2275};
2276
2277static int do_format(int drive, struct format_descr *tmp_format_req)
2278{
2279 int ret;
2280
2281 LOCK_FDC(drive, 1);
2282 set_floppy(drive);
2283 if (!_floppy ||
2284 _floppy->track > DP->tracks ||
2285 tmp_format_req->track >= _floppy->track ||
2286 tmp_format_req->head >= _floppy->head ||
2287 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2288 !_floppy->fmt_gap) {
2289 process_fd_request();
2290 return -EINVAL;
2291 }
2292 format_req = *tmp_format_req;
2293 format_errors = 0;
2294 cont = &format_cont;
2295 errors = &format_errors;
2296 IWAIT(redo_format);
2297 process_fd_request();
2298 return ret;
2299}
2300
2301/*
2302 * Buffer read/write and support
2303 * =============================
2304 */
2305
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002306static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307{
2308 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002309 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
2311 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002312 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002313 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002314 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
2317 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002318 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 current_req = NULL;
2320}
2321
2322/* new request_done. Can handle physical sectors which are smaller than a
2323 * logical buffer */
2324static void request_done(int uptodate)
2325{
2326 struct request_queue *q = floppy_queue;
2327 struct request *req = current_req;
2328 unsigned long flags;
2329 int block;
2330
2331 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002332 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
2334 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002335 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 return;
2337 }
2338
2339 if (uptodate) {
2340 /* maintain values for invalidation on geometry
2341 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002342 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 INFBOUND(DRS->maxblock, block);
2344 if (block > _floppy->sect)
2345 DRS->maxtrack = 1;
2346
2347 /* unlock chained buffers */
2348 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002349 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 spin_unlock_irqrestore(q->queue_lock, flags);
2351 } else {
2352 if (rq_data_dir(req) == WRITE) {
2353 /* record write error information */
2354 DRWE->write_errors++;
2355 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002356 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 DRWE->first_error_generation = DRS->generation;
2358 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002359 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 DRWE->last_error_generation = DRS->generation;
2361 }
2362 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002363 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 spin_unlock_irqrestore(q->queue_lock, flags);
2365 }
2366}
2367
2368/* Interrupt handler evaluating the result of the r/w operation */
2369static void rw_interrupt(void)
2370{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002371 int eoc;
2372 int ssize;
2373 int heads;
2374 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
2376 if (R_HEAD >= 2) {
2377 /* some Toshiba floppy controllers occasionnally seem to
2378 * return bogus interrupts after read/write operations, which
2379 * can be recognized by a bad head number (>= 2) */
2380 return;
2381 }
2382
2383 if (!DRS->first_read_date)
2384 DRS->first_read_date = jiffies;
2385
2386 nr_sectors = 0;
2387 CODE2SIZE;
2388
2389 if (ST1 & ST1_EOC)
2390 eoc = 1;
2391 else
2392 eoc = 0;
2393
2394 if (COMMAND & 0x80)
2395 heads = 2;
2396 else
2397 heads = 1;
2398
2399 nr_sectors = (((R_TRACK - TRACK) * heads +
2400 R_HEAD - HEAD) * SECT_PER_TRACK +
2401 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2402
2403#ifdef FLOPPY_SANITY_CHECK
2404 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002405 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 DPRINT("long rw: %x instead of %lx\n",
2407 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002408 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2409 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2410 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2411 pr_info("heads=%d eoc=%d\n", heads, eoc);
2412 pr_info("spt=%d st=%d ss=%d\n",
2413 SECT_PER_TRACK, fsector_t, ssize);
2414 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 }
2416#endif
2417
2418 nr_sectors -= in_sector_offset;
2419 INFBOUND(nr_sectors, 0);
2420 SUPBOUND(current_count_sectors, nr_sectors);
2421
2422 switch (interpret_errors()) {
2423 case 2:
2424 cont->redo();
2425 return;
2426 case 1:
2427 if (!current_count_sectors) {
2428 cont->error();
2429 cont->redo();
2430 return;
2431 }
2432 break;
2433 case 0:
2434 if (!current_count_sectors) {
2435 cont->redo();
2436 return;
2437 }
2438 current_type[current_drive] = _floppy;
2439 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2440 break;
2441 }
2442
2443 if (probing) {
2444 if (DP->flags & FTD_MSG)
2445 DPRINT("Auto-detected floppy type %s in fd%d\n",
2446 _floppy->name, current_drive);
2447 current_type[current_drive] = _floppy;
2448 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2449 probing = 0;
2450 }
2451
2452 if (CT(COMMAND) != FD_READ ||
2453 raw_cmd->kernel_data == current_req->buffer) {
2454 /* transfer directly from buffer */
2455 cont->done(1);
2456 } else if (CT(COMMAND) == FD_READ) {
2457 buffer_track = raw_cmd->track;
2458 buffer_drive = current_drive;
2459 INFBOUND(buffer_max, nr_sectors + fsector_t);
2460 }
2461 cont->redo();
2462}
2463
2464/* Compute maximal contiguous buffer size. */
2465static int buffer_chain_size(void)
2466{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002468 int size;
2469 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 char *base;
2471
2472 base = bio_data(current_req->bio);
2473 size = 0;
2474
NeilBrown5705f702007-09-25 12:35:59 +02002475 rq_for_each_segment(bv, current_req, iter) {
2476 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2477 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
NeilBrown5705f702007-09-25 12:35:59 +02002479 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 }
2481
2482 return size >> 9;
2483}
2484
2485/* Compute the maximal transfer size */
2486static int transfer_size(int ssize, int max_sector, int max_size)
2487{
2488 SUPBOUND(max_sector, fsector_t + max_size);
2489
2490 /* alignment */
2491 max_sector -= (max_sector % _floppy->sect) % ssize;
2492
2493 /* transfer size, beginning not aligned */
2494 current_count_sectors = max_sector - fsector_t;
2495
2496 return max_sector;
2497}
2498
2499/*
2500 * Move data from/to the track buffer to/from the buffer cache.
2501 */
2502static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2503{
2504 int remaining; /* number of transferred 512-byte sectors */
2505 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002506 char *buffer;
2507 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002508 int size;
2509 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 max_sector = transfer_size(ssize,
2512 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002513 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
2515 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002516 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002518 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
2520 remaining = current_count_sectors << 9;
2521#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002522 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002524 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2525 pr_info("remaining=%d\n", remaining >> 9);
2526 pr_info("current_req->nr_sectors=%u\n",
2527 blk_rq_sectors(current_req));
2528 pr_info("current_req->current_nr_sectors=%u\n",
2529 blk_rq_cur_sectors(current_req));
2530 pr_info("max_sector=%d\n", max_sector);
2531 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 }
2533#endif
2534
2535 buffer_max = max(max_sector, buffer_max);
2536
2537 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2538
Tejun Heo1011c1b2009-05-07 22:24:45 +09002539 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
NeilBrown5705f702007-09-25 12:35:59 +02002541 rq_for_each_segment(bv, current_req, iter) {
2542 if (!remaining)
2543 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
NeilBrown5705f702007-09-25 12:35:59 +02002545 size = bv->bv_len;
2546 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
NeilBrown5705f702007-09-25 12:35:59 +02002548 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002550 if (dma_buffer + size >
2551 floppy_track_buffer + (max_buffer_sectors << 10) ||
2552 dma_buffer < floppy_track_buffer) {
2553 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002554 (int)((floppy_track_buffer - dma_buffer) >> 9));
2555 pr_info("fsector_t=%d buffer_min=%d\n",
2556 fsector_t, buffer_min);
2557 pr_info("current_count_sectors=%ld\n",
2558 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002560 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002561 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002562 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002563 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 }
NeilBrown5705f702007-09-25 12:35:59 +02002565 if (((unsigned long)buffer) % 512)
2566 DPRINT("%p buffer not aligned\n", buffer);
2567#endif
2568 if (CT(COMMAND) == FD_READ)
2569 memcpy(buffer, dma_buffer, size);
2570 else
2571 memcpy(dma_buffer, buffer, size);
2572
2573 remaining -= size;
2574 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 }
2576#ifdef FLOPPY_SANITY_CHECK
2577 if (remaining) {
2578 if (remaining > 0)
2579 max_sector -= remaining >> 9;
2580 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2581 }
2582#endif
2583}
2584
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585/* work around a bug in pseudo DMA
2586 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2587 * sending data. Hence we need a different way to signal the
2588 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2589 * does not work with MT, hence we can only transfer one head at
2590 * a time
2591 */
2592static void virtualdmabug_workaround(void)
2593{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002594 int hard_sectors;
2595 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596
2597 if (CT(COMMAND) == FD_WRITE) {
2598 COMMAND &= ~0x80; /* switch off multiple track mode */
2599
2600 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2601 end_sector = SECTOR + hard_sectors - 1;
2602#ifdef FLOPPY_SANITY_CHECK
2603 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002604 pr_info("too many sectors %d > %d\n",
2605 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 return;
2607 }
2608#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002609 SECT_PER_TRACK = end_sector;
2610 /* make sure SECT_PER_TRACK
2611 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 }
2613}
2614
2615/*
2616 * Formulate a read/write request.
2617 * this routine decides where to load the data (directly to buffer, or to
2618 * tmp floppy area), how much data to load (the size of the buffer, the whole
2619 * track, or a single sector)
2620 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2621 * allocation on the fly, it should be done here. No other part should need
2622 * modification.
2623 */
2624
2625static int make_raw_rw_request(void)
2626{
2627 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002628 int max_sector;
2629 int max_size;
2630 int tracksize;
2631 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
2633 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002634 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 return 0;
2636 }
2637
2638 set_fdc((long)current_req->rq_disk->private_data);
2639
2640 raw_cmd = &default_raw_cmd;
2641 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2642 FD_RAW_NEED_SEEK;
2643 raw_cmd->cmd_count = NR_RW;
2644 if (rq_data_dir(current_req) == READ) {
2645 raw_cmd->flags |= FD_RAW_READ;
2646 COMMAND = FM_MODE(_floppy, FD_READ);
2647 } else if (rq_data_dir(current_req) == WRITE) {
2648 raw_cmd->flags |= FD_RAW_WRITE;
2649 COMMAND = FM_MODE(_floppy, FD_WRITE);
2650 } else {
2651 DPRINT("make_raw_rw_request: unknown command\n");
2652 return 0;
2653 }
2654
2655 max_sector = _floppy->sect * _floppy->head;
2656
Tejun Heo83096eb2009-05-07 22:24:39 +09002657 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2658 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002660 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 current_count_sectors = 1;
2662 return 1;
2663 } else
2664 return 0;
2665 }
2666 HEAD = fsector_t / _floppy->sect;
2667
Keith Wansbrough9e491842008-09-22 14:57:17 -07002668 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2670 max_sector = _floppy->sect;
2671
2672 /* 2M disks have phantom sectors on the first track */
2673 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2674 max_sector = 2 * _floppy->sect / 3;
2675 if (fsector_t >= max_sector) {
2676 current_count_sectors =
2677 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002678 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 return 1;
2680 }
2681 SIZECODE = 2;
2682 } else
2683 SIZECODE = FD_SIZECODE(_floppy);
2684 raw_cmd->rate = _floppy->rate & 0x43;
2685 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2686 raw_cmd->rate = 1;
2687
2688 if (SIZECODE)
2689 SIZECODE2 = 0xff;
2690 else
2691 SIZECODE2 = 0x80;
2692 raw_cmd->track = TRACK << STRETCH(_floppy);
2693 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2694 GAP = _floppy->gap;
2695 CODE2SIZE;
2696 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2697 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002698 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
2700 /* tracksize describes the size which can be filled up with sectors
2701 * of size ssize.
2702 */
2703 tracksize = _floppy->sect - _floppy->sect % ssize;
2704 if (tracksize < _floppy->sect) {
2705 SECT_PER_TRACK++;
2706 if (tracksize <= fsector_t % _floppy->sect)
2707 SECTOR--;
2708
2709 /* if we are beyond tracksize, fill up using smaller sectors */
2710 while (tracksize <= fsector_t % _floppy->sect) {
2711 while (tracksize + ssize > _floppy->sect) {
2712 SIZECODE--;
2713 ssize >>= 1;
2714 }
2715 SECTOR++;
2716 SECT_PER_TRACK++;
2717 tracksize += ssize;
2718 }
2719 max_sector = HEAD * _floppy->sect + tracksize;
2720 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2721 max_sector = _floppy->sect;
2722 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2723 /* for virtual DMA bug workaround */
2724 max_sector = _floppy->sect;
2725 }
2726
2727 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2728 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002729 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 if ((raw_cmd->track == buffer_track) &&
2731 (current_drive == buffer_drive) &&
2732 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2733 /* data already in track buffer */
2734 if (CT(COMMAND) == FD_READ) {
2735 copy_buffer(1, max_sector, buffer_max);
2736 return 1;
2737 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002738 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002740 unsigned int sectors;
2741
2742 sectors = fsector_t + blk_rq_sectors(current_req);
2743 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 max_size = ssize + ssize;
2745 else
2746 max_size = ssize;
2747 }
2748 raw_cmd->flags &= ~FD_RAW_WRITE;
2749 raw_cmd->flags |= FD_RAW_READ;
2750 COMMAND = FM_MODE(_floppy, FD_READ);
2751 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2752 unsigned long dma_limit;
2753 int direct, indirect;
2754
2755 indirect =
2756 transfer_size(ssize, max_sector,
2757 max_buffer_sectors * 2) - fsector_t;
2758
2759 /*
2760 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2761 * on a 64 bit machine!
2762 */
2763 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002764 dma_limit = (MAX_DMA_ADDRESS -
2765 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002766 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 /* 64 kb boundaries */
2769 if (CROSS_64KB(current_req->buffer, max_size << 9))
2770 max_size = (K_64 -
2771 ((unsigned long)current_req->buffer) %
2772 K_64) >> 9;
2773 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2774 /*
2775 * We try to read tracks, but if we get too many errors, we
2776 * go back to reading just one sector at a time.
2777 *
2778 * This means we should be able to read a sector even if there
2779 * are other bad sectors on this track.
2780 */
2781 if (!direct ||
2782 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002783 *errors < DP->max_errors.read_track &&
2784 ((!probing ||
2785 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002786 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 } else {
2788 raw_cmd->kernel_data = current_req->buffer;
2789 raw_cmd->length = current_count_sectors << 9;
2790 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002791 DPRINT("zero dma transfer attempted from make_raw_request\n");
2792 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 indirect, direct, fsector_t);
2794 return 0;
2795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 virtualdmabug_workaround();
2797 return 2;
2798 }
2799 }
2800
2801 if (CT(COMMAND) == FD_READ)
2802 max_size = max_sector; /* unbounded */
2803
2804 /* claim buffer track if needed */
2805 if (buffer_track != raw_cmd->track || /* bad track */
2806 buffer_drive != current_drive || /* bad drive */
2807 fsector_t > buffer_max ||
2808 fsector_t < buffer_min ||
2809 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002810 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002812 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2813 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 buffer_track = -1;
2815 buffer_drive = current_drive;
2816 buffer_max = buffer_min = aligned_sector_t;
2817 }
2818 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002819 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
2821 if (CT(COMMAND) == FD_WRITE) {
2822 /* copy write buffer to track buffer.
2823 * if we get here, we know that the write
2824 * is either aligned or the data already in the buffer
2825 * (buffer will be overwritten) */
2826#ifdef FLOPPY_SANITY_CHECK
2827 if (in_sector_offset && buffer_track == -1)
2828 DPRINT("internal error offset !=0 on write\n");
2829#endif
2830 buffer_track = raw_cmd->track;
2831 buffer_drive = current_drive;
2832 copy_buffer(ssize, max_sector,
2833 2 * max_buffer_sectors + buffer_min);
2834 } else
2835 transfer_size(ssize, max_sector,
2836 2 * max_buffer_sectors + buffer_min -
2837 aligned_sector_t);
2838
2839 /* round up current_count_sectors to get dma xfer size */
2840 raw_cmd->length = in_sector_offset + current_count_sectors;
2841 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2842 raw_cmd->length <<= 9;
2843#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 if ((raw_cmd->length < current_count_sectors << 9) ||
2845 (raw_cmd->kernel_data != current_req->buffer &&
2846 CT(COMMAND) == FD_WRITE &&
2847 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2848 aligned_sector_t < buffer_min)) ||
2849 raw_cmd->length % (128 << SIZECODE) ||
2850 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2851 DPRINT("fractionary current count b=%lx s=%lx\n",
2852 raw_cmd->length, current_count_sectors);
2853 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002854 pr_info("addr=%d, length=%ld\n",
2855 (int)((raw_cmd->kernel_data -
2856 floppy_track_buffer) >> 9),
2857 current_count_sectors);
2858 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2859 fsector_t, aligned_sector_t, max_sector, max_size);
2860 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2861 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2862 COMMAND, SECTOR, HEAD, TRACK);
2863 pr_info("buffer drive=%d\n", buffer_drive);
2864 pr_info("buffer track=%d\n", buffer_track);
2865 pr_info("buffer_min=%d\n", buffer_min);
2866 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 return 0;
2868 }
2869
2870 if (raw_cmd->kernel_data != current_req->buffer) {
2871 if (raw_cmd->kernel_data < floppy_track_buffer ||
2872 current_count_sectors < 0 ||
2873 raw_cmd->length < 0 ||
2874 raw_cmd->kernel_data + raw_cmd->length >
2875 floppy_track_buffer + (max_buffer_sectors << 10)) {
2876 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002877 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2878 fsector_t, buffer_min, raw_cmd->length >> 9);
2879 pr_info("current_count_sectors=%ld\n",
2880 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002882 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002884 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 return 0;
2886 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002887 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002888 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 DPRINT("buffer overrun in direct transfer\n");
2890 return 0;
2891 } else if (raw_cmd->length < current_count_sectors << 9) {
2892 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002893 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2894 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 }
2896 if (raw_cmd->length == 0) {
2897 DPRINT("zero dma transfer attempted from make_raw_request\n");
2898 return 0;
2899 }
2900#endif
2901
2902 virtualdmabug_workaround();
2903 return 2;
2904}
2905
2906static void redo_fd_request(void)
2907{
2908#define REPEAT {request_done(0); continue; }
2909 int drive;
2910 int tmp;
2911
2912 lastredo = jiffies;
2913 if (current_drive < N_DRIVE)
2914 floppy_off(current_drive);
2915
2916 for (;;) {
2917 if (!current_req) {
2918 struct request *req;
2919
2920 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002921 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 spin_unlock_irq(floppy_queue->queue_lock);
2923 if (!req) {
2924 do_floppy = NULL;
2925 unlock_fdc();
2926 return;
2927 }
2928 current_req = req;
2929 }
2930 drive = (long)current_req->rq_disk->private_data;
2931 set_fdc(drive);
2932 reschedule_timeout(current_reqD, "redo fd request", 0);
2933
2934 set_floppy(drive);
2935 raw_cmd = &default_raw_cmd;
2936 raw_cmd->flags = 0;
2937 if (start_motor(redo_fd_request))
2938 return;
2939 disk_change(current_drive);
2940 if (test_bit(current_drive, &fake_change) ||
2941 TESTF(FD_DISK_CHANGED)) {
2942 DPRINT("disk absent or changed during operation\n");
2943 REPEAT;
2944 }
2945 if (!_floppy) { /* Autodetection */
2946 if (!probing) {
2947 DRS->probed_format = 0;
2948 if (next_valid_format()) {
2949 DPRINT("no autodetectable formats\n");
2950 _floppy = NULL;
2951 REPEAT;
2952 }
2953 }
2954 probing = 1;
2955 _floppy =
2956 floppy_type + DP->autodetect[DRS->probed_format];
2957 } else
2958 probing = 0;
2959 errors = &(current_req->errors);
2960 tmp = make_raw_rw_request();
2961 if (tmp < 2) {
2962 request_done(tmp);
2963 continue;
2964 }
2965
2966 if (TESTF(FD_NEED_TWADDLE))
2967 twaddle();
2968 schedule_bh(floppy_start);
2969 debugt("queue fd request");
2970 return;
2971 }
2972#undef REPEAT
2973}
2974
2975static struct cont_t rw_cont = {
2976 .interrupt = rw_interrupt,
2977 .redo = redo_fd_request,
2978 .error = bad_flp_intr,
2979 .done = request_done
2980};
2981
2982static void process_fd_request(void)
2983{
2984 cont = &rw_cont;
2985 schedule_bh(redo_fd_request);
2986}
2987
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002988static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989{
2990 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002991 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 return;
2993 }
2994
2995 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002996 pr_info("warning: usage count=0, current_req=%p exiting\n",
2997 current_req);
2998 pr_info("sect=%ld type=%x flags=%x\n",
2999 (long)blk_rq_pos(current_req), current_req->cmd_type,
3000 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 return;
3002 }
3003 if (test_bit(0, &fdc_busy)) {
3004 /* fdc busy, this new request will be treated when the
3005 current one is done */
3006 is_alive("do fd request, old request running");
3007 return;
3008 }
3009 lock_fdc(MAXTIMEOUT, 0);
3010 process_fd_request();
3011 is_alive("do fd request");
3012}
3013
3014static struct cont_t poll_cont = {
3015 .interrupt = success_and_wakeup,
3016 .redo = floppy_ready,
3017 .error = generic_failure,
3018 .done = generic_done
3019};
3020
3021static int poll_drive(int interruptible, int flag)
3022{
3023 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003024
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 /* no auto-sense, just clear dcl */
3026 raw_cmd = &default_raw_cmd;
3027 raw_cmd->flags = flag;
3028 raw_cmd->track = 0;
3029 raw_cmd->cmd_count = 0;
3030 cont = &poll_cont;
3031#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003032 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 DPRINT("setting NEWCHANGE in poll_drive\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034#endif
3035 SETF(FD_DISK_NEWCHANGE);
3036 WAIT(floppy_ready);
3037 return ret;
3038}
3039
3040/*
3041 * User triggered reset
3042 * ====================
3043 */
3044
3045static void reset_intr(void)
3046{
Joe Perchesb46df352010-03-10 15:20:46 -08003047 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048}
3049
3050static struct cont_t reset_cont = {
3051 .interrupt = reset_intr,
3052 .redo = success_and_wakeup,
3053 .error = generic_failure,
3054 .done = generic_done
3055};
3056
3057static int user_reset_fdc(int drive, int arg, int interruptible)
3058{
3059 int ret;
3060
3061 ret = 0;
3062 LOCK_FDC(drive, interruptible);
3063 if (arg == FD_RESET_ALWAYS)
3064 FDCS->reset = 1;
3065 if (FDCS->reset) {
3066 cont = &reset_cont;
3067 WAIT(reset_fdc);
3068 }
3069 process_fd_request();
3070 return ret;
3071}
3072
3073/*
3074 * Misc Ioctl's and support
3075 * ========================
3076 */
3077static inline int fd_copyout(void __user *param, const void *address,
3078 unsigned long size)
3079{
3080 return copy_to_user(param, address, size) ? -EFAULT : 0;
3081}
3082
Joe Perches48c8cee2010-03-10 15:20:45 -08003083static inline int fd_copyin(void __user *param, void *address,
3084 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085{
3086 return copy_from_user(address, param, size) ? -EFAULT : 0;
3087}
3088
Joe Perches48c8cee2010-03-10 15:20:45 -08003089#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3090 ? -EFAULT : 0)
3091#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3092 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093
Joe Perches48c8cee2010-03-10 15:20:45 -08003094#define COPYOUT(x) ECALL(_COPYOUT(x))
3095#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
3097static inline const char *drive_name(int type, int drive)
3098{
3099 struct floppy_struct *floppy;
3100
3101 if (type)
3102 floppy = floppy_type + type;
3103 else {
3104 if (UDP->native_format)
3105 floppy = floppy_type + UDP->native_format;
3106 else
3107 return "(null)";
3108 }
3109 if (floppy->name)
3110 return floppy->name;
3111 else
3112 return "(null)";
3113}
3114
3115/* raw commands */
3116static void raw_cmd_done(int flag)
3117{
3118 int i;
3119
3120 if (!flag) {
3121 raw_cmd->flags |= FD_RAW_FAILURE;
3122 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3123 } else {
3124 raw_cmd->reply_count = inr;
3125 if (raw_cmd->reply_count > MAX_REPLIES)
3126 raw_cmd->reply_count = 0;
3127 for (i = 0; i < raw_cmd->reply_count; i++)
3128 raw_cmd->reply[i] = reply_buffer[i];
3129
3130 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3131 unsigned long flags;
3132 flags = claim_dma_lock();
3133 raw_cmd->length = fd_get_dma_residue();
3134 release_dma_lock(flags);
3135 }
3136
3137 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3138 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3139 raw_cmd->flags |= FD_RAW_FAILURE;
3140
3141 if (disk_change(current_drive))
3142 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3143 else
3144 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3145 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3146 motor_off_callback(current_drive);
3147
3148 if (raw_cmd->next &&
3149 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3150 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3151 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3152 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3153 raw_cmd = raw_cmd->next;
3154 return;
3155 }
3156 }
3157 generic_done(flag);
3158}
3159
3160static struct cont_t raw_cmd_cont = {
3161 .interrupt = success_and_wakeup,
3162 .redo = floppy_start,
3163 .error = generic_failure,
3164 .done = raw_cmd_done
3165};
3166
3167static inline int raw_cmd_copyout(int cmd, char __user *param,
3168 struct floppy_raw_cmd *ptr)
3169{
3170 int ret;
3171
3172 while (ptr) {
3173 COPYOUT(*ptr);
3174 param += sizeof(struct floppy_raw_cmd);
3175 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003176 if (ptr->length >= 0 &&
3177 ptr->length <= ptr->buffer_length) {
3178 long length = ptr->buffer_length - ptr->length;
3179 ECALL(fd_copyout(ptr->data, ptr->kernel_data,
3180 length));
3181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 }
3183 ptr = ptr->next;
3184 }
3185 return 0;
3186}
3187
3188static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3189{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003190 struct floppy_raw_cmd *next;
3191 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
3193 this = *ptr;
3194 *ptr = NULL;
3195 while (this) {
3196 if (this->buffer_length) {
3197 fd_dma_mem_free((unsigned long)this->kernel_data,
3198 this->buffer_length);
3199 this->buffer_length = 0;
3200 }
3201 next = this->next;
3202 kfree(this);
3203 this = next;
3204 }
3205}
3206
3207static inline int raw_cmd_copyin(int cmd, char __user *param,
3208 struct floppy_raw_cmd **rcmd)
3209{
3210 struct floppy_raw_cmd *ptr;
3211 int ret;
3212 int i;
3213
3214 *rcmd = NULL;
3215 while (1) {
3216 ptr = (struct floppy_raw_cmd *)
3217 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3218 if (!ptr)
3219 return -ENOMEM;
3220 *rcmd = ptr;
3221 COPYIN(*ptr);
3222 ptr->next = NULL;
3223 ptr->buffer_length = 0;
3224 param += sizeof(struct floppy_raw_cmd);
3225 if (ptr->cmd_count > 33)
3226 /* the command may now also take up the space
3227 * initially intended for the reply & the
3228 * reply count. Needed for long 82078 commands
3229 * such as RESTORE, which takes ... 17 command
3230 * bytes. Murphy's law #137: When you reserve
3231 * 16 bytes for a structure, you'll one day
3232 * discover that you really need 17...
3233 */
3234 return -EINVAL;
3235
3236 for (i = 0; i < 16; i++)
3237 ptr->reply[i] = 0;
3238 ptr->resultcode = 0;
3239 ptr->kernel_data = NULL;
3240
3241 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3242 if (ptr->length <= 0)
3243 return -EINVAL;
3244 ptr->kernel_data =
3245 (char *)fd_dma_mem_alloc(ptr->length);
3246 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3247 if (!ptr->kernel_data)
3248 return -ENOMEM;
3249 ptr->buffer_length = ptr->length;
3250 }
3251 if (ptr->flags & FD_RAW_WRITE)
3252 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3253 ptr->length));
3254 rcmd = &(ptr->next);
3255 if (!(ptr->flags & FD_RAW_MORE))
3256 return 0;
3257 ptr->rate &= 0x43;
3258 }
3259}
3260
3261static int raw_cmd_ioctl(int cmd, void __user *param)
3262{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003264 int drive;
3265 int ret2;
3266 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267
3268 if (FDCS->rawcmd <= 1)
3269 FDCS->rawcmd = 1;
3270 for (drive = 0; drive < N_DRIVE; drive++) {
3271 if (FDC(drive) != fdc)
3272 continue;
3273 if (drive == current_drive) {
3274 if (UDRS->fd_ref > 1) {
3275 FDCS->rawcmd = 2;
3276 break;
3277 }
3278 } else if (UDRS->fd_ref) {
3279 FDCS->rawcmd = 2;
3280 break;
3281 }
3282 }
3283
3284 if (FDCS->reset)
3285 return -EIO;
3286
3287 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3288 if (ret) {
3289 raw_cmd_free(&my_raw_cmd);
3290 return ret;
3291 }
3292
3293 raw_cmd = my_raw_cmd;
3294 cont = &raw_cmd_cont;
3295 ret = wait_til_done(floppy_start, 1);
3296#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003297 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 DPRINT("calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299#endif
3300
3301 if (ret != -EINTR && FDCS->reset)
3302 ret = -EIO;
3303
3304 DRS->track = NO_TRACK;
3305
3306 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3307 if (!ret)
3308 ret = ret2;
3309 raw_cmd_free(&my_raw_cmd);
3310 return ret;
3311}
3312
3313static int invalidate_drive(struct block_device *bdev)
3314{
3315 /* invalidate the buffer track to force a reread */
3316 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3317 process_fd_request();
3318 check_disk_change(bdev);
3319 return 0;
3320}
3321
3322static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3323 int drive, int type, struct block_device *bdev)
3324{
3325 int cnt;
3326
3327 /* sanity checking for parameters. */
3328 if (g->sect <= 0 ||
3329 g->head <= 0 ||
3330 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3331 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003332 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 return -EINVAL;
3334 if (type) {
3335 if (!capable(CAP_SYS_ADMIN))
3336 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003337 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003338 if (lock_fdc(drive, 1)) {
3339 mutex_unlock(&open_lock);
3340 return -EINTR;
3341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 floppy_type[type] = *g;
3343 floppy_type[type].name = "user format";
3344 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3345 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3346 floppy_type[type].size + 1;
3347 process_fd_request();
3348 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3349 struct block_device *bdev = opened_bdev[cnt];
3350 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3351 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003352 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003354 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 } else {
3356 int oldStretch;
3357 LOCK_FDC(drive, 1);
3358 if (cmd != FDDEFPRM)
3359 /* notice a disk change immediately, else
3360 * we lose our settings immediately*/
3361 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3362 oldStretch = g->stretch;
3363 user_params[drive] = *g;
3364 if (buffer_drive == drive)
3365 SUPBOUND(buffer_max, user_params[drive].sect);
3366 current_type[drive] = &user_params[drive];
3367 floppy_sizes[drive] = user_params[drive].size;
3368 if (cmd == FDDEFPRM)
3369 DRS->keep_data = -1;
3370 else
3371 DRS->keep_data = 1;
3372 /* invalidation. Invalidate only when needed, i.e.
3373 * when there are already sectors in the buffer cache
3374 * whose number will change. This is useful, because
3375 * mtools often changes the geometry of the disk after
3376 * looking at the boot block */
3377 if (DRS->maxblock > user_params[drive].sect ||
3378 DRS->maxtrack ||
3379 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003380 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 invalidate_drive(bdev);
3382 else
3383 process_fd_request();
3384 }
3385 return 0;
3386}
3387
3388/* handle obsolete ioctl's */
3389static int ioctl_table[] = {
3390 FDCLRPRM,
3391 FDSETPRM,
3392 FDDEFPRM,
3393 FDGETPRM,
3394 FDMSGON,
3395 FDMSGOFF,
3396 FDFMTBEG,
3397 FDFMTTRK,
3398 FDFMTEND,
3399 FDSETEMSGTRESH,
3400 FDFLUSH,
3401 FDSETMAXERRS,
3402 FDGETMAXERRS,
3403 FDGETDRVTYP,
3404 FDSETDRVPRM,
3405 FDGETDRVPRM,
3406 FDGETDRVSTAT,
3407 FDPOLLDRVSTAT,
3408 FDRESET,
3409 FDGETFDCSTAT,
3410 FDWERRORCLR,
3411 FDWERRORGET,
3412 FDRAWCMD,
3413 FDEJECT,
3414 FDTWADDLE
3415};
3416
3417static inline int normalize_ioctl(int *cmd, int *size)
3418{
3419 int i;
3420
3421 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3422 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3423 *size = _IOC_SIZE(*cmd);
3424 *cmd = ioctl_table[i];
3425 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003426 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 return -EFAULT;
3428 }
3429 return 0;
3430 }
3431 }
3432 return -EINVAL;
3433}
3434
3435static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3436{
3437 if (type)
3438 *g = &floppy_type[type];
3439 else {
3440 LOCK_FDC(drive, 0);
3441 CALL(poll_drive(0, 0));
3442 process_fd_request();
3443 *g = current_type[drive];
3444 }
3445 if (!*g)
3446 return -ENODEV;
3447 return 0;
3448}
3449
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003450static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3451{
3452 int drive = (long)bdev->bd_disk->private_data;
3453 int type = ITYPE(drive_state[drive].fd_device);
3454 struct floppy_struct *g;
3455 int ret;
3456
3457 ret = get_floppy_geometry(drive, type, &g);
3458 if (ret)
3459 return ret;
3460
3461 geo->heads = g->head;
3462 geo->sectors = g->sect;
3463 geo->cylinders = g->track;
3464 return 0;
3465}
3466
Al Viroa4af9b42008-03-02 09:27:55 -05003467static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 unsigned long param)
3469{
Al Viroa4af9b42008-03-02 09:27:55 -05003470#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471#define OUT(c,x) case c: outparam = (const char *) (x); break
3472#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
3473
Al Viroa4af9b42008-03-02 09:27:55 -05003474 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003475 int type = ITYPE(UDRS->fd_device);
3476 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 int ret;
3478 int size;
3479 union inparam {
3480 struct floppy_struct g; /* geometry */
3481 struct format_descr f;
3482 struct floppy_max_errors max_errors;
3483 struct floppy_drive_params dp;
3484 } inparam; /* parameters coming from user space */
3485 const char *outparam; /* parameters passed back to user space */
3486
3487 /* convert compatibility eject ioctls into floppy eject ioctl.
3488 * We do this in order to provide a means to eject floppy disks before
3489 * installing the new fdutils package */
3490 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003491 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 DPRINT("obsolete eject ioctl\n");
3493 DPRINT("please use floppycontrol --eject\n");
3494 cmd = FDEJECT;
3495 }
3496
Joe Perchesa81ee542010-03-10 15:20:46 -08003497 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 return -EINVAL;
3499
Joe Perchesa81ee542010-03-10 15:20:46 -08003500 /* convert the old style command into a new style command */
3501 ECALL(normalize_ioctl(&cmd, &size));
3502
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 /* permission checks */
3504 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3505 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3506 return -EPERM;
3507
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003508 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3509 return -EINVAL;
3510
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 /* copyin */
3512 CLEARSTRUCT(&inparam);
3513 if (_IOC_DIR(cmd) & _IOC_WRITE)
3514 ECALL(fd_copyin((void __user *)param, &inparam, size))
3515
3516 switch (cmd) {
3517 case FDEJECT:
3518 if (UDRS->fd_ref != 1)
3519 /* somebody else has this drive open */
3520 return -EBUSY;
3521 LOCK_FDC(drive, 1);
3522
3523 /* do the actual eject. Fails on
3524 * non-Sparc architectures */
3525 ret = fd_eject(UNIT(drive));
3526
3527 USETF(FD_DISK_CHANGED);
3528 USETF(FD_VERIFY);
3529 process_fd_request();
3530 return ret;
3531 case FDCLRPRM:
3532 LOCK_FDC(drive, 1);
3533 current_type[drive] = NULL;
3534 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3535 UDRS->keep_data = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003536 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 case FDSETPRM:
3538 case FDDEFPRM:
3539 return set_geometry(cmd, &inparam.g,
Al Viroa4af9b42008-03-02 09:27:55 -05003540 drive, type, bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 case FDGETPRM:
3542 ECALL(get_floppy_geometry(drive, type,
3543 (struct floppy_struct **)
3544 &outparam));
3545 break;
3546
3547 case FDMSGON:
3548 UDP->flags |= FTD_MSG;
3549 return 0;
3550 case FDMSGOFF:
3551 UDP->flags &= ~FTD_MSG;
3552 return 0;
3553
3554 case FDFMTBEG:
3555 LOCK_FDC(drive, 1);
3556 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3557 ret = UDRS->flags;
3558 process_fd_request();
3559 if (ret & FD_VERIFY)
3560 return -ENODEV;
3561 if (!(ret & FD_DISK_WRITABLE))
3562 return -EROFS;
3563 return 0;
3564 case FDFMTTRK:
3565 if (UDRS->fd_ref != 1)
3566 return -EBUSY;
3567 return do_format(drive, &inparam.f);
3568 case FDFMTEND:
3569 case FDFLUSH:
3570 LOCK_FDC(drive, 1);
Al Viroa4af9b42008-03-02 09:27:55 -05003571 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
3573 case FDSETEMSGTRESH:
3574 UDP->max_errors.reporting =
3575 (unsigned short)(param & 0x0f);
3576 return 0;
3577 OUT(FDGETMAXERRS, &UDP->max_errors);
3578 IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
3579
3580 case FDGETDRVTYP:
3581 outparam = drive_name(type, drive);
3582 SUPBOUND(size, strlen(outparam) + 1);
3583 break;
3584
3585 IN(FDSETDRVPRM, UDP, dp);
3586 OUT(FDGETDRVPRM, UDP);
3587
3588 case FDPOLLDRVSTAT:
3589 LOCK_FDC(drive, 1);
3590 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3591 process_fd_request();
3592 /* fall through */
3593 OUT(FDGETDRVSTAT, UDRS);
3594
3595 case FDRESET:
3596 return user_reset_fdc(drive, (int)param, 1);
3597
3598 OUT(FDGETFDCSTAT, UFDCS);
3599
3600 case FDWERRORCLR:
3601 CLEARSTRUCT(UDRWE);
3602 return 0;
3603 OUT(FDWERRORGET, UDRWE);
3604
3605 case FDRAWCMD:
3606 if (type)
3607 return -EINVAL;
3608 LOCK_FDC(drive, 1);
3609 set_floppy(drive);
3610 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3611 process_fd_request();
3612 return i;
3613
3614 case FDTWADDLE:
3615 LOCK_FDC(drive, 1);
3616 twaddle();
3617 process_fd_request();
3618 return 0;
3619
3620 default:
3621 return -EINVAL;
3622 }
3623
3624 if (_IOC_DIR(cmd) & _IOC_READ)
3625 return fd_copyout((void __user *)param, outparam, size);
3626 else
3627 return 0;
3628#undef OUT
3629#undef IN
3630}
3631
3632static void __init config_types(void)
3633{
Joe Perchesb46df352010-03-10 15:20:46 -08003634 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 int drive;
3636
3637 /* read drive info out of physical CMOS */
3638 drive = 0;
3639 if (!UDP->cmos)
3640 UDP->cmos = FLOPPY0_TYPE;
3641 drive = 1;
3642 if (!UDP->cmos && FLOPPY1_TYPE)
3643 UDP->cmos = FLOPPY1_TYPE;
3644
Jesper Juhl06f748c2007-10-16 23:30:57 -07003645 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646
3647 for (drive = 0; drive < N_DRIVE; drive++) {
3648 unsigned int type = UDP->cmos;
3649 struct floppy_drive_params *params;
3650 const char *name = NULL;
3651 static char temparea[32];
3652
Tobias Klauser945f3902006-01-08 01:05:11 -08003653 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 params = &default_drive_params[type].params;
3655 if (type) {
3656 name = default_drive_params[type].name;
3657 allowed_drive_mask |= 1 << drive;
3658 } else
3659 allowed_drive_mask &= ~(1 << drive);
3660 } else {
3661 params = &default_drive_params[0].params;
3662 sprintf(temparea, "unknown type %d (usb?)", type);
3663 name = temparea;
3664 }
3665 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003666 const char *prepend;
3667 if (!has_drive) {
3668 prepend = "";
3669 has_drive = true;
3670 pr_info("Floppy drive(s):");
3671 } else {
3672 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 }
Joe Perchesb46df352010-03-10 15:20:46 -08003674
3675 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 }
3677 *UDP = *params;
3678 }
Joe Perchesb46df352010-03-10 15:20:46 -08003679
3680 if (has_drive)
3681 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682}
3683
Al Viroa4af9b42008-03-02 09:27:55 -05003684static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685{
Al Viroa4af9b42008-03-02 09:27:55 -05003686 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003688 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 if (UDRS->fd_ref < 0)
3690 UDRS->fd_ref = 0;
3691 else if (!UDRS->fd_ref--) {
3692 DPRINT("floppy_release with fd_ref == 0");
3693 UDRS->fd_ref = 0;
3694 }
3695 if (!UDRS->fd_ref)
3696 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003697 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003698
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 return 0;
3700}
3701
3702/*
3703 * floppy_open check for aliasing (/dev/fd0 can be the same as
3704 * /dev/PS0 etc), and disallows simultaneous access to the same
3705 * drive with different device numbers.
3706 */
Al Viroa4af9b42008-03-02 09:27:55 -05003707static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708{
Al Viroa4af9b42008-03-02 09:27:55 -05003709 int drive = (long)bdev->bd_disk->private_data;
3710 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 int try;
3712 int res = -EBUSY;
3713 char *tmp;
3714
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003715 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003717 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 goto out2;
3719
3720 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3721 USETF(FD_DISK_CHANGED);
3722 USETF(FD_VERIFY);
3723 }
3724
Al Viroa4af9b42008-03-02 09:27:55 -05003725 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 goto out2;
3727
Al Viroa4af9b42008-03-02 09:27:55 -05003728 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 UDRS->fd_ref = -1;
3730 else
3731 UDRS->fd_ref++;
3732
Al Viroa4af9b42008-03-02 09:27:55 -05003733 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734
3735 res = -ENXIO;
3736
3737 if (!floppy_track_buffer) {
3738 /* if opening an ED drive, reserve a big buffer,
3739 * else reserve a small one */
3740 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3741 try = 64; /* Only 48 actually useful */
3742 else
3743 try = 32; /* Only 24 actually useful */
3744
3745 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3746 if (!tmp && !floppy_track_buffer) {
3747 try >>= 1; /* buffer only one side */
3748 INFBOUND(try, 16);
3749 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3750 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003751 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 if (!tmp && !floppy_track_buffer) {
3754 DPRINT("Unable to allocate DMA memory\n");
3755 goto out;
3756 }
3757 if (floppy_track_buffer) {
3758 if (tmp)
3759 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3760 } else {
3761 buffer_min = buffer_max = -1;
3762 floppy_track_buffer = tmp;
3763 max_buffer_sectors = try;
3764 }
3765 }
3766
Al Viroa4af9b42008-03-02 09:27:55 -05003767 new_dev = MINOR(bdev->bd_dev);
3768 UDRS->fd_device = new_dev;
3769 set_capacity(disks[drive], floppy_sizes[new_dev]);
3770 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 if (buffer_drive == drive)
3772 buffer_track = -1;
3773 }
3774
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 if (UFDCS->rawcmd == 1)
3776 UFDCS->rawcmd = 2;
3777
Al Viroa4af9b42008-03-02 09:27:55 -05003778 if (!(mode & FMODE_NDELAY)) {
3779 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003781 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 if (UTESTF(FD_DISK_CHANGED))
3783 goto out;
3784 }
3785 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003786 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 goto out;
3788 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003789 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 return 0;
3791out:
3792 if (UDRS->fd_ref < 0)
3793 UDRS->fd_ref = 0;
3794 else
3795 UDRS->fd_ref--;
3796 if (!UDRS->fd_ref)
3797 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003799 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 return res;
3801}
3802
3803/*
3804 * Check if the disk has been changed or if a change has been faked.
3805 */
3806static int check_floppy_change(struct gendisk *disk)
3807{
3808 int drive = (long)disk->private_data;
3809
3810 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3811 return 1;
3812
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003813 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 lock_fdc(drive, 0);
3815 poll_drive(0, 0);
3816 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 }
3818
3819 if (UTESTF(FD_DISK_CHANGED) ||
3820 UTESTF(FD_VERIFY) ||
3821 test_bit(drive, &fake_change) ||
3822 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3823 return 1;
3824 return 0;
3825}
3826
3827/*
3828 * This implements "read block 0" for floppy_revalidate().
3829 * Needed for format autodetection, checking whether there is
3830 * a disk in the drive, and whether that disk is writable.
3831 */
3832
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003833static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834{
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;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003948 r = result();
3949 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 return FDC_NONE; /* No FDC present ??? */
3951 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003952 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3954 }
3955 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003956 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3957 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 return FDC_UNKNOWN;
3959 }
3960
3961 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003962 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3964 }
3965
3966 output_byte(FD_PERPENDICULAR);
3967 if (need_more_output() == MORE_OUTPUT) {
3968 output_byte(0);
3969 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003970 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 return FDC_82072A; /* 82072A as found on Sparcs. */
3972 }
3973
3974 output_byte(FD_UNLOCK);
3975 r = result();
3976 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003977 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003978 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 * LOCK/UNLOCK */
3980 }
3981 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003982 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3983 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 return FDC_UNKNOWN;
3985 }
3986 output_byte(FD_PARTID);
3987 r = result();
3988 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003989 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3990 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 return FDC_UNKNOWN;
3992 }
3993 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003994 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 return FDC_82077; /* Revised 82077AA passes all the tests */
3996 }
3997 switch (reply_buffer[0] >> 5) {
3998 case 0x0:
3999 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08004000 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 return FDC_82078;
4002 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004003 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 return FDC_82078;
4005 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004006 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 return FDC_S82078B;
4008 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004009 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 return FDC_87306;
4011 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004012 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4013 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 return FDC_82078_UNKN;
4015 }
4016} /* get_fdc_version */
4017
4018/* lilo configuration */
4019
4020static void __init floppy_set_flags(int *ints, int param, int param2)
4021{
4022 int i;
4023
4024 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4025 if (param)
4026 default_drive_params[i].params.flags |= param2;
4027 else
4028 default_drive_params[i].params.flags &= ~param2;
4029 }
4030 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4031}
4032
4033static void __init daring(int *ints, int param, int param2)
4034{
4035 int i;
4036
4037 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4038 if (param) {
4039 default_drive_params[i].params.select_delay = 0;
4040 default_drive_params[i].params.flags |=
4041 FD_SILENT_DCL_CLEAR;
4042 } else {
4043 default_drive_params[i].params.select_delay =
4044 2 * HZ / 100;
4045 default_drive_params[i].params.flags &=
4046 ~FD_SILENT_DCL_CLEAR;
4047 }
4048 }
4049 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4050}
4051
4052static void __init set_cmos(int *ints, int dummy, int dummy2)
4053{
4054 int current_drive = 0;
4055
4056 if (ints[0] != 2) {
4057 DPRINT("wrong number of parameters for CMOS\n");
4058 return;
4059 }
4060 current_drive = ints[1];
4061 if (current_drive < 0 || current_drive >= 8) {
4062 DPRINT("bad drive for set_cmos\n");
4063 return;
4064 }
4065#if N_FDC > 1
4066 if (current_drive >= 4 && !FDC2)
4067 FDC2 = 0x370;
4068#endif
4069 DP->cmos = ints[2];
4070 DPRINT("setting CMOS code to %d\n", ints[2]);
4071}
4072
4073static struct param_table {
4074 const char *name;
4075 void (*fn) (int *ints, int param, int param2);
4076 int *var;
4077 int def_param;
4078 int param2;
4079} config_params[] __initdata = {
4080 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4081 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4082 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4083 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4084 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4085 {"daring", daring, NULL, 1, 0},
4086#if N_FDC > 1
4087 {"two_fdc", NULL, &FDC2, 0x370, 0},
4088 {"one_fdc", NULL, &FDC2, 0, 0},
4089#endif
4090 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4091 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4092 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4093 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4094 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4095 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4096 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4097 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4098 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4099 {"nofifo", NULL, &no_fifo, 0x20, 0},
4100 {"usefifo", NULL, &no_fifo, 0, 0},
4101 {"cmos", set_cmos, NULL, 0, 0},
4102 {"slow", NULL, &slow_floppy, 1, 0},
4103 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4104 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4105 {"L40SX", NULL, &print_unex, 0, 0}
4106
4107 EXTRA_FLOPPY_PARAMS
4108};
4109
4110static int __init floppy_setup(char *str)
4111{
4112 int i;
4113 int param;
4114 int ints[11];
4115
4116 str = get_options(str, ARRAY_SIZE(ints), ints);
4117 if (str) {
4118 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4119 if (strcmp(str, config_params[i].name) == 0) {
4120 if (ints[0])
4121 param = ints[1];
4122 else
4123 param = config_params[i].def_param;
4124 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004125 config_params[i].fn(ints, param,
4126 config_params[i].
4127 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 if (config_params[i].var) {
4129 DPRINT("%s=%d\n", str, param);
4130 *config_params[i].var = param;
4131 }
4132 return 1;
4133 }
4134 }
4135 }
4136 if (str) {
4137 DPRINT("unknown floppy option [%s]\n", str);
4138
4139 DPRINT("allowed options are:");
4140 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004141 pr_cont(" %s", config_params[i].name);
4142 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 } else
4144 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004145 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 return 0;
4147}
4148
4149static int have_no_fdc = -ENODEV;
4150
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004151static ssize_t floppy_cmos_show(struct device *dev,
4152 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004153{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004154 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004155 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004156
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004157 drive = p->id;
4158 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004159}
Joe Perches48c8cee2010-03-10 15:20:45 -08004160
4161DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004162
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163static void floppy_device_release(struct device *dev)
4164{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165}
4166
Frans Popc90cd332009-07-25 22:24:54 +02004167static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004168{
4169 int fdc;
4170
4171 for (fdc = 0; fdc < N_FDC; fdc++)
4172 if (FDCS->address != -1)
4173 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4174
4175 return 0;
4176}
4177
Alexey Dobriyan47145212009-12-14 18:00:08 -08004178static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004179 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004180 .restore = floppy_resume,
4181};
4182
4183static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004184 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004185 .name = "floppy",
4186 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004187 },
4188};
4189
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004190static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191
4192static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4193{
4194 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4195 if (drive >= N_DRIVE ||
4196 !(allowed_drive_mask & (1 << drive)) ||
4197 fdc_state[FDC(drive)].version == FDC_NONE)
4198 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004199 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 return NULL;
4201 *part = 0;
4202 return get_disk(disks[drive]);
4203}
4204
4205static int __init floppy_init(void)
4206{
4207 int i, unit, drive;
4208 int err, dr;
4209
Kumar Gala68e1ee62008-09-22 14:41:31 -07004210#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004211 if (check_legacy_ioport(FDC1))
4212 return -ENODEV;
4213#endif
4214
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 raw_cmd = NULL;
4216
4217 for (dr = 0; dr < N_DRIVE; dr++) {
4218 disks[dr] = alloc_disk(1);
4219 if (!disks[dr]) {
4220 err = -ENOMEM;
4221 goto out_put_disk;
4222 }
4223
4224 disks[dr]->major = FLOPPY_MAJOR;
4225 disks[dr]->first_minor = TOMINOR(dr);
4226 disks[dr]->fops = &floppy_fops;
4227 sprintf(disks[dr]->disk_name, "fd%d", dr);
4228
4229 init_timer(&motor_off_timer[dr]);
4230 motor_off_timer[dr].data = dr;
4231 motor_off_timer[dr].function = motor_off_callback;
4232 }
4233
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 err = register_blkdev(FLOPPY_MAJOR, "fd");
4235 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004236 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004238 err = platform_driver_register(&floppy_driver);
4239 if (err)
4240 goto out_unreg_blkdev;
4241
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4243 if (!floppy_queue) {
4244 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004245 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004247 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248
4249 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4250 floppy_find, NULL, NULL);
4251
4252 for (i = 0; i < 256; i++)
4253 if (ITYPE(i))
4254 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4255 else
4256 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4257
4258 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4259 config_types();
4260
4261 for (i = 0; i < N_FDC; i++) {
4262 fdc = i;
4263 CLEARSTRUCT(FDCS);
4264 FDCS->dtr = -1;
4265 FDCS->dor = 0x4;
4266#if defined(__sparc__) || defined(__mc68000__)
4267 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
4268#ifdef __mc68000__
4269 if (MACH_IS_SUN3X)
4270#endif
4271 FDCS->version = FDC_82072A;
4272#endif
4273 }
4274
4275 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 fdc_state[0].address = FDC1;
4277 if (fdc_state[0].address == -1) {
4278 del_timer(&fd_timeout);
4279 err = -ENODEV;
4280 goto out_unreg_region;
4281 }
4282#if N_FDC > 1
4283 fdc_state[1].address = FDC2;
4284#endif
4285
4286 fdc = 0; /* reset fdc in case of unexpected interrupt */
4287 err = floppy_grab_irq_and_dma();
4288 if (err) {
4289 del_timer(&fd_timeout);
4290 err = -EBUSY;
4291 goto out_unreg_region;
4292 }
4293
4294 /* initialise drive state */
4295 for (drive = 0; drive < N_DRIVE; drive++) {
4296 CLEARSTRUCT(UDRS);
4297 CLEARSTRUCT(UDRWE);
4298 USETF(FD_DISK_NEWCHANGE);
4299 USETF(FD_DISK_CHANGED);
4300 USETF(FD_VERIFY);
4301 UDRS->fd_device = -1;
4302 floppy_track_buffer = NULL;
4303 max_buffer_sectors = 0;
4304 }
4305 /*
4306 * Small 10 msec delay to let through any interrupt that
4307 * initialization might have triggered, to not
4308 * confuse detection:
4309 */
4310 msleep(10);
4311
4312 for (i = 0; i < N_FDC; i++) {
4313 fdc = i;
4314 FDCS->driver_version = FD_DRIVER_VERSION;
4315 for (unit = 0; unit < 4; unit++)
4316 FDCS->track[unit] = 0;
4317 if (FDCS->address == -1)
4318 continue;
4319 FDCS->rawcmd = 2;
4320 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4321 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004322 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 FDCS->address = -1;
4324 FDCS->version = FDC_NONE;
4325 continue;
4326 }
4327 /* Try to determine the floppy controller type */
4328 FDCS->version = get_fdc_version();
4329 if (FDCS->version == FDC_NONE) {
4330 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004331 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 FDCS->address = -1;
4333 continue;
4334 }
4335 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4336 can_use_virtual_dma = 0;
4337
4338 have_no_fdc = 0;
4339 /* Not all FDCs seem to be able to handle the version command
4340 * properly, so force a reset for the standard FDC clones,
4341 * to avoid interrupt garbage.
4342 */
4343 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4344 }
4345 fdc = 0;
4346 del_timer(&fd_timeout);
4347 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 initialising = 0;
4349 if (have_no_fdc) {
4350 DPRINT("no floppy controllers found\n");
4351 err = have_no_fdc;
4352 goto out_flush_work;
4353 }
4354
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 for (drive = 0; drive < N_DRIVE; drive++) {
4356 if (!(allowed_drive_mask & (1 << drive)))
4357 continue;
4358 if (fdc_state[FDC(drive)].version == FDC_NONE)
4359 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004360
4361 floppy_device[drive].name = floppy_device_name;
4362 floppy_device[drive].id = drive;
4363 floppy_device[drive].dev.release = floppy_device_release;
4364
4365 err = platform_device_register(&floppy_device[drive]);
4366 if (err)
4367 goto out_flush_work;
4368
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004369 err = device_create_file(&floppy_device[drive].dev,
4370 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004371 if (err)
4372 goto out_unreg_platform_dev;
4373
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 /* to be cleaned up... */
4375 disks[drive]->private_data = (void *)(long)drive;
4376 disks[drive]->queue = floppy_queue;
4377 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004378 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 add_disk(disks[drive]);
4380 }
4381
4382 return 0;
4383
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004384out_unreg_platform_dev:
4385 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386out_flush_work:
4387 flush_scheduled_work();
4388 if (usage_count)
4389 floppy_release_irq_and_dma();
4390out_unreg_region:
4391 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4392 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004393out_unreg_driver:
4394 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395out_unreg_blkdev:
4396 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397out_put_disk:
4398 while (dr--) {
4399 del_timer(&motor_off_timer[dr]);
4400 put_disk(disks[dr]);
4401 }
4402 return err;
4403}
4404
4405static DEFINE_SPINLOCK(floppy_usage_lock);
4406
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004407static const struct io_region {
4408 int offset;
4409 int size;
4410} io_regions[] = {
4411 { 2, 1 },
4412 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4413 { 4, 2 },
4414 /* address + 6 is reserved, and may be taken by IDE.
4415 * Unfortunately, Adaptec doesn't know this :-(, */
4416 { 7, 1 },
4417};
4418
4419static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4420{
4421 while (p != io_regions) {
4422 p--;
4423 release_region(FDCS->address + p->offset, p->size);
4424 }
4425}
4426
4427#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4428
4429static int floppy_request_regions(int fdc)
4430{
4431 const struct io_region *p;
4432
4433 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004434 if (!request_region(FDCS->address + p->offset,
4435 p->size, "floppy")) {
4436 DPRINT("Floppy io-port 0x%04lx in use\n",
4437 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004438 floppy_release_allocated_regions(fdc, p);
4439 return -EBUSY;
4440 }
4441 }
4442 return 0;
4443}
4444
4445static void floppy_release_regions(int fdc)
4446{
4447 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4448}
4449
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450static int floppy_grab_irq_and_dma(void)
4451{
4452 unsigned long flags;
4453
4454 spin_lock_irqsave(&floppy_usage_lock, flags);
4455 if (usage_count++) {
4456 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4457 return 0;
4458 }
4459 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004460
4461 /*
4462 * We might have scheduled a free_irq(), wait it to
4463 * drain first:
4464 */
4465 flush_scheduled_work();
4466
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 if (fd_request_irq()) {
4468 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4469 FLOPPY_IRQ);
4470 spin_lock_irqsave(&floppy_usage_lock, flags);
4471 usage_count--;
4472 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4473 return -1;
4474 }
4475 if (fd_request_dma()) {
4476 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4477 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004478 if (can_use_virtual_dma & 2)
4479 use_virtual_dma = can_use_virtual_dma = 1;
4480 if (!(can_use_virtual_dma & 1)) {
4481 fd_free_irq();
4482 spin_lock_irqsave(&floppy_usage_lock, flags);
4483 usage_count--;
4484 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4485 return -1;
4486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 }
4488
4489 for (fdc = 0; fdc < N_FDC; fdc++) {
4490 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004491 if (floppy_request_regions(fdc))
4492 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 }
4494 }
4495 for (fdc = 0; fdc < N_FDC; fdc++) {
4496 if (FDCS->address != -1) {
4497 reset_fdc_info(1);
4498 fd_outb(FDCS->dor, FD_DOR);
4499 }
4500 }
4501 fdc = 0;
4502 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4503
4504 for (fdc = 0; fdc < N_FDC; fdc++)
4505 if (FDCS->address != -1)
4506 fd_outb(FDCS->dor, FD_DOR);
4507 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004508 * The driver will try and free resources and relies on us
4509 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 */
4511 fdc = 0;
4512 irqdma_allocated = 1;
4513 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004514cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 fd_free_irq();
4516 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004517 while (--fdc >= 0)
4518 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 spin_lock_irqsave(&floppy_usage_lock, flags);
4520 usage_count--;
4521 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4522 return -1;
4523}
4524
4525static void floppy_release_irq_and_dma(void)
4526{
4527 int old_fdc;
4528#ifdef FLOPPY_SANITY_CHECK
4529#ifndef __sparc__
4530 int drive;
4531#endif
4532#endif
4533 long tmpsize;
4534 unsigned long tmpaddr;
4535 unsigned long flags;
4536
4537 spin_lock_irqsave(&floppy_usage_lock, flags);
4538 if (--usage_count) {
4539 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4540 return;
4541 }
4542 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4543 if (irqdma_allocated) {
4544 fd_disable_dma();
4545 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004546 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 irqdma_allocated = 0;
4548 }
4549 set_dor(0, ~0, 8);
4550#if N_FDC > 1
4551 set_dor(1, ~8, 0);
4552#endif
4553 floppy_enable_hlt();
4554
4555 if (floppy_track_buffer && max_buffer_sectors) {
4556 tmpsize = max_buffer_sectors * 1024;
4557 tmpaddr = (unsigned long)floppy_track_buffer;
4558 floppy_track_buffer = NULL;
4559 max_buffer_sectors = 0;
4560 buffer_min = buffer_max = -1;
4561 fd_dma_mem_free(tmpaddr, tmpsize);
4562 }
4563#ifdef FLOPPY_SANITY_CHECK
4564#ifndef __sparc__
4565 for (drive = 0; drive < N_FDC * 4; drive++)
4566 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004567 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568#endif
4569
4570 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004571 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004573 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004574 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004575 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576#endif
4577 old_fdc = fdc;
4578 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004579 if (FDCS->address != -1)
4580 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 fdc = old_fdc;
4582}
4583
4584#ifdef MODULE
4585
4586static char *floppy;
4587
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588static void __init parse_floppy_cfg_string(char *cfg)
4589{
4590 char *ptr;
4591
4592 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004593 ptr = cfg;
4594 while (*cfg && *cfg != ' ' && *cfg != '\t')
4595 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 if (*cfg) {
4597 *cfg = '\0';
4598 cfg++;
4599 }
4600 if (*ptr)
4601 floppy_setup(ptr);
4602 }
4603}
4604
Jon Schindler7afea3b2008-04-29 00:59:21 -07004605static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606{
4607 if (floppy)
4608 parse_floppy_cfg_string(floppy);
4609 return floppy_init();
4610}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004611module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612
Jon Schindler7afea3b2008-04-29 00:59:21 -07004613static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614{
4615 int drive;
4616
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4618 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004619 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
4621 for (drive = 0; drive < N_DRIVE; drive++) {
4622 del_timer_sync(&motor_off_timer[drive]);
4623
4624 if ((allowed_drive_mask & (1 << drive)) &&
4625 fdc_state[FDC(drive)].version != FDC_NONE) {
4626 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004627 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4628 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 }
4630 put_disk(disks[drive]);
4631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632
4633 del_timer_sync(&fd_timeout);
4634 del_timer_sync(&fd_timer);
4635 blk_cleanup_queue(floppy_queue);
4636
4637 if (usage_count)
4638 floppy_release_irq_and_dma();
4639
4640 /* eject disk, if any */
4641 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642}
Joe Perches48c8cee2010-03-10 15:20:45 -08004643
Jon Schindler7afea3b2008-04-29 00:59:21 -07004644module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645
4646module_param(floppy, charp, 0);
4647module_param(FLOPPY_IRQ, int, 0);
4648module_param(FLOPPY_DMA, int, 0);
4649MODULE_AUTHOR("Alain L. Knaff");
4650MODULE_SUPPORTED_DEVICE("fd");
4651MODULE_LICENSE("GPL");
4652
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004653/* This doesn't actually get used other than for module information */
4654static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004655 {"PNP0700", 0},
4656 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004657};
Joe Perches48c8cee2010-03-10 15:20:45 -08004658
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004659MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4660
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661#else
4662
4663__setup("floppy=", floppy_setup);
4664module_init(floppy_init)
4665#endif
4666
4667MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);