blob: 88a741c75110066bb284a0b66b5bd786cfa195a5 [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{
1178 int status;
1179
1180 if ((status = wait_til_ready()) < 0)
1181 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
1201#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
1202
1203/* gets the response from the fdc */
1204static int result(void)
1205{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001206 int i;
1207 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
1209 for (i = 0; i < MAX_REPLIES; i++) {
1210 if ((status = wait_til_ready()) < 0)
1211 break;
1212 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1213 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1214#ifdef FLOPPY_SANITY_CHECK
1215 resultjiffies = jiffies;
1216 resultsize = i;
1217#endif
1218 return i;
1219 }
1220 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1221 reply_buffer[i] = fd_inb(FD_DATA);
1222 else
1223 break;
1224 }
1225 if (!initialising) {
1226 DPRINT
1227 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1228 fdc, status, i);
1229 show_floppy();
1230 }
1231 FDCS->reset = 1;
1232 return -1;
1233}
1234
1235#define MORE_OUTPUT -2
1236/* does the fdc need more output? */
1237static int need_more_output(void)
1238{
1239 int status;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 if ((status = wait_til_ready()) < 0)
1242 return -1;
1243 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1244 return MORE_OUTPUT;
1245 return result();
1246}
1247
1248/* Set perpendicular mode as required, based on data rate, if supported.
1249 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1250 */
1251static inline void perpendicular_mode(void)
1252{
1253 unsigned char perp_mode;
1254
1255 if (raw_cmd->rate & 0x40) {
1256 switch (raw_cmd->rate & 3) {
1257 case 0:
1258 perp_mode = 2;
1259 break;
1260 case 3:
1261 perp_mode = 3;
1262 break;
1263 default:
1264 DPRINT("Invalid data rate for perpendicular mode!\n");
1265 cont->done(0);
1266 FDCS->reset = 1; /* convenient way to return to
1267 * redo without to much hassle (deep
1268 * stack et al. */
1269 return;
1270 }
1271 } else
1272 perp_mode = 0;
1273
1274 if (FDCS->perp_mode == perp_mode)
1275 return;
1276 if (FDCS->version >= FDC_82077_ORIG) {
1277 output_byte(FD_PERPENDICULAR);
1278 output_byte(perp_mode);
1279 FDCS->perp_mode = perp_mode;
1280 } else if (perp_mode) {
1281 DPRINT("perpendicular mode not supported by this FDC.\n");
1282 }
1283} /* perpendicular_mode */
1284
1285static int fifo_depth = 0xa;
1286static int no_fifo;
1287
1288static int fdc_configure(void)
1289{
1290 /* Turn on FIFO */
1291 output_byte(FD_CONFIGURE);
1292 if (need_more_output() != MORE_OUTPUT)
1293 return 0;
1294 output_byte(0);
1295 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1296 output_byte(0); /* pre-compensation from track
1297 0 upwards */
1298 return 1;
1299}
1300
1301#define NOMINAL_DTR 500
1302
1303/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1304 * head load time, and DMA disable flag to values needed by floppy.
1305 *
1306 * The value "dtr" is the data transfer rate in Kbps. It is needed
1307 * to account for the data rate-based scaling done by the 82072 and 82077
1308 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1309 * 8272a).
1310 *
1311 * Note that changing the data transfer rate has a (probably deleterious)
1312 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1313 * fdc_specify is called again after each data transfer rate
1314 * change.
1315 *
1316 * srt: 1000 to 16000 in microseconds
1317 * hut: 16 to 240 milliseconds
1318 * hlt: 2 to 254 milliseconds
1319 *
1320 * These values are rounded up to the next highest available delay time.
1321 */
1322static void fdc_specify(void)
1323{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001324 unsigned char spec1;
1325 unsigned char spec2;
1326 unsigned long srt;
1327 unsigned long hlt;
1328 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 unsigned long dtr = NOMINAL_DTR;
1330 unsigned long scale_dtr = NOMINAL_DTR;
1331 int hlt_max_code = 0x7f;
1332 int hut_max_code = 0xf;
1333
1334 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1335 fdc_configure();
1336 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 }
1338
1339 switch (raw_cmd->rate & 0x03) {
1340 case 3:
1341 dtr = 1000;
1342 break;
1343 case 1:
1344 dtr = 300;
1345 if (FDCS->version >= FDC_82078) {
1346 /* chose the default rate table, not the one
1347 * where 1 = 2 Mbps */
1348 output_byte(FD_DRIVESPEC);
1349 if (need_more_output() == MORE_OUTPUT) {
1350 output_byte(UNIT(current_drive));
1351 output_byte(0xc0);
1352 }
1353 }
1354 break;
1355 case 2:
1356 dtr = 250;
1357 break;
1358 }
1359
1360 if (FDCS->version >= FDC_82072) {
1361 scale_dtr = dtr;
1362 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1363 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1364 }
1365
1366 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001367 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001368 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 SUPBOUND(srt, 0xf);
1372 INFBOUND(srt, 0);
1373
Julia Lawall061837b2008-09-22 14:57:16 -07001374 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if (hlt < 0x01)
1376 hlt = 0x01;
1377 else if (hlt > 0x7f)
1378 hlt = hlt_max_code;
1379
Julia Lawall061837b2008-09-22 14:57:16 -07001380 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (hut < 0x1)
1382 hut = 0x1;
1383 else if (hut > 0xf)
1384 hut = hut_max_code;
1385
1386 spec1 = (srt << 4) | hut;
1387 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1388
1389 /* If these parameters did not change, just return with success */
1390 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1391 /* Go ahead and set spec1 and spec2 */
1392 output_byte(FD_SPECIFY);
1393 output_byte(FDCS->spec1 = spec1);
1394 output_byte(FDCS->spec2 = spec2);
1395 }
1396} /* fdc_specify */
1397
1398/* Set the FDC's data transfer rate on behalf of the specified drive.
1399 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1400 * of the specify command (i.e. using the fdc_specify function).
1401 */
1402static int fdc_dtr(void)
1403{
1404 /* If data rate not already set to desired value, set it. */
1405 if ((raw_cmd->rate & 3) == FDCS->dtr)
1406 return 0;
1407
1408 /* Set dtr */
1409 fd_outb(raw_cmd->rate & 3, FD_DCR);
1410
1411 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1412 * need a stabilization period of several milliseconds to be
1413 * enforced after data rate changes before R/W operations.
1414 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1415 */
1416 FDCS->dtr = raw_cmd->rate & 3;
1417 return (fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1418 (timeout_fn) floppy_ready));
1419} /* fdc_dtr */
1420
1421static void tell_sector(void)
1422{
Joe Perchesb46df352010-03-10 15:20:46 -08001423 pr_cont(": track %d, head %d, sector %d, size %d",
1424 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425} /* tell_sector */
1426
Joe Perchesb46df352010-03-10 15:20:46 -08001427static void print_errors(void)
1428{
1429 DPRINT("");
1430 if (ST0 & ST0_ECE) {
1431 pr_cont("Recalibrate failed!");
1432 } else if (ST2 & ST2_CRC) {
1433 pr_cont("data CRC error");
1434 tell_sector();
1435 } else if (ST1 & ST1_CRC) {
1436 pr_cont("CRC error");
1437 tell_sector();
1438 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1439 (ST2 & ST2_MAM)) {
1440 if (!probing) {
1441 pr_cont("sector not found");
1442 tell_sector();
1443 } else
1444 pr_cont("probe failed...");
1445 } else if (ST2 & ST2_WC) { /* seek error */
1446 pr_cont("wrong cylinder");
1447 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1448 pr_cont("bad cylinder");
1449 } else {
1450 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1451 ST0, ST1, ST2);
1452 tell_sector();
1453 }
1454 pr_cont("\n");
1455}
1456
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457/*
1458 * OK, this error interpreting routine is called after a
1459 * DMA read/write has succeeded
1460 * or failed, so we check the results, and copy any buffers.
1461 * hhb: Added better error reporting.
1462 * ak: Made this into a separate routine.
1463 */
1464static int interpret_errors(void)
1465{
1466 char bad;
1467
1468 if (inr != 7) {
1469 DPRINT("-- FDC reply error");
1470 FDCS->reset = 1;
1471 return 1;
1472 }
1473
1474 /* check IC to find cause of interrupt */
1475 switch (ST0 & ST0_INTR) {
1476 case 0x40: /* error occurred during command execution */
1477 if (ST1 & ST1_EOC)
1478 return 0; /* occurs with pseudo-DMA */
1479 bad = 1;
1480 if (ST1 & ST1_WP) {
1481 DPRINT("Drive is write protected\n");
1482 CLEARF(FD_DISK_WRITABLE);
1483 cont->done(0);
1484 bad = 2;
1485 } else if (ST1 & ST1_ND) {
1486 SETF(FD_NEED_TWADDLE);
1487 } else if (ST1 & ST1_OR) {
1488 if (DP->flags & FTD_MSG)
1489 DPRINT("Over/Underrun - retrying\n");
1490 bad = 0;
1491 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001492 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 }
1494 if (ST2 & ST2_WC || ST2 & ST2_BC)
1495 /* wrong cylinder => recal */
1496 DRS->track = NEED_2_RECAL;
1497 return bad;
1498 case 0x80: /* invalid command given */
1499 DPRINT("Invalid FDC command given!\n");
1500 cont->done(0);
1501 return 2;
1502 case 0xc0:
1503 DPRINT("Abnormal termination caused by polling\n");
1504 cont->error();
1505 return 2;
1506 default: /* (0) Normal command termination */
1507 return 0;
1508 }
1509}
1510
1511/*
1512 * This routine is called when everything should be correctly set up
1513 * for the transfer (i.e. floppy motor is on, the correct floppy is
1514 * selected, and the head is sitting on the right track).
1515 */
1516static void setup_rw_floppy(void)
1517{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001518 int i;
1519 int r;
1520 int flags;
1521 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 unsigned long ready_date;
1523 timeout_fn function;
1524
1525 flags = raw_cmd->flags;
1526 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1527 flags |= FD_RAW_INTR;
1528
1529 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1530 ready_date = DRS->spinup_date + DP->spinup;
1531 /* If spinup will take a long time, rerun scandrives
1532 * again just before spinup completion. Beware that
1533 * after scandrives, we must again wait for selection.
1534 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001535 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 ready_date -= DP->select_delay;
1537 function = (timeout_fn) floppy_start;
1538 } else
1539 function = (timeout_fn) setup_rw_floppy;
1540
1541 /* wait until the floppy is spinning fast enough */
1542 if (fd_wait_for_completion(ready_date, function))
1543 return;
1544 }
1545 dflags = DRS->flags;
1546
1547 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1548 setup_DMA();
1549
1550 if (flags & FD_RAW_INTR)
1551 do_floppy = main_command_interrupt;
1552
1553 r = 0;
1554 for (i = 0; i < raw_cmd->cmd_count; i++)
1555 r |= output_byte(raw_cmd->cmd[i]);
1556
1557 debugt("rw_command: ");
1558
1559 if (r) {
1560 cont->error();
1561 reset_fdc();
1562 return;
1563 }
1564
1565 if (!(flags & FD_RAW_INTR)) {
1566 inr = result();
1567 cont->interrupt();
1568 } else if (flags & FD_RAW_NEED_DISK)
1569 fd_watchdog();
1570}
1571
1572static int blind_seek;
1573
1574/*
1575 * This is the routine called after every seek (or recalibrate) interrupt
1576 * from the floppy controller.
1577 */
1578static void seek_interrupt(void)
1579{
1580 debugt("seek interrupt:");
1581 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1582 DPRINT("seek failed\n");
1583 DRS->track = NEED_2_RECAL;
1584 cont->error();
1585 cont->redo();
1586 return;
1587 }
1588 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
1589#ifdef DCL_DEBUG
1590 if (DP->flags & FD_DEBUG) {
Joe Perchesb46df352010-03-10 15:20:46 -08001591 DPRINT("clearing NEWCHANGE flag because of effective seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 DPRINT("jiffies=%lu\n", jiffies);
1593 }
1594#endif
1595 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1596 DRS->select_date = jiffies;
1597 }
1598 DRS->track = ST1;
1599 floppy_ready();
1600}
1601
1602static void check_wp(void)
1603{
1604 if (TESTF(FD_VERIFY)) {
1605 /* check write protection */
1606 output_byte(FD_GETSTATUS);
1607 output_byte(UNIT(current_drive));
1608 if (result() != 1) {
1609 FDCS->reset = 1;
1610 return;
1611 }
1612 CLEARF(FD_VERIFY);
1613 CLEARF(FD_NEED_TWADDLE);
1614#ifdef DCL_DEBUG
1615 if (DP->flags & FD_DEBUG) {
1616 DPRINT("checking whether disk is write protected\n");
1617 DPRINT("wp=%x\n", ST3 & 0x40);
1618 }
1619#endif
1620 if (!(ST3 & 0x40))
1621 SETF(FD_DISK_WRITABLE);
1622 else
1623 CLEARF(FD_DISK_WRITABLE);
1624 }
1625}
1626
1627static void seek_floppy(void)
1628{
1629 int track;
1630
1631 blind_seek = 0;
1632
1633#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001634 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 DPRINT("calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636#endif
1637
1638 if (!TESTF(FD_DISK_NEWCHANGE) &&
1639 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1640 /* the media changed flag should be cleared after the seek.
1641 * If it isn't, this means that there is really no disk in
1642 * the drive.
1643 */
1644 SETF(FD_DISK_CHANGED);
1645 cont->done(0);
1646 cont->redo();
1647 return;
1648 }
1649 if (DRS->track <= NEED_1_RECAL) {
1650 recalibrate_floppy();
1651 return;
1652 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1653 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1654 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1655 /* we seek to clear the media-changed condition. Does anybody
1656 * know a more elegant way, which works on all drives? */
1657 if (raw_cmd->track)
1658 track = raw_cmd->track - 1;
1659 else {
1660 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1661 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1662 blind_seek = 1;
1663 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1664 }
1665 track = 1;
1666 }
1667 } else {
1668 check_wp();
1669 if (raw_cmd->track != DRS->track &&
1670 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1671 track = raw_cmd->track;
1672 else {
1673 setup_rw_floppy();
1674 return;
1675 }
1676 }
1677
1678 do_floppy = seek_interrupt;
1679 output_byte(FD_SEEK);
1680 output_byte(UNIT(current_drive));
1681 LAST_OUT(track);
1682 debugt("seek command:");
1683}
1684
1685static void recal_interrupt(void)
1686{
1687 debugt("recal interrupt:");
1688 if (inr != 2)
1689 FDCS->reset = 1;
1690 else if (ST0 & ST0_ECE) {
1691 switch (DRS->track) {
1692 case NEED_1_RECAL:
1693 debugt("recal interrupt need 1 recal:");
1694 /* after a second recalibrate, we still haven't
1695 * reached track 0. Probably no drive. Raise an
1696 * error, as failing immediately might upset
1697 * computers possessed by the Devil :-) */
1698 cont->error();
1699 cont->redo();
1700 return;
1701 case NEED_2_RECAL:
1702 debugt("recal interrupt need 2 recal:");
1703 /* If we already did a recalibrate,
1704 * and we are not at track 0, this
1705 * means we have moved. (The only way
1706 * not to move at recalibration is to
1707 * be already at track 0.) Clear the
1708 * new change flag */
1709#ifdef DCL_DEBUG
Joe Perchesb46df352010-03-10 15:20:46 -08001710 if (DP->flags & FD_DEBUG)
1711 DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712#endif
1713
1714 CLEARF(FD_DISK_NEWCHANGE);
1715 DRS->select_date = jiffies;
1716 /* fall through */
1717 default:
1718 debugt("recal interrupt default:");
1719 /* Recalibrate moves the head by at
1720 * most 80 steps. If after one
1721 * recalibrate we don't have reached
1722 * track 0, this might mean that we
1723 * started beyond track 80. Try
1724 * again. */
1725 DRS->track = NEED_1_RECAL;
1726 break;
1727 }
1728 } else
1729 DRS->track = ST1;
1730 floppy_ready();
1731}
1732
1733static void print_result(char *message, int inr)
1734{
1735 int i;
1736
1737 DPRINT("%s ", message);
1738 if (inr >= 0)
1739 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001740 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1741 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742}
1743
1744/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001745irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 int do_print;
1748 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001749 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
1751 lasthandler = handler;
1752 interruptjiffies = jiffies;
1753
1754 f = claim_dma_lock();
1755 fd_disable_dma();
1756 release_dma_lock(f);
1757
1758 floppy_enable_hlt();
1759 do_floppy = NULL;
1760 if (fdc >= N_FDC || FDCS->address == -1) {
1761 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001762 pr_info("DOR0=%x\n", fdc_state[0].dor);
1763 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1764 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 is_alive("bizarre fdc");
1766 return IRQ_NONE;
1767 }
1768
1769 FDCS->reset = 0;
1770 /* We have to clear the reset flag here, because apparently on boxes
1771 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1772 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1773 * emission of the SENSEI's.
1774 * It is OK to emit floppy commands because we are in an interrupt
1775 * handler here, and thus we have to fear no interference of other
1776 * activity.
1777 */
1778
1779 do_print = !handler && print_unex && !initialising;
1780
1781 inr = result();
1782 if (do_print)
1783 print_result("unexpected interrupt", inr);
1784 if (inr == 0) {
1785 int max_sensei = 4;
1786 do {
1787 output_byte(FD_SENSEI);
1788 inr = result();
1789 if (do_print)
1790 print_result("sensei", inr);
1791 max_sensei--;
1792 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1793 && max_sensei);
1794 }
1795 if (!handler) {
1796 FDCS->reset = 1;
1797 return IRQ_NONE;
1798 }
1799 schedule_bh(handler);
1800 is_alive("normal interrupt end");
1801
1802 /* FIXME! Was it really for us? */
1803 return IRQ_HANDLED;
1804}
1805
1806static void recalibrate_floppy(void)
1807{
1808 debugt("recalibrate floppy:");
1809 do_floppy = recal_interrupt;
1810 output_byte(FD_RECALIBRATE);
1811 LAST_OUT(UNIT(current_drive));
1812}
1813
1814/*
1815 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1816 */
1817static void reset_interrupt(void)
1818{
1819 debugt("reset interrupt:");
1820 result(); /* get the status ready for set_fdc */
1821 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001822 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 cont->error(); /* a reset just after a reset. BAD! */
1824 }
1825 cont->redo();
1826}
1827
1828/*
1829 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1830 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1831 */
1832static void reset_fdc(void)
1833{
1834 unsigned long flags;
1835
1836 do_floppy = reset_interrupt;
1837 FDCS->reset = 0;
1838 reset_fdc_info(0);
1839
1840 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1841 /* Irrelevant for systems with true DMA (i386). */
1842
1843 flags = claim_dma_lock();
1844 fd_disable_dma();
1845 release_dma_lock(flags);
1846
1847 if (FDCS->version >= FDC_82072A)
1848 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1849 else {
1850 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1851 udelay(FD_RESET_DELAY);
1852 fd_outb(FDCS->dor, FD_DOR);
1853 }
1854}
1855
1856static void show_floppy(void)
1857{
1858 int i;
1859
Joe Perchesb46df352010-03-10 15:20:46 -08001860 pr_info("\n");
1861 pr_info("floppy driver state\n");
1862 pr_info("-------------------\n");
1863 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1864 jiffies, interruptjiffies, jiffies - interruptjiffies,
1865 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
1867#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001868 pr_info("timeout_message=%s\n", timeout_message);
1869 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001871 pr_info("%2x %2x %lu\n",
1872 output_log[(i + output_log_pos) % OLOGSIZE].data,
1873 output_log[(i + output_log_pos) % OLOGSIZE].status,
1874 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1875 pr_info("last result at %lu\n", resultjiffies);
1876 pr_info("last redo_fd_request at %lu\n", lastredo);
1877 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1878 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879#endif
1880
Joe Perchesb46df352010-03-10 15:20:46 -08001881 pr_info("status=%x\n", fd_inb(FD_STATUS));
1882 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001884 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001885 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001886 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001888 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001890 pr_info("timer_function=%p\n", fd_timeout.function);
1891 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1892 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 }
Joe Perchesb46df352010-03-10 15:20:46 -08001894 pr_info("cont=%p\n", cont);
1895 pr_info("current_req=%p\n", current_req);
1896 pr_info("command_status=%d\n", command_status);
1897 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898}
1899
1900static void floppy_shutdown(unsigned long data)
1901{
1902 unsigned long flags;
1903
1904 if (!initialising)
1905 show_floppy();
1906 cancel_activity();
1907
1908 floppy_enable_hlt();
1909
1910 flags = claim_dma_lock();
1911 fd_disable_dma();
1912 release_dma_lock(flags);
1913
1914 /* avoid dma going to a random drive after shutdown */
1915
1916 if (!initialising)
1917 DPRINT("floppy timeout called\n");
1918 FDCS->reset = 1;
1919 if (cont) {
1920 cont->done(0);
1921 cont->redo(); /* this will recall reset when needed */
1922 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001923 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 process_fd_request();
1925 }
1926 is_alive("floppy shutdown");
1927}
1928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001930static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001932 int mask;
1933 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
1935 mask = 0xfc;
1936 data = UNIT(current_drive);
1937 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1938 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1939 set_debugt();
1940 /* no read since this drive is running */
1941 DRS->first_read_date = 0;
1942 /* note motor start time if motor is not yet running */
1943 DRS->spinup_date = jiffies;
1944 data |= (0x10 << UNIT(current_drive));
1945 }
1946 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1947 mask &= ~(0x10 << UNIT(current_drive));
1948
1949 /* starts motor and selects floppy */
1950 del_timer(motor_off_timer + current_drive);
1951 set_dor(fdc, mask, data);
1952
1953 /* wait_for_completion also schedules reset if needed. */
1954 return (fd_wait_for_completion(DRS->select_date + DP->select_delay,
1955 (timeout_fn) function));
1956}
1957
1958static void floppy_ready(void)
1959{
Joe Perches045f9832010-03-10 15:20:47 -08001960 if (FDCS->reset) {
1961 reset_fdc();
1962 return;
1963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 if (start_motor(floppy_ready))
1965 return;
1966 if (fdc_dtr())
1967 return;
1968
1969#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001970 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 DPRINT("calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972#endif
1973 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1974 disk_change(current_drive) && !DP->select_delay)
1975 twaddle(); /* this clears the dcl on certain drive/controller
1976 * combinations */
1977
1978#ifdef fd_chose_dma_mode
1979 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1980 unsigned long flags = claim_dma_lock();
1981 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1982 release_dma_lock(flags);
1983 }
1984#endif
1985
1986 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1987 perpendicular_mode();
1988 fdc_specify(); /* must be done here because of hut, hlt ... */
1989 seek_floppy();
1990 } else {
1991 if ((raw_cmd->flags & FD_RAW_READ) ||
1992 (raw_cmd->flags & FD_RAW_WRITE))
1993 fdc_specify();
1994 setup_rw_floppy();
1995 }
1996}
1997
1998static void floppy_start(void)
1999{
2000 reschedule_timeout(current_reqD, "floppy start", 0);
2001
2002 scandrives();
2003#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08002004 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 DPRINT("setting NEWCHANGE in floppy_start\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006#endif
2007 SETF(FD_DISK_NEWCHANGE);
2008 floppy_ready();
2009}
2010
2011/*
2012 * ========================================================================
2013 * here ends the bottom half. Exported routines are:
2014 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2015 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2016 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2017 * and set_dor.
2018 * ========================================================================
2019 */
2020/*
2021 * General purpose continuations.
2022 * ==============================
2023 */
2024
2025static void do_wakeup(void)
2026{
2027 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2028 cont = NULL;
2029 command_status += 2;
2030 wake_up(&command_done);
2031}
2032
2033static struct cont_t wakeup_cont = {
2034 .interrupt = empty,
2035 .redo = do_wakeup,
2036 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002037 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038};
2039
2040static struct cont_t intr_cont = {
2041 .interrupt = empty,
2042 .redo = process_fd_request,
2043 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002044 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045};
2046
Jesper Juhl06f748c2007-10-16 23:30:57 -07002047static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
2049 int ret;
2050
2051 schedule_bh(handler);
2052
2053 if (command_status < 2 && NO_SIGNAL) {
2054 DECLARE_WAITQUEUE(wait, current);
2055
2056 add_wait_queue(&command_done, &wait);
2057 for (;;) {
2058 set_current_state(interruptible ?
2059 TASK_INTERRUPTIBLE :
2060 TASK_UNINTERRUPTIBLE);
2061
2062 if (command_status >= 2 || !NO_SIGNAL)
2063 break;
2064
2065 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 schedule();
2067 }
2068
2069 set_current_state(TASK_RUNNING);
2070 remove_wait_queue(&command_done, &wait);
2071 }
2072
2073 if (command_status < 2) {
2074 cancel_activity();
2075 cont = &intr_cont;
2076 reset_fdc();
2077 return -EINTR;
2078 }
2079
2080 if (FDCS->reset)
2081 command_status = FD_COMMAND_ERROR;
2082 if (command_status == FD_COMMAND_OKAY)
2083 ret = 0;
2084 else
2085 ret = -EIO;
2086 command_status = FD_COMMAND_NONE;
2087 return ret;
2088}
2089
2090static void generic_done(int result)
2091{
2092 command_status = result;
2093 cont = &wakeup_cont;
2094}
2095
2096static void generic_success(void)
2097{
2098 cont->done(1);
2099}
2100
2101static void generic_failure(void)
2102{
2103 cont->done(0);
2104}
2105
2106static void success_and_wakeup(void)
2107{
2108 generic_success();
2109 cont->redo();
2110}
2111
2112/*
2113 * formatting and rw support.
2114 * ==========================
2115 */
2116
2117static int next_valid_format(void)
2118{
2119 int probed_format;
2120
2121 probed_format = DRS->probed_format;
2122 while (1) {
2123 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2124 DRS->probed_format = 0;
2125 return 1;
2126 }
2127 if (floppy_type[DP->autodetect[probed_format]].sect) {
2128 DRS->probed_format = probed_format;
2129 return 0;
2130 }
2131 probed_format++;
2132 }
2133}
2134
2135static void bad_flp_intr(void)
2136{
2137 int err_count;
2138
2139 if (probing) {
2140 DRS->probed_format++;
2141 if (!next_valid_format())
2142 return;
2143 }
2144 err_count = ++(*errors);
2145 INFBOUND(DRWE->badness, err_count);
2146 if (err_count > DP->max_errors.abort)
2147 cont->done(0);
2148 if (err_count > DP->max_errors.reset)
2149 FDCS->reset = 1;
2150 else if (err_count > DP->max_errors.recal)
2151 DRS->track = NEED_2_RECAL;
2152}
2153
2154static void set_floppy(int drive)
2155{
2156 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002157
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 if (type)
2159 _floppy = floppy_type + type;
2160 else
2161 _floppy = current_type[drive];
2162}
2163
2164/*
2165 * formatting support.
2166 * ===================
2167 */
2168static void format_interrupt(void)
2169{
2170 switch (interpret_errors()) {
2171 case 1:
2172 cont->error();
2173 case 2:
2174 break;
2175 case 0:
2176 cont->done(1);
2177 }
2178 cont->redo();
2179}
2180
2181#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002182#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002184
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185static void setup_format_params(int track)
2186{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002187 int n;
2188 int il;
2189 int count;
2190 int head_shift;
2191 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 struct fparm {
2193 unsigned char track, head, sect, size;
2194 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
2196 raw_cmd = &default_raw_cmd;
2197 raw_cmd->track = track;
2198
Joe Perches48c8cee2010-03-10 15:20:45 -08002199 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2200 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 raw_cmd->rate = _floppy->rate & 0x43;
2202 raw_cmd->cmd_count = NR_F;
2203 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2204 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2205 F_SIZECODE = FD_SIZECODE(_floppy);
2206 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2207 F_GAP = _floppy->fmt_gap;
2208 F_FILL = FD_FILL_BYTE;
2209
2210 raw_cmd->kernel_data = floppy_track_buffer;
2211 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2212
2213 /* allow for about 30ms for data transport per track */
2214 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2215
2216 /* a ``cylinder'' is two tracks plus a little stepping time */
2217 track_shift = 2 * head_shift + 3;
2218
2219 /* position of logical sector 1 on this track */
2220 n = (track_shift * format_req.track + head_shift * format_req.head)
2221 % F_SECT_PER_TRACK;
2222
2223 /* determine interleave */
2224 il = 1;
2225 if (_floppy->fmt_gap < 0x22)
2226 il++;
2227
2228 /* initialize field */
2229 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2230 here[count].track = format_req.track;
2231 here[count].head = format_req.head;
2232 here[count].sect = 0;
2233 here[count].size = F_SIZECODE;
2234 }
2235 /* place logical sectors */
2236 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2237 here[n].sect = count;
2238 n = (n + il) % F_SECT_PER_TRACK;
2239 if (here[n].sect) { /* sector busy, find next free sector */
2240 ++n;
2241 if (n >= F_SECT_PER_TRACK) {
2242 n -= F_SECT_PER_TRACK;
2243 while (here[n].sect)
2244 ++n;
2245 }
2246 }
2247 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002248 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002250 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 }
2252}
2253
2254static void redo_format(void)
2255{
2256 buffer_track = -1;
2257 setup_format_params(format_req.track << STRETCH(_floppy));
2258 floppy_start();
2259 debugt("queue format request");
2260}
2261
2262static struct cont_t format_cont = {
2263 .interrupt = format_interrupt,
2264 .redo = redo_format,
2265 .error = bad_flp_intr,
2266 .done = generic_done
2267};
2268
2269static int do_format(int drive, struct format_descr *tmp_format_req)
2270{
2271 int ret;
2272
2273 LOCK_FDC(drive, 1);
2274 set_floppy(drive);
2275 if (!_floppy ||
2276 _floppy->track > DP->tracks ||
2277 tmp_format_req->track >= _floppy->track ||
2278 tmp_format_req->head >= _floppy->head ||
2279 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2280 !_floppy->fmt_gap) {
2281 process_fd_request();
2282 return -EINVAL;
2283 }
2284 format_req = *tmp_format_req;
2285 format_errors = 0;
2286 cont = &format_cont;
2287 errors = &format_errors;
2288 IWAIT(redo_format);
2289 process_fd_request();
2290 return ret;
2291}
2292
2293/*
2294 * Buffer read/write and support
2295 * =============================
2296 */
2297
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002298static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299{
2300 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002301 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
2303 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002304 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002305 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002306 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
2309 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002310 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 current_req = NULL;
2312}
2313
2314/* new request_done. Can handle physical sectors which are smaller than a
2315 * logical buffer */
2316static void request_done(int uptodate)
2317{
2318 struct request_queue *q = floppy_queue;
2319 struct request *req = current_req;
2320 unsigned long flags;
2321 int block;
2322
2323 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002324 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
2326 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002327 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 return;
2329 }
2330
2331 if (uptodate) {
2332 /* maintain values for invalidation on geometry
2333 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002334 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 INFBOUND(DRS->maxblock, block);
2336 if (block > _floppy->sect)
2337 DRS->maxtrack = 1;
2338
2339 /* unlock chained buffers */
2340 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002341 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 spin_unlock_irqrestore(q->queue_lock, flags);
2343 } else {
2344 if (rq_data_dir(req) == WRITE) {
2345 /* record write error information */
2346 DRWE->write_errors++;
2347 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002348 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 DRWE->first_error_generation = DRS->generation;
2350 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002351 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 DRWE->last_error_generation = DRS->generation;
2353 }
2354 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002355 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 spin_unlock_irqrestore(q->queue_lock, flags);
2357 }
2358}
2359
2360/* Interrupt handler evaluating the result of the r/w operation */
2361static void rw_interrupt(void)
2362{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002363 int eoc;
2364 int ssize;
2365 int heads;
2366 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
2368 if (R_HEAD >= 2) {
2369 /* some Toshiba floppy controllers occasionnally seem to
2370 * return bogus interrupts after read/write operations, which
2371 * can be recognized by a bad head number (>= 2) */
2372 return;
2373 }
2374
2375 if (!DRS->first_read_date)
2376 DRS->first_read_date = jiffies;
2377
2378 nr_sectors = 0;
2379 CODE2SIZE;
2380
2381 if (ST1 & ST1_EOC)
2382 eoc = 1;
2383 else
2384 eoc = 0;
2385
2386 if (COMMAND & 0x80)
2387 heads = 2;
2388 else
2389 heads = 1;
2390
2391 nr_sectors = (((R_TRACK - TRACK) * heads +
2392 R_HEAD - HEAD) * SECT_PER_TRACK +
2393 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2394
2395#ifdef FLOPPY_SANITY_CHECK
2396 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002397 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 DPRINT("long rw: %x instead of %lx\n",
2399 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002400 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2401 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2402 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2403 pr_info("heads=%d eoc=%d\n", heads, eoc);
2404 pr_info("spt=%d st=%d ss=%d\n",
2405 SECT_PER_TRACK, fsector_t, ssize);
2406 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 }
2408#endif
2409
2410 nr_sectors -= in_sector_offset;
2411 INFBOUND(nr_sectors, 0);
2412 SUPBOUND(current_count_sectors, nr_sectors);
2413
2414 switch (interpret_errors()) {
2415 case 2:
2416 cont->redo();
2417 return;
2418 case 1:
2419 if (!current_count_sectors) {
2420 cont->error();
2421 cont->redo();
2422 return;
2423 }
2424 break;
2425 case 0:
2426 if (!current_count_sectors) {
2427 cont->redo();
2428 return;
2429 }
2430 current_type[current_drive] = _floppy;
2431 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2432 break;
2433 }
2434
2435 if (probing) {
2436 if (DP->flags & FTD_MSG)
2437 DPRINT("Auto-detected floppy type %s in fd%d\n",
2438 _floppy->name, current_drive);
2439 current_type[current_drive] = _floppy;
2440 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2441 probing = 0;
2442 }
2443
2444 if (CT(COMMAND) != FD_READ ||
2445 raw_cmd->kernel_data == current_req->buffer) {
2446 /* transfer directly from buffer */
2447 cont->done(1);
2448 } else if (CT(COMMAND) == FD_READ) {
2449 buffer_track = raw_cmd->track;
2450 buffer_drive = current_drive;
2451 INFBOUND(buffer_max, nr_sectors + fsector_t);
2452 }
2453 cont->redo();
2454}
2455
2456/* Compute maximal contiguous buffer size. */
2457static int buffer_chain_size(void)
2458{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002460 int size;
2461 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 char *base;
2463
2464 base = bio_data(current_req->bio);
2465 size = 0;
2466
NeilBrown5705f702007-09-25 12:35:59 +02002467 rq_for_each_segment(bv, current_req, iter) {
2468 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2469 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470
NeilBrown5705f702007-09-25 12:35:59 +02002471 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 }
2473
2474 return size >> 9;
2475}
2476
2477/* Compute the maximal transfer size */
2478static int transfer_size(int ssize, int max_sector, int max_size)
2479{
2480 SUPBOUND(max_sector, fsector_t + max_size);
2481
2482 /* alignment */
2483 max_sector -= (max_sector % _floppy->sect) % ssize;
2484
2485 /* transfer size, beginning not aligned */
2486 current_count_sectors = max_sector - fsector_t;
2487
2488 return max_sector;
2489}
2490
2491/*
2492 * Move data from/to the track buffer to/from the buffer cache.
2493 */
2494static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2495{
2496 int remaining; /* number of transferred 512-byte sectors */
2497 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002498 char *buffer;
2499 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002500 int size;
2501 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
2503 max_sector = transfer_size(ssize,
2504 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002505 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506
2507 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002508 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002510 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512 remaining = current_count_sectors << 9;
2513#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002514 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002516 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2517 pr_info("remaining=%d\n", remaining >> 9);
2518 pr_info("current_req->nr_sectors=%u\n",
2519 blk_rq_sectors(current_req));
2520 pr_info("current_req->current_nr_sectors=%u\n",
2521 blk_rq_cur_sectors(current_req));
2522 pr_info("max_sector=%d\n", max_sector);
2523 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 }
2525#endif
2526
2527 buffer_max = max(max_sector, buffer_max);
2528
2529 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2530
Tejun Heo1011c1b2009-05-07 22:24:45 +09002531 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532
NeilBrown5705f702007-09-25 12:35:59 +02002533 rq_for_each_segment(bv, current_req, iter) {
2534 if (!remaining)
2535 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
NeilBrown5705f702007-09-25 12:35:59 +02002537 size = bv->bv_len;
2538 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
NeilBrown5705f702007-09-25 12:35:59 +02002540 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002542 if (dma_buffer + size >
2543 floppy_track_buffer + (max_buffer_sectors << 10) ||
2544 dma_buffer < floppy_track_buffer) {
2545 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002546 (int)((floppy_track_buffer - dma_buffer) >> 9));
2547 pr_info("fsector_t=%d buffer_min=%d\n",
2548 fsector_t, buffer_min);
2549 pr_info("current_count_sectors=%ld\n",
2550 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002552 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002553 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002554 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002555 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 }
NeilBrown5705f702007-09-25 12:35:59 +02002557 if (((unsigned long)buffer) % 512)
2558 DPRINT("%p buffer not aligned\n", buffer);
2559#endif
2560 if (CT(COMMAND) == FD_READ)
2561 memcpy(buffer, dma_buffer, size);
2562 else
2563 memcpy(dma_buffer, buffer, size);
2564
2565 remaining -= size;
2566 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 }
2568#ifdef FLOPPY_SANITY_CHECK
2569 if (remaining) {
2570 if (remaining > 0)
2571 max_sector -= remaining >> 9;
2572 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2573 }
2574#endif
2575}
2576
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577/* work around a bug in pseudo DMA
2578 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2579 * sending data. Hence we need a different way to signal the
2580 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2581 * does not work with MT, hence we can only transfer one head at
2582 * a time
2583 */
2584static void virtualdmabug_workaround(void)
2585{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002586 int hard_sectors;
2587 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588
2589 if (CT(COMMAND) == FD_WRITE) {
2590 COMMAND &= ~0x80; /* switch off multiple track mode */
2591
2592 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2593 end_sector = SECTOR + hard_sectors - 1;
2594#ifdef FLOPPY_SANITY_CHECK
2595 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002596 pr_info("too many sectors %d > %d\n",
2597 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 return;
2599 }
2600#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002601 SECT_PER_TRACK = end_sector;
2602 /* make sure SECT_PER_TRACK
2603 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 }
2605}
2606
2607/*
2608 * Formulate a read/write request.
2609 * this routine decides where to load the data (directly to buffer, or to
2610 * tmp floppy area), how much data to load (the size of the buffer, the whole
2611 * track, or a single sector)
2612 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2613 * allocation on the fly, it should be done here. No other part should need
2614 * modification.
2615 */
2616
2617static int make_raw_rw_request(void)
2618{
2619 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002620 int max_sector;
2621 int max_size;
2622 int tracksize;
2623 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624
2625 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002626 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 return 0;
2628 }
2629
2630 set_fdc((long)current_req->rq_disk->private_data);
2631
2632 raw_cmd = &default_raw_cmd;
2633 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2634 FD_RAW_NEED_SEEK;
2635 raw_cmd->cmd_count = NR_RW;
2636 if (rq_data_dir(current_req) == READ) {
2637 raw_cmd->flags |= FD_RAW_READ;
2638 COMMAND = FM_MODE(_floppy, FD_READ);
2639 } else if (rq_data_dir(current_req) == WRITE) {
2640 raw_cmd->flags |= FD_RAW_WRITE;
2641 COMMAND = FM_MODE(_floppy, FD_WRITE);
2642 } else {
2643 DPRINT("make_raw_rw_request: unknown command\n");
2644 return 0;
2645 }
2646
2647 max_sector = _floppy->sect * _floppy->head;
2648
Tejun Heo83096eb2009-05-07 22:24:39 +09002649 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2650 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002652 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 current_count_sectors = 1;
2654 return 1;
2655 } else
2656 return 0;
2657 }
2658 HEAD = fsector_t / _floppy->sect;
2659
Keith Wansbrough9e491842008-09-22 14:57:17 -07002660 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2662 max_sector = _floppy->sect;
2663
2664 /* 2M disks have phantom sectors on the first track */
2665 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2666 max_sector = 2 * _floppy->sect / 3;
2667 if (fsector_t >= max_sector) {
2668 current_count_sectors =
2669 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002670 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 return 1;
2672 }
2673 SIZECODE = 2;
2674 } else
2675 SIZECODE = FD_SIZECODE(_floppy);
2676 raw_cmd->rate = _floppy->rate & 0x43;
2677 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2678 raw_cmd->rate = 1;
2679
2680 if (SIZECODE)
2681 SIZECODE2 = 0xff;
2682 else
2683 SIZECODE2 = 0x80;
2684 raw_cmd->track = TRACK << STRETCH(_floppy);
2685 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2686 GAP = _floppy->gap;
2687 CODE2SIZE;
2688 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2689 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002690 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
2692 /* tracksize describes the size which can be filled up with sectors
2693 * of size ssize.
2694 */
2695 tracksize = _floppy->sect - _floppy->sect % ssize;
2696 if (tracksize < _floppy->sect) {
2697 SECT_PER_TRACK++;
2698 if (tracksize <= fsector_t % _floppy->sect)
2699 SECTOR--;
2700
2701 /* if we are beyond tracksize, fill up using smaller sectors */
2702 while (tracksize <= fsector_t % _floppy->sect) {
2703 while (tracksize + ssize > _floppy->sect) {
2704 SIZECODE--;
2705 ssize >>= 1;
2706 }
2707 SECTOR++;
2708 SECT_PER_TRACK++;
2709 tracksize += ssize;
2710 }
2711 max_sector = HEAD * _floppy->sect + tracksize;
2712 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2713 max_sector = _floppy->sect;
2714 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2715 /* for virtual DMA bug workaround */
2716 max_sector = _floppy->sect;
2717 }
2718
2719 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2720 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002721 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 if ((raw_cmd->track == buffer_track) &&
2723 (current_drive == buffer_drive) &&
2724 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2725 /* data already in track buffer */
2726 if (CT(COMMAND) == FD_READ) {
2727 copy_buffer(1, max_sector, buffer_max);
2728 return 1;
2729 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002730 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 if (CT(COMMAND) == FD_WRITE) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002732 if (fsector_t + blk_rq_sectors(current_req) > ssize &&
2733 fsector_t + blk_rq_sectors(current_req) < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 max_size = ssize + ssize;
2735 else
2736 max_size = ssize;
2737 }
2738 raw_cmd->flags &= ~FD_RAW_WRITE;
2739 raw_cmd->flags |= FD_RAW_READ;
2740 COMMAND = FM_MODE(_floppy, FD_READ);
2741 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2742 unsigned long dma_limit;
2743 int direct, indirect;
2744
2745 indirect =
2746 transfer_size(ssize, max_sector,
2747 max_buffer_sectors * 2) - fsector_t;
2748
2749 /*
2750 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2751 * on a 64 bit machine!
2752 */
2753 max_size = buffer_chain_size();
2754 dma_limit =
2755 (MAX_DMA_ADDRESS -
2756 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002757 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 /* 64 kb boundaries */
2760 if (CROSS_64KB(current_req->buffer, max_size << 9))
2761 max_size = (K_64 -
2762 ((unsigned long)current_req->buffer) %
2763 K_64) >> 9;
2764 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2765 /*
2766 * We try to read tracks, but if we get too many errors, we
2767 * go back to reading just one sector at a time.
2768 *
2769 * This means we should be able to read a sector even if there
2770 * are other bad sectors on this track.
2771 */
2772 if (!direct ||
2773 (indirect * 2 > direct * 3 &&
Jesper Juhlaee90412007-10-16 23:30:58 -07002774 *errors < DP->max_errors.read_track && ((!probing
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 || (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002776 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 } else {
2778 raw_cmd->kernel_data = current_req->buffer;
2779 raw_cmd->length = current_count_sectors << 9;
2780 if (raw_cmd->length == 0) {
2781 DPRINT
2782 ("zero dma transfer attempted from make_raw_request\n");
2783 DPRINT("indirect=%d direct=%d fsector_t=%d",
2784 indirect, direct, fsector_t);
2785 return 0;
2786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 virtualdmabug_workaround();
2788 return 2;
2789 }
2790 }
2791
2792 if (CT(COMMAND) == FD_READ)
2793 max_size = max_sector; /* unbounded */
2794
2795 /* claim buffer track if needed */
2796 if (buffer_track != raw_cmd->track || /* bad track */
2797 buffer_drive != current_drive || /* bad drive */
2798 fsector_t > buffer_max ||
2799 fsector_t < buffer_min ||
2800 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002801 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 max_sector > 2 * max_buffer_sectors + buffer_min &&
2803 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
2804 /* not enough space */
2805 ) {
2806 buffer_track = -1;
2807 buffer_drive = current_drive;
2808 buffer_max = buffer_min = aligned_sector_t;
2809 }
2810 raw_cmd->kernel_data = floppy_track_buffer +
2811 ((aligned_sector_t - buffer_min) << 9);
2812
2813 if (CT(COMMAND) == FD_WRITE) {
2814 /* copy write buffer to track buffer.
2815 * if we get here, we know that the write
2816 * is either aligned or the data already in the buffer
2817 * (buffer will be overwritten) */
2818#ifdef FLOPPY_SANITY_CHECK
2819 if (in_sector_offset && buffer_track == -1)
2820 DPRINT("internal error offset !=0 on write\n");
2821#endif
2822 buffer_track = raw_cmd->track;
2823 buffer_drive = current_drive;
2824 copy_buffer(ssize, max_sector,
2825 2 * max_buffer_sectors + buffer_min);
2826 } else
2827 transfer_size(ssize, max_sector,
2828 2 * max_buffer_sectors + buffer_min -
2829 aligned_sector_t);
2830
2831 /* round up current_count_sectors to get dma xfer size */
2832 raw_cmd->length = in_sector_offset + current_count_sectors;
2833 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2834 raw_cmd->length <<= 9;
2835#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 if ((raw_cmd->length < current_count_sectors << 9) ||
2837 (raw_cmd->kernel_data != current_req->buffer &&
2838 CT(COMMAND) == FD_WRITE &&
2839 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2840 aligned_sector_t < buffer_min)) ||
2841 raw_cmd->length % (128 << SIZECODE) ||
2842 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2843 DPRINT("fractionary current count b=%lx s=%lx\n",
2844 raw_cmd->length, current_count_sectors);
2845 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002846 pr_info("addr=%d, length=%ld\n",
2847 (int)((raw_cmd->kernel_data -
2848 floppy_track_buffer) >> 9),
2849 current_count_sectors);
2850 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2851 fsector_t, aligned_sector_t, max_sector, max_size);
2852 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2853 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2854 COMMAND, SECTOR, HEAD, TRACK);
2855 pr_info("buffer drive=%d\n", buffer_drive);
2856 pr_info("buffer track=%d\n", buffer_track);
2857 pr_info("buffer_min=%d\n", buffer_min);
2858 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 return 0;
2860 }
2861
2862 if (raw_cmd->kernel_data != current_req->buffer) {
2863 if (raw_cmd->kernel_data < floppy_track_buffer ||
2864 current_count_sectors < 0 ||
2865 raw_cmd->length < 0 ||
2866 raw_cmd->kernel_data + raw_cmd->length >
2867 floppy_track_buffer + (max_buffer_sectors << 10)) {
2868 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002869 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2870 fsector_t, buffer_min, raw_cmd->length >> 9);
2871 pr_info("current_count_sectors=%ld\n",
2872 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002874 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002876 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 return 0;
2878 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002879 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002880 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 DPRINT("buffer overrun in direct transfer\n");
2882 return 0;
2883 } else if (raw_cmd->length < current_count_sectors << 9) {
2884 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002885 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2886 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 }
2888 if (raw_cmd->length == 0) {
2889 DPRINT("zero dma transfer attempted from make_raw_request\n");
2890 return 0;
2891 }
2892#endif
2893
2894 virtualdmabug_workaround();
2895 return 2;
2896}
2897
2898static void redo_fd_request(void)
2899{
2900#define REPEAT {request_done(0); continue; }
2901 int drive;
2902 int tmp;
2903
2904 lastredo = jiffies;
2905 if (current_drive < N_DRIVE)
2906 floppy_off(current_drive);
2907
2908 for (;;) {
2909 if (!current_req) {
2910 struct request *req;
2911
2912 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002913 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 spin_unlock_irq(floppy_queue->queue_lock);
2915 if (!req) {
2916 do_floppy = NULL;
2917 unlock_fdc();
2918 return;
2919 }
2920 current_req = req;
2921 }
2922 drive = (long)current_req->rq_disk->private_data;
2923 set_fdc(drive);
2924 reschedule_timeout(current_reqD, "redo fd request", 0);
2925
2926 set_floppy(drive);
2927 raw_cmd = &default_raw_cmd;
2928 raw_cmd->flags = 0;
2929 if (start_motor(redo_fd_request))
2930 return;
2931 disk_change(current_drive);
2932 if (test_bit(current_drive, &fake_change) ||
2933 TESTF(FD_DISK_CHANGED)) {
2934 DPRINT("disk absent or changed during operation\n");
2935 REPEAT;
2936 }
2937 if (!_floppy) { /* Autodetection */
2938 if (!probing) {
2939 DRS->probed_format = 0;
2940 if (next_valid_format()) {
2941 DPRINT("no autodetectable formats\n");
2942 _floppy = NULL;
2943 REPEAT;
2944 }
2945 }
2946 probing = 1;
2947 _floppy =
2948 floppy_type + DP->autodetect[DRS->probed_format];
2949 } else
2950 probing = 0;
2951 errors = &(current_req->errors);
2952 tmp = make_raw_rw_request();
2953 if (tmp < 2) {
2954 request_done(tmp);
2955 continue;
2956 }
2957
2958 if (TESTF(FD_NEED_TWADDLE))
2959 twaddle();
2960 schedule_bh(floppy_start);
2961 debugt("queue fd request");
2962 return;
2963 }
2964#undef REPEAT
2965}
2966
2967static struct cont_t rw_cont = {
2968 .interrupt = rw_interrupt,
2969 .redo = redo_fd_request,
2970 .error = bad_flp_intr,
2971 .done = request_done
2972};
2973
2974static void process_fd_request(void)
2975{
2976 cont = &rw_cont;
2977 schedule_bh(redo_fd_request);
2978}
2979
Jens Axboe165125e2007-07-24 09:28:11 +02002980static void do_fd_request(struct request_queue * q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981{
2982 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002983 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 return;
2985 }
2986
2987 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002988 pr_info("warning: usage count=0, current_req=%p exiting\n",
2989 current_req);
2990 pr_info("sect=%ld type=%x flags=%x\n",
2991 (long)blk_rq_pos(current_req), current_req->cmd_type,
2992 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 return;
2994 }
2995 if (test_bit(0, &fdc_busy)) {
2996 /* fdc busy, this new request will be treated when the
2997 current one is done */
2998 is_alive("do fd request, old request running");
2999 return;
3000 }
3001 lock_fdc(MAXTIMEOUT, 0);
3002 process_fd_request();
3003 is_alive("do fd request");
3004}
3005
3006static struct cont_t poll_cont = {
3007 .interrupt = success_and_wakeup,
3008 .redo = floppy_ready,
3009 .error = generic_failure,
3010 .done = generic_done
3011};
3012
3013static int poll_drive(int interruptible, int flag)
3014{
3015 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003016
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 /* no auto-sense, just clear dcl */
3018 raw_cmd = &default_raw_cmd;
3019 raw_cmd->flags = flag;
3020 raw_cmd->track = 0;
3021 raw_cmd->cmd_count = 0;
3022 cont = &poll_cont;
3023#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003024 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 DPRINT("setting NEWCHANGE in poll_drive\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026#endif
3027 SETF(FD_DISK_NEWCHANGE);
3028 WAIT(floppy_ready);
3029 return ret;
3030}
3031
3032/*
3033 * User triggered reset
3034 * ====================
3035 */
3036
3037static void reset_intr(void)
3038{
Joe Perchesb46df352010-03-10 15:20:46 -08003039 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040}
3041
3042static struct cont_t reset_cont = {
3043 .interrupt = reset_intr,
3044 .redo = success_and_wakeup,
3045 .error = generic_failure,
3046 .done = generic_done
3047};
3048
3049static int user_reset_fdc(int drive, int arg, int interruptible)
3050{
3051 int ret;
3052
3053 ret = 0;
3054 LOCK_FDC(drive, interruptible);
3055 if (arg == FD_RESET_ALWAYS)
3056 FDCS->reset = 1;
3057 if (FDCS->reset) {
3058 cont = &reset_cont;
3059 WAIT(reset_fdc);
3060 }
3061 process_fd_request();
3062 return ret;
3063}
3064
3065/*
3066 * Misc Ioctl's and support
3067 * ========================
3068 */
3069static inline int fd_copyout(void __user *param, const void *address,
3070 unsigned long size)
3071{
3072 return copy_to_user(param, address, size) ? -EFAULT : 0;
3073}
3074
Joe Perches48c8cee2010-03-10 15:20:45 -08003075static inline int fd_copyin(void __user *param, void *address,
3076 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077{
3078 return copy_from_user(address, param, size) ? -EFAULT : 0;
3079}
3080
Joe Perches48c8cee2010-03-10 15:20:45 -08003081#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3082 ? -EFAULT : 0)
3083#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3084 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
Joe Perches48c8cee2010-03-10 15:20:45 -08003086#define COPYOUT(x) ECALL(_COPYOUT(x))
3087#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
3089static inline const char *drive_name(int type, int drive)
3090{
3091 struct floppy_struct *floppy;
3092
3093 if (type)
3094 floppy = floppy_type + type;
3095 else {
3096 if (UDP->native_format)
3097 floppy = floppy_type + UDP->native_format;
3098 else
3099 return "(null)";
3100 }
3101 if (floppy->name)
3102 return floppy->name;
3103 else
3104 return "(null)";
3105}
3106
3107/* raw commands */
3108static void raw_cmd_done(int flag)
3109{
3110 int i;
3111
3112 if (!flag) {
3113 raw_cmd->flags |= FD_RAW_FAILURE;
3114 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3115 } else {
3116 raw_cmd->reply_count = inr;
3117 if (raw_cmd->reply_count > MAX_REPLIES)
3118 raw_cmd->reply_count = 0;
3119 for (i = 0; i < raw_cmd->reply_count; i++)
3120 raw_cmd->reply[i] = reply_buffer[i];
3121
3122 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3123 unsigned long flags;
3124 flags = claim_dma_lock();
3125 raw_cmd->length = fd_get_dma_residue();
3126 release_dma_lock(flags);
3127 }
3128
3129 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3130 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3131 raw_cmd->flags |= FD_RAW_FAILURE;
3132
3133 if (disk_change(current_drive))
3134 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3135 else
3136 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3137 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3138 motor_off_callback(current_drive);
3139
3140 if (raw_cmd->next &&
3141 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3142 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3143 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3144 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3145 raw_cmd = raw_cmd->next;
3146 return;
3147 }
3148 }
3149 generic_done(flag);
3150}
3151
3152static struct cont_t raw_cmd_cont = {
3153 .interrupt = success_and_wakeup,
3154 .redo = floppy_start,
3155 .error = generic_failure,
3156 .done = raw_cmd_done
3157};
3158
3159static inline int raw_cmd_copyout(int cmd, char __user *param,
3160 struct floppy_raw_cmd *ptr)
3161{
3162 int ret;
3163
3164 while (ptr) {
3165 COPYOUT(*ptr);
3166 param += sizeof(struct floppy_raw_cmd);
3167 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
3168 if (ptr->length >= 0
3169 && ptr->length <= ptr->buffer_length)
3170 ECALL(fd_copyout
3171 (ptr->data, ptr->kernel_data,
3172 ptr->buffer_length - ptr->length));
3173 }
3174 ptr = ptr->next;
3175 }
3176 return 0;
3177}
3178
3179static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3180{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003181 struct floppy_raw_cmd *next;
3182 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
3184 this = *ptr;
3185 *ptr = NULL;
3186 while (this) {
3187 if (this->buffer_length) {
3188 fd_dma_mem_free((unsigned long)this->kernel_data,
3189 this->buffer_length);
3190 this->buffer_length = 0;
3191 }
3192 next = this->next;
3193 kfree(this);
3194 this = next;
3195 }
3196}
3197
3198static inline int raw_cmd_copyin(int cmd, char __user *param,
3199 struct floppy_raw_cmd **rcmd)
3200{
3201 struct floppy_raw_cmd *ptr;
3202 int ret;
3203 int i;
3204
3205 *rcmd = NULL;
3206 while (1) {
3207 ptr = (struct floppy_raw_cmd *)
3208 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3209 if (!ptr)
3210 return -ENOMEM;
3211 *rcmd = ptr;
3212 COPYIN(*ptr);
3213 ptr->next = NULL;
3214 ptr->buffer_length = 0;
3215 param += sizeof(struct floppy_raw_cmd);
3216 if (ptr->cmd_count > 33)
3217 /* the command may now also take up the space
3218 * initially intended for the reply & the
3219 * reply count. Needed for long 82078 commands
3220 * such as RESTORE, which takes ... 17 command
3221 * bytes. Murphy's law #137: When you reserve
3222 * 16 bytes for a structure, you'll one day
3223 * discover that you really need 17...
3224 */
3225 return -EINVAL;
3226
3227 for (i = 0; i < 16; i++)
3228 ptr->reply[i] = 0;
3229 ptr->resultcode = 0;
3230 ptr->kernel_data = NULL;
3231
3232 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3233 if (ptr->length <= 0)
3234 return -EINVAL;
3235 ptr->kernel_data =
3236 (char *)fd_dma_mem_alloc(ptr->length);
3237 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3238 if (!ptr->kernel_data)
3239 return -ENOMEM;
3240 ptr->buffer_length = ptr->length;
3241 }
3242 if (ptr->flags & FD_RAW_WRITE)
3243 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3244 ptr->length));
3245 rcmd = &(ptr->next);
3246 if (!(ptr->flags & FD_RAW_MORE))
3247 return 0;
3248 ptr->rate &= 0x43;
3249 }
3250}
3251
3252static int raw_cmd_ioctl(int cmd, void __user *param)
3253{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003255 int drive;
3256 int ret2;
3257 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
3259 if (FDCS->rawcmd <= 1)
3260 FDCS->rawcmd = 1;
3261 for (drive = 0; drive < N_DRIVE; drive++) {
3262 if (FDC(drive) != fdc)
3263 continue;
3264 if (drive == current_drive) {
3265 if (UDRS->fd_ref > 1) {
3266 FDCS->rawcmd = 2;
3267 break;
3268 }
3269 } else if (UDRS->fd_ref) {
3270 FDCS->rawcmd = 2;
3271 break;
3272 }
3273 }
3274
3275 if (FDCS->reset)
3276 return -EIO;
3277
3278 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3279 if (ret) {
3280 raw_cmd_free(&my_raw_cmd);
3281 return ret;
3282 }
3283
3284 raw_cmd = my_raw_cmd;
3285 cont = &raw_cmd_cont;
3286 ret = wait_til_done(floppy_start, 1);
3287#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003288 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 DPRINT("calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290#endif
3291
3292 if (ret != -EINTR && FDCS->reset)
3293 ret = -EIO;
3294
3295 DRS->track = NO_TRACK;
3296
3297 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3298 if (!ret)
3299 ret = ret2;
3300 raw_cmd_free(&my_raw_cmd);
3301 return ret;
3302}
3303
3304static int invalidate_drive(struct block_device *bdev)
3305{
3306 /* invalidate the buffer track to force a reread */
3307 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3308 process_fd_request();
3309 check_disk_change(bdev);
3310 return 0;
3311}
3312
3313static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3314 int drive, int type, struct block_device *bdev)
3315{
3316 int cnt;
3317
3318 /* sanity checking for parameters. */
3319 if (g->sect <= 0 ||
3320 g->head <= 0 ||
3321 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3322 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003323 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 return -EINVAL;
3325 if (type) {
3326 if (!capable(CAP_SYS_ADMIN))
3327 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003328 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003329 if (lock_fdc(drive, 1)) {
3330 mutex_unlock(&open_lock);
3331 return -EINTR;
3332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 floppy_type[type] = *g;
3334 floppy_type[type].name = "user format";
3335 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3336 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3337 floppy_type[type].size + 1;
3338 process_fd_request();
3339 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3340 struct block_device *bdev = opened_bdev[cnt];
3341 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3342 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003343 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003345 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 } else {
3347 int oldStretch;
3348 LOCK_FDC(drive, 1);
3349 if (cmd != FDDEFPRM)
3350 /* notice a disk change immediately, else
3351 * we lose our settings immediately*/
3352 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3353 oldStretch = g->stretch;
3354 user_params[drive] = *g;
3355 if (buffer_drive == drive)
3356 SUPBOUND(buffer_max, user_params[drive].sect);
3357 current_type[drive] = &user_params[drive];
3358 floppy_sizes[drive] = user_params[drive].size;
3359 if (cmd == FDDEFPRM)
3360 DRS->keep_data = -1;
3361 else
3362 DRS->keep_data = 1;
3363 /* invalidation. Invalidate only when needed, i.e.
3364 * when there are already sectors in the buffer cache
3365 * whose number will change. This is useful, because
3366 * mtools often changes the geometry of the disk after
3367 * looking at the boot block */
3368 if (DRS->maxblock > user_params[drive].sect ||
3369 DRS->maxtrack ||
3370 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003371 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 invalidate_drive(bdev);
3373 else
3374 process_fd_request();
3375 }
3376 return 0;
3377}
3378
3379/* handle obsolete ioctl's */
3380static int ioctl_table[] = {
3381 FDCLRPRM,
3382 FDSETPRM,
3383 FDDEFPRM,
3384 FDGETPRM,
3385 FDMSGON,
3386 FDMSGOFF,
3387 FDFMTBEG,
3388 FDFMTTRK,
3389 FDFMTEND,
3390 FDSETEMSGTRESH,
3391 FDFLUSH,
3392 FDSETMAXERRS,
3393 FDGETMAXERRS,
3394 FDGETDRVTYP,
3395 FDSETDRVPRM,
3396 FDGETDRVPRM,
3397 FDGETDRVSTAT,
3398 FDPOLLDRVSTAT,
3399 FDRESET,
3400 FDGETFDCSTAT,
3401 FDWERRORCLR,
3402 FDWERRORGET,
3403 FDRAWCMD,
3404 FDEJECT,
3405 FDTWADDLE
3406};
3407
3408static inline int normalize_ioctl(int *cmd, int *size)
3409{
3410 int i;
3411
3412 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3413 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3414 *size = _IOC_SIZE(*cmd);
3415 *cmd = ioctl_table[i];
3416 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003417 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 return -EFAULT;
3419 }
3420 return 0;
3421 }
3422 }
3423 return -EINVAL;
3424}
3425
3426static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3427{
3428 if (type)
3429 *g = &floppy_type[type];
3430 else {
3431 LOCK_FDC(drive, 0);
3432 CALL(poll_drive(0, 0));
3433 process_fd_request();
3434 *g = current_type[drive];
3435 }
3436 if (!*g)
3437 return -ENODEV;
3438 return 0;
3439}
3440
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003441static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3442{
3443 int drive = (long)bdev->bd_disk->private_data;
3444 int type = ITYPE(drive_state[drive].fd_device);
3445 struct floppy_struct *g;
3446 int ret;
3447
3448 ret = get_floppy_geometry(drive, type, &g);
3449 if (ret)
3450 return ret;
3451
3452 geo->heads = g->head;
3453 geo->sectors = g->sect;
3454 geo->cylinders = g->track;
3455 return 0;
3456}
3457
Al Viroa4af9b42008-03-02 09:27:55 -05003458static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 unsigned long param)
3460{
Al Viroa4af9b42008-03-02 09:27:55 -05003461#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462#define OUT(c,x) case c: outparam = (const char *) (x); break
3463#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
3464
Al Viroa4af9b42008-03-02 09:27:55 -05003465 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003466 int type = ITYPE(UDRS->fd_device);
3467 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 int ret;
3469 int size;
3470 union inparam {
3471 struct floppy_struct g; /* geometry */
3472 struct format_descr f;
3473 struct floppy_max_errors max_errors;
3474 struct floppy_drive_params dp;
3475 } inparam; /* parameters coming from user space */
3476 const char *outparam; /* parameters passed back to user space */
3477
3478 /* convert compatibility eject ioctls into floppy eject ioctl.
3479 * We do this in order to provide a means to eject floppy disks before
3480 * installing the new fdutils package */
3481 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003482 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 DPRINT("obsolete eject ioctl\n");
3484 DPRINT("please use floppycontrol --eject\n");
3485 cmd = FDEJECT;
3486 }
3487
Joe Perchesa81ee542010-03-10 15:20:46 -08003488 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 return -EINVAL;
3490
Joe Perchesa81ee542010-03-10 15:20:46 -08003491 /* convert the old style command into a new style command */
3492 ECALL(normalize_ioctl(&cmd, &size));
3493
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 /* permission checks */
3495 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3496 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3497 return -EPERM;
3498
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003499 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3500 return -EINVAL;
3501
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 /* copyin */
3503 CLEARSTRUCT(&inparam);
3504 if (_IOC_DIR(cmd) & _IOC_WRITE)
3505 ECALL(fd_copyin((void __user *)param, &inparam, size))
3506
3507 switch (cmd) {
3508 case FDEJECT:
3509 if (UDRS->fd_ref != 1)
3510 /* somebody else has this drive open */
3511 return -EBUSY;
3512 LOCK_FDC(drive, 1);
3513
3514 /* do the actual eject. Fails on
3515 * non-Sparc architectures */
3516 ret = fd_eject(UNIT(drive));
3517
3518 USETF(FD_DISK_CHANGED);
3519 USETF(FD_VERIFY);
3520 process_fd_request();
3521 return ret;
3522 case FDCLRPRM:
3523 LOCK_FDC(drive, 1);
3524 current_type[drive] = NULL;
3525 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3526 UDRS->keep_data = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003527 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 case FDSETPRM:
3529 case FDDEFPRM:
3530 return set_geometry(cmd, &inparam.g,
Al Viroa4af9b42008-03-02 09:27:55 -05003531 drive, type, bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 case FDGETPRM:
3533 ECALL(get_floppy_geometry(drive, type,
3534 (struct floppy_struct **)
3535 &outparam));
3536 break;
3537
3538 case FDMSGON:
3539 UDP->flags |= FTD_MSG;
3540 return 0;
3541 case FDMSGOFF:
3542 UDP->flags &= ~FTD_MSG;
3543 return 0;
3544
3545 case FDFMTBEG:
3546 LOCK_FDC(drive, 1);
3547 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3548 ret = UDRS->flags;
3549 process_fd_request();
3550 if (ret & FD_VERIFY)
3551 return -ENODEV;
3552 if (!(ret & FD_DISK_WRITABLE))
3553 return -EROFS;
3554 return 0;
3555 case FDFMTTRK:
3556 if (UDRS->fd_ref != 1)
3557 return -EBUSY;
3558 return do_format(drive, &inparam.f);
3559 case FDFMTEND:
3560 case FDFLUSH:
3561 LOCK_FDC(drive, 1);
Al Viroa4af9b42008-03-02 09:27:55 -05003562 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
3564 case FDSETEMSGTRESH:
3565 UDP->max_errors.reporting =
3566 (unsigned short)(param & 0x0f);
3567 return 0;
3568 OUT(FDGETMAXERRS, &UDP->max_errors);
3569 IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
3570
3571 case FDGETDRVTYP:
3572 outparam = drive_name(type, drive);
3573 SUPBOUND(size, strlen(outparam) + 1);
3574 break;
3575
3576 IN(FDSETDRVPRM, UDP, dp);
3577 OUT(FDGETDRVPRM, UDP);
3578
3579 case FDPOLLDRVSTAT:
3580 LOCK_FDC(drive, 1);
3581 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3582 process_fd_request();
3583 /* fall through */
3584 OUT(FDGETDRVSTAT, UDRS);
3585
3586 case FDRESET:
3587 return user_reset_fdc(drive, (int)param, 1);
3588
3589 OUT(FDGETFDCSTAT, UFDCS);
3590
3591 case FDWERRORCLR:
3592 CLEARSTRUCT(UDRWE);
3593 return 0;
3594 OUT(FDWERRORGET, UDRWE);
3595
3596 case FDRAWCMD:
3597 if (type)
3598 return -EINVAL;
3599 LOCK_FDC(drive, 1);
3600 set_floppy(drive);
3601 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3602 process_fd_request();
3603 return i;
3604
3605 case FDTWADDLE:
3606 LOCK_FDC(drive, 1);
3607 twaddle();
3608 process_fd_request();
3609 return 0;
3610
3611 default:
3612 return -EINVAL;
3613 }
3614
3615 if (_IOC_DIR(cmd) & _IOC_READ)
3616 return fd_copyout((void __user *)param, outparam, size);
3617 else
3618 return 0;
3619#undef OUT
3620#undef IN
3621}
3622
3623static void __init config_types(void)
3624{
Joe Perchesb46df352010-03-10 15:20:46 -08003625 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 int drive;
3627
3628 /* read drive info out of physical CMOS */
3629 drive = 0;
3630 if (!UDP->cmos)
3631 UDP->cmos = FLOPPY0_TYPE;
3632 drive = 1;
3633 if (!UDP->cmos && FLOPPY1_TYPE)
3634 UDP->cmos = FLOPPY1_TYPE;
3635
Jesper Juhl06f748c2007-10-16 23:30:57 -07003636 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637
3638 for (drive = 0; drive < N_DRIVE; drive++) {
3639 unsigned int type = UDP->cmos;
3640 struct floppy_drive_params *params;
3641 const char *name = NULL;
3642 static char temparea[32];
3643
Tobias Klauser945f3902006-01-08 01:05:11 -08003644 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 params = &default_drive_params[type].params;
3646 if (type) {
3647 name = default_drive_params[type].name;
3648 allowed_drive_mask |= 1 << drive;
3649 } else
3650 allowed_drive_mask &= ~(1 << drive);
3651 } else {
3652 params = &default_drive_params[0].params;
3653 sprintf(temparea, "unknown type %d (usb?)", type);
3654 name = temparea;
3655 }
3656 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003657 const char *prepend;
3658 if (!has_drive) {
3659 prepend = "";
3660 has_drive = true;
3661 pr_info("Floppy drive(s):");
3662 } else {
3663 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 }
Joe Perchesb46df352010-03-10 15:20:46 -08003665
3666 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 }
3668 *UDP = *params;
3669 }
Joe Perchesb46df352010-03-10 15:20:46 -08003670
3671 if (has_drive)
3672 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673}
3674
Al Viroa4af9b42008-03-02 09:27:55 -05003675static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676{
Al Viroa4af9b42008-03-02 09:27:55 -05003677 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003679 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 if (UDRS->fd_ref < 0)
3681 UDRS->fd_ref = 0;
3682 else if (!UDRS->fd_ref--) {
3683 DPRINT("floppy_release with fd_ref == 0");
3684 UDRS->fd_ref = 0;
3685 }
3686 if (!UDRS->fd_ref)
3687 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003688 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003689
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 return 0;
3691}
3692
3693/*
3694 * floppy_open check for aliasing (/dev/fd0 can be the same as
3695 * /dev/PS0 etc), and disallows simultaneous access to the same
3696 * drive with different device numbers.
3697 */
Al Viroa4af9b42008-03-02 09:27:55 -05003698static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699{
Al Viroa4af9b42008-03-02 09:27:55 -05003700 int drive = (long)bdev->bd_disk->private_data;
3701 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 int try;
3703 int res = -EBUSY;
3704 char *tmp;
3705
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003706 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003708 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 goto out2;
3710
3711 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3712 USETF(FD_DISK_CHANGED);
3713 USETF(FD_VERIFY);
3714 }
3715
Al Viroa4af9b42008-03-02 09:27:55 -05003716 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 goto out2;
3718
Al Viroa4af9b42008-03-02 09:27:55 -05003719 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 UDRS->fd_ref = -1;
3721 else
3722 UDRS->fd_ref++;
3723
Al Viroa4af9b42008-03-02 09:27:55 -05003724 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725
3726 res = -ENXIO;
3727
3728 if (!floppy_track_buffer) {
3729 /* if opening an ED drive, reserve a big buffer,
3730 * else reserve a small one */
3731 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3732 try = 64; /* Only 48 actually useful */
3733 else
3734 try = 32; /* Only 24 actually useful */
3735
3736 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3737 if (!tmp && !floppy_track_buffer) {
3738 try >>= 1; /* buffer only one side */
3739 INFBOUND(try, 16);
3740 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3741 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003742 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 if (!tmp && !floppy_track_buffer) {
3745 DPRINT("Unable to allocate DMA memory\n");
3746 goto out;
3747 }
3748 if (floppy_track_buffer) {
3749 if (tmp)
3750 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3751 } else {
3752 buffer_min = buffer_max = -1;
3753 floppy_track_buffer = tmp;
3754 max_buffer_sectors = try;
3755 }
3756 }
3757
Al Viroa4af9b42008-03-02 09:27:55 -05003758 new_dev = MINOR(bdev->bd_dev);
3759 UDRS->fd_device = new_dev;
3760 set_capacity(disks[drive], floppy_sizes[new_dev]);
3761 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 if (buffer_drive == drive)
3763 buffer_track = -1;
3764 }
3765
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 if (UFDCS->rawcmd == 1)
3767 UFDCS->rawcmd = 2;
3768
Al Viroa4af9b42008-03-02 09:27:55 -05003769 if (!(mode & FMODE_NDELAY)) {
3770 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003772 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 if (UTESTF(FD_DISK_CHANGED))
3774 goto out;
3775 }
3776 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003777 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 goto out;
3779 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003780 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 return 0;
3782out:
3783 if (UDRS->fd_ref < 0)
3784 UDRS->fd_ref = 0;
3785 else
3786 UDRS->fd_ref--;
3787 if (!UDRS->fd_ref)
3788 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003790 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 return res;
3792}
3793
3794/*
3795 * Check if the disk has been changed or if a change has been faked.
3796 */
3797static int check_floppy_change(struct gendisk *disk)
3798{
3799 int drive = (long)disk->private_data;
3800
3801 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3802 return 1;
3803
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003804 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 lock_fdc(drive, 0);
3806 poll_drive(0, 0);
3807 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 }
3809
3810 if (UTESTF(FD_DISK_CHANGED) ||
3811 UTESTF(FD_VERIFY) ||
3812 test_bit(drive, &fake_change) ||
3813 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3814 return 1;
3815 return 0;
3816}
3817
3818/*
3819 * This implements "read block 0" for floppy_revalidate().
3820 * Needed for format autodetection, checking whether there is
3821 * a disk in the drive, and whether that disk is writable.
3822 */
3823
NeilBrown6712ecf2007-09-27 12:47:43 +02003824static void floppy_rb0_complete(struct bio *bio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 int err)
3826{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828}
3829
3830static int __floppy_read_block_0(struct block_device *bdev)
3831{
3832 struct bio bio;
3833 struct bio_vec bio_vec;
3834 struct completion complete;
3835 struct page *page;
3836 size_t size;
3837
3838 page = alloc_page(GFP_NOIO);
3839 if (!page) {
3840 process_fd_request();
3841 return -ENOMEM;
3842 }
3843
3844 size = bdev->bd_block_size;
3845 if (!size)
3846 size = 1024;
3847
3848 bio_init(&bio);
3849 bio.bi_io_vec = &bio_vec;
3850 bio_vec.bv_page = page;
3851 bio_vec.bv_len = size;
3852 bio_vec.bv_offset = 0;
3853 bio.bi_vcnt = 1;
3854 bio.bi_idx = 0;
3855 bio.bi_size = size;
3856 bio.bi_bdev = bdev;
3857 bio.bi_sector = 0;
3858 init_completion(&complete);
3859 bio.bi_private = &complete;
3860 bio.bi_end_io = floppy_rb0_complete;
3861
3862 submit_bio(READ, &bio);
3863 generic_unplug_device(bdev_get_queue(bdev));
3864 process_fd_request();
3865 wait_for_completion(&complete);
3866
3867 __free_page(page);
3868
3869 return 0;
3870}
3871
3872/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3873 * the bootblock (block 0). "Autodetection" is also needed to check whether
3874 * there is a disk in the drive at all... Thus we also do it for fixed
3875 * geometry formats */
3876static int floppy_revalidate(struct gendisk *disk)
3877{
3878 int drive = (long)disk->private_data;
3879#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3880 int cf;
3881 int res = 0;
3882
3883 if (UTESTF(FD_DISK_CHANGED) ||
3884 UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
3885 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003886 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 return -EFAULT;
3888 }
3889 lock_fdc(drive, 0);
3890 cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
3891 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3892 process_fd_request(); /*already done by another thread */
3893 return 0;
3894 }
3895 UDRS->maxblock = 0;
3896 UDRS->maxtrack = 0;
3897 if (buffer_drive == drive)
3898 buffer_track = -1;
3899 clear_bit(drive, &fake_change);
3900 UCLEARF(FD_DISK_CHANGED);
3901 if (cf)
3902 UDRS->generation++;
3903 if (NO_GEOM) {
3904 /* auto-sensing */
3905 res = __floppy_read_block_0(opened_bdev[drive]);
3906 } else {
3907 if (cf)
3908 poll_drive(0, FD_RAW_NEED_DISK);
3909 process_fd_request();
3910 }
3911 }
3912 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3913 return res;
3914}
3915
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003916static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003917 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003918 .open = floppy_open,
3919 .release = floppy_release,
3920 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003921 .getgeo = fd_getgeo,
3922 .media_changed = check_floppy_change,
3923 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926/*
3927 * Floppy Driver initialization
3928 * =============================
3929 */
3930
3931/* Determine the floppy disk controller type */
3932/* This routine was written by David C. Niemi */
3933static char __init get_fdc_version(void)
3934{
3935 int r;
3936
3937 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3938 if (FDCS->reset)
3939 return FDC_NONE;
3940 if ((r = result()) <= 0x00)
3941 return FDC_NONE; /* No FDC present ??? */
3942 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003943 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3945 }
3946 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003947 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3948 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 return FDC_UNKNOWN;
3950 }
3951
3952 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003953 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3955 }
3956
3957 output_byte(FD_PERPENDICULAR);
3958 if (need_more_output() == MORE_OUTPUT) {
3959 output_byte(0);
3960 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003961 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 return FDC_82072A; /* 82072A as found on Sparcs. */
3963 }
3964
3965 output_byte(FD_UNLOCK);
3966 r = result();
3967 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003968 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
3970 * LOCK/UNLOCK */
3971 }
3972 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003973 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3974 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 return FDC_UNKNOWN;
3976 }
3977 output_byte(FD_PARTID);
3978 r = result();
3979 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003980 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3981 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 return FDC_UNKNOWN;
3983 }
3984 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003985 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 return FDC_82077; /* Revised 82077AA passes all the tests */
3987 }
3988 switch (reply_buffer[0] >> 5) {
3989 case 0x0:
3990 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003991 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 return FDC_82078;
3993 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003994 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 return FDC_82078;
3996 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003997 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 return FDC_S82078B;
3999 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004000 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 return FDC_87306;
4002 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004003 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4004 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 return FDC_82078_UNKN;
4006 }
4007} /* get_fdc_version */
4008
4009/* lilo configuration */
4010
4011static void __init floppy_set_flags(int *ints, int param, int param2)
4012{
4013 int i;
4014
4015 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4016 if (param)
4017 default_drive_params[i].params.flags |= param2;
4018 else
4019 default_drive_params[i].params.flags &= ~param2;
4020 }
4021 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4022}
4023
4024static void __init daring(int *ints, int param, int param2)
4025{
4026 int i;
4027
4028 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4029 if (param) {
4030 default_drive_params[i].params.select_delay = 0;
4031 default_drive_params[i].params.flags |=
4032 FD_SILENT_DCL_CLEAR;
4033 } else {
4034 default_drive_params[i].params.select_delay =
4035 2 * HZ / 100;
4036 default_drive_params[i].params.flags &=
4037 ~FD_SILENT_DCL_CLEAR;
4038 }
4039 }
4040 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4041}
4042
4043static void __init set_cmos(int *ints, int dummy, int dummy2)
4044{
4045 int current_drive = 0;
4046
4047 if (ints[0] != 2) {
4048 DPRINT("wrong number of parameters for CMOS\n");
4049 return;
4050 }
4051 current_drive = ints[1];
4052 if (current_drive < 0 || current_drive >= 8) {
4053 DPRINT("bad drive for set_cmos\n");
4054 return;
4055 }
4056#if N_FDC > 1
4057 if (current_drive >= 4 && !FDC2)
4058 FDC2 = 0x370;
4059#endif
4060 DP->cmos = ints[2];
4061 DPRINT("setting CMOS code to %d\n", ints[2]);
4062}
4063
4064static struct param_table {
4065 const char *name;
4066 void (*fn) (int *ints, int param, int param2);
4067 int *var;
4068 int def_param;
4069 int param2;
4070} config_params[] __initdata = {
4071 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4072 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4073 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4074 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4075 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4076 {"daring", daring, NULL, 1, 0},
4077#if N_FDC > 1
4078 {"two_fdc", NULL, &FDC2, 0x370, 0},
4079 {"one_fdc", NULL, &FDC2, 0, 0},
4080#endif
4081 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4082 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4083 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4084 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4085 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4086 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4087 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4088 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4089 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4090 {"nofifo", NULL, &no_fifo, 0x20, 0},
4091 {"usefifo", NULL, &no_fifo, 0, 0},
4092 {"cmos", set_cmos, NULL, 0, 0},
4093 {"slow", NULL, &slow_floppy, 1, 0},
4094 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4095 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4096 {"L40SX", NULL, &print_unex, 0, 0}
4097
4098 EXTRA_FLOPPY_PARAMS
4099};
4100
4101static int __init floppy_setup(char *str)
4102{
4103 int i;
4104 int param;
4105 int ints[11];
4106
4107 str = get_options(str, ARRAY_SIZE(ints), ints);
4108 if (str) {
4109 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4110 if (strcmp(str, config_params[i].name) == 0) {
4111 if (ints[0])
4112 param = ints[1];
4113 else
4114 param = config_params[i].def_param;
4115 if (config_params[i].fn)
4116 config_params[i].
4117 fn(ints, param,
4118 config_params[i].param2);
4119 if (config_params[i].var) {
4120 DPRINT("%s=%d\n", str, param);
4121 *config_params[i].var = param;
4122 }
4123 return 1;
4124 }
4125 }
4126 }
4127 if (str) {
4128 DPRINT("unknown floppy option [%s]\n", str);
4129
4130 DPRINT("allowed options are:");
4131 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004132 pr_cont(" %s", config_params[i].name);
4133 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 } else
4135 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004136 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 return 0;
4138}
4139
4140static int have_no_fdc = -ENODEV;
4141
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004142static ssize_t floppy_cmos_show(struct device *dev,
4143 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004144{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004145 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004146 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004147
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004148 drive = p->id;
4149 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004150}
Joe Perches48c8cee2010-03-10 15:20:45 -08004151
4152DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004153
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154static void floppy_device_release(struct device *dev)
4155{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156}
4157
Frans Popc90cd332009-07-25 22:24:54 +02004158static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004159{
4160 int fdc;
4161
4162 for (fdc = 0; fdc < N_FDC; fdc++)
4163 if (FDCS->address != -1)
4164 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4165
4166 return 0;
4167}
4168
Alexey Dobriyan47145212009-12-14 18:00:08 -08004169static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004170 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004171 .restore = floppy_resume,
4172};
4173
4174static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004175 .driver = {
4176 .name = "floppy",
Frans Popc90cd332009-07-25 22:24:54 +02004177 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004178 },
4179};
4180
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004181static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
4183static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4184{
4185 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4186 if (drive >= N_DRIVE ||
4187 !(allowed_drive_mask & (1 << drive)) ||
4188 fdc_state[FDC(drive)].version == FDC_NONE)
4189 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004190 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 return NULL;
4192 *part = 0;
4193 return get_disk(disks[drive]);
4194}
4195
4196static int __init floppy_init(void)
4197{
4198 int i, unit, drive;
4199 int err, dr;
4200
Kumar Gala68e1ee62008-09-22 14:41:31 -07004201#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004202 if (check_legacy_ioport(FDC1))
4203 return -ENODEV;
4204#endif
4205
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 raw_cmd = NULL;
4207
4208 for (dr = 0; dr < N_DRIVE; dr++) {
4209 disks[dr] = alloc_disk(1);
4210 if (!disks[dr]) {
4211 err = -ENOMEM;
4212 goto out_put_disk;
4213 }
4214
4215 disks[dr]->major = FLOPPY_MAJOR;
4216 disks[dr]->first_minor = TOMINOR(dr);
4217 disks[dr]->fops = &floppy_fops;
4218 sprintf(disks[dr]->disk_name, "fd%d", dr);
4219
4220 init_timer(&motor_off_timer[dr]);
4221 motor_off_timer[dr].data = dr;
4222 motor_off_timer[dr].function = motor_off_callback;
4223 }
4224
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 err = register_blkdev(FLOPPY_MAJOR, "fd");
4226 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004227 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004229 err = platform_driver_register(&floppy_driver);
4230 if (err)
4231 goto out_unreg_blkdev;
4232
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4234 if (!floppy_queue) {
4235 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004236 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004238 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239
4240 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4241 floppy_find, NULL, NULL);
4242
4243 for (i = 0; i < 256; i++)
4244 if (ITYPE(i))
4245 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4246 else
4247 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4248
4249 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4250 config_types();
4251
4252 for (i = 0; i < N_FDC; i++) {
4253 fdc = i;
4254 CLEARSTRUCT(FDCS);
4255 FDCS->dtr = -1;
4256 FDCS->dor = 0x4;
4257#if defined(__sparc__) || defined(__mc68000__)
4258 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
4259#ifdef __mc68000__
4260 if (MACH_IS_SUN3X)
4261#endif
4262 FDCS->version = FDC_82072A;
4263#endif
4264 }
4265
4266 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 fdc_state[0].address = FDC1;
4268 if (fdc_state[0].address == -1) {
4269 del_timer(&fd_timeout);
4270 err = -ENODEV;
4271 goto out_unreg_region;
4272 }
4273#if N_FDC > 1
4274 fdc_state[1].address = FDC2;
4275#endif
4276
4277 fdc = 0; /* reset fdc in case of unexpected interrupt */
4278 err = floppy_grab_irq_and_dma();
4279 if (err) {
4280 del_timer(&fd_timeout);
4281 err = -EBUSY;
4282 goto out_unreg_region;
4283 }
4284
4285 /* initialise drive state */
4286 for (drive = 0; drive < N_DRIVE; drive++) {
4287 CLEARSTRUCT(UDRS);
4288 CLEARSTRUCT(UDRWE);
4289 USETF(FD_DISK_NEWCHANGE);
4290 USETF(FD_DISK_CHANGED);
4291 USETF(FD_VERIFY);
4292 UDRS->fd_device = -1;
4293 floppy_track_buffer = NULL;
4294 max_buffer_sectors = 0;
4295 }
4296 /*
4297 * Small 10 msec delay to let through any interrupt that
4298 * initialization might have triggered, to not
4299 * confuse detection:
4300 */
4301 msleep(10);
4302
4303 for (i = 0; i < N_FDC; i++) {
4304 fdc = i;
4305 FDCS->driver_version = FD_DRIVER_VERSION;
4306 for (unit = 0; unit < 4; unit++)
4307 FDCS->track[unit] = 0;
4308 if (FDCS->address == -1)
4309 continue;
4310 FDCS->rawcmd = 2;
4311 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4312 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004313 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 FDCS->address = -1;
4315 FDCS->version = FDC_NONE;
4316 continue;
4317 }
4318 /* Try to determine the floppy controller type */
4319 FDCS->version = get_fdc_version();
4320 if (FDCS->version == FDC_NONE) {
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 continue;
4325 }
4326 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4327 can_use_virtual_dma = 0;
4328
4329 have_no_fdc = 0;
4330 /* Not all FDCs seem to be able to handle the version command
4331 * properly, so force a reset for the standard FDC clones,
4332 * to avoid interrupt garbage.
4333 */
4334 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4335 }
4336 fdc = 0;
4337 del_timer(&fd_timeout);
4338 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 initialising = 0;
4340 if (have_no_fdc) {
4341 DPRINT("no floppy controllers found\n");
4342 err = have_no_fdc;
4343 goto out_flush_work;
4344 }
4345
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 for (drive = 0; drive < N_DRIVE; drive++) {
4347 if (!(allowed_drive_mask & (1 << drive)))
4348 continue;
4349 if (fdc_state[FDC(drive)].version == FDC_NONE)
4350 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004351
4352 floppy_device[drive].name = floppy_device_name;
4353 floppy_device[drive].id = drive;
4354 floppy_device[drive].dev.release = floppy_device_release;
4355
4356 err = platform_device_register(&floppy_device[drive]);
4357 if (err)
4358 goto out_flush_work;
4359
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004360 err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
4361 if (err)
4362 goto out_unreg_platform_dev;
4363
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 /* to be cleaned up... */
4365 disks[drive]->private_data = (void *)(long)drive;
4366 disks[drive]->queue = floppy_queue;
4367 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004368 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 add_disk(disks[drive]);
4370 }
4371
4372 return 0;
4373
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004374out_unreg_platform_dev:
4375 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376out_flush_work:
4377 flush_scheduled_work();
4378 if (usage_count)
4379 floppy_release_irq_and_dma();
4380out_unreg_region:
4381 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4382 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004383out_unreg_driver:
4384 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385out_unreg_blkdev:
4386 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387out_put_disk:
4388 while (dr--) {
4389 del_timer(&motor_off_timer[dr]);
4390 put_disk(disks[dr]);
4391 }
4392 return err;
4393}
4394
4395static DEFINE_SPINLOCK(floppy_usage_lock);
4396
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004397static const struct io_region {
4398 int offset;
4399 int size;
4400} io_regions[] = {
4401 { 2, 1 },
4402 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4403 { 4, 2 },
4404 /* address + 6 is reserved, and may be taken by IDE.
4405 * Unfortunately, Adaptec doesn't know this :-(, */
4406 { 7, 1 },
4407};
4408
4409static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4410{
4411 while (p != io_regions) {
4412 p--;
4413 release_region(FDCS->address + p->offset, p->size);
4414 }
4415}
4416
4417#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4418
4419static int floppy_request_regions(int fdc)
4420{
4421 const struct io_region *p;
4422
4423 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
4424 if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
4425 DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
4426 floppy_release_allocated_regions(fdc, p);
4427 return -EBUSY;
4428 }
4429 }
4430 return 0;
4431}
4432
4433static void floppy_release_regions(int fdc)
4434{
4435 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4436}
4437
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438static int floppy_grab_irq_and_dma(void)
4439{
4440 unsigned long flags;
4441
4442 spin_lock_irqsave(&floppy_usage_lock, flags);
4443 if (usage_count++) {
4444 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4445 return 0;
4446 }
4447 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004448
4449 /*
4450 * We might have scheduled a free_irq(), wait it to
4451 * drain first:
4452 */
4453 flush_scheduled_work();
4454
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 if (fd_request_irq()) {
4456 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4457 FLOPPY_IRQ);
4458 spin_lock_irqsave(&floppy_usage_lock, flags);
4459 usage_count--;
4460 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4461 return -1;
4462 }
4463 if (fd_request_dma()) {
4464 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4465 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004466 if (can_use_virtual_dma & 2)
4467 use_virtual_dma = can_use_virtual_dma = 1;
4468 if (!(can_use_virtual_dma & 1)) {
4469 fd_free_irq();
4470 spin_lock_irqsave(&floppy_usage_lock, flags);
4471 usage_count--;
4472 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4473 return -1;
4474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 }
4476
4477 for (fdc = 0; fdc < N_FDC; fdc++) {
4478 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004479 if (floppy_request_regions(fdc))
4480 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 }
4482 }
4483 for (fdc = 0; fdc < N_FDC; fdc++) {
4484 if (FDCS->address != -1) {
4485 reset_fdc_info(1);
4486 fd_outb(FDCS->dor, FD_DOR);
4487 }
4488 }
4489 fdc = 0;
4490 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4491
4492 for (fdc = 0; fdc < N_FDC; fdc++)
4493 if (FDCS->address != -1)
4494 fd_outb(FDCS->dor, FD_DOR);
4495 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004496 * The driver will try and free resources and relies on us
4497 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 */
4499 fdc = 0;
4500 irqdma_allocated = 1;
4501 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004502cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 fd_free_irq();
4504 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004505 while (--fdc >= 0)
4506 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 spin_lock_irqsave(&floppy_usage_lock, flags);
4508 usage_count--;
4509 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4510 return -1;
4511}
4512
4513static void floppy_release_irq_and_dma(void)
4514{
4515 int old_fdc;
4516#ifdef FLOPPY_SANITY_CHECK
4517#ifndef __sparc__
4518 int drive;
4519#endif
4520#endif
4521 long tmpsize;
4522 unsigned long tmpaddr;
4523 unsigned long flags;
4524
4525 spin_lock_irqsave(&floppy_usage_lock, flags);
4526 if (--usage_count) {
4527 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4528 return;
4529 }
4530 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4531 if (irqdma_allocated) {
4532 fd_disable_dma();
4533 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004534 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 irqdma_allocated = 0;
4536 }
4537 set_dor(0, ~0, 8);
4538#if N_FDC > 1
4539 set_dor(1, ~8, 0);
4540#endif
4541 floppy_enable_hlt();
4542
4543 if (floppy_track_buffer && max_buffer_sectors) {
4544 tmpsize = max_buffer_sectors * 1024;
4545 tmpaddr = (unsigned long)floppy_track_buffer;
4546 floppy_track_buffer = NULL;
4547 max_buffer_sectors = 0;
4548 buffer_min = buffer_max = -1;
4549 fd_dma_mem_free(tmpaddr, tmpsize);
4550 }
4551#ifdef FLOPPY_SANITY_CHECK
4552#ifndef __sparc__
4553 for (drive = 0; drive < N_FDC * 4; drive++)
4554 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004555 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556#endif
4557
4558 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004559 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004561 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004562 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004563 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564#endif
4565 old_fdc = fdc;
4566 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004567 if (FDCS->address != -1)
4568 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 fdc = old_fdc;
4570}
4571
4572#ifdef MODULE
4573
4574static char *floppy;
4575
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576static void __init parse_floppy_cfg_string(char *cfg)
4577{
4578 char *ptr;
4579
4580 while (*cfg) {
4581 for (ptr = cfg; *cfg && *cfg != ' ' && *cfg != '\t'; cfg++) ;
4582 if (*cfg) {
4583 *cfg = '\0';
4584 cfg++;
4585 }
4586 if (*ptr)
4587 floppy_setup(ptr);
4588 }
4589}
4590
Jon Schindler7afea3b2008-04-29 00:59:21 -07004591static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592{
4593 if (floppy)
4594 parse_floppy_cfg_string(floppy);
4595 return floppy_init();
4596}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004597module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598
Jon Schindler7afea3b2008-04-29 00:59:21 -07004599static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600{
4601 int drive;
4602
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4604 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004605 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606
4607 for (drive = 0; drive < N_DRIVE; drive++) {
4608 del_timer_sync(&motor_off_timer[drive]);
4609
4610 if ((allowed_drive_mask & (1 << drive)) &&
4611 fdc_state[FDC(drive)].version != FDC_NONE) {
4612 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004613 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4614 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 }
4616 put_disk(disks[drive]);
4617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618
4619 del_timer_sync(&fd_timeout);
4620 del_timer_sync(&fd_timer);
4621 blk_cleanup_queue(floppy_queue);
4622
4623 if (usage_count)
4624 floppy_release_irq_and_dma();
4625
4626 /* eject disk, if any */
4627 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628}
Joe Perches48c8cee2010-03-10 15:20:45 -08004629
Jon Schindler7afea3b2008-04-29 00:59:21 -07004630module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631
4632module_param(floppy, charp, 0);
4633module_param(FLOPPY_IRQ, int, 0);
4634module_param(FLOPPY_DMA, int, 0);
4635MODULE_AUTHOR("Alain L. Knaff");
4636MODULE_SUPPORTED_DEVICE("fd");
4637MODULE_LICENSE("GPL");
4638
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004639/* This doesn't actually get used other than for module information */
4640static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004641 {"PNP0700", 0},
4642 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004643};
Joe Perches48c8cee2010-03-10 15:20:45 -08004644
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004645MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4646
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647#else
4648
4649__setup("floppy=", floppy_setup);
4650module_init(floppy_init)
4651#endif
4652
4653MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);