blob: 3072003d81ca5b2f5757187e1e20c5c4dd898076 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/block/floppy.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1993, 1994 Alain Knaff
6 * Copyright (C) 1998 Alan Cox
7 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009/*
10 * 02.12.91 - Changed to static variables to indicate need for reset
11 * and recalibrate. This makes some things easier (output_byte reset
12 * checking etc), and means less interrupt jumping in case of errors,
13 * so the code is hopefully easier to understand.
14 */
15
16/*
17 * This file is certainly a mess. I've tried my best to get it working,
18 * but I don't like programming floppies, and I have only one anyway.
19 * Urgel. I should check for more errors, and do more graceful error
20 * recovery. Seems there are problems with several drives. I've tried to
21 * correct them. No promises.
22 */
23
24/*
25 * As with hd.c, all routines within this file can (and will) be called
26 * by interrupts, so extreme caution is needed. A hardware interrupt
27 * handler may not sleep, or a kernel panic will happen. Thus I cannot
28 * call "floppy-on" directly, but have to set a special timer interrupt
29 * etc.
30 */
31
32/*
33 * 28.02.92 - made track-buffering routines, based on the routines written
34 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
35 */
36
37/*
38 * Automatic floppy-detection and formatting written by Werner Almesberger
39 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
40 * the floppy-change signal detection.
41 */
42
43/*
44 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
45 * FDC data overrun bug, added some preliminary stuff for vertical
46 * recording support.
47 *
48 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
49 *
50 * TODO: Errors are still not counted properly.
51 */
52
53/* 1992/9/20
54 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
55 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
56 * Christoph H. Hochst\"atter.
57 * I have fixed the shift values to the ones I always use. Maybe a new
58 * ioctl() should be created to be able to modify them.
59 * There is a bug in the driver that makes it impossible to format a
60 * floppy as the first thing after bootup.
61 */
62
63/*
64 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
65 * this helped the floppy driver as well. Much cleaner, and still seems to
66 * work.
67 */
68
69/* 1994/6/24 --bbroad-- added the floppy table entries and made
70 * minor modifications to allow 2.88 floppies to be run.
71 */
72
73/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
74 * disk types.
75 */
76
77/*
78 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
79 * format bug fixes, but unfortunately some new bugs too...
80 */
81
82/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
83 * errors to allow safe writing by specialized programs.
84 */
85
86/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
87 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
88 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
89 * drives are "upside-down").
90 */
91
92/*
93 * 1995/8/26 -- Andreas Busse -- added Mips support.
94 */
95
96/*
97 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
98 * features to asm/floppy.h.
99 */
100
101/*
James Nelsonb88b0982005-11-08 16:52:12 +0100102 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
103 */
104
105/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
107 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
108 * use of '0' for NULL.
109 */
110
111/*
112 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
113 * failures.
114 */
115
116/*
117 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
118 */
119
120/*
121 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
122 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
123 * being used to store jiffies, which are unsigned longs).
124 */
125
126/*
127 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
128 * - get rid of check_region
129 * - s/suser/capable/
130 */
131
132/*
133 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
134 * floppy controller (lingering task on list after module is gone... boom.)
135 */
136
137/*
138 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
139 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
140 * requires many non-obvious changes in arch dependent code.
141 */
142
143/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
144 * Better audit of register_blkdev.
145 */
146
147#define FLOPPY_SANITY_CHECK
148#undef FLOPPY_SILENT_DCL_CLEAR
149
150#define REALLY_SLOW_IO
151
152#define DEBUGT 2
Joe Perches48c8cee2010-03-10 15:20:45 -0800153#define DCL_DEBUG /* debug disk change line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155/* do print messages for unexpected interrupts */
156static int print_unex = 1;
157#include <linux/module.h>
158#include <linux/sched.h>
159#include <linux/fs.h>
160#include <linux/kernel.h>
161#include <linux/timer.h>
162#include <linux/workqueue.h>
163#define FDPATCHES
164#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165#include <linux/fd.h>
166#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167#include <linux/errno.h>
168#include <linux/slab.h>
169#include <linux/mm.h>
170#include <linux/bio.h>
171#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800172#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173#include <linux/fcntl.h>
174#include <linux/delay.h>
175#include <linux/mc146818rtc.h> /* CMOS defines */
176#include <linux/ioport.h>
177#include <linux/interrupt.h>
178#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100179#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700180#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800182#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800183#include <linux/io.h>
184#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186/*
187 * PS/2 floppies have much slower step rates than regular floppies.
188 * It's been recommended that take about 1/4 of the default speed
189 * in some more extreme cases.
190 */
191static int slow_floppy;
192
193#include <asm/dma.h>
194#include <asm/irq.h>
195#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197static int FLOPPY_IRQ = 6;
198static int FLOPPY_DMA = 2;
199static int can_use_virtual_dma = 2;
200/* =======
201 * can use virtual DMA:
202 * 0 = use of virtual DMA disallowed by config
203 * 1 = use of virtual DMA prescribed by config
204 * 2 = no virtual DMA preference configured. By default try hard DMA,
205 * but fall back on virtual DMA when not enough memory available
206 */
207
208static int use_virtual_dma;
209/* =======
210 * use virtual DMA
211 * 0 using hard DMA
212 * 1 using virtual DMA
213 * This variable is set to virtual when a DMA mem problem arises, and
214 * reset back in floppy_grab_irq_and_dma.
215 * It is not safe to reset it in other circumstances, because the floppy
216 * driver may have several buffers in use at once, and we do currently not
217 * record each buffers capabilities
218 */
219
220static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100223irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226#define K_64 0x10000 /* 64KB */
227
228/* the following is the mask of allowed drives. By default units 2 and
229 * 3 of both floppy controllers are disabled, because switching on the
230 * motor of these drives causes system hangs on some PCI computers. drive
231 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
232 * a drive is allowed.
233 *
234 * NOTE: This must come before we include the arch floppy header because
235 * some ports reference this variable from there. -DaveM
236 */
237
238static int allowed_drive_mask = 0x33;
239
240#include <asm/floppy.h>
241
242static int irqdma_allocated;
243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244#define DEVICE_NAME "floppy"
245
246#include <linux/blkdev.h>
247#include <linux/blkpg.h>
248#include <linux/cdrom.h> /* for the compatibility eject ioctl */
249#include <linux/completion.h>
250
251static struct request *current_req;
252static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800253static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255#ifndef fd_get_dma_residue
256#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
257#endif
258
259/* Dma Memory related stuff */
260
261#ifndef fd_dma_mem_free
262#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
263#endif
264
265#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800266#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267#endif
268
269static inline void fallback_on_nodma_alloc(char **addr, size_t l)
270{
271#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
272 if (*addr)
273 return; /* we have the memory */
274 if (can_use_virtual_dma != 2)
275 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800276 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 *addr = (char *)nodma_mem_alloc(l);
278#else
279 return;
280#endif
281}
282
283/* End dma memory related stuff */
284
285static unsigned long fake_change;
286static int initialising = 1;
287
Joe Perches48c8cee2010-03-10 15:20:45 -0800288#define ITYPE(x) (((x) >> 2) & 0x1f)
289#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
290#define UNIT(x) ((x) & 0x03) /* drive on fdc */
291#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700292 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Joe Perches48c8cee2010-03-10 15:20:45 -0800295#define DP (&drive_params[current_drive])
296#define DRS (&drive_state[current_drive])
297#define DRWE (&write_errors[current_drive])
298#define FDCS (&fdc_state[fdc])
299#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
300#define SETF(x) set_bit(x##_BIT, &DRS->flags)
301#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Joe Perches48c8cee2010-03-10 15:20:45 -0800303#define UDP (&drive_params[drive])
304#define UDRS (&drive_state[drive])
305#define UDRWE (&write_errors[drive])
306#define UFDCS (&fdc_state[FDC(drive)])
307#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
308#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
309#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Joe Perches48c8cee2010-03-10 15:20:45 -0800311#define DPRINT(format, args...) \
Joe Perchesb46df352010-03-10 15:20:46 -0800312 pr_info(DEVICE_NAME "%d: " format, current_drive, ##args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Joe Perches48c8cee2010-03-10 15:20:45 -0800314#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
315#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
316
317#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800320#define COMMAND (raw_cmd->cmd[0])
321#define DR_SELECT (raw_cmd->cmd[1])
322#define TRACK (raw_cmd->cmd[2])
323#define HEAD (raw_cmd->cmd[3])
324#define SECTOR (raw_cmd->cmd[4])
325#define SIZECODE (raw_cmd->cmd[5])
326#define SECT_PER_TRACK (raw_cmd->cmd[6])
327#define GAP (raw_cmd->cmd[7])
328#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329#define NR_RW 9
330
331/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800332#define F_SIZECODE (raw_cmd->cmd[2])
333#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
334#define F_GAP (raw_cmd->cmd[4])
335#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336#define NR_F 6
337
338/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800339 * Maximum disk size (in kilobytes).
340 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 * [Now it is rather a minimum]
342 */
343#define MAX_DISK_SIZE 4 /* 3984 */
344
345/*
346 * globals used by 'result()'
347 */
348#define MAX_REPLIES 16
349static unsigned char reply_buffer[MAX_REPLIES];
350static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800351#define ST0 (reply_buffer[0])
352#define ST1 (reply_buffer[1])
353#define ST2 (reply_buffer[2])
354#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
355#define R_TRACK (reply_buffer[3])
356#define R_HEAD (reply_buffer[4])
357#define R_SECTOR (reply_buffer[5])
358#define R_SIZECODE (reply_buffer[6])
359
360#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362/*
363 * this struct defines the different floppy drive types.
364 */
365static struct {
366 struct floppy_drive_params params;
367 const char *name; /* name printed while booting */
368} default_drive_params[] = {
369/* NOTE: the time values in jiffies should be in msec!
370 CMOS drive type
371 | Maximum data rate supported by drive type
372 | | Head load time, msec
373 | | | Head unload time, msec (not used)
374 | | | | Step rate interval, usec
375 | | | | | Time needed for spinup time (jiffies)
376 | | | | | | Timeout for spinning down (jiffies)
377 | | | | | | | Spindown offset (where disk stops)
378 | | | | | | | | Select delay
379 | | | | | | | | | RPS
380 | | | | | | | | | | Max number of tracks
381 | | | | | | | | | | | Interrupt timeout
382 | | | | | | | | | | | | Max nonintlv. sectors
383 | | | | | | | | | | | | | -Max Errors- flags */
384{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
385 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
386
387{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
388 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
389
390{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
391 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
392
393{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
394 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
395
396{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
397 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
398
399{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
400 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
401
402{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
403 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
404/* | --autodetected formats--- | | |
405 * read_track | | Name printed when booting
406 * | Native format
407 * Frequency of disk change checks */
408};
409
410static struct floppy_drive_params drive_params[N_DRIVE];
411static struct floppy_drive_struct drive_state[N_DRIVE];
412static struct floppy_write_errors write_errors[N_DRIVE];
413static struct timer_list motor_off_timer[N_DRIVE];
414static struct gendisk *disks[N_DRIVE];
415static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800416static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
418
419/*
420 * This struct defines the different floppy types.
421 *
422 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
423 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
424 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
425 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
426 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
427 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
428 * side 0 is on physical side 0 (but with the misnamed sector IDs).
429 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700430 * 'options'.
431 *
432 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
433 * The LSB (bit 2) is flipped. For most disks, the first sector
434 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
435 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
436 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
437 *
438 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 */
440/*
441 Size
442 | Sectors per track
443 | | Head
444 | | | Tracks
445 | | | | Stretch
446 | | | | | Gap 1 size
447 | | | | | | Data rate, | 0x40 for perp
448 | | | | | | | Spec1 (stepping rate, head unload
449 | | | | | | | | /fmt gap (gap2) */
450static struct floppy_struct floppy_type[32] = {
451 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
452 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
453 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
454 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
455 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
456 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
457 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
458 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
459 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
460 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
461
462 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
463 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
464 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
465 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
466 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
467 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
468 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
469 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
470 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
471 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
472
473 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
474 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
475 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
476 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
477 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
478 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
479 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
480 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
481 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
485 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
486};
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488#define SECTSIZE (_FD_SECTSIZE(*floppy))
489
490/* Auto-detection: Disk type used until the next media change occurs. */
491static struct floppy_struct *current_type[N_DRIVE];
492
493/*
494 * User-provided type information. current_type points to
495 * the respective entry of this array.
496 */
497static struct floppy_struct user_params[N_DRIVE];
498
499static sector_t floppy_sizes[256];
500
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200501static char floppy_device_name[] = "floppy";
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503/*
504 * The driver is trying to determine the correct media format
505 * while probing is set. rw_interrupt() clears it after a
506 * successful access.
507 */
508static int probing;
509
510/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800511#define FD_COMMAND_NONE -1
512#define FD_COMMAND_ERROR 2
513#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515static volatile int command_status = FD_COMMAND_NONE;
516static unsigned long fdc_busy;
517static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
518static DECLARE_WAIT_QUEUE_HEAD(command_done);
519
520#define NO_SIGNAL (!interruptible || !signal_pending(current))
Joe Perches48c8cee2010-03-10 15:20:45 -0800521#define CALL(x) if ((x) == -EINTR) return -EINTR
522#define ECALL(x) if ((ret = (x))) return ret;
523#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
524#define WAIT(x) _WAIT((x),interruptible)
525#define IWAIT(x) _WAIT((x),1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527/* Errors during formatting are counted here. */
528static int format_errors;
529
530/* Format request descriptor. */
531static struct format_descr format_req;
532
533/*
534 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
535 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
536 * H is head unload time (1=16ms, 2=32ms, etc)
537 */
538
539/*
540 * Track buffer
541 * Because these are written to by the DMA controller, they must
542 * not contain a 64k byte boundary crossing, or data will be
543 * corrupted/lost.
544 */
545static char *floppy_track_buffer;
546static int max_buffer_sectors;
547
548static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700549typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800551 void (*interrupt)(void);
552 /* this is called after the interrupt of the
553 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700554 void (*redo)(void); /* this is called to retry the operation */
555 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 done_f done; /* this is called to say if the operation has
557 * succeeded/failed */
558} *cont;
559
560static void floppy_ready(void);
561static void floppy_start(void);
562static void process_fd_request(void);
563static void recalibrate_floppy(void);
564static void floppy_shutdown(unsigned long);
565
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800566static int floppy_request_regions(int);
567static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568static int floppy_grab_irq_and_dma(void);
569static void floppy_release_irq_and_dma(void);
570
571/*
572 * The "reset" variable should be tested whenever an interrupt is scheduled,
573 * after the commands have been sent. This is to ensure that the driver doesn't
574 * get wedged when the interrupt doesn't come because of a failed command.
575 * reset doesn't need to be tested before sending commands, because
576 * output_byte is automatically disabled when reset is set.
577 */
578#define CHECK_RESET { if (FDCS->reset){ reset_fdc(); return; } }
579static void reset_fdc(void);
580
581/*
582 * These are global variables, as that's the easiest way to give
583 * information to interrupts. They are the data used for the current
584 * request.
585 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800586#define NO_TRACK -1
587#define NEED_1_RECAL -2
588#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590static int usage_count;
591
592/* buffer related variables */
593static int buffer_track = -1;
594static int buffer_drive = -1;
595static int buffer_min = -1;
596static int buffer_max = -1;
597
598/* fdc related variables, should end up in a struct */
599static struct floppy_fdc_state fdc_state[N_FDC];
600static int fdc; /* current fdc */
601
602static struct floppy_struct *_floppy = floppy_type;
603static unsigned char current_drive;
604static long current_count_sectors;
605static unsigned char fsector_t; /* sector in track */
606static unsigned char in_sector_offset; /* offset within physical sector,
607 * expressed in units of 512 bytes */
608
609#ifndef fd_eject
610static inline int fd_eject(int drive)
611{
612 return -EINVAL;
613}
614#endif
615
616/*
617 * Debugging
618 * =========
619 */
620#ifdef DEBUGT
621static long unsigned debugtimer;
622
623static inline void set_debugt(void)
624{
625 debugtimer = jiffies;
626}
627
628static inline void debugt(const char *message)
629{
630 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800631 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632}
633#else
634static inline void set_debugt(void) { }
635static inline void debugt(const char *message) { }
636#endif /* DEBUGT */
637
638typedef void (*timeout_fn) (unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700639static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641static const char *timeout_message;
642
643#ifdef FLOPPY_SANITY_CHECK
644static void is_alive(const char *message)
645{
646 /* this routine checks whether the floppy driver is "alive" */
647 if (test_bit(0, &fdc_busy) && command_status < 2
648 && !timer_pending(&fd_timeout)) {
649 DPRINT("timeout handler died: %s\n", message);
650 }
651}
652#endif
653
Joe Perches48c8cee2010-03-10 15:20:45 -0800654static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656#ifdef FLOPPY_SANITY_CHECK
657
658#define OLOGSIZE 20
659
Joe Perches48c8cee2010-03-10 15:20:45 -0800660static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661static unsigned long interruptjiffies;
662static unsigned long resultjiffies;
663static int resultsize;
664static unsigned long lastredo;
665
666static struct output_log {
667 unsigned char data;
668 unsigned char status;
669 unsigned long jiffies;
670} output_log[OLOGSIZE];
671
672static int output_log_pos;
673#endif
674
675#define current_reqD -1
676#define MAXTIMEOUT -2
677
678static void __reschedule_timeout(int drive, const char *message, int marg)
679{
680 if (drive == current_reqD)
681 drive = current_drive;
682 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700683 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 fd_timeout.expires = jiffies + 20UL * HZ;
685 drive = 0;
686 } else
687 fd_timeout.expires = jiffies + UDP->timeout;
688 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800689 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800690 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 timeout_message = message;
692}
693
694static void reschedule_timeout(int drive, const char *message, int marg)
695{
696 unsigned long flags;
697
698 spin_lock_irqsave(&floppy_lock, flags);
699 __reschedule_timeout(drive, message, marg);
700 spin_unlock_irqrestore(&floppy_lock, flags);
701}
702
Joe Perches48c8cee2010-03-10 15:20:45 -0800703#define INFBOUND(a, b) (a) = max_t(int, a, b)
704#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706/*
707 * Bottom half floppy driver.
708 * ==========================
709 *
710 * This part of the file contains the code talking directly to the hardware,
711 * and also the main service loop (seek-configure-spinup-command)
712 */
713
714/*
715 * disk change.
716 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
717 * and the last_checked date.
718 *
719 * last_checked is the date of the last check which showed 'no disk change'
720 * FD_DISK_CHANGE is set under two conditions:
721 * 1. The floppy has been changed after some i/o to that floppy already
722 * took place.
723 * 2. No floppy disk is in the drive. This is done in order to ensure that
724 * requests are quickly flushed in case there is no disk in the drive. It
725 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
726 * the drive.
727 *
728 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
729 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
730 * each seek. If a disk is present, the disk change line should also be
731 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
732 * change line is set, this means either that no disk is in the drive, or
733 * that it has been removed since the last seek.
734 *
735 * This means that we really have a third possibility too:
736 * The floppy has been changed after the last seek.
737 */
738
739static int disk_change(int drive)
740{
741 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800744 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 DPRINT("WARNING disk change called early\n");
746 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
747 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
748 DPRINT("probing disk change on unselected drive\n");
749 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
750 (unsigned int)FDCS->dor);
751 }
752#endif
753
754#ifdef DCL_DEBUG
755 if (UDP->flags & FD_DEBUG) {
756 DPRINT("checking disk change line for drive %d\n", drive);
757 DPRINT("jiffies=%lu\n", jiffies);
758 DPRINT("disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
759 DPRINT("flags=%lx\n", UDRS->flags);
760 }
761#endif
762 if (UDP->flags & FD_BROKEN_DCL)
763 return UTESTF(FD_DISK_CHANGED);
764 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
765 USETF(FD_VERIFY); /* verify write protection */
766 if (UDRS->maxblock) {
767 /* mark it changed */
768 USETF(FD_DISK_CHANGED);
769 }
770
771 /* invalidate its geometry */
772 if (UDRS->keep_data >= 0) {
773 if ((UDP->flags & FTD_MSG) &&
774 current_type[drive] != NULL)
775 DPRINT("Disk type is undefined after "
776 "disk change\n");
777 current_type[drive] = NULL;
778 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
779 }
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 return 1;
782 } else {
783 UDRS->last_checked = jiffies;
784 UCLEARF(FD_DISK_NEWCHANGE);
785 }
786 return 0;
787}
788
789static inline int is_selected(int dor, int unit)
790{
791 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
792}
793
794static int set_dor(int fdc, char mask, char data)
795{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700796 unsigned char unit;
797 unsigned char drive;
798 unsigned char newdor;
799 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 if (FDCS->address == -1)
802 return -1;
803
804 olddor = FDCS->dor;
805 newdor = (olddor & mask) | data;
806 if (newdor != olddor) {
807 unit = olddor & 0x3;
808 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
809 drive = REVDRIVE(fdc, unit);
810#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -0800811 if (UDP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 DPRINT("calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813#endif
814 disk_change(drive);
815 }
816 FDCS->dor = newdor;
817 fd_outb(newdor, FD_DOR);
818
819 unit = newdor & 0x3;
820 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
821 drive = REVDRIVE(fdc, unit);
822 UDRS->select_date = jiffies;
823 }
824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 return olddor;
826}
827
828static void twaddle(void)
829{
830 if (DP->select_delay)
831 return;
832 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
833 fd_outb(FDCS->dor, FD_DOR);
834 DRS->select_date = jiffies;
835}
836
837/* reset all driver information about the current fdc. This is needed after
838 * a reset, and after a raw command. */
839static void reset_fdc_info(int mode)
840{
841 int drive;
842
843 FDCS->spec1 = FDCS->spec2 = -1;
844 FDCS->need_configure = 1;
845 FDCS->perp_mode = 1;
846 FDCS->rawcmd = 0;
847 for (drive = 0; drive < N_DRIVE; drive++)
848 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
849 UDRS->track = NEED_2_RECAL;
850}
851
852/* selects the fdc and drive, and enables the fdc's input/dma. */
853static void set_fdc(int drive)
854{
855 if (drive >= 0 && drive < N_DRIVE) {
856 fdc = FDC(drive);
857 current_drive = drive;
858 }
859 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800860 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 return;
862 }
863 set_dor(fdc, ~0, 8);
864#if N_FDC > 1
865 set_dor(1 - fdc, ~8, 0);
866#endif
867 if (FDCS->rawcmd == 2)
868 reset_fdc_info(1);
869 if (fd_inb(FD_STATUS) != STATUS_READY)
870 FDCS->reset = 1;
871}
872
873/* locks the driver */
874static int _lock_fdc(int drive, int interruptible, int line)
875{
876 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800877 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 line);
879 return -1;
880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 if (test_and_set_bit(0, &fdc_busy)) {
883 DECLARE_WAITQUEUE(wait, current);
884 add_wait_queue(&fdc_wait, &wait);
885
886 for (;;) {
887 set_current_state(TASK_INTERRUPTIBLE);
888
889 if (!test_and_set_bit(0, &fdc_busy))
890 break;
891
892 schedule();
893
894 if (!NO_SIGNAL) {
895 remove_wait_queue(&fdc_wait, &wait);
896 return -EINTR;
897 }
898 }
899
900 set_current_state(TASK_RUNNING);
901 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700902 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
904 command_status = FD_COMMAND_NONE;
905
906 __reschedule_timeout(drive, "lock fdc", 0);
907 set_fdc(drive);
908 return 0;
909}
910
Joe Perches48c8cee2010-03-10 15:20:45 -0800911#define lock_fdc(drive, interruptible) \
912 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Joe Perches48c8cee2010-03-10 15:20:45 -0800914#define LOCK_FDC(drive, interruptible) \
915 if (lock_fdc(drive, interruptible)) \
916 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918/* unlocks the driver */
919static inline void unlock_fdc(void)
920{
921 unsigned long flags;
922
923 raw_cmd = NULL;
924 if (!test_bit(0, &fdc_busy))
925 DPRINT("FDC access conflict!\n");
926
927 if (do_floppy)
928 DPRINT("device interrupt still active at FDC release: %p!\n",
929 do_floppy);
930 command_status = FD_COMMAND_NONE;
931 spin_lock_irqsave(&floppy_lock, flags);
932 del_timer(&fd_timeout);
933 cont = NULL;
934 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900935 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 do_fd_request(floppy_queue);
937 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 wake_up(&fdc_wait);
939}
940
941/* switches the motor off after a given timeout */
942static void motor_off_callback(unsigned long nr)
943{
944 unsigned char mask = ~(0x10 << UNIT(nr));
945
946 set_dor(FDC(nr), mask, 0);
947}
948
949/* schedules motor off */
950static void floppy_off(unsigned int drive)
951{
952 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700953 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 if (!(FDCS->dor & (0x10 << UNIT(drive))))
956 return;
957
958 del_timer(motor_off_timer + drive);
959
960 /* make spindle stop in a position which minimizes spinup time
961 * next time */
962 if (UDP->rps) {
963 delta = jiffies - UDRS->first_read_date + HZ -
964 UDP->spindown_offset;
965 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
966 motor_off_timer[drive].expires =
967 jiffies + UDP->spindown - delta;
968 }
969 add_timer(motor_off_timer + drive);
970}
971
972/*
973 * cycle through all N_DRIVE floppy drives, for disk change testing.
974 * stopping at current drive. This is done before any long operation, to
975 * be sure to have up to date disk change information.
976 */
977static void scandrives(void)
978{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700979 int i;
980 int drive;
981 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 if (DP->select_delay)
984 return;
985
986 saved_drive = current_drive;
987 for (i = 0; i < N_DRIVE; i++) {
988 drive = (saved_drive + i + 1) % N_DRIVE;
989 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
990 continue; /* skip closed drives */
991 set_fdc(drive);
992 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
993 (0x10 << UNIT(drive))))
994 /* switch the motor off again, if it was off to
995 * begin with */
996 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
997 }
998 set_fdc(saved_drive);
999}
1000
1001static void empty(void)
1002{
1003}
1004
David Howells65f27f32006-11-22 14:55:48 +00001005static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Joe Perches48c8cee2010-03-10 15:20:45 -08001007static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
David Howells65f27f32006-11-22 14:55:48 +00001009 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 schedule_work(&floppy_work);
1011}
1012
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001013static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015static void cancel_activity(void)
1016{
1017 unsigned long flags;
1018
1019 spin_lock_irqsave(&floppy_lock, flags);
1020 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001021 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 del_timer(&fd_timer);
1023 spin_unlock_irqrestore(&floppy_lock, flags);
1024}
1025
1026/* this function makes sure that the disk stays in the drive during the
1027 * transfer */
1028static void fd_watchdog(void)
1029{
1030#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001031 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 DPRINT("calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033#endif
1034
1035 if (disk_change(current_drive)) {
1036 DPRINT("disk removed during i/o\n");
1037 cancel_activity();
1038 cont->done(0);
1039 reset_fdc();
1040 } else {
1041 del_timer(&fd_timer);
1042 fd_timer.function = (timeout_fn) fd_watchdog;
1043 fd_timer.expires = jiffies + HZ / 10;
1044 add_timer(&fd_timer);
1045 }
1046}
1047
1048static void main_command_interrupt(void)
1049{
1050 del_timer(&fd_timer);
1051 cont->interrupt();
1052}
1053
1054/* waits for a delay (spinup or select) to pass */
1055static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1056{
1057 if (FDCS->reset) {
1058 reset_fdc(); /* do the reset during sleep to win time
1059 * if we don't need to sleep, it's a good
1060 * occasion anyways */
1061 return 1;
1062 }
1063
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001064 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 del_timer(&fd_timer);
1066 fd_timer.function = function;
1067 fd_timer.expires = delay;
1068 add_timer(&fd_timer);
1069 return 1;
1070 }
1071 return 0;
1072}
1073
1074static DEFINE_SPINLOCK(floppy_hlt_lock);
1075static int hlt_disabled;
1076static void floppy_disable_hlt(void)
1077{
1078 unsigned long flags;
1079
1080 spin_lock_irqsave(&floppy_hlt_lock, flags);
1081 if (!hlt_disabled) {
1082 hlt_disabled = 1;
1083#ifdef HAVE_DISABLE_HLT
1084 disable_hlt();
1085#endif
1086 }
1087 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1088}
1089
1090static void floppy_enable_hlt(void)
1091{
1092 unsigned long flags;
1093
1094 spin_lock_irqsave(&floppy_hlt_lock, flags);
1095 if (hlt_disabled) {
1096 hlt_disabled = 0;
1097#ifdef HAVE_DISABLE_HLT
1098 enable_hlt();
1099#endif
1100 }
1101 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1102}
1103
1104static void setup_DMA(void)
1105{
1106 unsigned long f;
1107
1108#ifdef FLOPPY_SANITY_CHECK
1109 if (raw_cmd->length == 0) {
1110 int i;
1111
Joe Perchesb46df352010-03-10 15:20:46 -08001112 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001114 pr_cont("%x,", raw_cmd->cmd[i]);
1115 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 cont->done(0);
1117 FDCS->reset = 1;
1118 return;
1119 }
1120 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001121 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 cont->done(0);
1123 FDCS->reset = 1;
1124 return;
1125 }
1126#endif
1127 f = claim_dma_lock();
1128 fd_disable_dma();
1129#ifdef fd_dma_setup
1130 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1131 (raw_cmd->flags & FD_RAW_READ) ?
1132 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1133 release_dma_lock(f);
1134 cont->done(0);
1135 FDCS->reset = 1;
1136 return;
1137 }
1138 release_dma_lock(f);
1139#else
1140 fd_clear_dma_ff();
1141 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1142 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1143 DMA_MODE_READ : DMA_MODE_WRITE);
1144 fd_set_dma_addr(raw_cmd->kernel_data);
1145 fd_set_dma_count(raw_cmd->length);
1146 virtual_dma_port = FDCS->address;
1147 fd_enable_dma();
1148 release_dma_lock(f);
1149#endif
1150 floppy_disable_hlt();
1151}
1152
1153static void show_floppy(void);
1154
1155/* waits until the fdc becomes ready */
1156static int wait_til_ready(void)
1157{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001158 int status;
1159 int counter;
1160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (FDCS->reset)
1162 return -1;
1163 for (counter = 0; counter < 10000; counter++) {
1164 status = fd_inb(FD_STATUS);
1165 if (status & STATUS_READY)
1166 return status;
1167 }
1168 if (!initialising) {
1169 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1170 show_floppy();
1171 }
1172 FDCS->reset = 1;
1173 return -1;
1174}
1175
1176/* sends a command byte to the fdc */
1177static int output_byte(char byte)
1178{
1179 int status;
1180
1181 if ((status = wait_til_ready()) < 0)
1182 return -1;
1183 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1184 fd_outb(byte, FD_DATA);
1185#ifdef FLOPPY_SANITY_CHECK
1186 output_log[output_log_pos].data = byte;
1187 output_log[output_log_pos].status = status;
1188 output_log[output_log_pos].jiffies = jiffies;
1189 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1190#endif
1191 return 0;
1192 }
1193 FDCS->reset = 1;
1194 if (!initialising) {
1195 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1196 byte, fdc, status);
1197 show_floppy();
1198 }
1199 return -1;
1200}
1201
1202#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
1203
1204/* gets the response from the fdc */
1205static int result(void)
1206{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001207 int i;
1208 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
1210 for (i = 0; i < MAX_REPLIES; i++) {
1211 if ((status = wait_til_ready()) < 0)
1212 break;
1213 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1214 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1215#ifdef FLOPPY_SANITY_CHECK
1216 resultjiffies = jiffies;
1217 resultsize = i;
1218#endif
1219 return i;
1220 }
1221 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1222 reply_buffer[i] = fd_inb(FD_DATA);
1223 else
1224 break;
1225 }
1226 if (!initialising) {
1227 DPRINT
1228 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1229 fdc, status, i);
1230 show_floppy();
1231 }
1232 FDCS->reset = 1;
1233 return -1;
1234}
1235
1236#define MORE_OUTPUT -2
1237/* does the fdc need more output? */
1238static int need_more_output(void)
1239{
1240 int status;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 if ((status = wait_til_ready()) < 0)
1243 return -1;
1244 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1245 return MORE_OUTPUT;
1246 return result();
1247}
1248
1249/* Set perpendicular mode as required, based on data rate, if supported.
1250 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1251 */
1252static inline void perpendicular_mode(void)
1253{
1254 unsigned char perp_mode;
1255
1256 if (raw_cmd->rate & 0x40) {
1257 switch (raw_cmd->rate & 3) {
1258 case 0:
1259 perp_mode = 2;
1260 break;
1261 case 3:
1262 perp_mode = 3;
1263 break;
1264 default:
1265 DPRINT("Invalid data rate for perpendicular mode!\n");
1266 cont->done(0);
1267 FDCS->reset = 1; /* convenient way to return to
1268 * redo without to much hassle (deep
1269 * stack et al. */
1270 return;
1271 }
1272 } else
1273 perp_mode = 0;
1274
1275 if (FDCS->perp_mode == perp_mode)
1276 return;
1277 if (FDCS->version >= FDC_82077_ORIG) {
1278 output_byte(FD_PERPENDICULAR);
1279 output_byte(perp_mode);
1280 FDCS->perp_mode = perp_mode;
1281 } else if (perp_mode) {
1282 DPRINT("perpendicular mode not supported by this FDC.\n");
1283 }
1284} /* perpendicular_mode */
1285
1286static int fifo_depth = 0xa;
1287static int no_fifo;
1288
1289static int fdc_configure(void)
1290{
1291 /* Turn on FIFO */
1292 output_byte(FD_CONFIGURE);
1293 if (need_more_output() != MORE_OUTPUT)
1294 return 0;
1295 output_byte(0);
1296 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1297 output_byte(0); /* pre-compensation from track
1298 0 upwards */
1299 return 1;
1300}
1301
1302#define NOMINAL_DTR 500
1303
1304/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1305 * head load time, and DMA disable flag to values needed by floppy.
1306 *
1307 * The value "dtr" is the data transfer rate in Kbps. It is needed
1308 * to account for the data rate-based scaling done by the 82072 and 82077
1309 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1310 * 8272a).
1311 *
1312 * Note that changing the data transfer rate has a (probably deleterious)
1313 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1314 * fdc_specify is called again after each data transfer rate
1315 * change.
1316 *
1317 * srt: 1000 to 16000 in microseconds
1318 * hut: 16 to 240 milliseconds
1319 * hlt: 2 to 254 milliseconds
1320 *
1321 * These values are rounded up to the next highest available delay time.
1322 */
1323static void fdc_specify(void)
1324{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001325 unsigned char spec1;
1326 unsigned char spec2;
1327 unsigned long srt;
1328 unsigned long hlt;
1329 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 unsigned long dtr = NOMINAL_DTR;
1331 unsigned long scale_dtr = NOMINAL_DTR;
1332 int hlt_max_code = 0x7f;
1333 int hut_max_code = 0xf;
1334
1335 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1336 fdc_configure();
1337 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
1339
1340 switch (raw_cmd->rate & 0x03) {
1341 case 3:
1342 dtr = 1000;
1343 break;
1344 case 1:
1345 dtr = 300;
1346 if (FDCS->version >= FDC_82078) {
1347 /* chose the default rate table, not the one
1348 * where 1 = 2 Mbps */
1349 output_byte(FD_DRIVESPEC);
1350 if (need_more_output() == MORE_OUTPUT) {
1351 output_byte(UNIT(current_drive));
1352 output_byte(0xc0);
1353 }
1354 }
1355 break;
1356 case 2:
1357 dtr = 250;
1358 break;
1359 }
1360
1361 if (FDCS->version >= FDC_82072) {
1362 scale_dtr = dtr;
1363 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1364 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1365 }
1366
1367 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001368 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001369 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 SUPBOUND(srt, 0xf);
1373 INFBOUND(srt, 0);
1374
Julia Lawall061837b2008-09-22 14:57:16 -07001375 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (hlt < 0x01)
1377 hlt = 0x01;
1378 else if (hlt > 0x7f)
1379 hlt = hlt_max_code;
1380
Julia Lawall061837b2008-09-22 14:57:16 -07001381 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (hut < 0x1)
1383 hut = 0x1;
1384 else if (hut > 0xf)
1385 hut = hut_max_code;
1386
1387 spec1 = (srt << 4) | hut;
1388 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1389
1390 /* If these parameters did not change, just return with success */
1391 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1392 /* Go ahead and set spec1 and spec2 */
1393 output_byte(FD_SPECIFY);
1394 output_byte(FDCS->spec1 = spec1);
1395 output_byte(FDCS->spec2 = spec2);
1396 }
1397} /* fdc_specify */
1398
1399/* Set the FDC's data transfer rate on behalf of the specified drive.
1400 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1401 * of the specify command (i.e. using the fdc_specify function).
1402 */
1403static int fdc_dtr(void)
1404{
1405 /* If data rate not already set to desired value, set it. */
1406 if ((raw_cmd->rate & 3) == FDCS->dtr)
1407 return 0;
1408
1409 /* Set dtr */
1410 fd_outb(raw_cmd->rate & 3, FD_DCR);
1411
1412 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1413 * need a stabilization period of several milliseconds to be
1414 * enforced after data rate changes before R/W operations.
1415 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1416 */
1417 FDCS->dtr = raw_cmd->rate & 3;
1418 return (fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1419 (timeout_fn) floppy_ready));
1420} /* fdc_dtr */
1421
1422static void tell_sector(void)
1423{
Joe Perchesb46df352010-03-10 15:20:46 -08001424 pr_cont(": track %d, head %d, sector %d, size %d",
1425 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426} /* tell_sector */
1427
Joe Perchesb46df352010-03-10 15:20:46 -08001428static void print_errors(void)
1429{
1430 DPRINT("");
1431 if (ST0 & ST0_ECE) {
1432 pr_cont("Recalibrate failed!");
1433 } else if (ST2 & ST2_CRC) {
1434 pr_cont("data CRC error");
1435 tell_sector();
1436 } else if (ST1 & ST1_CRC) {
1437 pr_cont("CRC error");
1438 tell_sector();
1439 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1440 (ST2 & ST2_MAM)) {
1441 if (!probing) {
1442 pr_cont("sector not found");
1443 tell_sector();
1444 } else
1445 pr_cont("probe failed...");
1446 } else if (ST2 & ST2_WC) { /* seek error */
1447 pr_cont("wrong cylinder");
1448 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1449 pr_cont("bad cylinder");
1450 } else {
1451 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1452 ST0, ST1, ST2);
1453 tell_sector();
1454 }
1455 pr_cont("\n");
1456}
1457
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458/*
1459 * OK, this error interpreting routine is called after a
1460 * DMA read/write has succeeded
1461 * or failed, so we check the results, and copy any buffers.
1462 * hhb: Added better error reporting.
1463 * ak: Made this into a separate routine.
1464 */
1465static int interpret_errors(void)
1466{
1467 char bad;
1468
1469 if (inr != 7) {
1470 DPRINT("-- FDC reply error");
1471 FDCS->reset = 1;
1472 return 1;
1473 }
1474
1475 /* check IC to find cause of interrupt */
1476 switch (ST0 & ST0_INTR) {
1477 case 0x40: /* error occurred during command execution */
1478 if (ST1 & ST1_EOC)
1479 return 0; /* occurs with pseudo-DMA */
1480 bad = 1;
1481 if (ST1 & ST1_WP) {
1482 DPRINT("Drive is write protected\n");
1483 CLEARF(FD_DISK_WRITABLE);
1484 cont->done(0);
1485 bad = 2;
1486 } else if (ST1 & ST1_ND) {
1487 SETF(FD_NEED_TWADDLE);
1488 } else if (ST1 & ST1_OR) {
1489 if (DP->flags & FTD_MSG)
1490 DPRINT("Over/Underrun - retrying\n");
1491 bad = 0;
1492 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001493 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 }
1495 if (ST2 & ST2_WC || ST2 & ST2_BC)
1496 /* wrong cylinder => recal */
1497 DRS->track = NEED_2_RECAL;
1498 return bad;
1499 case 0x80: /* invalid command given */
1500 DPRINT("Invalid FDC command given!\n");
1501 cont->done(0);
1502 return 2;
1503 case 0xc0:
1504 DPRINT("Abnormal termination caused by polling\n");
1505 cont->error();
1506 return 2;
1507 default: /* (0) Normal command termination */
1508 return 0;
1509 }
1510}
1511
1512/*
1513 * This routine is called when everything should be correctly set up
1514 * for the transfer (i.e. floppy motor is on, the correct floppy is
1515 * selected, and the head is sitting on the right track).
1516 */
1517static void setup_rw_floppy(void)
1518{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001519 int i;
1520 int r;
1521 int flags;
1522 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 unsigned long ready_date;
1524 timeout_fn function;
1525
1526 flags = raw_cmd->flags;
1527 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1528 flags |= FD_RAW_INTR;
1529
1530 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1531 ready_date = DRS->spinup_date + DP->spinup;
1532 /* If spinup will take a long time, rerun scandrives
1533 * again just before spinup completion. Beware that
1534 * after scandrives, we must again wait for selection.
1535 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001536 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 ready_date -= DP->select_delay;
1538 function = (timeout_fn) floppy_start;
1539 } else
1540 function = (timeout_fn) setup_rw_floppy;
1541
1542 /* wait until the floppy is spinning fast enough */
1543 if (fd_wait_for_completion(ready_date, function))
1544 return;
1545 }
1546 dflags = DRS->flags;
1547
1548 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1549 setup_DMA();
1550
1551 if (flags & FD_RAW_INTR)
1552 do_floppy = main_command_interrupt;
1553
1554 r = 0;
1555 for (i = 0; i < raw_cmd->cmd_count; i++)
1556 r |= output_byte(raw_cmd->cmd[i]);
1557
1558 debugt("rw_command: ");
1559
1560 if (r) {
1561 cont->error();
1562 reset_fdc();
1563 return;
1564 }
1565
1566 if (!(flags & FD_RAW_INTR)) {
1567 inr = result();
1568 cont->interrupt();
1569 } else if (flags & FD_RAW_NEED_DISK)
1570 fd_watchdog();
1571}
1572
1573static int blind_seek;
1574
1575/*
1576 * This is the routine called after every seek (or recalibrate) interrupt
1577 * from the floppy controller.
1578 */
1579static void seek_interrupt(void)
1580{
1581 debugt("seek interrupt:");
1582 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1583 DPRINT("seek failed\n");
1584 DRS->track = NEED_2_RECAL;
1585 cont->error();
1586 cont->redo();
1587 return;
1588 }
1589 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
1590#ifdef DCL_DEBUG
1591 if (DP->flags & FD_DEBUG) {
Joe Perchesb46df352010-03-10 15:20:46 -08001592 DPRINT("clearing NEWCHANGE flag because of effective seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 DPRINT("jiffies=%lu\n", jiffies);
1594 }
1595#endif
1596 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1597 DRS->select_date = jiffies;
1598 }
1599 DRS->track = ST1;
1600 floppy_ready();
1601}
1602
1603static void check_wp(void)
1604{
1605 if (TESTF(FD_VERIFY)) {
1606 /* check write protection */
1607 output_byte(FD_GETSTATUS);
1608 output_byte(UNIT(current_drive));
1609 if (result() != 1) {
1610 FDCS->reset = 1;
1611 return;
1612 }
1613 CLEARF(FD_VERIFY);
1614 CLEARF(FD_NEED_TWADDLE);
1615#ifdef DCL_DEBUG
1616 if (DP->flags & FD_DEBUG) {
1617 DPRINT("checking whether disk is write protected\n");
1618 DPRINT("wp=%x\n", ST3 & 0x40);
1619 }
1620#endif
1621 if (!(ST3 & 0x40))
1622 SETF(FD_DISK_WRITABLE);
1623 else
1624 CLEARF(FD_DISK_WRITABLE);
1625 }
1626}
1627
1628static void seek_floppy(void)
1629{
1630 int track;
1631
1632 blind_seek = 0;
1633
1634#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001635 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 DPRINT("calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637#endif
1638
1639 if (!TESTF(FD_DISK_NEWCHANGE) &&
1640 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1641 /* the media changed flag should be cleared after the seek.
1642 * If it isn't, this means that there is really no disk in
1643 * the drive.
1644 */
1645 SETF(FD_DISK_CHANGED);
1646 cont->done(0);
1647 cont->redo();
1648 return;
1649 }
1650 if (DRS->track <= NEED_1_RECAL) {
1651 recalibrate_floppy();
1652 return;
1653 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1654 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1655 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1656 /* we seek to clear the media-changed condition. Does anybody
1657 * know a more elegant way, which works on all drives? */
1658 if (raw_cmd->track)
1659 track = raw_cmd->track - 1;
1660 else {
1661 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1662 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1663 blind_seek = 1;
1664 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1665 }
1666 track = 1;
1667 }
1668 } else {
1669 check_wp();
1670 if (raw_cmd->track != DRS->track &&
1671 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1672 track = raw_cmd->track;
1673 else {
1674 setup_rw_floppy();
1675 return;
1676 }
1677 }
1678
1679 do_floppy = seek_interrupt;
1680 output_byte(FD_SEEK);
1681 output_byte(UNIT(current_drive));
1682 LAST_OUT(track);
1683 debugt("seek command:");
1684}
1685
1686static void recal_interrupt(void)
1687{
1688 debugt("recal interrupt:");
1689 if (inr != 2)
1690 FDCS->reset = 1;
1691 else if (ST0 & ST0_ECE) {
1692 switch (DRS->track) {
1693 case NEED_1_RECAL:
1694 debugt("recal interrupt need 1 recal:");
1695 /* after a second recalibrate, we still haven't
1696 * reached track 0. Probably no drive. Raise an
1697 * error, as failing immediately might upset
1698 * computers possessed by the Devil :-) */
1699 cont->error();
1700 cont->redo();
1701 return;
1702 case NEED_2_RECAL:
1703 debugt("recal interrupt need 2 recal:");
1704 /* If we already did a recalibrate,
1705 * and we are not at track 0, this
1706 * means we have moved. (The only way
1707 * not to move at recalibration is to
1708 * be already at track 0.) Clear the
1709 * new change flag */
1710#ifdef DCL_DEBUG
Joe Perchesb46df352010-03-10 15:20:46 -08001711 if (DP->flags & FD_DEBUG)
1712 DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713#endif
1714
1715 CLEARF(FD_DISK_NEWCHANGE);
1716 DRS->select_date = jiffies;
1717 /* fall through */
1718 default:
1719 debugt("recal interrupt default:");
1720 /* Recalibrate moves the head by at
1721 * most 80 steps. If after one
1722 * recalibrate we don't have reached
1723 * track 0, this might mean that we
1724 * started beyond track 80. Try
1725 * again. */
1726 DRS->track = NEED_1_RECAL;
1727 break;
1728 }
1729 } else
1730 DRS->track = ST1;
1731 floppy_ready();
1732}
1733
1734static void print_result(char *message, int inr)
1735{
1736 int i;
1737
1738 DPRINT("%s ", message);
1739 if (inr >= 0)
1740 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001741 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1742 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743}
1744
1745/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001746irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 int do_print;
1749 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001750 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
1752 lasthandler = handler;
1753 interruptjiffies = jiffies;
1754
1755 f = claim_dma_lock();
1756 fd_disable_dma();
1757 release_dma_lock(f);
1758
1759 floppy_enable_hlt();
1760 do_floppy = NULL;
1761 if (fdc >= N_FDC || FDCS->address == -1) {
1762 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001763 pr_info("DOR0=%x\n", fdc_state[0].dor);
1764 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1765 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 is_alive("bizarre fdc");
1767 return IRQ_NONE;
1768 }
1769
1770 FDCS->reset = 0;
1771 /* We have to clear the reset flag here, because apparently on boxes
1772 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1773 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1774 * emission of the SENSEI's.
1775 * It is OK to emit floppy commands because we are in an interrupt
1776 * handler here, and thus we have to fear no interference of other
1777 * activity.
1778 */
1779
1780 do_print = !handler && print_unex && !initialising;
1781
1782 inr = result();
1783 if (do_print)
1784 print_result("unexpected interrupt", inr);
1785 if (inr == 0) {
1786 int max_sensei = 4;
1787 do {
1788 output_byte(FD_SENSEI);
1789 inr = result();
1790 if (do_print)
1791 print_result("sensei", inr);
1792 max_sensei--;
1793 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1794 && max_sensei);
1795 }
1796 if (!handler) {
1797 FDCS->reset = 1;
1798 return IRQ_NONE;
1799 }
1800 schedule_bh(handler);
1801 is_alive("normal interrupt end");
1802
1803 /* FIXME! Was it really for us? */
1804 return IRQ_HANDLED;
1805}
1806
1807static void recalibrate_floppy(void)
1808{
1809 debugt("recalibrate floppy:");
1810 do_floppy = recal_interrupt;
1811 output_byte(FD_RECALIBRATE);
1812 LAST_OUT(UNIT(current_drive));
1813}
1814
1815/*
1816 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1817 */
1818static void reset_interrupt(void)
1819{
1820 debugt("reset interrupt:");
1821 result(); /* get the status ready for set_fdc */
1822 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001823 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 cont->error(); /* a reset just after a reset. BAD! */
1825 }
1826 cont->redo();
1827}
1828
1829/*
1830 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1831 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1832 */
1833static void reset_fdc(void)
1834{
1835 unsigned long flags;
1836
1837 do_floppy = reset_interrupt;
1838 FDCS->reset = 0;
1839 reset_fdc_info(0);
1840
1841 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1842 /* Irrelevant for systems with true DMA (i386). */
1843
1844 flags = claim_dma_lock();
1845 fd_disable_dma();
1846 release_dma_lock(flags);
1847
1848 if (FDCS->version >= FDC_82072A)
1849 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1850 else {
1851 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1852 udelay(FD_RESET_DELAY);
1853 fd_outb(FDCS->dor, FD_DOR);
1854 }
1855}
1856
1857static void show_floppy(void)
1858{
1859 int i;
1860
Joe Perchesb46df352010-03-10 15:20:46 -08001861 pr_info("\n");
1862 pr_info("floppy driver state\n");
1863 pr_info("-------------------\n");
1864 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1865 jiffies, interruptjiffies, jiffies - interruptjiffies,
1866 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001869 pr_info("timeout_message=%s\n", timeout_message);
1870 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001872 pr_info("%2x %2x %lu\n",
1873 output_log[(i + output_log_pos) % OLOGSIZE].data,
1874 output_log[(i + output_log_pos) % OLOGSIZE].status,
1875 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1876 pr_info("last result at %lu\n", resultjiffies);
1877 pr_info("last redo_fd_request at %lu\n", lastredo);
1878 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1879 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880#endif
1881
Joe Perchesb46df352010-03-10 15:20:46 -08001882 pr_info("status=%x\n", fd_inb(FD_STATUS));
1883 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001885 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001886 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001887 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001889 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001891 pr_info("timer_function=%p\n", fd_timeout.function);
1892 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1893 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
Joe Perchesb46df352010-03-10 15:20:46 -08001895 pr_info("cont=%p\n", cont);
1896 pr_info("current_req=%p\n", current_req);
1897 pr_info("command_status=%d\n", command_status);
1898 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899}
1900
1901static void floppy_shutdown(unsigned long data)
1902{
1903 unsigned long flags;
1904
1905 if (!initialising)
1906 show_floppy();
1907 cancel_activity();
1908
1909 floppy_enable_hlt();
1910
1911 flags = claim_dma_lock();
1912 fd_disable_dma();
1913 release_dma_lock(flags);
1914
1915 /* avoid dma going to a random drive after shutdown */
1916
1917 if (!initialising)
1918 DPRINT("floppy timeout called\n");
1919 FDCS->reset = 1;
1920 if (cont) {
1921 cont->done(0);
1922 cont->redo(); /* this will recall reset when needed */
1923 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001924 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 process_fd_request();
1926 }
1927 is_alive("floppy shutdown");
1928}
1929
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001931static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001933 int mask;
1934 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
1936 mask = 0xfc;
1937 data = UNIT(current_drive);
1938 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1939 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1940 set_debugt();
1941 /* no read since this drive is running */
1942 DRS->first_read_date = 0;
1943 /* note motor start time if motor is not yet running */
1944 DRS->spinup_date = jiffies;
1945 data |= (0x10 << UNIT(current_drive));
1946 }
1947 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1948 mask &= ~(0x10 << UNIT(current_drive));
1949
1950 /* starts motor and selects floppy */
1951 del_timer(motor_off_timer + current_drive);
1952 set_dor(fdc, mask, data);
1953
1954 /* wait_for_completion also schedules reset if needed. */
1955 return (fd_wait_for_completion(DRS->select_date + DP->select_delay,
1956 (timeout_fn) function));
1957}
1958
1959static void floppy_ready(void)
1960{
1961 CHECK_RESET;
1962 if (start_motor(floppy_ready))
1963 return;
1964 if (fdc_dtr())
1965 return;
1966
1967#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001968 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 DPRINT("calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970#endif
1971 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1972 disk_change(current_drive) && !DP->select_delay)
1973 twaddle(); /* this clears the dcl on certain drive/controller
1974 * combinations */
1975
1976#ifdef fd_chose_dma_mode
1977 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1978 unsigned long flags = claim_dma_lock();
1979 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1980 release_dma_lock(flags);
1981 }
1982#endif
1983
1984 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1985 perpendicular_mode();
1986 fdc_specify(); /* must be done here because of hut, hlt ... */
1987 seek_floppy();
1988 } else {
1989 if ((raw_cmd->flags & FD_RAW_READ) ||
1990 (raw_cmd->flags & FD_RAW_WRITE))
1991 fdc_specify();
1992 setup_rw_floppy();
1993 }
1994}
1995
1996static void floppy_start(void)
1997{
1998 reschedule_timeout(current_reqD, "floppy start", 0);
1999
2000 scandrives();
2001#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08002002 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 DPRINT("setting NEWCHANGE in floppy_start\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004#endif
2005 SETF(FD_DISK_NEWCHANGE);
2006 floppy_ready();
2007}
2008
2009/*
2010 * ========================================================================
2011 * here ends the bottom half. Exported routines are:
2012 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2013 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2014 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2015 * and set_dor.
2016 * ========================================================================
2017 */
2018/*
2019 * General purpose continuations.
2020 * ==============================
2021 */
2022
2023static void do_wakeup(void)
2024{
2025 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2026 cont = NULL;
2027 command_status += 2;
2028 wake_up(&command_done);
2029}
2030
2031static struct cont_t wakeup_cont = {
2032 .interrupt = empty,
2033 .redo = do_wakeup,
2034 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002035 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036};
2037
2038static struct cont_t intr_cont = {
2039 .interrupt = empty,
2040 .redo = process_fd_request,
2041 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002042 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043};
2044
Jesper Juhl06f748c2007-10-16 23:30:57 -07002045static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046{
2047 int ret;
2048
2049 schedule_bh(handler);
2050
2051 if (command_status < 2 && NO_SIGNAL) {
2052 DECLARE_WAITQUEUE(wait, current);
2053
2054 add_wait_queue(&command_done, &wait);
2055 for (;;) {
2056 set_current_state(interruptible ?
2057 TASK_INTERRUPTIBLE :
2058 TASK_UNINTERRUPTIBLE);
2059
2060 if (command_status >= 2 || !NO_SIGNAL)
2061 break;
2062
2063 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 schedule();
2065 }
2066
2067 set_current_state(TASK_RUNNING);
2068 remove_wait_queue(&command_done, &wait);
2069 }
2070
2071 if (command_status < 2) {
2072 cancel_activity();
2073 cont = &intr_cont;
2074 reset_fdc();
2075 return -EINTR;
2076 }
2077
2078 if (FDCS->reset)
2079 command_status = FD_COMMAND_ERROR;
2080 if (command_status == FD_COMMAND_OKAY)
2081 ret = 0;
2082 else
2083 ret = -EIO;
2084 command_status = FD_COMMAND_NONE;
2085 return ret;
2086}
2087
2088static void generic_done(int result)
2089{
2090 command_status = result;
2091 cont = &wakeup_cont;
2092}
2093
2094static void generic_success(void)
2095{
2096 cont->done(1);
2097}
2098
2099static void generic_failure(void)
2100{
2101 cont->done(0);
2102}
2103
2104static void success_and_wakeup(void)
2105{
2106 generic_success();
2107 cont->redo();
2108}
2109
2110/*
2111 * formatting and rw support.
2112 * ==========================
2113 */
2114
2115static int next_valid_format(void)
2116{
2117 int probed_format;
2118
2119 probed_format = DRS->probed_format;
2120 while (1) {
2121 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2122 DRS->probed_format = 0;
2123 return 1;
2124 }
2125 if (floppy_type[DP->autodetect[probed_format]].sect) {
2126 DRS->probed_format = probed_format;
2127 return 0;
2128 }
2129 probed_format++;
2130 }
2131}
2132
2133static void bad_flp_intr(void)
2134{
2135 int err_count;
2136
2137 if (probing) {
2138 DRS->probed_format++;
2139 if (!next_valid_format())
2140 return;
2141 }
2142 err_count = ++(*errors);
2143 INFBOUND(DRWE->badness, err_count);
2144 if (err_count > DP->max_errors.abort)
2145 cont->done(0);
2146 if (err_count > DP->max_errors.reset)
2147 FDCS->reset = 1;
2148 else if (err_count > DP->max_errors.recal)
2149 DRS->track = NEED_2_RECAL;
2150}
2151
2152static void set_floppy(int drive)
2153{
2154 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002155
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 if (type)
2157 _floppy = floppy_type + type;
2158 else
2159 _floppy = current_type[drive];
2160}
2161
2162/*
2163 * formatting support.
2164 * ===================
2165 */
2166static void format_interrupt(void)
2167{
2168 switch (interpret_errors()) {
2169 case 1:
2170 cont->error();
2171 case 2:
2172 break;
2173 case 0:
2174 cont->done(1);
2175 }
2176 cont->redo();
2177}
2178
2179#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002180#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002182
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183static void setup_format_params(int track)
2184{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002185 int n;
2186 int il;
2187 int count;
2188 int head_shift;
2189 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 struct fparm {
2191 unsigned char track, head, sect, size;
2192 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
2194 raw_cmd = &default_raw_cmd;
2195 raw_cmd->track = track;
2196
Joe Perches48c8cee2010-03-10 15:20:45 -08002197 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2198 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 raw_cmd->rate = _floppy->rate & 0x43;
2200 raw_cmd->cmd_count = NR_F;
2201 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2202 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2203 F_SIZECODE = FD_SIZECODE(_floppy);
2204 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2205 F_GAP = _floppy->fmt_gap;
2206 F_FILL = FD_FILL_BYTE;
2207
2208 raw_cmd->kernel_data = floppy_track_buffer;
2209 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2210
2211 /* allow for about 30ms for data transport per track */
2212 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2213
2214 /* a ``cylinder'' is two tracks plus a little stepping time */
2215 track_shift = 2 * head_shift + 3;
2216
2217 /* position of logical sector 1 on this track */
2218 n = (track_shift * format_req.track + head_shift * format_req.head)
2219 % F_SECT_PER_TRACK;
2220
2221 /* determine interleave */
2222 il = 1;
2223 if (_floppy->fmt_gap < 0x22)
2224 il++;
2225
2226 /* initialize field */
2227 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2228 here[count].track = format_req.track;
2229 here[count].head = format_req.head;
2230 here[count].sect = 0;
2231 here[count].size = F_SIZECODE;
2232 }
2233 /* place logical sectors */
2234 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2235 here[n].sect = count;
2236 n = (n + il) % F_SECT_PER_TRACK;
2237 if (here[n].sect) { /* sector busy, find next free sector */
2238 ++n;
2239 if (n >= F_SECT_PER_TRACK) {
2240 n -= F_SECT_PER_TRACK;
2241 while (here[n].sect)
2242 ++n;
2243 }
2244 }
2245 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002246 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002248 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 }
2250}
2251
2252static void redo_format(void)
2253{
2254 buffer_track = -1;
2255 setup_format_params(format_req.track << STRETCH(_floppy));
2256 floppy_start();
2257 debugt("queue format request");
2258}
2259
2260static struct cont_t format_cont = {
2261 .interrupt = format_interrupt,
2262 .redo = redo_format,
2263 .error = bad_flp_intr,
2264 .done = generic_done
2265};
2266
2267static int do_format(int drive, struct format_descr *tmp_format_req)
2268{
2269 int ret;
2270
2271 LOCK_FDC(drive, 1);
2272 set_floppy(drive);
2273 if (!_floppy ||
2274 _floppy->track > DP->tracks ||
2275 tmp_format_req->track >= _floppy->track ||
2276 tmp_format_req->head >= _floppy->head ||
2277 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2278 !_floppy->fmt_gap) {
2279 process_fd_request();
2280 return -EINVAL;
2281 }
2282 format_req = *tmp_format_req;
2283 format_errors = 0;
2284 cont = &format_cont;
2285 errors = &format_errors;
2286 IWAIT(redo_format);
2287 process_fd_request();
2288 return ret;
2289}
2290
2291/*
2292 * Buffer read/write and support
2293 * =============================
2294 */
2295
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002296static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297{
2298 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002299 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300
2301 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002302 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002303 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002304 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002308 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 current_req = NULL;
2310}
2311
2312/* new request_done. Can handle physical sectors which are smaller than a
2313 * logical buffer */
2314static void request_done(int uptodate)
2315{
2316 struct request_queue *q = floppy_queue;
2317 struct request *req = current_req;
2318 unsigned long flags;
2319 int block;
2320
2321 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002322 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
2324 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002325 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 return;
2327 }
2328
2329 if (uptodate) {
2330 /* maintain values for invalidation on geometry
2331 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002332 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 INFBOUND(DRS->maxblock, block);
2334 if (block > _floppy->sect)
2335 DRS->maxtrack = 1;
2336
2337 /* unlock chained buffers */
2338 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002339 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 spin_unlock_irqrestore(q->queue_lock, flags);
2341 } else {
2342 if (rq_data_dir(req) == WRITE) {
2343 /* record write error information */
2344 DRWE->write_errors++;
2345 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002346 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 DRWE->first_error_generation = DRS->generation;
2348 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002349 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 DRWE->last_error_generation = DRS->generation;
2351 }
2352 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002353 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 spin_unlock_irqrestore(q->queue_lock, flags);
2355 }
2356}
2357
2358/* Interrupt handler evaluating the result of the r/w operation */
2359static void rw_interrupt(void)
2360{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002361 int eoc;
2362 int ssize;
2363 int heads;
2364 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
2366 if (R_HEAD >= 2) {
2367 /* some Toshiba floppy controllers occasionnally seem to
2368 * return bogus interrupts after read/write operations, which
2369 * can be recognized by a bad head number (>= 2) */
2370 return;
2371 }
2372
2373 if (!DRS->first_read_date)
2374 DRS->first_read_date = jiffies;
2375
2376 nr_sectors = 0;
2377 CODE2SIZE;
2378
2379 if (ST1 & ST1_EOC)
2380 eoc = 1;
2381 else
2382 eoc = 0;
2383
2384 if (COMMAND & 0x80)
2385 heads = 2;
2386 else
2387 heads = 1;
2388
2389 nr_sectors = (((R_TRACK - TRACK) * heads +
2390 R_HEAD - HEAD) * SECT_PER_TRACK +
2391 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2392
2393#ifdef FLOPPY_SANITY_CHECK
2394 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002395 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 DPRINT("long rw: %x instead of %lx\n",
2397 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002398 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2399 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2400 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2401 pr_info("heads=%d eoc=%d\n", heads, eoc);
2402 pr_info("spt=%d st=%d ss=%d\n",
2403 SECT_PER_TRACK, fsector_t, ssize);
2404 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 }
2406#endif
2407
2408 nr_sectors -= in_sector_offset;
2409 INFBOUND(nr_sectors, 0);
2410 SUPBOUND(current_count_sectors, nr_sectors);
2411
2412 switch (interpret_errors()) {
2413 case 2:
2414 cont->redo();
2415 return;
2416 case 1:
2417 if (!current_count_sectors) {
2418 cont->error();
2419 cont->redo();
2420 return;
2421 }
2422 break;
2423 case 0:
2424 if (!current_count_sectors) {
2425 cont->redo();
2426 return;
2427 }
2428 current_type[current_drive] = _floppy;
2429 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2430 break;
2431 }
2432
2433 if (probing) {
2434 if (DP->flags & FTD_MSG)
2435 DPRINT("Auto-detected floppy type %s in fd%d\n",
2436 _floppy->name, current_drive);
2437 current_type[current_drive] = _floppy;
2438 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2439 probing = 0;
2440 }
2441
2442 if (CT(COMMAND) != FD_READ ||
2443 raw_cmd->kernel_data == current_req->buffer) {
2444 /* transfer directly from buffer */
2445 cont->done(1);
2446 } else if (CT(COMMAND) == FD_READ) {
2447 buffer_track = raw_cmd->track;
2448 buffer_drive = current_drive;
2449 INFBOUND(buffer_max, nr_sectors + fsector_t);
2450 }
2451 cont->redo();
2452}
2453
2454/* Compute maximal contiguous buffer size. */
2455static int buffer_chain_size(void)
2456{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002458 int size;
2459 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 char *base;
2461
2462 base = bio_data(current_req->bio);
2463 size = 0;
2464
NeilBrown5705f702007-09-25 12:35:59 +02002465 rq_for_each_segment(bv, current_req, iter) {
2466 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468
NeilBrown5705f702007-09-25 12:35:59 +02002469 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 }
2471
2472 return size >> 9;
2473}
2474
2475/* Compute the maximal transfer size */
2476static int transfer_size(int ssize, int max_sector, int max_size)
2477{
2478 SUPBOUND(max_sector, fsector_t + max_size);
2479
2480 /* alignment */
2481 max_sector -= (max_sector % _floppy->sect) % ssize;
2482
2483 /* transfer size, beginning not aligned */
2484 current_count_sectors = max_sector - fsector_t;
2485
2486 return max_sector;
2487}
2488
2489/*
2490 * Move data from/to the track buffer to/from the buffer cache.
2491 */
2492static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2493{
2494 int remaining; /* number of transferred 512-byte sectors */
2495 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002496 char *buffer;
2497 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002498 int size;
2499 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
2501 max_sector = transfer_size(ssize,
2502 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002503 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
2505 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002506 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002508 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
2510 remaining = current_count_sectors << 9;
2511#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002512 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002514 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2515 pr_info("remaining=%d\n", remaining >> 9);
2516 pr_info("current_req->nr_sectors=%u\n",
2517 blk_rq_sectors(current_req));
2518 pr_info("current_req->current_nr_sectors=%u\n",
2519 blk_rq_cur_sectors(current_req));
2520 pr_info("max_sector=%d\n", max_sector);
2521 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
2523#endif
2524
2525 buffer_max = max(max_sector, buffer_max);
2526
2527 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2528
Tejun Heo1011c1b2009-05-07 22:24:45 +09002529 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
NeilBrown5705f702007-09-25 12:35:59 +02002531 rq_for_each_segment(bv, current_req, iter) {
2532 if (!remaining)
2533 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
NeilBrown5705f702007-09-25 12:35:59 +02002535 size = bv->bv_len;
2536 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
NeilBrown5705f702007-09-25 12:35:59 +02002538 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002540 if (dma_buffer + size >
2541 floppy_track_buffer + (max_buffer_sectors << 10) ||
2542 dma_buffer < floppy_track_buffer) {
2543 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002544 (int)((floppy_track_buffer - dma_buffer) >> 9));
2545 pr_info("fsector_t=%d buffer_min=%d\n",
2546 fsector_t, buffer_min);
2547 pr_info("current_count_sectors=%ld\n",
2548 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002550 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002551 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002552 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002553 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 }
NeilBrown5705f702007-09-25 12:35:59 +02002555 if (((unsigned long)buffer) % 512)
2556 DPRINT("%p buffer not aligned\n", buffer);
2557#endif
2558 if (CT(COMMAND) == FD_READ)
2559 memcpy(buffer, dma_buffer, size);
2560 else
2561 memcpy(dma_buffer, buffer, size);
2562
2563 remaining -= size;
2564 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 }
2566#ifdef FLOPPY_SANITY_CHECK
2567 if (remaining) {
2568 if (remaining > 0)
2569 max_sector -= remaining >> 9;
2570 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2571 }
2572#endif
2573}
2574
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575/* work around a bug in pseudo DMA
2576 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2577 * sending data. Hence we need a different way to signal the
2578 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2579 * does not work with MT, hence we can only transfer one head at
2580 * a time
2581 */
2582static void virtualdmabug_workaround(void)
2583{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002584 int hard_sectors;
2585 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 if (CT(COMMAND) == FD_WRITE) {
2588 COMMAND &= ~0x80; /* switch off multiple track mode */
2589
2590 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2591 end_sector = SECTOR + hard_sectors - 1;
2592#ifdef FLOPPY_SANITY_CHECK
2593 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002594 pr_info("too many sectors %d > %d\n",
2595 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 return;
2597 }
2598#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002599 SECT_PER_TRACK = end_sector;
2600 /* make sure SECT_PER_TRACK
2601 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 }
2603}
2604
2605/*
2606 * Formulate a read/write request.
2607 * this routine decides where to load the data (directly to buffer, or to
2608 * tmp floppy area), how much data to load (the size of the buffer, the whole
2609 * track, or a single sector)
2610 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2611 * allocation on the fly, it should be done here. No other part should need
2612 * modification.
2613 */
2614
2615static int make_raw_rw_request(void)
2616{
2617 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002618 int max_sector;
2619 int max_size;
2620 int tracksize;
2621 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
2623 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002624 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 return 0;
2626 }
2627
2628 set_fdc((long)current_req->rq_disk->private_data);
2629
2630 raw_cmd = &default_raw_cmd;
2631 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2632 FD_RAW_NEED_SEEK;
2633 raw_cmd->cmd_count = NR_RW;
2634 if (rq_data_dir(current_req) == READ) {
2635 raw_cmd->flags |= FD_RAW_READ;
2636 COMMAND = FM_MODE(_floppy, FD_READ);
2637 } else if (rq_data_dir(current_req) == WRITE) {
2638 raw_cmd->flags |= FD_RAW_WRITE;
2639 COMMAND = FM_MODE(_floppy, FD_WRITE);
2640 } else {
2641 DPRINT("make_raw_rw_request: unknown command\n");
2642 return 0;
2643 }
2644
2645 max_sector = _floppy->sect * _floppy->head;
2646
Tejun Heo83096eb2009-05-07 22:24:39 +09002647 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2648 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002650 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 current_count_sectors = 1;
2652 return 1;
2653 } else
2654 return 0;
2655 }
2656 HEAD = fsector_t / _floppy->sect;
2657
Keith Wansbrough9e491842008-09-22 14:57:17 -07002658 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2660 max_sector = _floppy->sect;
2661
2662 /* 2M disks have phantom sectors on the first track */
2663 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2664 max_sector = 2 * _floppy->sect / 3;
2665 if (fsector_t >= max_sector) {
2666 current_count_sectors =
2667 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002668 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 return 1;
2670 }
2671 SIZECODE = 2;
2672 } else
2673 SIZECODE = FD_SIZECODE(_floppy);
2674 raw_cmd->rate = _floppy->rate & 0x43;
2675 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2676 raw_cmd->rate = 1;
2677
2678 if (SIZECODE)
2679 SIZECODE2 = 0xff;
2680 else
2681 SIZECODE2 = 0x80;
2682 raw_cmd->track = TRACK << STRETCH(_floppy);
2683 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2684 GAP = _floppy->gap;
2685 CODE2SIZE;
2686 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2687 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002688 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
2690 /* tracksize describes the size which can be filled up with sectors
2691 * of size ssize.
2692 */
2693 tracksize = _floppy->sect - _floppy->sect % ssize;
2694 if (tracksize < _floppy->sect) {
2695 SECT_PER_TRACK++;
2696 if (tracksize <= fsector_t % _floppy->sect)
2697 SECTOR--;
2698
2699 /* if we are beyond tracksize, fill up using smaller sectors */
2700 while (tracksize <= fsector_t % _floppy->sect) {
2701 while (tracksize + ssize > _floppy->sect) {
2702 SIZECODE--;
2703 ssize >>= 1;
2704 }
2705 SECTOR++;
2706 SECT_PER_TRACK++;
2707 tracksize += ssize;
2708 }
2709 max_sector = HEAD * _floppy->sect + tracksize;
2710 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2711 max_sector = _floppy->sect;
2712 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2713 /* for virtual DMA bug workaround */
2714 max_sector = _floppy->sect;
2715 }
2716
2717 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2718 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002719 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 if ((raw_cmd->track == buffer_track) &&
2721 (current_drive == buffer_drive) &&
2722 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2723 /* data already in track buffer */
2724 if (CT(COMMAND) == FD_READ) {
2725 copy_buffer(1, max_sector, buffer_max);
2726 return 1;
2727 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002728 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 if (CT(COMMAND) == FD_WRITE) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002730 if (fsector_t + blk_rq_sectors(current_req) > ssize &&
2731 fsector_t + blk_rq_sectors(current_req) < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 max_size = ssize + ssize;
2733 else
2734 max_size = ssize;
2735 }
2736 raw_cmd->flags &= ~FD_RAW_WRITE;
2737 raw_cmd->flags |= FD_RAW_READ;
2738 COMMAND = FM_MODE(_floppy, FD_READ);
2739 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2740 unsigned long dma_limit;
2741 int direct, indirect;
2742
2743 indirect =
2744 transfer_size(ssize, max_sector,
2745 max_buffer_sectors * 2) - fsector_t;
2746
2747 /*
2748 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2749 * on a 64 bit machine!
2750 */
2751 max_size = buffer_chain_size();
2752 dma_limit =
2753 (MAX_DMA_ADDRESS -
2754 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002755 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 /* 64 kb boundaries */
2758 if (CROSS_64KB(current_req->buffer, max_size << 9))
2759 max_size = (K_64 -
2760 ((unsigned long)current_req->buffer) %
2761 K_64) >> 9;
2762 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2763 /*
2764 * We try to read tracks, but if we get too many errors, we
2765 * go back to reading just one sector at a time.
2766 *
2767 * This means we should be able to read a sector even if there
2768 * are other bad sectors on this track.
2769 */
2770 if (!direct ||
2771 (indirect * 2 > direct * 3 &&
Jesper Juhlaee90412007-10-16 23:30:58 -07002772 *errors < DP->max_errors.read_track && ((!probing
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 || (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002774 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 } else {
2776 raw_cmd->kernel_data = current_req->buffer;
2777 raw_cmd->length = current_count_sectors << 9;
2778 if (raw_cmd->length == 0) {
2779 DPRINT
2780 ("zero dma transfer attempted from make_raw_request\n");
2781 DPRINT("indirect=%d direct=%d fsector_t=%d",
2782 indirect, direct, fsector_t);
2783 return 0;
2784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 virtualdmabug_workaround();
2786 return 2;
2787 }
2788 }
2789
2790 if (CT(COMMAND) == FD_READ)
2791 max_size = max_sector; /* unbounded */
2792
2793 /* claim buffer track if needed */
2794 if (buffer_track != raw_cmd->track || /* bad track */
2795 buffer_drive != current_drive || /* bad drive */
2796 fsector_t > buffer_max ||
2797 fsector_t < buffer_min ||
2798 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002799 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 max_sector > 2 * max_buffer_sectors + buffer_min &&
2801 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
2802 /* not enough space */
2803 ) {
2804 buffer_track = -1;
2805 buffer_drive = current_drive;
2806 buffer_max = buffer_min = aligned_sector_t;
2807 }
2808 raw_cmd->kernel_data = floppy_track_buffer +
2809 ((aligned_sector_t - buffer_min) << 9);
2810
2811 if (CT(COMMAND) == FD_WRITE) {
2812 /* copy write buffer to track buffer.
2813 * if we get here, we know that the write
2814 * is either aligned or the data already in the buffer
2815 * (buffer will be overwritten) */
2816#ifdef FLOPPY_SANITY_CHECK
2817 if (in_sector_offset && buffer_track == -1)
2818 DPRINT("internal error offset !=0 on write\n");
2819#endif
2820 buffer_track = raw_cmd->track;
2821 buffer_drive = current_drive;
2822 copy_buffer(ssize, max_sector,
2823 2 * max_buffer_sectors + buffer_min);
2824 } else
2825 transfer_size(ssize, max_sector,
2826 2 * max_buffer_sectors + buffer_min -
2827 aligned_sector_t);
2828
2829 /* round up current_count_sectors to get dma xfer size */
2830 raw_cmd->length = in_sector_offset + current_count_sectors;
2831 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2832 raw_cmd->length <<= 9;
2833#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 if ((raw_cmd->length < current_count_sectors << 9) ||
2835 (raw_cmd->kernel_data != current_req->buffer &&
2836 CT(COMMAND) == FD_WRITE &&
2837 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2838 aligned_sector_t < buffer_min)) ||
2839 raw_cmd->length % (128 << SIZECODE) ||
2840 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2841 DPRINT("fractionary current count b=%lx s=%lx\n",
2842 raw_cmd->length, current_count_sectors);
2843 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002844 pr_info("addr=%d, length=%ld\n",
2845 (int)((raw_cmd->kernel_data -
2846 floppy_track_buffer) >> 9),
2847 current_count_sectors);
2848 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2849 fsector_t, aligned_sector_t, max_sector, max_size);
2850 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2851 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2852 COMMAND, SECTOR, HEAD, TRACK);
2853 pr_info("buffer drive=%d\n", buffer_drive);
2854 pr_info("buffer track=%d\n", buffer_track);
2855 pr_info("buffer_min=%d\n", buffer_min);
2856 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 return 0;
2858 }
2859
2860 if (raw_cmd->kernel_data != current_req->buffer) {
2861 if (raw_cmd->kernel_data < floppy_track_buffer ||
2862 current_count_sectors < 0 ||
2863 raw_cmd->length < 0 ||
2864 raw_cmd->kernel_data + raw_cmd->length >
2865 floppy_track_buffer + (max_buffer_sectors << 10)) {
2866 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002867 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2868 fsector_t, buffer_min, raw_cmd->length >> 9);
2869 pr_info("current_count_sectors=%ld\n",
2870 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002872 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002874 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 return 0;
2876 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002877 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002878 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 DPRINT("buffer overrun in direct transfer\n");
2880 return 0;
2881 } else if (raw_cmd->length < current_count_sectors << 9) {
2882 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002883 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2884 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 }
2886 if (raw_cmd->length == 0) {
2887 DPRINT("zero dma transfer attempted from make_raw_request\n");
2888 return 0;
2889 }
2890#endif
2891
2892 virtualdmabug_workaround();
2893 return 2;
2894}
2895
2896static void redo_fd_request(void)
2897{
2898#define REPEAT {request_done(0); continue; }
2899 int drive;
2900 int tmp;
2901
2902 lastredo = jiffies;
2903 if (current_drive < N_DRIVE)
2904 floppy_off(current_drive);
2905
2906 for (;;) {
2907 if (!current_req) {
2908 struct request *req;
2909
2910 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002911 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 spin_unlock_irq(floppy_queue->queue_lock);
2913 if (!req) {
2914 do_floppy = NULL;
2915 unlock_fdc();
2916 return;
2917 }
2918 current_req = req;
2919 }
2920 drive = (long)current_req->rq_disk->private_data;
2921 set_fdc(drive);
2922 reschedule_timeout(current_reqD, "redo fd request", 0);
2923
2924 set_floppy(drive);
2925 raw_cmd = &default_raw_cmd;
2926 raw_cmd->flags = 0;
2927 if (start_motor(redo_fd_request))
2928 return;
2929 disk_change(current_drive);
2930 if (test_bit(current_drive, &fake_change) ||
2931 TESTF(FD_DISK_CHANGED)) {
2932 DPRINT("disk absent or changed during operation\n");
2933 REPEAT;
2934 }
2935 if (!_floppy) { /* Autodetection */
2936 if (!probing) {
2937 DRS->probed_format = 0;
2938 if (next_valid_format()) {
2939 DPRINT("no autodetectable formats\n");
2940 _floppy = NULL;
2941 REPEAT;
2942 }
2943 }
2944 probing = 1;
2945 _floppy =
2946 floppy_type + DP->autodetect[DRS->probed_format];
2947 } else
2948 probing = 0;
2949 errors = &(current_req->errors);
2950 tmp = make_raw_rw_request();
2951 if (tmp < 2) {
2952 request_done(tmp);
2953 continue;
2954 }
2955
2956 if (TESTF(FD_NEED_TWADDLE))
2957 twaddle();
2958 schedule_bh(floppy_start);
2959 debugt("queue fd request");
2960 return;
2961 }
2962#undef REPEAT
2963}
2964
2965static struct cont_t rw_cont = {
2966 .interrupt = rw_interrupt,
2967 .redo = redo_fd_request,
2968 .error = bad_flp_intr,
2969 .done = request_done
2970};
2971
2972static void process_fd_request(void)
2973{
2974 cont = &rw_cont;
2975 schedule_bh(redo_fd_request);
2976}
2977
Jens Axboe165125e2007-07-24 09:28:11 +02002978static void do_fd_request(struct request_queue * q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979{
2980 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002981 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 return;
2983 }
2984
2985 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002986 pr_info("warning: usage count=0, current_req=%p exiting\n",
2987 current_req);
2988 pr_info("sect=%ld type=%x flags=%x\n",
2989 (long)blk_rq_pos(current_req), current_req->cmd_type,
2990 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 return;
2992 }
2993 if (test_bit(0, &fdc_busy)) {
2994 /* fdc busy, this new request will be treated when the
2995 current one is done */
2996 is_alive("do fd request, old request running");
2997 return;
2998 }
2999 lock_fdc(MAXTIMEOUT, 0);
3000 process_fd_request();
3001 is_alive("do fd request");
3002}
3003
3004static struct cont_t poll_cont = {
3005 .interrupt = success_and_wakeup,
3006 .redo = floppy_ready,
3007 .error = generic_failure,
3008 .done = generic_done
3009};
3010
3011static int poll_drive(int interruptible, int flag)
3012{
3013 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003014
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 /* no auto-sense, just clear dcl */
3016 raw_cmd = &default_raw_cmd;
3017 raw_cmd->flags = flag;
3018 raw_cmd->track = 0;
3019 raw_cmd->cmd_count = 0;
3020 cont = &poll_cont;
3021#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003022 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 DPRINT("setting NEWCHANGE in poll_drive\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024#endif
3025 SETF(FD_DISK_NEWCHANGE);
3026 WAIT(floppy_ready);
3027 return ret;
3028}
3029
3030/*
3031 * User triggered reset
3032 * ====================
3033 */
3034
3035static void reset_intr(void)
3036{
Joe Perchesb46df352010-03-10 15:20:46 -08003037 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038}
3039
3040static struct cont_t reset_cont = {
3041 .interrupt = reset_intr,
3042 .redo = success_and_wakeup,
3043 .error = generic_failure,
3044 .done = generic_done
3045};
3046
3047static int user_reset_fdc(int drive, int arg, int interruptible)
3048{
3049 int ret;
3050
3051 ret = 0;
3052 LOCK_FDC(drive, interruptible);
3053 if (arg == FD_RESET_ALWAYS)
3054 FDCS->reset = 1;
3055 if (FDCS->reset) {
3056 cont = &reset_cont;
3057 WAIT(reset_fdc);
3058 }
3059 process_fd_request();
3060 return ret;
3061}
3062
3063/*
3064 * Misc Ioctl's and support
3065 * ========================
3066 */
3067static inline int fd_copyout(void __user *param, const void *address,
3068 unsigned long size)
3069{
3070 return copy_to_user(param, address, size) ? -EFAULT : 0;
3071}
3072
Joe Perches48c8cee2010-03-10 15:20:45 -08003073static inline int fd_copyin(void __user *param, void *address,
3074 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075{
3076 return copy_from_user(address, param, size) ? -EFAULT : 0;
3077}
3078
Joe Perches48c8cee2010-03-10 15:20:45 -08003079#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3080 ? -EFAULT : 0)
3081#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3082 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
Joe Perches48c8cee2010-03-10 15:20:45 -08003084#define COPYOUT(x) ECALL(_COPYOUT(x))
3085#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
3087static inline const char *drive_name(int type, int drive)
3088{
3089 struct floppy_struct *floppy;
3090
3091 if (type)
3092 floppy = floppy_type + type;
3093 else {
3094 if (UDP->native_format)
3095 floppy = floppy_type + UDP->native_format;
3096 else
3097 return "(null)";
3098 }
3099 if (floppy->name)
3100 return floppy->name;
3101 else
3102 return "(null)";
3103}
3104
3105/* raw commands */
3106static void raw_cmd_done(int flag)
3107{
3108 int i;
3109
3110 if (!flag) {
3111 raw_cmd->flags |= FD_RAW_FAILURE;
3112 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3113 } else {
3114 raw_cmd->reply_count = inr;
3115 if (raw_cmd->reply_count > MAX_REPLIES)
3116 raw_cmd->reply_count = 0;
3117 for (i = 0; i < raw_cmd->reply_count; i++)
3118 raw_cmd->reply[i] = reply_buffer[i];
3119
3120 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3121 unsigned long flags;
3122 flags = claim_dma_lock();
3123 raw_cmd->length = fd_get_dma_residue();
3124 release_dma_lock(flags);
3125 }
3126
3127 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3128 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3129 raw_cmd->flags |= FD_RAW_FAILURE;
3130
3131 if (disk_change(current_drive))
3132 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3133 else
3134 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3135 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3136 motor_off_callback(current_drive);
3137
3138 if (raw_cmd->next &&
3139 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3140 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3141 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3142 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3143 raw_cmd = raw_cmd->next;
3144 return;
3145 }
3146 }
3147 generic_done(flag);
3148}
3149
3150static struct cont_t raw_cmd_cont = {
3151 .interrupt = success_and_wakeup,
3152 .redo = floppy_start,
3153 .error = generic_failure,
3154 .done = raw_cmd_done
3155};
3156
3157static inline int raw_cmd_copyout(int cmd, char __user *param,
3158 struct floppy_raw_cmd *ptr)
3159{
3160 int ret;
3161
3162 while (ptr) {
3163 COPYOUT(*ptr);
3164 param += sizeof(struct floppy_raw_cmd);
3165 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
3166 if (ptr->length >= 0
3167 && ptr->length <= ptr->buffer_length)
3168 ECALL(fd_copyout
3169 (ptr->data, ptr->kernel_data,
3170 ptr->buffer_length - ptr->length));
3171 }
3172 ptr = ptr->next;
3173 }
3174 return 0;
3175}
3176
3177static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3178{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003179 struct floppy_raw_cmd *next;
3180 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181
3182 this = *ptr;
3183 *ptr = NULL;
3184 while (this) {
3185 if (this->buffer_length) {
3186 fd_dma_mem_free((unsigned long)this->kernel_data,
3187 this->buffer_length);
3188 this->buffer_length = 0;
3189 }
3190 next = this->next;
3191 kfree(this);
3192 this = next;
3193 }
3194}
3195
3196static inline int raw_cmd_copyin(int cmd, char __user *param,
3197 struct floppy_raw_cmd **rcmd)
3198{
3199 struct floppy_raw_cmd *ptr;
3200 int ret;
3201 int i;
3202
3203 *rcmd = NULL;
3204 while (1) {
3205 ptr = (struct floppy_raw_cmd *)
3206 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3207 if (!ptr)
3208 return -ENOMEM;
3209 *rcmd = ptr;
3210 COPYIN(*ptr);
3211 ptr->next = NULL;
3212 ptr->buffer_length = 0;
3213 param += sizeof(struct floppy_raw_cmd);
3214 if (ptr->cmd_count > 33)
3215 /* the command may now also take up the space
3216 * initially intended for the reply & the
3217 * reply count. Needed for long 82078 commands
3218 * such as RESTORE, which takes ... 17 command
3219 * bytes. Murphy's law #137: When you reserve
3220 * 16 bytes for a structure, you'll one day
3221 * discover that you really need 17...
3222 */
3223 return -EINVAL;
3224
3225 for (i = 0; i < 16; i++)
3226 ptr->reply[i] = 0;
3227 ptr->resultcode = 0;
3228 ptr->kernel_data = NULL;
3229
3230 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3231 if (ptr->length <= 0)
3232 return -EINVAL;
3233 ptr->kernel_data =
3234 (char *)fd_dma_mem_alloc(ptr->length);
3235 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3236 if (!ptr->kernel_data)
3237 return -ENOMEM;
3238 ptr->buffer_length = ptr->length;
3239 }
3240 if (ptr->flags & FD_RAW_WRITE)
3241 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3242 ptr->length));
3243 rcmd = &(ptr->next);
3244 if (!(ptr->flags & FD_RAW_MORE))
3245 return 0;
3246 ptr->rate &= 0x43;
3247 }
3248}
3249
3250static int raw_cmd_ioctl(int cmd, void __user *param)
3251{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003253 int drive;
3254 int ret2;
3255 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256
3257 if (FDCS->rawcmd <= 1)
3258 FDCS->rawcmd = 1;
3259 for (drive = 0; drive < N_DRIVE; drive++) {
3260 if (FDC(drive) != fdc)
3261 continue;
3262 if (drive == current_drive) {
3263 if (UDRS->fd_ref > 1) {
3264 FDCS->rawcmd = 2;
3265 break;
3266 }
3267 } else if (UDRS->fd_ref) {
3268 FDCS->rawcmd = 2;
3269 break;
3270 }
3271 }
3272
3273 if (FDCS->reset)
3274 return -EIO;
3275
3276 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3277 if (ret) {
3278 raw_cmd_free(&my_raw_cmd);
3279 return ret;
3280 }
3281
3282 raw_cmd = my_raw_cmd;
3283 cont = &raw_cmd_cont;
3284 ret = wait_til_done(floppy_start, 1);
3285#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003286 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 DPRINT("calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288#endif
3289
3290 if (ret != -EINTR && FDCS->reset)
3291 ret = -EIO;
3292
3293 DRS->track = NO_TRACK;
3294
3295 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3296 if (!ret)
3297 ret = ret2;
3298 raw_cmd_free(&my_raw_cmd);
3299 return ret;
3300}
3301
3302static int invalidate_drive(struct block_device *bdev)
3303{
3304 /* invalidate the buffer track to force a reread */
3305 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3306 process_fd_request();
3307 check_disk_change(bdev);
3308 return 0;
3309}
3310
3311static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3312 int drive, int type, struct block_device *bdev)
3313{
3314 int cnt;
3315
3316 /* sanity checking for parameters. */
3317 if (g->sect <= 0 ||
3318 g->head <= 0 ||
3319 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3320 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003321 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 return -EINVAL;
3323 if (type) {
3324 if (!capable(CAP_SYS_ADMIN))
3325 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003326 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003327 if (lock_fdc(drive, 1)) {
3328 mutex_unlock(&open_lock);
3329 return -EINTR;
3330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 floppy_type[type] = *g;
3332 floppy_type[type].name = "user format";
3333 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3334 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3335 floppy_type[type].size + 1;
3336 process_fd_request();
3337 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3338 struct block_device *bdev = opened_bdev[cnt];
3339 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3340 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003341 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003343 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 } else {
3345 int oldStretch;
3346 LOCK_FDC(drive, 1);
3347 if (cmd != FDDEFPRM)
3348 /* notice a disk change immediately, else
3349 * we lose our settings immediately*/
3350 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3351 oldStretch = g->stretch;
3352 user_params[drive] = *g;
3353 if (buffer_drive == drive)
3354 SUPBOUND(buffer_max, user_params[drive].sect);
3355 current_type[drive] = &user_params[drive];
3356 floppy_sizes[drive] = user_params[drive].size;
3357 if (cmd == FDDEFPRM)
3358 DRS->keep_data = -1;
3359 else
3360 DRS->keep_data = 1;
3361 /* invalidation. Invalidate only when needed, i.e.
3362 * when there are already sectors in the buffer cache
3363 * whose number will change. This is useful, because
3364 * mtools often changes the geometry of the disk after
3365 * looking at the boot block */
3366 if (DRS->maxblock > user_params[drive].sect ||
3367 DRS->maxtrack ||
3368 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003369 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 invalidate_drive(bdev);
3371 else
3372 process_fd_request();
3373 }
3374 return 0;
3375}
3376
3377/* handle obsolete ioctl's */
3378static int ioctl_table[] = {
3379 FDCLRPRM,
3380 FDSETPRM,
3381 FDDEFPRM,
3382 FDGETPRM,
3383 FDMSGON,
3384 FDMSGOFF,
3385 FDFMTBEG,
3386 FDFMTTRK,
3387 FDFMTEND,
3388 FDSETEMSGTRESH,
3389 FDFLUSH,
3390 FDSETMAXERRS,
3391 FDGETMAXERRS,
3392 FDGETDRVTYP,
3393 FDSETDRVPRM,
3394 FDGETDRVPRM,
3395 FDGETDRVSTAT,
3396 FDPOLLDRVSTAT,
3397 FDRESET,
3398 FDGETFDCSTAT,
3399 FDWERRORCLR,
3400 FDWERRORGET,
3401 FDRAWCMD,
3402 FDEJECT,
3403 FDTWADDLE
3404};
3405
3406static inline int normalize_ioctl(int *cmd, int *size)
3407{
3408 int i;
3409
3410 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3411 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3412 *size = _IOC_SIZE(*cmd);
3413 *cmd = ioctl_table[i];
3414 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003415 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 return -EFAULT;
3417 }
3418 return 0;
3419 }
3420 }
3421 return -EINVAL;
3422}
3423
3424static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3425{
3426 if (type)
3427 *g = &floppy_type[type];
3428 else {
3429 LOCK_FDC(drive, 0);
3430 CALL(poll_drive(0, 0));
3431 process_fd_request();
3432 *g = current_type[drive];
3433 }
3434 if (!*g)
3435 return -ENODEV;
3436 return 0;
3437}
3438
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003439static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3440{
3441 int drive = (long)bdev->bd_disk->private_data;
3442 int type = ITYPE(drive_state[drive].fd_device);
3443 struct floppy_struct *g;
3444 int ret;
3445
3446 ret = get_floppy_geometry(drive, type, &g);
3447 if (ret)
3448 return ret;
3449
3450 geo->heads = g->head;
3451 geo->sectors = g->sect;
3452 geo->cylinders = g->track;
3453 return 0;
3454}
3455
Al Viroa4af9b42008-03-02 09:27:55 -05003456static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 unsigned long param)
3458{
Al Viroa4af9b42008-03-02 09:27:55 -05003459#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460#define OUT(c,x) case c: outparam = (const char *) (x); break
3461#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
3462
Al Viroa4af9b42008-03-02 09:27:55 -05003463 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003464 int type = ITYPE(UDRS->fd_device);
3465 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 int ret;
3467 int size;
3468 union inparam {
3469 struct floppy_struct g; /* geometry */
3470 struct format_descr f;
3471 struct floppy_max_errors max_errors;
3472 struct floppy_drive_params dp;
3473 } inparam; /* parameters coming from user space */
3474 const char *outparam; /* parameters passed back to user space */
3475
3476 /* convert compatibility eject ioctls into floppy eject ioctl.
3477 * We do this in order to provide a means to eject floppy disks before
3478 * installing the new fdutils package */
3479 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003480 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 DPRINT("obsolete eject ioctl\n");
3482 DPRINT("please use floppycontrol --eject\n");
3483 cmd = FDEJECT;
3484 }
3485
Joe Perchesa81ee542010-03-10 15:20:46 -08003486 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 return -EINVAL;
3488
Joe Perchesa81ee542010-03-10 15:20:46 -08003489 /* convert the old style command into a new style command */
3490 ECALL(normalize_ioctl(&cmd, &size));
3491
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 /* permission checks */
3493 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3494 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3495 return -EPERM;
3496
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003497 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3498 return -EINVAL;
3499
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 /* copyin */
3501 CLEARSTRUCT(&inparam);
3502 if (_IOC_DIR(cmd) & _IOC_WRITE)
3503 ECALL(fd_copyin((void __user *)param, &inparam, size))
3504
3505 switch (cmd) {
3506 case FDEJECT:
3507 if (UDRS->fd_ref != 1)
3508 /* somebody else has this drive open */
3509 return -EBUSY;
3510 LOCK_FDC(drive, 1);
3511
3512 /* do the actual eject. Fails on
3513 * non-Sparc architectures */
3514 ret = fd_eject(UNIT(drive));
3515
3516 USETF(FD_DISK_CHANGED);
3517 USETF(FD_VERIFY);
3518 process_fd_request();
3519 return ret;
3520 case FDCLRPRM:
3521 LOCK_FDC(drive, 1);
3522 current_type[drive] = NULL;
3523 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3524 UDRS->keep_data = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003525 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 case FDSETPRM:
3527 case FDDEFPRM:
3528 return set_geometry(cmd, &inparam.g,
Al Viroa4af9b42008-03-02 09:27:55 -05003529 drive, type, bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 case FDGETPRM:
3531 ECALL(get_floppy_geometry(drive, type,
3532 (struct floppy_struct **)
3533 &outparam));
3534 break;
3535
3536 case FDMSGON:
3537 UDP->flags |= FTD_MSG;
3538 return 0;
3539 case FDMSGOFF:
3540 UDP->flags &= ~FTD_MSG;
3541 return 0;
3542
3543 case FDFMTBEG:
3544 LOCK_FDC(drive, 1);
3545 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3546 ret = UDRS->flags;
3547 process_fd_request();
3548 if (ret & FD_VERIFY)
3549 return -ENODEV;
3550 if (!(ret & FD_DISK_WRITABLE))
3551 return -EROFS;
3552 return 0;
3553 case FDFMTTRK:
3554 if (UDRS->fd_ref != 1)
3555 return -EBUSY;
3556 return do_format(drive, &inparam.f);
3557 case FDFMTEND:
3558 case FDFLUSH:
3559 LOCK_FDC(drive, 1);
Al Viroa4af9b42008-03-02 09:27:55 -05003560 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
3562 case FDSETEMSGTRESH:
3563 UDP->max_errors.reporting =
3564 (unsigned short)(param & 0x0f);
3565 return 0;
3566 OUT(FDGETMAXERRS, &UDP->max_errors);
3567 IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
3568
3569 case FDGETDRVTYP:
3570 outparam = drive_name(type, drive);
3571 SUPBOUND(size, strlen(outparam) + 1);
3572 break;
3573
3574 IN(FDSETDRVPRM, UDP, dp);
3575 OUT(FDGETDRVPRM, UDP);
3576
3577 case FDPOLLDRVSTAT:
3578 LOCK_FDC(drive, 1);
3579 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3580 process_fd_request();
3581 /* fall through */
3582 OUT(FDGETDRVSTAT, UDRS);
3583
3584 case FDRESET:
3585 return user_reset_fdc(drive, (int)param, 1);
3586
3587 OUT(FDGETFDCSTAT, UFDCS);
3588
3589 case FDWERRORCLR:
3590 CLEARSTRUCT(UDRWE);
3591 return 0;
3592 OUT(FDWERRORGET, UDRWE);
3593
3594 case FDRAWCMD:
3595 if (type)
3596 return -EINVAL;
3597 LOCK_FDC(drive, 1);
3598 set_floppy(drive);
3599 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3600 process_fd_request();
3601 return i;
3602
3603 case FDTWADDLE:
3604 LOCK_FDC(drive, 1);
3605 twaddle();
3606 process_fd_request();
3607 return 0;
3608
3609 default:
3610 return -EINVAL;
3611 }
3612
3613 if (_IOC_DIR(cmd) & _IOC_READ)
3614 return fd_copyout((void __user *)param, outparam, size);
3615 else
3616 return 0;
3617#undef OUT
3618#undef IN
3619}
3620
3621static void __init config_types(void)
3622{
Joe Perchesb46df352010-03-10 15:20:46 -08003623 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 int drive;
3625
3626 /* read drive info out of physical CMOS */
3627 drive = 0;
3628 if (!UDP->cmos)
3629 UDP->cmos = FLOPPY0_TYPE;
3630 drive = 1;
3631 if (!UDP->cmos && FLOPPY1_TYPE)
3632 UDP->cmos = FLOPPY1_TYPE;
3633
Jesper Juhl06f748c2007-10-16 23:30:57 -07003634 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635
3636 for (drive = 0; drive < N_DRIVE; drive++) {
3637 unsigned int type = UDP->cmos;
3638 struct floppy_drive_params *params;
3639 const char *name = NULL;
3640 static char temparea[32];
3641
Tobias Klauser945f3902006-01-08 01:05:11 -08003642 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 params = &default_drive_params[type].params;
3644 if (type) {
3645 name = default_drive_params[type].name;
3646 allowed_drive_mask |= 1 << drive;
3647 } else
3648 allowed_drive_mask &= ~(1 << drive);
3649 } else {
3650 params = &default_drive_params[0].params;
3651 sprintf(temparea, "unknown type %d (usb?)", type);
3652 name = temparea;
3653 }
3654 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003655 const char *prepend;
3656 if (!has_drive) {
3657 prepend = "";
3658 has_drive = true;
3659 pr_info("Floppy drive(s):");
3660 } else {
3661 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 }
Joe Perchesb46df352010-03-10 15:20:46 -08003663
3664 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 }
3666 *UDP = *params;
3667 }
Joe Perchesb46df352010-03-10 15:20:46 -08003668
3669 if (has_drive)
3670 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671}
3672
Al Viroa4af9b42008-03-02 09:27:55 -05003673static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674{
Al Viroa4af9b42008-03-02 09:27:55 -05003675 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003677 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 if (UDRS->fd_ref < 0)
3679 UDRS->fd_ref = 0;
3680 else if (!UDRS->fd_ref--) {
3681 DPRINT("floppy_release with fd_ref == 0");
3682 UDRS->fd_ref = 0;
3683 }
3684 if (!UDRS->fd_ref)
3685 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003686 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003687
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 return 0;
3689}
3690
3691/*
3692 * floppy_open check for aliasing (/dev/fd0 can be the same as
3693 * /dev/PS0 etc), and disallows simultaneous access to the same
3694 * drive with different device numbers.
3695 */
Al Viroa4af9b42008-03-02 09:27:55 -05003696static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697{
Al Viroa4af9b42008-03-02 09:27:55 -05003698 int drive = (long)bdev->bd_disk->private_data;
3699 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 int try;
3701 int res = -EBUSY;
3702 char *tmp;
3703
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003704 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003706 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 goto out2;
3708
3709 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3710 USETF(FD_DISK_CHANGED);
3711 USETF(FD_VERIFY);
3712 }
3713
Al Viroa4af9b42008-03-02 09:27:55 -05003714 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 goto out2;
3716
Al Viroa4af9b42008-03-02 09:27:55 -05003717 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 UDRS->fd_ref = -1;
3719 else
3720 UDRS->fd_ref++;
3721
Al Viroa4af9b42008-03-02 09:27:55 -05003722 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723
3724 res = -ENXIO;
3725
3726 if (!floppy_track_buffer) {
3727 /* if opening an ED drive, reserve a big buffer,
3728 * else reserve a small one */
3729 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3730 try = 64; /* Only 48 actually useful */
3731 else
3732 try = 32; /* Only 24 actually useful */
3733
3734 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3735 if (!tmp && !floppy_track_buffer) {
3736 try >>= 1; /* buffer only one side */
3737 INFBOUND(try, 16);
3738 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3739 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003740 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 if (!tmp && !floppy_track_buffer) {
3743 DPRINT("Unable to allocate DMA memory\n");
3744 goto out;
3745 }
3746 if (floppy_track_buffer) {
3747 if (tmp)
3748 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3749 } else {
3750 buffer_min = buffer_max = -1;
3751 floppy_track_buffer = tmp;
3752 max_buffer_sectors = try;
3753 }
3754 }
3755
Al Viroa4af9b42008-03-02 09:27:55 -05003756 new_dev = MINOR(bdev->bd_dev);
3757 UDRS->fd_device = new_dev;
3758 set_capacity(disks[drive], floppy_sizes[new_dev]);
3759 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 if (buffer_drive == drive)
3761 buffer_track = -1;
3762 }
3763
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 if (UFDCS->rawcmd == 1)
3765 UFDCS->rawcmd = 2;
3766
Al Viroa4af9b42008-03-02 09:27:55 -05003767 if (!(mode & FMODE_NDELAY)) {
3768 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003770 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 if (UTESTF(FD_DISK_CHANGED))
3772 goto out;
3773 }
3774 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003775 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 goto out;
3777 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003778 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 return 0;
3780out:
3781 if (UDRS->fd_ref < 0)
3782 UDRS->fd_ref = 0;
3783 else
3784 UDRS->fd_ref--;
3785 if (!UDRS->fd_ref)
3786 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003788 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 return res;
3790}
3791
3792/*
3793 * Check if the disk has been changed or if a change has been faked.
3794 */
3795static int check_floppy_change(struct gendisk *disk)
3796{
3797 int drive = (long)disk->private_data;
3798
3799 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3800 return 1;
3801
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003802 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 lock_fdc(drive, 0);
3804 poll_drive(0, 0);
3805 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 }
3807
3808 if (UTESTF(FD_DISK_CHANGED) ||
3809 UTESTF(FD_VERIFY) ||
3810 test_bit(drive, &fake_change) ||
3811 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3812 return 1;
3813 return 0;
3814}
3815
3816/*
3817 * This implements "read block 0" for floppy_revalidate().
3818 * Needed for format autodetection, checking whether there is
3819 * a disk in the drive, and whether that disk is writable.
3820 */
3821
NeilBrown6712ecf2007-09-27 12:47:43 +02003822static void floppy_rb0_complete(struct bio *bio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 int err)
3824{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826}
3827
3828static int __floppy_read_block_0(struct block_device *bdev)
3829{
3830 struct bio bio;
3831 struct bio_vec bio_vec;
3832 struct completion complete;
3833 struct page *page;
3834 size_t size;
3835
3836 page = alloc_page(GFP_NOIO);
3837 if (!page) {
3838 process_fd_request();
3839 return -ENOMEM;
3840 }
3841
3842 size = bdev->bd_block_size;
3843 if (!size)
3844 size = 1024;
3845
3846 bio_init(&bio);
3847 bio.bi_io_vec = &bio_vec;
3848 bio_vec.bv_page = page;
3849 bio_vec.bv_len = size;
3850 bio_vec.bv_offset = 0;
3851 bio.bi_vcnt = 1;
3852 bio.bi_idx = 0;
3853 bio.bi_size = size;
3854 bio.bi_bdev = bdev;
3855 bio.bi_sector = 0;
3856 init_completion(&complete);
3857 bio.bi_private = &complete;
3858 bio.bi_end_io = floppy_rb0_complete;
3859
3860 submit_bio(READ, &bio);
3861 generic_unplug_device(bdev_get_queue(bdev));
3862 process_fd_request();
3863 wait_for_completion(&complete);
3864
3865 __free_page(page);
3866
3867 return 0;
3868}
3869
3870/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3871 * the bootblock (block 0). "Autodetection" is also needed to check whether
3872 * there is a disk in the drive at all... Thus we also do it for fixed
3873 * geometry formats */
3874static int floppy_revalidate(struct gendisk *disk)
3875{
3876 int drive = (long)disk->private_data;
3877#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3878 int cf;
3879 int res = 0;
3880
3881 if (UTESTF(FD_DISK_CHANGED) ||
3882 UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
3883 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003884 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 return -EFAULT;
3886 }
3887 lock_fdc(drive, 0);
3888 cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
3889 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3890 process_fd_request(); /*already done by another thread */
3891 return 0;
3892 }
3893 UDRS->maxblock = 0;
3894 UDRS->maxtrack = 0;
3895 if (buffer_drive == drive)
3896 buffer_track = -1;
3897 clear_bit(drive, &fake_change);
3898 UCLEARF(FD_DISK_CHANGED);
3899 if (cf)
3900 UDRS->generation++;
3901 if (NO_GEOM) {
3902 /* auto-sensing */
3903 res = __floppy_read_block_0(opened_bdev[drive]);
3904 } else {
3905 if (cf)
3906 poll_drive(0, FD_RAW_NEED_DISK);
3907 process_fd_request();
3908 }
3909 }
3910 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3911 return res;
3912}
3913
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003914static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003915 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003916 .open = floppy_open,
3917 .release = floppy_release,
3918 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003919 .getgeo = fd_getgeo,
3920 .media_changed = check_floppy_change,
3921 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924/*
3925 * Floppy Driver initialization
3926 * =============================
3927 */
3928
3929/* Determine the floppy disk controller type */
3930/* This routine was written by David C. Niemi */
3931static char __init get_fdc_version(void)
3932{
3933 int r;
3934
3935 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3936 if (FDCS->reset)
3937 return FDC_NONE;
3938 if ((r = result()) <= 0x00)
3939 return FDC_NONE; /* No FDC present ??? */
3940 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003941 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3943 }
3944 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003945 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3946 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 return FDC_UNKNOWN;
3948 }
3949
3950 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003951 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3953 }
3954
3955 output_byte(FD_PERPENDICULAR);
3956 if (need_more_output() == MORE_OUTPUT) {
3957 output_byte(0);
3958 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003959 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 return FDC_82072A; /* 82072A as found on Sparcs. */
3961 }
3962
3963 output_byte(FD_UNLOCK);
3964 r = result();
3965 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003966 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
3968 * LOCK/UNLOCK */
3969 }
3970 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003971 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3972 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 return FDC_UNKNOWN;
3974 }
3975 output_byte(FD_PARTID);
3976 r = result();
3977 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003978 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3979 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 return FDC_UNKNOWN;
3981 }
3982 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003983 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 return FDC_82077; /* Revised 82077AA passes all the tests */
3985 }
3986 switch (reply_buffer[0] >> 5) {
3987 case 0x0:
3988 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003989 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 return FDC_82078;
3991 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003992 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 return FDC_82078;
3994 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003995 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 return FDC_S82078B;
3997 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003998 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 return FDC_87306;
4000 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004001 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4002 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 return FDC_82078_UNKN;
4004 }
4005} /* get_fdc_version */
4006
4007/* lilo configuration */
4008
4009static void __init floppy_set_flags(int *ints, int param, int param2)
4010{
4011 int i;
4012
4013 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4014 if (param)
4015 default_drive_params[i].params.flags |= param2;
4016 else
4017 default_drive_params[i].params.flags &= ~param2;
4018 }
4019 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4020}
4021
4022static void __init daring(int *ints, int param, int param2)
4023{
4024 int i;
4025
4026 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4027 if (param) {
4028 default_drive_params[i].params.select_delay = 0;
4029 default_drive_params[i].params.flags |=
4030 FD_SILENT_DCL_CLEAR;
4031 } else {
4032 default_drive_params[i].params.select_delay =
4033 2 * HZ / 100;
4034 default_drive_params[i].params.flags &=
4035 ~FD_SILENT_DCL_CLEAR;
4036 }
4037 }
4038 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4039}
4040
4041static void __init set_cmos(int *ints, int dummy, int dummy2)
4042{
4043 int current_drive = 0;
4044
4045 if (ints[0] != 2) {
4046 DPRINT("wrong number of parameters for CMOS\n");
4047 return;
4048 }
4049 current_drive = ints[1];
4050 if (current_drive < 0 || current_drive >= 8) {
4051 DPRINT("bad drive for set_cmos\n");
4052 return;
4053 }
4054#if N_FDC > 1
4055 if (current_drive >= 4 && !FDC2)
4056 FDC2 = 0x370;
4057#endif
4058 DP->cmos = ints[2];
4059 DPRINT("setting CMOS code to %d\n", ints[2]);
4060}
4061
4062static struct param_table {
4063 const char *name;
4064 void (*fn) (int *ints, int param, int param2);
4065 int *var;
4066 int def_param;
4067 int param2;
4068} config_params[] __initdata = {
4069 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4070 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4071 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4072 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4073 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4074 {"daring", daring, NULL, 1, 0},
4075#if N_FDC > 1
4076 {"two_fdc", NULL, &FDC2, 0x370, 0},
4077 {"one_fdc", NULL, &FDC2, 0, 0},
4078#endif
4079 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4080 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4081 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4082 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4083 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4084 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4085 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4086 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4087 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4088 {"nofifo", NULL, &no_fifo, 0x20, 0},
4089 {"usefifo", NULL, &no_fifo, 0, 0},
4090 {"cmos", set_cmos, NULL, 0, 0},
4091 {"slow", NULL, &slow_floppy, 1, 0},
4092 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4093 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4094 {"L40SX", NULL, &print_unex, 0, 0}
4095
4096 EXTRA_FLOPPY_PARAMS
4097};
4098
4099static int __init floppy_setup(char *str)
4100{
4101 int i;
4102 int param;
4103 int ints[11];
4104
4105 str = get_options(str, ARRAY_SIZE(ints), ints);
4106 if (str) {
4107 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4108 if (strcmp(str, config_params[i].name) == 0) {
4109 if (ints[0])
4110 param = ints[1];
4111 else
4112 param = config_params[i].def_param;
4113 if (config_params[i].fn)
4114 config_params[i].
4115 fn(ints, param,
4116 config_params[i].param2);
4117 if (config_params[i].var) {
4118 DPRINT("%s=%d\n", str, param);
4119 *config_params[i].var = param;
4120 }
4121 return 1;
4122 }
4123 }
4124 }
4125 if (str) {
4126 DPRINT("unknown floppy option [%s]\n", str);
4127
4128 DPRINT("allowed options are:");
4129 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004130 pr_cont(" %s", config_params[i].name);
4131 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 } else
4133 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004134 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 return 0;
4136}
4137
4138static int have_no_fdc = -ENODEV;
4139
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004140static ssize_t floppy_cmos_show(struct device *dev,
4141 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004142{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004143 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004144 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004145
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004146 drive = p->id;
4147 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004148}
Joe Perches48c8cee2010-03-10 15:20:45 -08004149
4150DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004151
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152static void floppy_device_release(struct device *dev)
4153{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154}
4155
Frans Popc90cd332009-07-25 22:24:54 +02004156static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004157{
4158 int fdc;
4159
4160 for (fdc = 0; fdc < N_FDC; fdc++)
4161 if (FDCS->address != -1)
4162 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4163
4164 return 0;
4165}
4166
Alexey Dobriyan47145212009-12-14 18:00:08 -08004167static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004168 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004169 .restore = floppy_resume,
4170};
4171
4172static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004173 .driver = {
4174 .name = "floppy",
Frans Popc90cd332009-07-25 22:24:54 +02004175 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004176 },
4177};
4178
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004179static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
4181static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4182{
4183 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4184 if (drive >= N_DRIVE ||
4185 !(allowed_drive_mask & (1 << drive)) ||
4186 fdc_state[FDC(drive)].version == FDC_NONE)
4187 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004188 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 return NULL;
4190 *part = 0;
4191 return get_disk(disks[drive]);
4192}
4193
4194static int __init floppy_init(void)
4195{
4196 int i, unit, drive;
4197 int err, dr;
4198
Kumar Gala68e1ee62008-09-22 14:41:31 -07004199#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004200 if (check_legacy_ioport(FDC1))
4201 return -ENODEV;
4202#endif
4203
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 raw_cmd = NULL;
4205
4206 for (dr = 0; dr < N_DRIVE; dr++) {
4207 disks[dr] = alloc_disk(1);
4208 if (!disks[dr]) {
4209 err = -ENOMEM;
4210 goto out_put_disk;
4211 }
4212
4213 disks[dr]->major = FLOPPY_MAJOR;
4214 disks[dr]->first_minor = TOMINOR(dr);
4215 disks[dr]->fops = &floppy_fops;
4216 sprintf(disks[dr]->disk_name, "fd%d", dr);
4217
4218 init_timer(&motor_off_timer[dr]);
4219 motor_off_timer[dr].data = dr;
4220 motor_off_timer[dr].function = motor_off_callback;
4221 }
4222
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 err = register_blkdev(FLOPPY_MAJOR, "fd");
4224 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004225 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004227 err = platform_driver_register(&floppy_driver);
4228 if (err)
4229 goto out_unreg_blkdev;
4230
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4232 if (!floppy_queue) {
4233 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004234 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004236 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
4238 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4239 floppy_find, NULL, NULL);
4240
4241 for (i = 0; i < 256; i++)
4242 if (ITYPE(i))
4243 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4244 else
4245 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4246
4247 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4248 config_types();
4249
4250 for (i = 0; i < N_FDC; i++) {
4251 fdc = i;
4252 CLEARSTRUCT(FDCS);
4253 FDCS->dtr = -1;
4254 FDCS->dor = 0x4;
4255#if defined(__sparc__) || defined(__mc68000__)
4256 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
4257#ifdef __mc68000__
4258 if (MACH_IS_SUN3X)
4259#endif
4260 FDCS->version = FDC_82072A;
4261#endif
4262 }
4263
4264 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 fdc_state[0].address = FDC1;
4266 if (fdc_state[0].address == -1) {
4267 del_timer(&fd_timeout);
4268 err = -ENODEV;
4269 goto out_unreg_region;
4270 }
4271#if N_FDC > 1
4272 fdc_state[1].address = FDC2;
4273#endif
4274
4275 fdc = 0; /* reset fdc in case of unexpected interrupt */
4276 err = floppy_grab_irq_and_dma();
4277 if (err) {
4278 del_timer(&fd_timeout);
4279 err = -EBUSY;
4280 goto out_unreg_region;
4281 }
4282
4283 /* initialise drive state */
4284 for (drive = 0; drive < N_DRIVE; drive++) {
4285 CLEARSTRUCT(UDRS);
4286 CLEARSTRUCT(UDRWE);
4287 USETF(FD_DISK_NEWCHANGE);
4288 USETF(FD_DISK_CHANGED);
4289 USETF(FD_VERIFY);
4290 UDRS->fd_device = -1;
4291 floppy_track_buffer = NULL;
4292 max_buffer_sectors = 0;
4293 }
4294 /*
4295 * Small 10 msec delay to let through any interrupt that
4296 * initialization might have triggered, to not
4297 * confuse detection:
4298 */
4299 msleep(10);
4300
4301 for (i = 0; i < N_FDC; i++) {
4302 fdc = i;
4303 FDCS->driver_version = FD_DRIVER_VERSION;
4304 for (unit = 0; unit < 4; unit++)
4305 FDCS->track[unit] = 0;
4306 if (FDCS->address == -1)
4307 continue;
4308 FDCS->rawcmd = 2;
4309 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4310 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004311 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 FDCS->address = -1;
4313 FDCS->version = FDC_NONE;
4314 continue;
4315 }
4316 /* Try to determine the floppy controller type */
4317 FDCS->version = get_fdc_version();
4318 if (FDCS->version == FDC_NONE) {
4319 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004320 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 FDCS->address = -1;
4322 continue;
4323 }
4324 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4325 can_use_virtual_dma = 0;
4326
4327 have_no_fdc = 0;
4328 /* Not all FDCs seem to be able to handle the version command
4329 * properly, so force a reset for the standard FDC clones,
4330 * to avoid interrupt garbage.
4331 */
4332 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4333 }
4334 fdc = 0;
4335 del_timer(&fd_timeout);
4336 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 initialising = 0;
4338 if (have_no_fdc) {
4339 DPRINT("no floppy controllers found\n");
4340 err = have_no_fdc;
4341 goto out_flush_work;
4342 }
4343
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 for (drive = 0; drive < N_DRIVE; drive++) {
4345 if (!(allowed_drive_mask & (1 << drive)))
4346 continue;
4347 if (fdc_state[FDC(drive)].version == FDC_NONE)
4348 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004349
4350 floppy_device[drive].name = floppy_device_name;
4351 floppy_device[drive].id = drive;
4352 floppy_device[drive].dev.release = floppy_device_release;
4353
4354 err = platform_device_register(&floppy_device[drive]);
4355 if (err)
4356 goto out_flush_work;
4357
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004358 err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
4359 if (err)
4360 goto out_unreg_platform_dev;
4361
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 /* to be cleaned up... */
4363 disks[drive]->private_data = (void *)(long)drive;
4364 disks[drive]->queue = floppy_queue;
4365 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004366 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 add_disk(disks[drive]);
4368 }
4369
4370 return 0;
4371
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004372out_unreg_platform_dev:
4373 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374out_flush_work:
4375 flush_scheduled_work();
4376 if (usage_count)
4377 floppy_release_irq_and_dma();
4378out_unreg_region:
4379 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4380 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004381out_unreg_driver:
4382 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383out_unreg_blkdev:
4384 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385out_put_disk:
4386 while (dr--) {
4387 del_timer(&motor_off_timer[dr]);
4388 put_disk(disks[dr]);
4389 }
4390 return err;
4391}
4392
4393static DEFINE_SPINLOCK(floppy_usage_lock);
4394
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004395static const struct io_region {
4396 int offset;
4397 int size;
4398} io_regions[] = {
4399 { 2, 1 },
4400 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4401 { 4, 2 },
4402 /* address + 6 is reserved, and may be taken by IDE.
4403 * Unfortunately, Adaptec doesn't know this :-(, */
4404 { 7, 1 },
4405};
4406
4407static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4408{
4409 while (p != io_regions) {
4410 p--;
4411 release_region(FDCS->address + p->offset, p->size);
4412 }
4413}
4414
4415#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4416
4417static int floppy_request_regions(int fdc)
4418{
4419 const struct io_region *p;
4420
4421 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
4422 if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
4423 DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
4424 floppy_release_allocated_regions(fdc, p);
4425 return -EBUSY;
4426 }
4427 }
4428 return 0;
4429}
4430
4431static void floppy_release_regions(int fdc)
4432{
4433 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4434}
4435
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436static int floppy_grab_irq_and_dma(void)
4437{
4438 unsigned long flags;
4439
4440 spin_lock_irqsave(&floppy_usage_lock, flags);
4441 if (usage_count++) {
4442 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4443 return 0;
4444 }
4445 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004446
4447 /*
4448 * We might have scheduled a free_irq(), wait it to
4449 * drain first:
4450 */
4451 flush_scheduled_work();
4452
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 if (fd_request_irq()) {
4454 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4455 FLOPPY_IRQ);
4456 spin_lock_irqsave(&floppy_usage_lock, flags);
4457 usage_count--;
4458 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4459 return -1;
4460 }
4461 if (fd_request_dma()) {
4462 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4463 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004464 if (can_use_virtual_dma & 2)
4465 use_virtual_dma = can_use_virtual_dma = 1;
4466 if (!(can_use_virtual_dma & 1)) {
4467 fd_free_irq();
4468 spin_lock_irqsave(&floppy_usage_lock, flags);
4469 usage_count--;
4470 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4471 return -1;
4472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 }
4474
4475 for (fdc = 0; fdc < N_FDC; fdc++) {
4476 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004477 if (floppy_request_regions(fdc))
4478 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 }
4480 }
4481 for (fdc = 0; fdc < N_FDC; fdc++) {
4482 if (FDCS->address != -1) {
4483 reset_fdc_info(1);
4484 fd_outb(FDCS->dor, FD_DOR);
4485 }
4486 }
4487 fdc = 0;
4488 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4489
4490 for (fdc = 0; fdc < N_FDC; fdc++)
4491 if (FDCS->address != -1)
4492 fd_outb(FDCS->dor, FD_DOR);
4493 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004494 * The driver will try and free resources and relies on us
4495 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 */
4497 fdc = 0;
4498 irqdma_allocated = 1;
4499 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004500cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 fd_free_irq();
4502 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004503 while (--fdc >= 0)
4504 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 spin_lock_irqsave(&floppy_usage_lock, flags);
4506 usage_count--;
4507 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4508 return -1;
4509}
4510
4511static void floppy_release_irq_and_dma(void)
4512{
4513 int old_fdc;
4514#ifdef FLOPPY_SANITY_CHECK
4515#ifndef __sparc__
4516 int drive;
4517#endif
4518#endif
4519 long tmpsize;
4520 unsigned long tmpaddr;
4521 unsigned long flags;
4522
4523 spin_lock_irqsave(&floppy_usage_lock, flags);
4524 if (--usage_count) {
4525 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4526 return;
4527 }
4528 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4529 if (irqdma_allocated) {
4530 fd_disable_dma();
4531 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004532 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 irqdma_allocated = 0;
4534 }
4535 set_dor(0, ~0, 8);
4536#if N_FDC > 1
4537 set_dor(1, ~8, 0);
4538#endif
4539 floppy_enable_hlt();
4540
4541 if (floppy_track_buffer && max_buffer_sectors) {
4542 tmpsize = max_buffer_sectors * 1024;
4543 tmpaddr = (unsigned long)floppy_track_buffer;
4544 floppy_track_buffer = NULL;
4545 max_buffer_sectors = 0;
4546 buffer_min = buffer_max = -1;
4547 fd_dma_mem_free(tmpaddr, tmpsize);
4548 }
4549#ifdef FLOPPY_SANITY_CHECK
4550#ifndef __sparc__
4551 for (drive = 0; drive < N_FDC * 4; drive++)
4552 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004553 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554#endif
4555
4556 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004557 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004559 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004560 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004561 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562#endif
4563 old_fdc = fdc;
4564 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004565 if (FDCS->address != -1)
4566 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 fdc = old_fdc;
4568}
4569
4570#ifdef MODULE
4571
4572static char *floppy;
4573
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574static void __init parse_floppy_cfg_string(char *cfg)
4575{
4576 char *ptr;
4577
4578 while (*cfg) {
4579 for (ptr = cfg; *cfg && *cfg != ' ' && *cfg != '\t'; cfg++) ;
4580 if (*cfg) {
4581 *cfg = '\0';
4582 cfg++;
4583 }
4584 if (*ptr)
4585 floppy_setup(ptr);
4586 }
4587}
4588
Jon Schindler7afea3b2008-04-29 00:59:21 -07004589static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590{
4591 if (floppy)
4592 parse_floppy_cfg_string(floppy);
4593 return floppy_init();
4594}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004595module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596
Jon Schindler7afea3b2008-04-29 00:59:21 -07004597static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598{
4599 int drive;
4600
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4602 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004603 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604
4605 for (drive = 0; drive < N_DRIVE; drive++) {
4606 del_timer_sync(&motor_off_timer[drive]);
4607
4608 if ((allowed_drive_mask & (1 << drive)) &&
4609 fdc_state[FDC(drive)].version != FDC_NONE) {
4610 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004611 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4612 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 }
4614 put_disk(disks[drive]);
4615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616
4617 del_timer_sync(&fd_timeout);
4618 del_timer_sync(&fd_timer);
4619 blk_cleanup_queue(floppy_queue);
4620
4621 if (usage_count)
4622 floppy_release_irq_and_dma();
4623
4624 /* eject disk, if any */
4625 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626}
Joe Perches48c8cee2010-03-10 15:20:45 -08004627
Jon Schindler7afea3b2008-04-29 00:59:21 -07004628module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629
4630module_param(floppy, charp, 0);
4631module_param(FLOPPY_IRQ, int, 0);
4632module_param(FLOPPY_DMA, int, 0);
4633MODULE_AUTHOR("Alain L. Knaff");
4634MODULE_SUPPORTED_DEVICE("fd");
4635MODULE_LICENSE("GPL");
4636
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004637/* This doesn't actually get used other than for module information */
4638static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004639 {"PNP0700", 0},
4640 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004641};
Joe Perches48c8cee2010-03-10 15:20:45 -08004642
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004643MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4644
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645#else
4646
4647__setup("floppy=", floppy_setup);
4648module_init(floppy_init)
4649#endif
4650
4651MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);